Estructurar el código en una aplicación DDD

Una de las cosas a las que le daba mas vueltas con respecto a DDD, es como estructuraría el código en un proyecto greenfield.

La estructura de Codesai

Según veo el libro de Vlad lo que comenta es que tengas una App Layer que sea el Api a tu dominio. Eso unido al tema de los comandos, me hace compararlo con la estructura de código que nos mostró Codesai:

auction_house/
├── business
│   ├── actions
│   │   └── commands
│   └── model
│       ├── auction
│       │   ├── events
│       │   ├── exceptions
│       │   └── services
│       ├── bidder
│       ├── generic
│       └── owner
└── infrastructure
    ├── api
    │   └── dtos
    ├── delivery_mechanism
    ├── events
    ├── processes
    └── repository

Dentro de un subdominio (auction_house) está separada la capa de business de la de infrastructure. Bajo model tenemos los diferentes agregados. Por ejemplo auction es un agregado. Dentro de dicho folder estará el codigo del agregado y del resto de entidades relacionadas con él.

Business

El dichoso agregado

¿Y por qué de ese nombre? El nombre viene de que es una entidad que define un límite de consistencia. De hecho las entidades no tienen sentido por ellas mismas, sino que se implementan en el contexto de un agregado. Básicamente es una jerarquía de entidades, de ahí el nombre (un agregado).

La consistencia se garantiza cambiando el estado del agregado sólo desde el código del propio agregado. Desde fuera sólo se puede cambiar el estado a través de su interfaz pública. Vlad comenta que el estado se cambia a través de comandos.

También es el límite transaccional.

Se puede relacionar con otros agregados por el id de la entidad padre de los otros agregados.

¡Y ojo! El agregado no sabe de persistencia. Vamos, que no hace commits ni rollbacks.

Actions

Las actions es un concepto que en Nextail también manejabamos. De hecho nosotros las teníamos divididas en Finders y Actions, y el concepto viene del Interaction driven Design (IDD) de Sandro Mancuso.

El action en la estructura propuesta por Codesai es el Api del dominio.

Una alternativa a tener las actions sería el tener un api en una ‘fachada’ por ejemplo, o N fachadas, una por agregado, se me ocurre. A día de hoy me gusta más usar las acciones.

La acción recibe el command, que ya tiene todos sus datos validados. Si por ejemplo tenemos un endpoint http donde se define un schema, ese schema a nivel de tipo de datos puede ser validado automáticamente por la validación automática del FW. Posteriormente, al construir el commando podríamos hacer validaciones adicionales.

Incluso si no haces DDD, salvo que estes puedes usar actions como punto de entrada a tus módulos funcionales. Te va a delimitar la capa de fricción entre ellos. Recalco lo de módulos funcionales, porque es un patrón que pedería su utilidad en librerías o frameworks.

Hexagonal Arquitecture

Concluyendo las acciones y los comandos son el application layer.

Generic

Otro folder que puede llamar la atención en la estructura anterior es generic. El nombre viene de los tipos de subdominios que usa DDD: core, generic and supporting. Aquí irán cosillas genéricas que no son específicas de un agregado concreto. Por ejemplo podemos meter ahí value objects que estemos usando en diferentes agregados.

Model

Model es otra palabra confusa… Ya que nos recuerda a los models del patrón active record. Por otro lado también es muy común ver domain como alternativa.

¿Pero que es model si DDD habla de entities? Entiendo que Coldesai hace uso de model, porque estamos hablando de un modelo de domino; una representación de la realidad.

Services

En el ejemplo anterior vemos que dentro del agregado hay un folder services. Ahí se deberán poner colaboradores del agregado que no tengan estado. También podríamos tener services bajo model, en el caso de tener un servicio que se reutilizara entre agregados.

Infrastructure

Dentro de la infraestructura tendremos el delivery mechanism. Hay un mito por ahí de que un comando no puede devolver datos. Pero es solo un mito… ¿Por qué no vas a devolver datos?

IMO puedes perfectamente devolver datos, es más, no veo ningún problema en llamar a una action y a un finder en un controller, si tiene sentido. No nos pongamos restricciones absurdas…

¿Y no podemos usar más de un agregado?

Si, si es posible. El libro de Vlad menciona un par de patrones: Saga y Process Manager. La principal diferencia es que el Process Manager necesita mantener el estado, por lo que será el mismo un agregado.

Supongo que una saga podría englobarse a nivel de código como un servicio a nivel del modelo, o incluso como servicio de un nivel superior.

Aparte de la Saga y el Process Manager, a mi parecer no veo ningún problema en acceder a más de un agregado en una acción si tu gestor de base de datos te lo permite. Simplemente todo deberá estar en la misma transacción.

Propuesta final de estructura de código

A día de hoy me decantaría por la siguiente estructura:

a_subdomain/
├── app
│   ├── actions
│   └── commands
├── domain
└── infra

He aplanado la estructura de Codesai y he cambiado al final model por domain. Este cambio me permitiría tener más de un modelo dentro del dominio, si es que tiene sentido… Por lo que leo un modelo diferente debiera ser un bounded context diferente ¯\_(ツ)_/¯.

Por otro lado el tener en el mismo nivel del arbol de directorio app, infra y domain tenemos claramente identificadas esas tres capas.

¿Y donde injectamos las dependencias?

La injección de las dependencias lo tenemos que tener en infra. Puede ser algo tan sencillo como una factoría.

Cesar Ortiz

Read more posts by this author.

Madrid, Spain