proyecto-clean-architecture Svelte Themes

Proyecto Clean Architecture

Chat con Clean Architecture en Go y Svelte

Message Service — Clean Architecture

Qué es Clean Architecture

Clean Architecture es un estilo de organizar el código en círculos concéntricos donde el centro es lo mas importante.

La regla clave:

Una capa mas interna no conoce ni depende de una más externa. Las dependencias solo apuntan hacia adentro.

Esto significa que el dominio:

  • Define sus propias interfaces (por ejemplo MessageRepository) según lo que necesita.
  • Las capas externas implementan esas interfaces sin que el dominio sepa cómo lo hacen.
Capa Qué contiene
domain/ Entidades con comportamiento, reglas de negocio e interfaces que el dominio necesita.
client/ Servidores (HTTP, gRPC), persistencia (memoria, disco, SQLite), inyección de dependencias y cualquier detalle de infraestructura.

Estructura del proyecto

back/
├── main.go                                  # Punto de entrada
├── go.mod                                   # Definición del módulo Go
│
├── domain/                                  # CAPA INTERNA — lógica de negocio
│   ├── message/
│   │   ├── message.go                       # Entidad Message + errores + factory
│   │   └── repository.go                    # Interfaz MessageRepository
│   └── service.go                           # Casos de uso (orquesta entidad + repo)
│
└── client/                                  # CAPA EXTERNA — infraestructura
    ├── persistence/
    │   ├── memory/
    │   │   └── repository.go                # Implementación en memoria (slice)
    │   ├── disk/
    │   │   └── repository.go                # Implementación en archivo JSON
    │   └── sqlite/
    │       └── repository.go                # Implementación en SQLite
    └── server/
        ├── rest/
        │   └── handler.go                   # Servidor HTTP REST
        ├── grpc/
        │   └── server.go                    # Servidor gRPC (esqueleto)
        └── dual/
            └── dual.go                      # Levanta REST + gRPC (esqueleto)

Flujo de una petición (ejemplo)

POST /messages {"author": "Ana", "text": "Hola"}
       │
       ▼
 ┌─────────────────────┐
 │  rest.Handler        │  Deserializa JSON, llama al servicio
 │  handleSend()        │
 └──────────┬───────────┘
            │
            ▼
 ┌─────────────────────┐
 │  domain.Service      │  Llama a message.NewMessage() → valida
 │  SendMessage()       │  Llama a repo.Save()
 └──────────┬───────────┘
            │
            ▼
 ┌─────────────────────┐
 │  memory/disk/sqlite  │  Persiste según la implementación
 │  Save()              │  inyectada
 └──────────┬───────────┘
            │
            ▼
 ┌─────────────────────┐
 │  rest.Handler        │  Responde HTTP 201 con el Message
 │  respondJSON()       │  serializado a JSON
 └─────────────────────┘

Mi punto de vista: por qué lo pensé así

La entidad

Message

Tiene cuatro campos: ID, Author, Text, Timestamp.

Campo Regla
ID Tiene que ser unico
Author No puede estar vacío
Text Tiene cierta longitud
Timestamp Se genera con la hora actual

La interfaz MessageRepository (contrato)

type MessageRepository interface {
    Save(msg Message) error
    GetAll() ([]Message, error)
    Delete(id string) error
}

Está definida en el dominio porque es lo que el dominio necesita para funcionar: que alguien le permita guardar, listar y borrar mensajes. No le importa quién ni cómo lo haga.

El orquestador (MessageService)

Coordina los pasos sin meter lógica pesada. SendMessage crea el mensaje con el factory (ahí se valida) y lo guarda. ListMessages y DeleteMessage solo delegan al repo, pero si mañana necesito permisos o paginación, el service es el lugar para agregarlo.

Recibe la interfaz MessageRepository, no una implementación concreta. Eso es lo que permite cambiar de persistor sin tocar una línea del dominio.

El client (persistencia + servidor)

Los tres persistors (memory, disk, SQLite) implementan la misma interfaz. Cambiar de uno a otro es cambiar un case en main.go. El dominio no se entera. Las tres implementaciones importan al dominio; el dominio no importa a ninguna de ellas.

El handler REST traduce HTTP ↔ dominio. No tiene lógica de negocio: no valida campos (eso lo hace la entidad), no decide cómo guardar (eso lo hace el repo). Solo mapea errores de dominio a códigos HTTP (400, 404, 500).


Cómo ejecutar

chmod +x run.sh

./run.sh

Top categories

Loading Svelte Themes