Saltar al contenido

Arquitectura de la Aplicación

Organizar el código por capas o por feature, y cómo hacer que las reglas de negocio no dependan de la base, de HTTP ni del framework.

6 min. de lectura

Una vez definida la estructura del sistema, todavía queda una pregunta:

¿Cómo organizamos el código dentro de cada aplicación o módulo?

Aquí aparecen dos ideas diferentes: estrategias de división y arquitecturas centradas en el dominio.

Estrategias de división

Una estrategia de división decide cómo partir el código: de forma horizontal o vertical.

Por capa — división horizontal

Organiza el código según responsabilidades técnicas:

payments/
├── controllers/
├── services/
├── repositories/
├── entities/
└── dto/

El flujo típico de una request es:

Supongamos que necesitamos agregar Refund Payment. Probablemente terminemos modificando RefundController, PaymentService, PaymentRepository, PaymentEntity y RefundDTO. La feature queda repartida horizontalmente.

Ventaja

Es simple de entender y puede funcionar muy bien en aplicaciones pequeñas.

Problema

A medida que crecen las features, disminuye la feature locality:

Un cambio de negocio obliga a recorrer muchas partes de la estructura.

Por feature — división vertical

La división vertical reorganiza el código en torno a features o casos de uso:

payments/

├── authorize-payment/
│   ├── endpoint
│   ├── validator
│   ├── handler
│   └── repository

├── capture-payment/
│   ├── endpoint
│   ├── validator
│   ├── handler
│   └── repository

└── refund-payment/
    ├── endpoint
    ├── validator
    ├── handler
    └── repository

Una feature puede atravesar todas las capas necesarias:

La ventaja principal es la localidad del cambio: cuando cambia Refund Payment, gran parte del trabajo queda concentrada en un mismo lugar.

La división vertical no es CQRS

Pueden combinarse división vertical, CQRS y DDD, pero son conceptos diferentes. La división vertical describe principalmente cómo organizamos el código. CQRS separa responsabilidades de commands y queries.

Tampoco reemplaza la inversión de dependencias

Una aplicación puede combinar división vertical con Hexagonal Architecture:

refund-payment/
├── RefundPaymentHandler
├── RefundPaymentValidator
├── RefundPaymentController
└── RefundPaymentPort

mientras los adapters concretos quedan en infrastructure.

Referencia principal

Jimmy Bogard popularizó el término Vertical Slice Architecture para referirse a organizar las aplicaciones en torno a features en lugar de capas técnicas. Vertical Slice Architecture — Jimmy Bogard.

Arquitecturas centradas en el dominio

Las estrategias de división responden “¿cómo organizamos el código?”. Hexagonal, Onion y Clean ponen el énfasis en otra pregunta:

¿Cómo evitamos que las reglas del negocio queden acopladas a los detalles de infraestructura?

El objetivo es que el core sea relativamente independiente de Database, HTTP, Framework, Message Broker, Cloud Provider y External APIs.

Hexagonal Architecture

Las arquitecturas centradas en el dominio son, en el fondo, el Principio de Inversión de Dependencias aplicado a la escala de una aplicación entera: el dominio define los puertos y la infraestructura los implementa, de modo que la flecha de dependencia apunta siempre hacia adentro.

También llamada Puertos y Adaptadores.

El core define puertos; los adapters implementan esos puertos:

PaymentRepository

        │ implements

PostgresPaymentRepository

Esto evita que el dominio conozca PostgreSQL.

Ejemplo

Domain
  └── PaymentRepository

Infrastructure
  └── PostgresPaymentRepository

La aplicación puede reemplazar PostgreSQL por otro almacenamiento sin modificar las reglas principales del dominio.

Onion Architecture

La idea fundamental es que las dependencias apunten hacia el centro:

El domain es el núcleo.

Clean Architecture

Clean Architecture propone un enfoque similar:

Su regla fundamental es:

Las dependencias deben apuntar hacia adentro.

El dominio no debería depender de Spring, Hibernate, PostgreSQL, Kafka, AWS o HTTP. Esas tecnologías pueden depender de las abstracciones definidas por el core.

Hexagonal vs. Onion vs. Clean

Son conceptualmente cercanas:

EstiloIdea central
HexagonalPuertos y Adaptadores
OnionLas dependencias apuntan hacia adentro
CleanRegla de dependencia + casos de uso + límites

No conviene tratarlas como tres soluciones completamente diferentes. En una aplicación real pueden incluso combinarse ideas de las tres.

Cuándo usar arquitecturas centradas en el dominio

Tiene mucho sentido cuando:

  • el dominio tiene reglas complejas;
  • el sistema debe sobrevivir a cambios de infraestructura;
  • se quiere testear la lógica de negocio de forma aislada;
  • existen múltiples adaptadores;
  • la aplicación tendrá una vida larga.

Cuándo evitarla

Para una aplicación muy sencilla (GET /products, POST /products), introducir cinco capas, múltiples puertos y una estructura empresarial puede agregar complejidad sin beneficio suficiente.

Tecnologías habituales

Este enfoque aparece frecuentemente en Spring Boot, .NET, NestJS, Kotlin, Java y TypeScript. El framework no determina la arquitectura.

Te sirvió, compartilo

// ¿te sirvió?
// compartilo