Pureza y completitud del modelo de dominio

Si nunca has escuchado los términos "pureza" o "completitud" de un modelo de dominio, no te preocupes; cuando leas este post te vas a dar cuenta de que han estado presentes en cada aplicación que has desarrollado.

Vamos a imaginar que estamos desarrollando una aplicación de gestión para bibliotecas. Los socios pueden registrarse introduciendo su nombre y DNI:

public class Library {

  public void registerMember(String name, String dni) {
    if (!Dni.isValid(dni)) {
      throw InvalidDniException();
    }
    // añadir miembro...
  } 

}

Como se obseva, estamos validando el DNI antes de añadir el nuevo socio. En este caso, decimos que el model del dominio es completo, porque toda la lógica necesaria para llevar a cabo esta funcionalidad está contenida en el modelo.

¿Qué pasa si antes de añadir un socio queremos comprobar si ya está registrado?

Para hacer esto, necesitamos hacer una consulta a nuestra fuente de datos, usando un repository. Podemos hacer esto, por ejemplo, en la capa del controller:

@POST("/members")
public Response registerMember(String name, String dni) {
  if (repository.existsMemberWithDni(dni)) {
    return Response.CONFLICT;
  }
  library.registerMember(name, dni);
  //...
}

Como vemos, la lógica encargada de comprobar si el socio ya existe se encuentra fuera del modelo del dominio. En este caso, decimos que existe una fragmentación en la lógica de dominio: tenemos lógica dentro y fuera del modelo. ¿Cómo podemos solucionar esto?

Una posible solución es, sencillamente, inyectar el repository en el método registerMember de la clase Library:

public class Library {

  public void registerMember(String name, String dni, Repository repo) {
    if (repo.existsMemberWithDni(dni)) {
      throw MemberAlreadyExistsException();
    }
    if (!Dni.isValid(dni)) {
      throw InvalidDniException();
    }
    // añadir miembro...
  } 

}

De esta manera, ya no existe ninguna fragmentación de la lógica, ya que está toda contenida en el modelo de dominio. Pero estamos sacrificando algo a cambio: la pureza del modelo.

Decimos que un modelo es puro cuando interactúa solamente con otras entidades o value objects del dominio o tipos primitivos. En este caso, no ocurre tal cosa, ya que el modelo (la clase Library) está interactuando con componentes ajenos al modelo (el repository).

Entonces, ¿qué es mas importante, la pureza o la completitud?

En mi opición, debemos elegir siempre pureza por encima de completitud. La lógica del dominio, que se encuentra en el modelo, es la más relevante y compleja por norma general. Por eso, es conveniente evitar hacerla aún más compleja añadiendo lógica "externa", complicando los tests unitarios y las dependencias entre componentes.

El modelo del dominio debe ser responsable únicamente de la lógica de negocio, ajeno completamente de las dependencias a sistemas externos como bases de datos o similares.