No debate dos modelos de domínio Rich vs. Anêmico, a Internet está cheia de conselhos filosóficos, mas com poucos exemplos de autoridade. O objetivo desta pergunta é encontrar diretrizes definitivas e exemplos concretos de modelos adequados de Design Orientado a Domínios. (Idealmente em c #.)
Para um exemplo do mundo real, essa implementação do DDD parece estar errada:
Os modelos de domínio WorkItem abaixo são nada além de pacotes de propriedades, usados pelo Entity Framework para um banco de dados com código primeiro. Para Fowler, é anêmico .
A camada WorkItemService é aparentemente uma percepção errada comum dos Serviços de Domínio; Ele contém toda a lógica de comportamento / negócios do WorkItem. Por Yemelyanov e outros, é processual . (pág. 6)
Então, se o abaixo está errado, como posso fazer isso certo?
O comportamento, ou seja, AddStatusUpdate ou Checkout , deve pertencer à classe WorkItem correta?
Quais dependências o modelo WorkItem deve ter?
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 exemplo foi simplificado para ser mais legível. O código definitivamente ainda é complicado, porque é uma tentativa confusa, mas o comportamento do domínio era: atualizar status adicionando o novo status ao histórico do arquivo. Finalmente, concordo com as outras respostas, este pode ser tratado pelo CRUD.)
Atualizar
O @AlexeyZimarev deu a melhor resposta, um vídeo perfeito sobre o assunto em c # por Jimmy Bogard, mas aparentemente foi movido para um comentário abaixo porque não forneceu informações suficientes além do link. Eu tenho um rascunho das minhas anotações resumindo o vídeo na minha resposta abaixo. Por favor, sinta-se livre para comentar a resposta com quaisquer correções. O vídeo dura uma hora, mas vale a pena assistir.
Atualização - 2 anos depois
Eu acho que é um sinal da maturidade nascente do DDD que, mesmo depois de estudá-lo por 2 anos, ainda não posso prometer que sei o "caminho certo" de fazê-lo. Linguagem onipresente, raízes agregadas e sua abordagem ao design orientado por comportamento são as valiosas contribuições da DDD para a indústria. A ignorância da persistência e a fonte de eventos causam confusão, e acho que uma filosofia assim impede a adoção mais ampla. Mas se eu tivesse que repetir esse código novamente, com o que aprendi, acho que seria algo assim:
Ainda agradeço qualquer resposta a esta postagem (muito ativa) que forneça qualquer código de práticas recomendadas para um modelo de domínio 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" no Entity Framework jargão não são os mesmos como "Entidades" como em "Modelo de Domínio"