CLEAN

``

Clean Architecture es un enfoque de diseño de software que busca aislar las reglas de negocio del resto del sistema, garantizando que los detalles técnicos (frameworks, bases de datos, interfaces) puedan cambiar sin afectar la lógica central. Su objetivo es construir sistemas mantenibles, testeables y fácilmente escalables.

Principios base:

  • Separación de concerns (preocupaciones o responsabilidades).
  • Inversión de dependencias: las capas externas dependen de las internas, nunca al revés.
  • Independencia de frameworks y bases de datos.
  • Requiere aplicar los principios SOLID.
  • Comunicación clara entre entidades y capas de negocio.

Inspirado en martinCleanArchitectureCraftsman2018 y el trabajo de Uncle Bob.


Estructura de Capas

1. Entidades (Entities)

  • Representan las reglas de dominio y conceptos de negocio fundamentales.
  • No dependen de frameworks ni de ninguna tecnología externa.
  • Encapsulan la lógica y las invariantes del dominio.
  • Ejemplo: Producto, Cliente, Pedido, Inventario.

2. Casos de Uso (Use Cases)

  • Contienen la lógica de aplicación o de negocio, orquestan entidades para lograr objetivos específicos.
  • Son independientes de la infraestructura.
  • Ejemplo: procesar pedido, calcular impuestos, actualizar stock.

3. Interfaces / Adaptadores

  • Definen cómo interactúan las capas externas (UI, API, CLI) con los casos de uso.
  • Ejemplo: controladores HTTP, interfaces de consola, adaptadores de mensajes, etc.

4. Infraestructura

  • Contiene la implementación concreta de detalles técnicos:
    • Bases de datos
    • Frameworks
    • APIs externas
    • Mecanismos de persistencia
  • Se diseñan para poder reemplazarse fácilmente sin afectar las capas superiores.

Comunicación entre Capas

  • Las dependencias siempre apuntan hacia el centro (de infraestructura → aplicación → dominio).
  • Las capas se comunican mediante interfaces o contratos, no implementaciones directas.
  • Se puede usar Dependency Injection para conectar las implementaciones reales a las interfaces definidas en el dominio o aplicación.

Principios de Diseño Aplicados

  • SOLID: especialmente el principio de Inversión de Dependencia (DIP).
  • Separación de responsabilidades: cada capa cumple un rol único.
  • Aislamiento de cambios: se pueden reemplazar frameworks, migrar bases de datos o actualizar librerías sin tocar la lógica central.
  • Alta cohesión y bajo acoplamiento.

Ejemplo: Proyecto TypeScript Clean Architecture

Referencias prácticas:

Estructura de carpetas típica:


src/
├── domain/
│   ├── entities/
│   └── repositories/
├── application/
│   └── use-cases/
├── infrastructure/
│   ├── database/
│   └── services/
└── interface/
└── controllers/

`


Ejemplo de Código: Inversión de Dependencias

Definición de Repositorio (Dominio)

// domain/repositories/ProductRepository.ts
export interface ProductRepository {
	getById(id: string): Promise<Product>;
	save(product: Product): Promise<void>;
}

`

Caso de Uso (Aplicación)

// application/use-cases/CreateProduct.ts
import { ProductRepository } from "../../domain/repositories/ProductRepository";
import { Product } from "../../domain/entities/Product";

export class CreateProduct {
	constructor(private repo: ProductRepository) {}

	async execute(data: { name: string; price: number }) {
		const product = new Product(data.name, data.price);
		await this.repo.save(product);
		return product;
	}
}

Implementación Concreta (Infraestructura)

// infrastructure/database/InMemoryProductRepository.ts
import { ProductRepository } from "../../domain/repositories/ProductRepository";
import { Product } from "../../domain/entities/Product";

export class InMemoryProductRepository implements ProductRepository {
	private store = new Map<string, Product>();

	async getById(id: string): Promise<Product> {
		return this.store.get(id)!;
	}

	async save(product: Product): Promise<void> {
		this.store.set(product.id, product);
	}
}

Recursos Recomendados


Ideas Clave

  • El negocio manda: todo lo demás se adapta a él.
  • Cambiar detalles no debe romper el sistema.
  • Capas independientes y comunicadas por interfaces.
  • Reglas de negocio inmutables ante cambios triviales.

CLEAN - Expansión de Conceptos Avanzados

``

Extensión de Conceptos Clave

Clean Architecture es un enfoque en constante evolución, aplicable más allá del backend tradicional. A continuación se amplían los conceptos para cubrir las dimensiones organizativas, arquitectónicas y de mantenimiento continuo que complementan la implementación técnica.


1. Mantenibilidad y Escalabilidad

  • Mantenibilidad: la arquitectura limpia permite evolucionar el sistema sin introducir deuda técnica.
    • Cambios en infraestructura o frameworks deben requerir modificaciones mínimas.
    • Las pruebas unitarias se centran en la lógica de dominio, no en detalles de infraestructura.
  • Escalabilidad estructural: las capas pueden escalar independientemente, lo que permite dividir el proyecto en módulos o microservicios manteniendo los mismos principios.

  • Simplicidad progresiva: un sistema Clean no busca complejidad innecesaria, sino una estructura evolutiva, donde los límites se vuelven más definidos a medida que el proyecto crece.

2. Testing en Clean Architecture

Tipos de pruebas por capa

  • Dominio: pruebas puras y determinísticas sobre entidades y lógica de negocio.
  • Casos de uso: validan flujos de aplicación sin tocar infraestructura.
  • Infraestructura: tests de integración sobre adaptadores, controladores y persistencia.

Beneficios

  • Se logra un alto grado de testabilidad sin necesidad de entornos pesados.
  • Permite aplicar TDD (Test-Driven Development) de manera natural: las interfaces se definen antes que las implementaciones.

3. Aplicación Práctica en Proyectos Reales

  • En proyectos grandes, cada bounded context puede aplicar su propia arquitectura limpia.
  • En entornos pequeños, puede simplificarse manteniendo los principios de independencia y separación.
  • Es compatible con patrones como:

Integración con Frameworks Modernos

  • En Node.js y TypeScript puede combinarse con frameworks como NestJS o Express sin perder la estructura limpia.
  • En frontend, los mismos principios pueden aplicarse para modularizar servicios, vistas y lógica de presentación (ej. React, Vue).

4. Patrones y Principios Relacionados

  • CQRS (Command Query Responsibility Segregation):
    • Complementa Clean Architecture separando comandos (acciones) de consultas (lecturas).
  • Event Sourcing:
    • Permite reconstruir el estado del dominio a partir de eventos, manteniendo la independencia de la base de datos.
  • Dependency Injection (DI):
    • Implementación práctica del principio de inversión de dependencias.
  • Ports and Adapters:
    • Cada interacción externa se realiza a través de un puerto (interfaz), conectado a un adaptador concreto.

5. Modularidad y Monorepos

  • Un monorepo bien estructurado puede mantener múltiples contextos de dominio, compartiendo utilidades o contratos comunes.
  • Cada módulo sigue los principios de Clean:
    • domain/ → lógica y entidades puras
    • application/ → casos de uso
    • infrastructure/ → adaptadores concretos
    • interface/ → endpoints, controladores o UIs

Ventaja

Favorece la independencia del despliegue y el reuso entre servicios, facilitando la transición hacia arquitecturas distribuidas.


6. Evolución y Refactorización Continua

  • Clean Architecture no es un estado final, sino un proceso de mejora constante.
  • Se recomienda evaluar periódicamente:
    • Dependencias cruzadas entre capas.
    • Tamaño y cohesión de los casos de uso.
    • Aislamiento del dominio frente a decisiones técnicas.
  • El objetivo es evitar el “Big Ball of Mud”, manteniendo límites claros entre qué hace el sistema (dominio) y cómo lo hace (infraestructura).

7. Extensión a Otros Contextos

En microservicios:

Cada servicio puede implementar su propio dominio limpio, comunicándose mediante eventos o APIs definidas como contratos estables.

En sistemas legacy:

  • Se puede introducir Clean Architecture de forma incremental:
    1. Aislar reglas de negocio existentes.
    2. Definir interfaces claras.
    3. Migrar gradualmente la infraestructura.

En inteligencia artificial y datos:

  • Separar capa de dominio (lógica del problema) de infraestructura de datos (modelos, pipelines, frameworks ML) permite entrenar, sustituir o mejorar modelos sin romper la aplicación.

8. Ejemplo de Integración con DDD y CQRS

// domain/events/ProductCreatedEvent.ts
export class ProductCreatedEvent {
	constructor(public readonly productId: string, public readonly timestamp: Date) {}
}

// application/commands/CreateProductCommand.ts
export class CreateProductCommand {
	constructor(public readonly name: string, public readonly price: number) {}
}

// application/handlers/CreateProductHandler.ts
import { ProductRepository } from "../../domain/repositories/ProductRepository";
import { CreateProductCommand } from "../commands/CreateProductCommand";
import { ProductCreatedEvent } from "../../domain/events/ProductCreatedEvent";

export class CreateProductHandler {
	constructor(private repo: ProductRepository) {}

	async handle(command: CreateProductCommand) {
		const product = await this.repo.save({ name: command.name, price: command.price });
		return new ProductCreatedEvent(product.id, new Date());
	}
}

`


9. Buenas Prácticas

  • Mantener interfaces pequeñas y específicas.
  • Evitar dependencias cíclicas entre módulos.
  • Usar nombres semánticos que reflejen el dominio.
  • Documentar las relaciones entre capas mediante diagramas o notas tipo C4 Model.
  • Aplicar revisiones arquitectónicas periódicas para garantizar la pureza de las capas.

10. Recursos Complementarios


Idea Final

La verdadera esencia de Clean Architecture no está en las capas o nombres de carpetas, sino en preservar la independencia del dominio frente al tiempo, la tecnología y los cambios externos. Un sistema limpio sobrevive a sus frameworks, evoluciona con su negocio y permite a los equipos trabajar con confianza.

CLEAN - Profundización Final

11. Gestión de Dependencias y Versionado Interno

  • En sistemas grandes, la gestión de dependencias internas entre módulos debe ser explícita:
    • Cada capa o módulo debe exponer contratos (interfaces, DTOs, eventos) en lugar de implementaciones.
    • Se recomienda mantener versionado semántico interno, especialmente cuando distintos equipos mantienen módulos separados.
  • En monorepos, herramientas como Nx o Turborepo permiten gestionar dependencias y builds de forma controlada siguiendo principios Clean.

12. Manejo de Errores y Excepciones

  • La arquitectura limpia promueve un flujo de errores consistente:
    • El dominio define sus propias excepciones (DomainError, ValidationError, etc.).
    • Los casos de uso traducen errores de negocio a tipos manejables por la infraestructura.
    • La capa de interfaz (ej. HTTP) transforma los errores en respuestas comprensibles para el usuario o cliente.
  • Evita propagar errores técnicos del framework hacia el dominio.

Ejemplo:

// domain/errors/DomainError.ts
export class DomainError extends Error {
	constructor(message: string) {
		super(message);
		this.name = "DomainError";
	}
}

`


13. Logging, Observabilidad y Métricas

  • Las capas internas no deben depender de herramientas concretas de logging (ej. Winston, Pino).
  • En su lugar, se define una interfaz genérica en la capa de aplicación:
// application/ports/Logger.ts
export interface Logger {
	info(message: string): void;
	error(message: string, meta?: any): void;
}
  • La implementación concreta (infraestructura) puede variar según el entorno (archivo, consola, servicio externo).
  • Esto mantiene la observabilidad desacoplada del dominio.

14. Seguridad en Clean Architecture

  • Los principios Clean también aplican a la seguridad:

    • La autenticación y autorización se manejan como concerns externos.
    • El dominio no conoce roles ni tokens, solo permisos lógicos o reglas de negocio.
  • Patrón recomendado: Security as a Cross-Cutting Concern.
  • Los middlewares o adaptadores de infraestructura aplican validaciones antes de llegar al caso de uso.

Ejemplo:

// interface/middleware/AuthMiddleware.ts
export function requireAuth(handler: Function) {
	return async (req, res) => {
		const user = await verifyToken(req.headers.authorization);
		if (!user) return res.status(401).send("Unauthorized");
		return handler(req, res, user);
	};
}

15. Integración Asíncrona y Eventos de Dominio

  • El dominio puede publicar eventos para que otras partes del sistema reaccionen sin acoplamiento directo.
  • Estos eventos se definen en la capa de dominio y se manejan en la capa de aplicación o infraestructura.
  • Facilita la integración con colas (RabbitMQ, Kafka, SNS, etc.) sin romper la independencia de capas.

Ejemplo:

// domain/events/ProductUpdatedEvent.ts
export class ProductUpdatedEvent {
	constructor(public readonly id: string, public readonly changes: any) {}
}
  • Los event handlers actúan como suscriptores dentro de la aplicación.
  • Permite construir arquitecturas event-driven respetando Clean Architecture.

16. Documentación y Modelado

  • Clean Architecture promueve una documentación viva:

    • Diagramas C4 o UML simples por módulo.
    • Notas de decisión arquitectónica (ADR) registrando cambios y justificaciones.
  • La documentación debe reflejar intención, dependencias y límites, no implementación.

Ejemplo de estructura de documentación:

/docs
├── architecture-overview.md
├── domain-model.png
├── adr/
│   ├── 001-choice-of-framework.md
│   └── 002-domain-separation.md

17. Migraciones y Transiciones Técnicas

  • Una de las mayores ventajas del enfoque Clean es la facilidad para migrar tecnologías:

    • Cambiar base de datos (MySQL → PostgreSQL → MongoDB).
    • Sustituir frameworks (Express → Fastify → NestJS).
    • Modificar proveedor cloud sin alterar la lógica del dominio.
  • Solo las capas externas se ven afectadas; la capa de dominio permanece inmutable.


18. Automatización y CI/CD

  • La modularidad facilita automatizar pipelines:

    • Tests unitarios → aplicación → integración → despliegue.
  • Cada capa o módulo puede validarse de forma independiente.
  • Se pueden usar herramientas como:

    • eslint y typescript para asegurar consistencia de código.
    • jest o vitest para testing de dominio y casos de uso.
    • husky y lint-staged para prevalidar cambios.

19. Anti-Patrones en Clean Architecture

Evitar estos errores comunes:

  • Anemia del dominio: entidades sin lógica, relegando toda la inteligencia a casos de uso.
  • Dependencias invertidas incorrectamente: el dominio importando infraestructura.
  • Exceso de abstracciones: crear interfaces o capas innecesarias que no aportan valor.
  • Framework-Driven Design: moldear la arquitectura en torno al framework, en lugar del negocio.
  • Controladores gordos, casos de uso finos: mala distribución de responsabilidades.

20. Clean Architecture como Cultura

Más allá del código, es una filosofía de desarrollo:

  • Diseñar para el cambio, no para la rigidez.
  • Fomentar la comprensión colectiva del sistema.
  • Priorizar el dominio y la intención del negocio por encima de herramientas o tendencias.
  • Convertir la arquitectura en un lenguaje compartido dentro del equipo.

21. Síntesis Final

Clean Architecture = Independencia. Independencia del tiempo, frameworks, bases de datos, proveedores y modas tecnológicas.

Su propósito no es la pureza técnica, sino la longevidad del software. Un sistema verdaderamente “clean” puede sobrevivir años, cambiar de infraestructura varias veces y seguir funcionando con la misma claridad en su núcleo de negocio.

CLEAN - Expansión Completa Final

22. Clean Architecture y el Ciclo de Vida del Software

  • La arquitectura limpia influye en todas las etapas del ciclo de vida:
    • Diseño: fomenta pensar en responsabilidades antes de escribir código.
    • Desarrollo: permite trabajo paralelo por capas o módulos.
    • Pruebas: cada capa tiene su propio nivel de testing y aislamiento.
    • Despliegue: la modularidad simplifica empaquetado y CI/CD.
    • Mantenimiento: facilita el reemplazo y la evolución incremental.
  • A lo largo del tiempo, el sistema debe mantener consistencia conceptual, no solo funcional.
    Esto se logra mediante límites claros y respeto por la independencia de las capas.

23. Adaptación a Diferentes Paradigmas

Programación Funcional

  • Se puede aplicar Clean Architecture en entornos funcionales (ej. Elixir, Haskell, [[F#]]).
  • Los casos de uso se definen como funciones puras.
  • Las dependencias externas se inyectan como argumentos.
  • Esto refuerza el principio de pureza del dominio y facilita el testing.

Programación Orientada a Objetos

  • Se enfatiza en entidades ricas y encapsulación de lógica.
  • Los objetos representan conceptos de negocio con comportamiento y estado.
  • Los casos de uso orquestan las entidades y gestionan el flujo de aplicación.

24. Clean Architecture en el Frontend

Aunque nació para el backend, los principios son aplicables en frontend moderno:

  • Dominio: lógica de negocio (validaciones, modelos, cálculos).
  • Aplicación: casos de uso (acciones, flujos de usuario).
  • Infraestructura: APIs, almacenamiento local, frameworks.
  • Interfaz: componentes UI (React, Vue, Svelte).

Ejemplo de estructura en React:


src/  
├── domain/  
│ ├── models/  
│ └── services/  
├── application/  
│ ├── use-cases/  
│ └── state/  
├── infrastructure/  
│ └── api/  
└── ui/  
├── components/  
└── pages/

`

  • Se facilita el testing de lógica sin renderizar interfaz.
  • Permite reutilizar el dominio entre plataformas (web, móvil, escritorio).

25. Clean Architecture en Data y Machine Learning

  • Dominio: define los problemas que el modelo debe resolver.
  • Casos de uso: gestionan entrenamiento, predicción y validación.
  • Infraestructura: contiene el framework (TensorFlow, PyTorch, scikit-learn, etc.).
  • Interfaz: expone endpoints o dashboards.

Beneficios:

  • Separar lógica de negocio de dependencias tecnológicas o del modelo.
  • Permite reemplazar el motor ML sin reescribir la aplicación.
  • Mejora el versionado y reproducibilidad de experimentos.

26. Clean Architecture y Domain Events (Eventos del Dominio)

  • Los eventos del dominio encapsulan hechos significativos del negocio.
  • Son inmutables y se emiten solo cuando algo importante cambia.
  • Facilitan auditoría, replicación de datos y comunicación entre microservicios.

Ejemplo conceptual:

export class OrderPaid {
	constructor(public readonly orderId: string, public readonly paidAt: Date) {}
}

`

  • Los event handlers suscritos ejecutan acciones sin acoplarse al origen (notificaciones, logs, integraciones externas).

27. Aplicación en Arquitecturas Distribuidas

  • En microservicios, cada servicio es un contexto limpio y autónomo.
  • Las comunicaciones interservicio deben basarse en contratos claros (REST, gRPC, eventos).
  • Los principios Clean ayudan a evitar
    • Acoplamiento entre servicios.
    • Duplicación de lógica de dominio.
    • Fuga de detalles técnicos al negocio.

Comunicación entre Servicios

  • Usar DTOs o mensajes específicos.
  • Evitar importar entidades directamente entre servicios.
  • Mantener cada dominio independiente y autocontenido

28. Documentación Viva y Autoexplicable

  • La estructura Clean favorece documentación implícita:
    • Los nombres de carpetas y clases reflejan la intención.
    • Los tests sirven como documentación funcional.
    • Los diagramas de flujo entre capas aclaran dependencias.
  • Se recomienda usar herramientas automáticas:
    • TypeDoc, Compodoc, o Swagger para documentar APIs.
    • Diagramas generados con PlantUML o Mermaid.
  • Mantener un índice de Bounded Contexts y sus dependencias para trazabilidad.

29. Migración hacia Clean Architecture

Migrar un sistema existente:

  1. Identificar reglas de negocio puras.
  2. Aislar dependencias externas.
  3. Crear interfaces para comunicación entre capas.
  4. Reubicar código gradualmente en las nuevas capas.
  5. Eliminar dependencias directas de frameworks dentro del dominio.

Este proceso se puede realizar de forma incremental, sin interrupciones de servicio.


30. Integración con Otros Patrones de Arquitectura

  • Event-Driven Architecture: usa Clean como base para sistemas reactivos y asincrónicos.
  • Microkernel Architecture: Clean puede representar el core, con plugins en infraestructura.
  • Service-Oriented Architecture (SOA): Clean ayuda a mantener coherencia entre servicios.
  • Layered Architecture vs Clean: Clean no solo define capas, sino dirección de dependencias.

31. Clean Architecture y Diseño Organizacional

  • Las capas pueden mapearse con equipos:
    • Dominio → negocio o analistas funcionales.
    • Aplicación → ingenieros de lógica y procesos.
    • Infraestructura → DevOps, integradores o especialistas.
  • Esto promueve alineación entre estructura técnica y estructura organizacional (Ley de Conway).

Beneficio:

Si el software refleja cómo se comunican los equipos, mantenerlo limpio también mejora la comunicación humana.


32. Clean Architecture y Performance

  • Aunque Clean no busca optimización temprana, facilita:
    • Medición clara por capas.
    • Sustitución de implementaciones costosas sin alterar la lógica.
    • Aplicación de patrones de rendimiento (caché, batch, async) solo en infraestructura.
  • Permite mantener la coherencia entre eficiencia y mantenibilidad.

33. Clean Architecture en DevOps y Cloud

  • Las capas se alinean naturalmente con prácticas DevOps:
    • Domain/Application → código versionado y testeado.
    • Infrastructure → gestionada como código (IaC con Terraform, Ansible, Pulumi).
    • Interface → integración continua (pipelines, API Gateway).
  • Clean facilita observabilidad, escalado y despliegue continuo, manteniendo el dominio inmutable ante cambios de entorno cloud.

34. Clean Architecture y Gobernanza Técnica

  • La arquitectura limpia fomenta políticas de gobernanza:
    • Control de dependencias y versiones.
    • Validación automática de capas mediante reglas (ej. depcruise, eslint-import).
    • Revisionez arquitectónicas como parte del proceso de CI.
  • Promueve estándares compartidos y decisiones documentadas en ADR.

35. Conclusión Total

Clean Architecture no es un patrón único, sino un marco de pensamiento.
Su esencia reside en proteger el corazón del negocio de los detalles técnicos, asegurando que el software pueda crecer, adaptarse y sobrevivir a los cambios inevitables del entorno.

“Clean Architecture no trata de frameworks. Trata de independencia, claridad y propósito.”
— Inspirado en martinCleanArchitectureCraftsman2018 y Uncle Bob