Está en la página 1de 5

Arquitectura Limpia

En los últimos años hemos visto gran cantidad de ideas sobre arquitectura de
sistemas. Algunas son:

 Hexagonal Architecture (también conocida como Ports and Adapters)


de Alistair Cockburn y adoptada por Steve Freman y Nat Pryce en su
libro Growing Object Oriented Software.
 Onion Architecture de Jeffrey Palermo.
 Screaming Architecture de Uncle Bob.
 DCI de James Coplien y Trygve Reenskaug.
 BCE de Ivar Jacobson expuesto en su libro “Object Oriented Software
Engineering: A Use-Case Driven Approach”.

Aunque todas estas arquitecturas pueden variar en algunos detalles, son muy
similares. Todos tienen el mismo objetivo, que es la separación de intereses o
principios (separation of concerns). Todos los frameworks descritos cumplen
esta separación dividiendo la aplicación en capas. Cada una de estas
arquitecturas produce sistemas con las siguientes características:

 Independiente de frameworks. La arquitectura no depende de la


existencia de ninguna librería cuyas características nos aten a sus
requisitos. Esto permite usar los frameworks como si fueran herramientas,
en lugar de someter el sistema a las restricciones impuestas.
 Testeable. La lógica de negocio se puede testear sin necesidad de la
interfaz de usuario (UI), base de datos, servidor web u otras herramientas
externas.
 Independiente de la UI. La interfaz gráfica de usuario puede cambiar
fácilmente sin cambiar el resto del sistema. Una UI web puede
reemplazarse con una interfaz de consola, sin tener que cambiar la lógica
de negocio.
 Independiente de la base de datos. Puedes cambiar desde una base de
datos en Oracle o SQL Server a MongoDB, BigTable, CouchDB o cualquier
otra. Las reglas del negocio no están ligadas a la base de datos.
 Independiente de factores externos. En realidad tus reglas de negocio
(lógica de negocio) no tienen constancia de nada que provenga del mundo
exterior.

El diagrama de la imagen del principio del artículo es un intento de integrar todas


estas arquitecturas en una sola idea entendible.

La regla de dependencia
Los círculos concéntricos representan diferentes áreas del software. En general,
cuanto más nos alejemos del núcleo mayor es el nivel del software. Los círculos
exteriores son mecanismos mientras que los interiores son políticas. La regla
primordial que hace que esta arquitectura funcione es la regla de dependencia.
Esta regla dice que las dependencias a nivel de código fuente sólo pueden
apuntar hacia dentro. Nada que se encuentre en un círculo interior puede saber
algo sobre lo que hay en un círculo exterior. Particularmente, algo declarado en
un círculo externo no puede ser mencionado desde el código situado en un
círculo interno. Eso incluye funciones, clases, variables o cualquier otra entidad
software. Por la misma razón, los formatos de datos usados en un círculo exterior
no deberían usarse por un círculo interior, especialmente si esos formatos son
generados por algún framework en un círculo situado al exterior. No queremos
que nada de un círculo exterior impacte en los círculos o niveles interiores.

Entidades
Las entidades encapsulan la lógica de negocio de la empresa (hablamos de
software empresarial). Una entidad puede ser un objeto con métodos, o puede
ser un conjunto de estructuras de datos y funciones. No importa mientras las
entidades se puedan re/utilizar desde diferentes aplicaciones de la empresa.

Si no tenemos una empresa, y solo estamos escribiendo una sola aplicación,


entonces esas entidades son los objetos de negocio de solo esa aplicación y no
de la empresa. Encapsulan la mayoría de la lógica general y de alto nivel. Son
los menos propensos a cambiar cuando algo externo cambia. Por ejemplo, no
se espera un cambio en las entidades habiendo modificado la navegación de
una página o la seguridad. Ningún cambio operacional de una aplicación
particular debería afectar a la capa de entidades.

Casos de uso
El software de esta capa contiene reglas de negocio específicas de la aplicación.
Encapsula e implementa todos los casos de uso del sistema. Estos casos de uso
dirigen el flujo de datos hacía y desde las entidades y hacen que las entidades
usen su lógica de negocio empresarial para conseguir el objetivo del caso de
uso. Los cambios en esta capa no deberían afectar a las entidades. Tampoco
esperamos que cambios externos como en la base de datos, algún framework o
la interfaz gráfica afecten a esta capa. Esta capa se encuentra aislada de ese
tipo de principios (concerns). En cambio si esperamos que cambios en las
operaciones de la aplicación afecten a los casos de uso y por tanto al software
de esta capa. Si los detalles de un caso de uso cambian, entonces algo de código
de esta capa cambiará indudablemente.

Interface Adapters (adaptadores de


interfaz)
El software de esta capa es un conjunto de adaptadores que convierten datos
desde el formato más conveniente para el caso de uso y entidades al formato
más conveniente o aceptado por elementos externos como la base de datos o la
web. Es esta capa, por ejemplo, la que contendrá toda la arquitectura MVC de
una interfaz gráfica. Los presentadores, vistas y controladores pertenecen a esta
capa. Los modelos son sólo estructuras que se pasan desde los controladores a
los casos de uso y de vuelta desde los casos de uso a los presentadores
(presenters) y vistas. Del mismo modo, los datos son convertidos en esta capa,
desde la forma de las entidades y casos de uso a la forma conveniente para
cualquiera que sea el framework de persistencia de datos.

El código interior a esta capa/círculo no debería tener constancia de nada


relacionado con la base de datos, por tanto toda sentencia SQL esta restringida
a esta capa y en particular a partes de esta capa que tengan que ver con la base
de datos. También en esta capa están los demás adaptadores encargados de
convertir datos obtenidos de una fuente externa, como un servicio externo, al
formato interno usado por los casos de uso y las entidades.

Frameworks y Drivers
El círculo o capa más externa se compone generalmente de frameworks y
herramientas como la base de datos, el framework web, etc. Normalmente en
esta capa sólo se escribe código que actúa de pegamento con los círculos o
capas interiores. En esta capa es donde van todos los detalles. La web es un
detalle. La base de datos es un detalle. Mantenemos estas cosas fuera del
alcance donde no pueden hacer mucho daño.

¿Sólo cuatro círculos?


No, los círculos son esquemáticos. Puede pasar que necesites más de los cuatro
ya expuestos. No hay ninguna regla que diga que siempre hay que tener los
cuatro. De todas formas, la regla de dependencia hay que aplicarla siempre. Las
dependencias a nivel de código solo apuntan hacia dentro, a capas o círculos
interiores. A medida que profundizamos en la arquitectura, el nivel de abstracción
aumenta. El círculo más exterior tiene un nivel de detalle bajo. A medida que
profundizamos el software se vuelve más abstracto y encapsula políticas de nivel
más alto. El círculo más interior es el más general.

Crossing boundaries (cruzar


límites/fronteras)
En la esquina inferior derecha del diagrama hay un ejemplo de cómo cruzamos
los límites del círculo. Muestra los controladores y presentadores que se
comunican con los casos de uso en la siguiente capa. Tenga en cuenta el flujo
de control. Comienza en el controlador, se mueve a través del caso de uso y
luego termina ejecutando en el presentador. Tenga en cuenta también las
dependencias del código fuente. Cada uno de ellos apunta hacia adentro hacia
los casos de uso.

Normalmente resolvemos esta aparente contradicción usando el principio de


inversión de dependencias. En un lenguaje como Java, por ejemplo,
desarrollaríamos interfaces y relaciones de herencia de tal manera que las
dependencias de código fuente se oponen al flujo de control en tan sólo los
puntos correctos a través de la frontera.

Consideremos por ejemplos, que los casos de uso necesitan llamar al


presentador. Sin embargo, esta llamada no puede ser directa ya que no se
cumpliría el principio de reglas de dependencias. Ningún nombre de un círculo
exterior puede ser mencionado por un círculo interior. En ese caso tenemos que
hacer el caso de uso llama a una interfaz en el círculo interno y hacer que el
presentador implemente dicha interfaz en el círculo exterior. La misma técnica
es usada para cruzar límites o fronteras en las arquitecturas. Aprovechamos el
polimorfismo dinámico para crear dependencias de código que se opongan al
flujo de control para cumplir la regla de dependencias sin importar en qué
dirección va el flujo.
Que datos cruzan los límites
Normalmente los datos que cruzan los límites son estructuras de datos simples.
Puedes usar estructuras simples o DTO (Data Transfer Objects) si así lo deseas.
O los datos pueden ser simplemente argumentos de una función. O puedes
empaquetar todo en un hashmap, o construir un objeto. Lo importante es que las
estructuras de datos aisladas y simples sean transportadas a través de los
límites. No queremos hacer trampas y pasar entidades o filas de base de datos.
No queremos que las estructuras de datos tengan alguna dependencia que haga
quebrantar la regla de dependencias. Por ejemplo, muchas base de datos
devuelven los datos en un forma propia como respuesta a una query (como
un cursor). Podemos llamarlo RowStructure. No queremos pasar esa estructura
como parámetro, ya que quebrantaría la regla de dependencias porque forzaría
a un círculo interno saber algo sobre un círculo externo. Entonces, siempre que
los datos tengan que cruzar límites se hará en el formato que mejor le convenga
al círculo interior.

Conclusión
Aplicar estas sencillas reglas no es difícil y nos ahorrarán un montón de dolores
de cabeza según avancemos. Separando el software en capas y aplicando la
regla de dependencias, crearemos un sistema intrínsecamente testeable con
todas las ventajas que implica. Cuando cualquiera de las partes del sistema se
vuelve obsoleta, como la base de datos, o el framework web, puedes
reemplazarlos sin mucho esfuerzo.

También podría gustarte