Arquitectura Limpia
Estructura sistemas para que la lógica de negocio sea independiente de frameworks.
50 lecciones
ADP: El Principio de Dependencias Acíclicas
No se permiten ciclos en el grafo de dependencias de componentes — los ciclos causan el síndrome de la mañana siguiente e impiden compilaciones y pruebas aisladas.
Límites Arquitectónicos: Trazando Líneas
La arquitectura traza líneas entre lo que importa (reglas de negocio) y lo que no (detalles técnicos) — estas líneas protegen la lógica central del negocio de los cambios en herramientas externas.
¿Qué es la Arquitectura? Soporte del Ciclo de Vida
El propósito principal de la arquitectura es soportar el ciclo de vida del sistema — desarrollo, despliegue, operación y mantenimiento — para maximizar la productividad y minimizar el costo.
Anatomía de un Límite: Cruzando Límites
Al cruzar un límite arquitectónico, las dependencias del código fuente deben apuntar en sentido contrario al flujo de control — el polimorfismo hace esto posible independientemente de quién llama a quién.
Reglas de Negocio y Entidades
Las Reglas de Negocio Críticas existirían incluso sin un ordenador — las Entidades encapsulan estas reglas y datos, formando el núcleo más estable del sistema, independiente de la UI y la persistencia.
Arquitectura Embebida Limpia: Evitando el Firmware
El software no se desgasta, pero el hardware queda obsoleto — una Capa de Abstracción de Hardware evita que la lógica de negocio se convierta en firmware atrapado en un procesador específico.
El Diagrama de Tensión de Componentes
REP, CCP y CRP tiran en direcciones opuestas — los arquitectos deben equilibrar estas tensiones a medida que el proyecto evoluciona del desarrollo a la reutilización.
Componentes: La Unidad de Despliegue
Los componentes son las unidades desplegables más pequeñas — JARs, DLLs, Gemas — los bloques de construcción de una arquitectura de plugins conectados en tiempo de ejecución.
Cohesión de Componentes: El Principio de Reutilización Común
No obligues a los usuarios de un componente a depender de cosas que no necesitan — depender de un componente significa depender de todo lo que contiene.
Modos de Desacoplamiento: Fuente, Despliegue y Servicio
El desacoplamiento puede ocurrir a nivel de código fuente, despliegue o servicio — una buena arquitectura te permite empezar como monolito y evolucionar hacia servicios si los límites están bien definidos.
La Regla de Dependencia en Clean Architecture
🔒Las dependencias del código fuente solo pueden apuntar hacia adentro — nada en un círculo interior puede saber nada de un círculo exterior, manteniendo el núcleo de negocio estable y reutilizable.
Los Detalles: Base de Datos, Web y Frameworks
🔒La base de datos, la capa web y los frameworks son mecanismos de entrega — un buen arquitecto postpone estas decisiones y mantiene las reglas de negocio independientes para evitar un matrimonio tecnológico costoso.
Independencia del Dispositivo
🔒Atar la lógica de negocio a dispositivos de E/S específicos es un error costoso — la arquitectura debe ser agnóstica a si los datos vienen de tarjetas, terminales, archivos o APIs.
DIP: El Principio de Inversión de Dependencias
🔒Las dependencias del código fuente deben apuntar solo a abstracciones — las Fábricas Abstractas crean la frontera arquitectónica entre el código concreto volátil y la política estable.
Inversión de Dependencias: Control sobre las Dependencias
🔒Con interfaces, los arquitectos hacen que las dependencias del código apunten contra el flujo de control, dando control absoluto sobre el acoplamiento.
La Matriz de Eisenhower en el Desarrollo
🔒La arquitectura es importante pero rara vez urgente. Los desarrolladores deben defender la buena estructura frente a la presión del negocio.
Capas de Arquitectura: Entidades y Casos de Uso
🔒Las Entidades contienen reglas de negocio críticas que existen en toda la empresa; los Casos de Uso orquestan flujos específicos de la aplicación y están aislados de los cambios de UI y base de datos.
Programación Funcional: El Valor de la Inmutabilidad
🔒La programación funcional disciplina la asignación. La inmutabilidad elimina condiciones de carrera, deadlocks y problemas de actualización concurrente.
El Objetivo de la Arquitectura y el Diseño
🔒El diseño y la arquitectura son lo mismo: su verdadera medida es el esfuerzo necesario para satisfacer al cliente minimizando el costo a largo plazo.
El Patrón Humble Object
🔒Separa el comportamiento difícil de probar del fácil de probar — el Presentador prepara toda la lógica en un ViewModel testeable; la Vista es un humble object que solo muestra lo que recibe.
El Diablo Está en los Detalles de Implementación
🔒La mejor arquitectura fracasa sin un uso disciplinado de los modificadores de acceso — el compilador es tu aliado más fuerte para hacer cumplir las reglas de Clean Architecture en todo el equipo.
Adaptadores de Interfaz y Paso de Datos
🔒Los Adaptadores de Interfaz convierten datos entre el formato que entienden los casos de uso y el que necesitan los sistemas externos — los límites siempre se cruzan con DTOs simples, nunca con entidades crudas o filas de BD.
ISP: El Principio de Segregación de Interfaces
🔒No dependas de cosas que no usas — las interfaces gordas fuerzan recompilaciones innecesarias y acoplamiento a fallos en código no relacionado.
Mantener las Opciones Abiertas
🔒Un buen arquitecto maximiza el número de decisiones aún no tomadas — separando la política de los detalles para que las elecciones de base de datos y framework puedan postponerse hasta saber más.
Desacoplamiento por Capas
🔒Separa lo que cambia a diferentes ritmos — UI, reglas de negocio de aplicación, reglas de dominio y base de datos cambian por razones distintas y deben ser capas horizontales.
LSP: El Principio de Sustitución de Liskov
🔒Los subtipos deben ser sustituibles por sus tipos base — las violaciones del LSP fuerzan lógica costosa de casos especiales en el diseño.
El Componente Main: El Último Detalle
🔒Main es el componente más sucio y de más bajo nivel — el punto de entrada que conecta todas las dependencias y entrega el control a la arquitectura limpia que está sobre él.
La Secuencia Principal: El Equilibrio A/I
🔒Los componentes deben equilibrar Abstracción (A) e Inestabilidad (I) — la Zona de Dolor (estable+concreto) y la Zona de Inutilidad (abstracto+inestable) son antipatrones a evitar.
OCP: El Principio Abierto/Cerrado
🔒Los artefactos de software deben estar abiertos para extensión pero cerrados para modificación — añadir nuevo comportamiento debe añadir código, no cambiarlo.
POO: La Realidad de la Encapsulación
🔒La POO no inventó la encapsulación — C tenía encapsulación perfecta antes de que C++ y Java la debilitaran con los archivos de cabecera.
Paquete por Componente: El Enfoque Híbrido
🔒Agrupa toda la responsabilidad de un límite de funcionalidad limpio en un paquete — la persistencia interna y la lógica permanecen privadas, el compilador hace cumplir lo que es visible para el resto del sistema.
Estrategias de Organización: Paquete por Funcionalidad
🔒Agrupa el código por funcionalidad de dominio — los paquetes de nivel superior revelan el negocio, cada funcionalidad está co-ubicada y la búsqueda mejora drásticamente a medida que el sistema crece.
Estrategias de Organización: Paquete por Capa
🔒La organización de código más simple agrupa por capa técnica (web/servicio/repositorio) — fácil de comenzar pero oculta la intención del negocio y permite atajos peligrosos entre capas.
Límites Parciales: Estrategias de Anticipación
🔒Los límites arquitectónicos completos son costosos — los límites parciales usando patrones Strategy o Facade preservan puntos de separación futura sin el costo total inicial.
El Antipatrón Periférico
🔒El antipatrón periférico ocurre cuando el código de infraestructura habla directamente con otro código de infraestructura, saltándose el dominio — como el anillo de París, el tráfico fluye alrededor de la ciudad en lugar de a través de ella.
Política y Nivel
🔒El nivel es la distancia a las entradas y salidas — cuanto más lejos de la E/S, mayor el nivel. Las dependencias del código fuente siempre deben apuntar hacia las políticas de más alto nivel y más estables.
Polimorfismo: El Poder de los Plugins
🔒El polimorfismo permite tratar dependencias externas como plugins intercambiables, haciendo que la lógica central sea independiente del dispositivo.
Puertos y Adaptadores (Arquitectura Hexagonal)
🔒El interior es el dominio; el exterior es la infraestructura — el exterior depende del interior, los puertos hablan el lenguaje del dominio y los adaptadores traducen entre el dominio y los sistemas externos.
Programación como Ciencia: Falsificabilidad y Testing
🔒Las pruebas no demuestran corrección, demuestran ausencia de incorrecciones conocidas. La buena arquitectura produce módulos fácilmente falsificables.
Paradigmas de Programación: Disciplina, No Herramientas
🔒Los tres paradigmas imponen disciplina eliminando capacidades, no añadiéndolas.
Cohesión de Componentes: REP y CCP
🔒REP agrupa las clases que se liberan juntas; CCP agrupa las que cambian juntas por la misma razón — ambas reflejan el SRP a escala de componente.
SAP: El Principio de Abstracciones Estables
🔒Un componente debe ser tan abstracto como estable — los componentes más estables deben ser interfaces puras para poder extenderse sin modificarse.
Arquitectura que Grita
🔒La estructura de carpetas debe revelar qué hace el sistema, no qué framework usa — un sistema de salud grita 'Salud', no 'Rails'.
SDP: El Principio de Dependencias Estables
🔒Depende en la dirección de la estabilidad — un componente volátil nunca debe ser dependido por uno estable, o esa estabilidad queda comprometida permanentemente.
Servicios y Microservicios: ¿Son Arquitectura?
🔒Los servicios no definen la arquitectura — un servicio con estructura interna pobre es solo una llamada de función costosa. Los límites arquitectónicos reales pueden existir dentro de un monolito o entre servicios.
SRP: El Principio de Responsabilidad Única
🔒Un módulo debe ser responsable ante un solo actor, evitando que los cambios de un departamento rompan accidentalmente otro.
Programación Estructurada: Disciplina sobre el Control Directo
🔒Dijkstra demostró que el goto sin restricciones es perjudicial. La secuencia, selección e iteración son suficientes para módulos correctos y descomponibles.
El Límite de las Pruebas
🔒Los tests son el círculo arquitectónico más externo — los tests frágiles acoplados a detalles de implementación hacen el sistema rígido; una API de Test desacopla la estructura de tests de la estructura de la aplicación.
Los Dos Valores del Software: Comportamiento vs Estructura
🔒El software tiene valor por su comportamiento y su estructura. Un sistema rígido dejará de funcionar cuando los requisitos cambien.
Desacoplamiento de Casos de Uso
🔒Los casos de uso son cortes verticales que atraviesan todas las capas — desacoplarlos permite que cada uno evolucione independientemente sin que los cambios de un caso de uso colisionen con los de otro.