En el debate de los modelos de dominio Rich vs.Anemic, Internet está llena de consejos filosóficos pero con pocos ejemplos autorizados. El objetivo de esta pregunta es encontrar pautas definitivas y ejemplos concretos de modelos de diseño impulsados por dominio adecuados. (Idealmente en C #.)
Para un ejemplo del mundo real, esta implementación de DDD parece estar mal:
Los siguientes modelos de dominio de WorkItem no son más que bolsas de propiedades, utilizadas por Entity Framework para una base de datos de código primero. Por Fowler, es anémico .
La capa WorkItemService es aparentemente una percepción errónea común de los Servicios de dominio; contiene todo el comportamiento / lógica de negocios para el WorkItem. Según Yemelyanov y otros, es de procedimiento . (pág. 6)
Entonces, si lo siguiente está mal, ¿cómo puedo corregirlo?
El comportamiento, es decir, AddStatusUpdate o Checkout , debe pertenecer a la clase WorkItem ¿correcto?
¿Qué dependencias debería tener el modelo WorkItem?
public class WorkItemService : IWorkItemService {
private IUnitOfWorkFactory _unitOfWorkFactory;
//using Unity for dependency injection
public WorkItemService(IUnitOfWorkFactory unitOfWorkFactory) {
_unitOfWorkFactory = unitOfWorkFactory;
}
public void AddStatusUpdate(int workItemId, int statusId) {
using (var unitOfWork = _unitOfWorkFactory.GetUnitOfWork<IWorkItemUnitOfWork>()) {
var workItemRepo = unitOfWork.WorkItemRepository;
var workItemStatusRepo = unitOfWork.WorkItemStatusRepository;
var workItem = workItemRepo.Read(wi => wi.Id == workItemId).FirstOrDefault();
if (workItem == null)
throw new ArgumentException(string.Format(@"The provided WorkItem Id '{0}' is not recognized", workItemId), "workItemId");
var status = workItemStatusRepo.Read(s => s.Id == statusId).FirstOrDefault();
if (status == null)
throw new ArgumentException(string.Format(@"The provided Status Id '{0}' is not recognized", statusId), "statusId");
workItem.StatusHistory.Add(status);
workItemRepo.Update(workItem);
unitOfWork.Save();
}
}
}
(Este ejemplo se simplificó para que sea más legible. El código definitivamente sigue siendo complicado, porque es un intento confuso, pero el comportamiento del dominio fue: actualizar el estado agregando el nuevo estado al historial del archivo. En última instancia, estoy de acuerdo con las otras respuestas, esto podría ser manejado por CRUD).
Actualizar
@AlexeyZimarev dio la mejor respuesta, un video perfecto sobre el tema en C # por Jimmy Bogard, pero aparentemente fue trasladado a un comentario a continuación porque no proporcionó suficiente información más allá del enlace. Tengo un borrador de mis notas que resumen el video en mi respuesta a continuación. No dude en comentar la respuesta con cualquier corrección. El video dura una hora pero vale la pena verlo.
Actualización - 2 años después
Creo que es una señal de la naciente madurez de DDD que incluso después de estudiarlo durante 2 años, todavía no puedo prometer que sé la "forma correcta" de hacerlo. El lenguaje ubicuo, las raíces agregadas y su enfoque del diseño basado en el comportamiento son las valiosas contribuciones de DDD a la industria. La ignorancia de la persistencia y el abastecimiento de eventos causa confusión, y creo que una filosofía como esa lo detiene de una adopción más amplia. Pero si tuviera que volver a hacer este código, con lo que he aprendido, creo que se vería así:
Todavía agradezco cualquier respuesta a esta publicación (muy activa) que proporcione cualquier código de mejores prácticas para un modelo de dominio válido.
"I don't want to duplicate all my entities into DTOs simply because I don't need it and it violates DRY, and I also don't want my client application to take a dependency on EntityFramework.dll"
. "Entidades" en la jerga de Entity Framework no son lo mismo que "Entidades" como en "Modelo de dominio"