How to avoid anemic domain models, or when to move methods from the entities into services
bdd, c#, domain-driven-design, inversion-of-control
Solution
I think this particular issue can be solved elegantly with a Domain Event.
Problem
I have a common scenario that I am looking for some guidance from people more experienced with DDD and Domain Modeling in general. Say I start out building a blog engine, and the first requirement is that after an Article is posted, users can start posting Comments on it. This starts fine, and leads to the following design: ``` public class Article { public int Id { get; set; } public void AddComment(Comment comment) { // Add Comment } } ``` My MVC Controller is designed like this: ``` public class ArticleController { private readonly IRepository _repository; public ArticleController(IRepository repository) { _repository = repository; } public void AddComment(int articleId, Comment comment) { var article = _repository.Get<Article>(articleId); article.AddComment(comment); _repository.Save(article); return RedirectToAction("Index"); } } ``` Now everything works fine, and it meets the requirement. Next iteration we get a requirement that every time a Comment is posted, the blog author should get an email notifying him. At this point, I have 2 choices that I can think of. 1) Modify Article to require an IEmailService (in the ctor?) or obtain an EmailService from a static reference to my DI container 1a) Seems pretty ugly. I believe it breaks some Domain model rules that my entities are aware of services? ``` public class Article { private readonly IEmailService _emailService; public Article(IEmailService emailService) { _emailService = emailService; } public void AddComment(Comment comment) { // Add Comment // Email admin _emailService.SendEmail(App.Config.AdminEmail, "New comment posted!"); } } ``` 1b) Also seems ugly, I now require a configured DI container which is accessed statically. ``` public class Article { public void AddComment(Comment comment) { // Add Comment // Email admin var emailService = App.DIContainer.Resolve<IEmailService>(); emailService.SendEmail(App.Config.AdminEmail, "New comment posted!"); } } ``` 2) Create an IArticleService and move the AddComment() method to this service instead of on the Article Entity itself. This solution is cleaner I believe, but Adding a comment is now less discoverable and requires an ArticleService to perform the work. It seems like AddComment should belong on the Article class itself. ``` public class ArticleService { private readonly IEmailService _emailService; public ArticleService(IEmailService emailService) { _emailService = emailService; } public void AddComment(Article article, Comment comment) { // Add comment // Email admin _emailService.SendEmail(App.Config.AdminEmail, "New comment posted!"); } } public class ArticleController { private readonly IRepository _repository; private readonly IArticleService _articleService; public ArticleController(IRepository repository, IArticleService articleService) { _repository = repository; _articleService = articleService; } public void AddComment(int articleId, Comment comment) { var article = _repository.Get<Article>(articleId); _articleService.AddComment(article, comment); _repository.Save(article); return RedirectToAction("Index"); } } ``` So I am basically look for advice from people more experienced in domain modeling. If I am missing a more obvious solution please let me know :) I generally dislike both solutions to be honest, because the Service option is less discoverable. I can no longer add a Comment to an instance of an Article without having an ArticleService available. It also feels less natural, since AddComment seems like such an obvious method on the Article type. Anyway I look forward to reading the input. Thanks in advance.