lunes, 18 de junio de 2018

La perversión repositoria.

Querido lector:

¿Se ha planteado, verdaderamente y a fondo, el propósito y la responsabilidad de un repositorio cuando está implementando una arquitectura que facilite DDD?


Repasemos las excusas más clásicas:
  • Encapsular la responsabilidad de las operaciones CRUD: Si tienes interfaz con operaciones CRUD la hemos fastidiado. Esto es DDD; no hay CRUD. El contexto y la intención del usuario deben filtrarse hasta las operaciones de persistencia.

  • DRY para las operaciones CRUD (AKA repositorio genérico): Pues como no debes tener CRUD, cualquier cosa derivada de ello es innecesaria.

  • Abstracción de la implementación de la persistencia: Si está usando un ORM éste ya es una abstracción de persistencia. Ya tiene un UoW, ya tiene monitoreo de cambios, ya tiene mapeo a clases... ¿Crear una abstracción de una abstracción? No way dude! Eso es sobrecomplicar las cosas. Y si no está usando ORM lo único que necesita es una interfaz implementada en la capa de infraestructura que responda al contexto y la intención del usuario.
Un repositorio debe servir únicamente a un solo objetivo; obtener aggregate roots de persistencia. Solo lectura. Repito: SOLO lectura.

Voy a poner las cosas en situación e ir despacio desgranando el razonamiento de esto.

¿Que es un agregado?

Un elemento que se encarga de aplicar las invariantes del dominio de una acción y determinar el estado válido después ser aplicada esta acción.

El elemento más básico que podemos tener que se pueda encargar de esto es una función estática. Sí sí, créame, una función estática puede ser un agregado perfectamente; no deje que la mentalidad OOP le nuble la vista; recuerde que FP existe y mola bastante.

Se realiza una llamada a esta función, pasándole por parámetro toda la información que necesita (VO y entidades) para aplicar la reglas de dominio y devolver los cambios que necesitan persistirse para mantener un estado válido, y tenemos la definición exacta de agregado.

¡Atención! NO se cambia el estado interno del agregado ni de ninguno de los parámetros de entrada. Solo se consultan para aplicar las invariantes y determinar la salida. FP Stateless en toda su gloria y bondad. Para no perder el contexto y la intención del usuario hacemos que el agregado retorne un evento de dominio que nos servirá, entre otras cosas, para realizar las escrituras en persistencia que nos dejen un estado válido.

El repositorio se alza

Pero llega un momento en que la cosa se hace grande (si no es grande y/o complejo ¿para que DDD?); nos encontramos con código repetido para obtener la información de persistencia y montar los VO's y las entidades, con que las funciones necesitan demasiados parámetros, con que existen acciones que requieren la misma información que otras, con que queremos desgranar y segregar responsabilidades dentro del código de la función que hace de agregado, etc...

¿Y qué podemos hacer para solucionarlo? Pues diseñar una serie de funcionalidades que se encarguen de obtener de persistencia la información necesaria, y montarla y encapsularla en un agregado raíz que exponga las operaciones realizables; necesitando, estas operaciones, como parámetros de entrada, la información proveniente de fuentes externas a la persistencia con respecto a la operación.

Las operaciones expuestas por el agregado raíz tienen que seguir siendo inmutables igual que lo eran con las funciones estáticas.

Estas funcionalidades se agrupan por contextos delimitados y lo que tenemos es un verdadero repositorio.

Guardar los cambios en persistencia es realizado por la implementación, en infraestructura, de una interfaz (que se puede llamar Persistencia sin ningún problema) que responde a los eventos de dominio.

No hay comentarios:

Publicar un comentario