¿Es posible aplicar conceptos de arquitectura limpia utilizando una arquitectura de N-capas?
A menudo se habla que para trabajar con Clean Architecture es posible si se realiza con arquitectura hexagonal (hexagonal architecture) o arquitectura de cebolla (Onion architecture), lo cual no es del todo cierto, debemos ver las Clean Architecture como una filosofía la cual debe basarse en construir soluciones bajo 3 pilares: escalabilidad, mantenibilidad e independientes de agentes externos.
Pero entonces, qué sucede con la muy utilizada, querida por muchos y odiada por pocos Arquitectura de N-capas, intentaré responder a esta pregunta bajo las luces de mi experiencia profesional.
Estado actual de las arquitecturas N-capas
Considero que cualquier persona que ha trabajado con Java los últimos 15 años debió haberse enfrentado a la siguiente imagen:
Donde en el momento de trabajar, lo hacemos bajo las siguientes afirmaciones:
“toda la lógica de negocio irá en la carpeta service”, “los accesos a la base de datos se harán en la carpeta repository”, “los controladores no deberían conocer a las entity (orm) y debería solo exponer dto”, entre otras afirmaciones.
Para proyectos pequeños o proyectos que tendrán una baja mantenibilidad y modificabilidad esta solucion anda a toda máquina, el problema aparece cuando la lógica de negocio es densa y la carpeta service se llena de clases “CualquierCosaService” no siendo otra cosa sino grandes ‘ cajas negras’ donde cuando se cambia lo mas mínimo desencadenaran una serie de cambios no previstos; en resumen, clases con una complejidad altísima que violan SRP (Single Responsibility Principle) indiscriminadamente.
Lo feo de como se concibieron y se hicieron famosas las arquitectura N-capas
Para dar un ejemplo, pongamos una solución de software hipotética para una librería en donde se necesitará inicialmente las siguientes funcionalidades: prestar un libro, verificar disponibilidad de un libro, buscar si existe, vender un libro, enviar una copia pdf por email al momento de comprar.
Cuantas veces se han enfrentado a este tipo de situaciones y han visto que crearon (o ustedes mismos crearon) la clase BookServiceImpl que contiene la solución de todos estos casos de uso haciendo que dicha clase tenga muchísimas razones para cambiar.
El problema parte de que al momento de comenzar el proyecto se dijo “en la carpeta service ira la lógica de negocio” y en el caso de necesitar algo sobre libro, agregalo en la clase BookServiceImpl, si necesitas algo sobre factura agregalo en FacturaServiceImpl y así sucesivamente. Estas afirmaciones son una clara violacion a varios de los principios SOLID, intentaré explicar a continuación cuales.
- SRP: Las clases tendrán muchas razones para cambiar y no habrá una razón de cambio específico para cada una de ellas, teniendo solo razones generales de cambio.
- OCP: Nuestras clases no tendrán una lógica cerrada al cambio ni permite ser extendida por otras clases para añadir características, en caso de abrir otra librería en otro país con otra forma de pagos, ¿se imaginan la cantidad “if” a agregar en la aplicación?
- ISP: A mi consideracion el más violado y menos respetado de este tipo de soluciones donde se dispone de una única interfaz general con una cantidad absurda de métodos, teniendo un contrato, que más que un contrato no termina representando nada dicha interfaz.
y ni hablar de cómo trabajamos el acceso a sistemas externos por medio de rest, soap, GraphQL, en nuestra carpeta service haciéndola altamente acoplada a sistemas externos o del cómo trabajamos con las ‘entity’ (objetos de base de datos) en la carpeta service, contaminandola de temas de base de datos en nuestra lógica de negocio, el más mínimo cambio a nivel de base de datos afectará directamente a nuestro ‘core’.
En resumen, este tipo de soluciones para proyectos medianamente grandes conservar los tres pilares de la arquitectura limpia sera bastante complicado (por no decir imposible), pero no teman, tiene solución. En el siguiente capítulo, daré mi visión de cómo trabajar con todos estos problemas y sus soluciones.