domain-driven-design single-responsibility-principle anemic-domain-model

domain driven design - ¿Puede un "modelo de dominio enriquecido" violar el principio de responsabilidad única?



domain-driven-design single-responsibility-principle (2)

Bueno, depende de cómo lo mires.

Otra forma es: "¿Puede el principio de responsabilidad única violar un modelo de dominio enriquecido?"

Ambos son lineamientos. No hay "principio" en ninguna parte del diseño de software. Hay, sin embargo, buenos diseños y malos diseños. Ambos conceptos se pueden utilizar de diferentes maneras, para lograr un buen diseño.

Un hilo interesante surgió cuando escribí esta pregunta justo ahora. Aunque no creo que responda a mi pregunta.

He estado trabajando mucho con .NET MVC3, donde es deseable tener un modelo anémico. Los modelos de vista y los modelos de edición son mejores como contenedores de datos simples que puede pasar de un controlador a una vista. Cualquier tipo de flujo de aplicación debe provenir de los controladores, y las vistas manejan los problemas de la interfaz de usuario. En MVC, no queremos ningún comportamiento en el modelo.

Sin embargo, tampoco queremos ninguna lógica de negocios en los controladores. Para aplicaciones más grandes, es mejor mantener el código de dominio separado e independiente de los modelos, vistas y controladores (y HTTP en general). Así que hay un proyecto separado que proporciona, antes que nada, un modelo de dominio (con entidades y objetos de valor, compuesto en agregados según DDD).

Hice algunos intentos para pasar de un modelo anémico a uno más rico en código de dominio, y estoy pensando en rendirme. Me parece que tener clases de entidad que contienen datos y comportamiento viola el SRP.

Tomemos, por ejemplo, un escenario muy común en la web, componiendo correos electrónicos. Dado algún evento, es responsabilidad del dominio componer un objeto EmailMessage dado una Plantilla de correo electrónico, Dirección de correo electrónico y valores personalizados. La plantilla existe como una entidad con propiedades y los valores personalizados se proporcionan como entrada por parte del usuario. Digamos también por el bien del argumento que la dirección FROM del mensaje de correo electrónico puede ser proporcionada por un servicio externo (IConfigurationManager.DefaultFromMailAddress). Dados esos requisitos, parece que un rico modelo de dominio podría otorgarle a EmailTemplate la responsabilidad de componer el EmailMessage:

public class EmailTemplate { public EmailMessage ComposeMessageTo(EmailAddress to, IDictionary<string, string> customValues, IConfigurationManager config) { var emailMessage = new EmailMessage(); // internal constructor // extension method emailMessage.Body = this.BodyFormat.ApplyCustomValues(customValues); emailMessage.From = this.From ?? config.DefaultFromMailAddress; // bla bla bla return emailMessage; } }

Este fue uno de mis intentos de modelo de dominio rico. Sin embargo, después de agregar este método, era responsabilidad de EmailTemplate contener las propiedades de los datos de la entidad y redactar los mensajes. Tenía alrededor de 15 líneas y parecía distraer a la clase de lo que realmente significa ser una Plantilla de Correo Electrónico, lo cual, IMO, es simplemente almacenar datos (formato del sujeto, formato del cuerpo, archivos adjuntos y direcciones opcionales de / responder a) ).

Terminé refactorizando este método en una clase dedicada cuya única responsabilidad es redactar un mensaje de correo electrónico teniendo en cuenta los argumentos anteriores, y estoy mucho más contento con él. De hecho, estoy empezando a preferir los dominios anémicos porque me ayuda a mantener las responsabilidades separadas, haciendo que las clases y las pruebas de unidad sean más cortas, más concisas y más centradas. Parece que hacer que las entidades y otros objetos de datos "sin comportamiento" puedan ser buenos para separar la responsabilidad. ¿O estoy fuera de pista aquí?


El argumento a favor de un modelo de dominio rico en lugar de un modelo anémico depende de una de las proposiciones de valor de la POO, que es mantener el comportamiento y los datos uno al lado del otro. El beneficio principal es el de la encapsulación y la cohesión que ayuda a razonar sobre el código. Un modelo de dominio enriquecido también se puede ver como una instancia del patrón experto en información . El valor de todos estos patrones, sin embargo, es en gran medida subjetivo. Si es más útil para usted mantener los datos y el comportamiento separados, hágalo así, aunque también podría considerar a otras personas que verán el código. Prefiero encapsular tanto como pueda. El otro beneficio de un modelo de dominio más rico en este caso sería la posibilidad de hacer ciertas propiedades privadas. Si una propiedad solo es utilizada por un método en la clase, ¿por qué hacerlo público?

Si un modelo de dominio rico viola el SRP depende de su definición de responsabilidad. Según SRP, una responsabilidad es una razón para cambiar, que a su vez requiere una definición. Esta definición dependerá generalmente del caso de uso en cuestión. Puede declarar que la responsabilidad de la clase de plantilla es ser una plantilla, con todas las implicaciones que surgen, una de las cuales es generar un mensaje desde la plantilla. Un cambio en una de las propiedades de la plantilla puede afectar el método ComposeMessageTo , lo que indica que tal vez estas sean una responsabilidad única. Además, el método ComposeMessageTo es la parte más interesante de la plantilla. A los clientes de la plantilla no les importa cómo se implementa el método o qué propiedades están presentes en la clase de plantilla. Solo quieren generar un mensaje basado en la plantilla. Esto también vota a favor de mantener los datos al lado del método.