Rich Domain Models — how, exactly, does behavior fit in?

In the debate of Rich vs. Anemic domain models, the internet is full of philosophical advice but short on authoritative examples. The objective of this question is to find definitive guidelines and concrete examples of proper Domain-Driven Design models. (Ideally in C#.)

For a real-world example, this implementation of DDD seems to be wrong:

The WorkItem domain models below are nothing but property bags, used by Entity Framework for a code-first database. Per Fowler, it is anemic.

The WorkItemService layer is apparently a common misperception of Domain Services; it contains all of the behavior / business logic for the WorkItem. Per Yemelyanov and others, it is procedural. (pg. 6)

So if the below is wrong, how can I make it right?
The behavior, i.e. AddStatusUpdate or Checkout, should belong in the WorkItem class correct?
What dependencies should the WorkItem model have?

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();
        }
    }
}

(This example was simplified to be more readable. The code is definitely still clunky, because it’s a confused attempt, but the domain behavior was: update status by adding the new status to the archive history. Ultimately I agree with the other answers, this could just be handled by CRUD.)

Update

@AlexeyZimarev gave the best answer, a perfect video on the subject in C# by Jimmy Bogard, but it was apparently moved into a comment below because it didn’t give enough information beyond the link. I have a rough draft of my notes summarizing the video in my answer below. Please feel free to comment on the answer with any corrections. The video is an hour long but very worth watching.

Update – 2 Years Later

I think it’s a sign of DDD’s nascent maturity that even after studying it for 2 years, I still can’t promise that I know the “right way” of doing it. Ubiquitous language, aggregate roots, and its approach to behavior-driven design are DDD’s valuable contributions to the industry. Persistence ignorance and event sourcing causes confusion, and I think philosophy like that holds it back from wider adoption. But if I had to do this code over again, with what I’ve learned, I think it would look something like this:

I still welcome any answers to this (very active) post that provide any best-practices code for a valid domain model.

8

The most helpful answer was given by Alexey Zimarev and got at least 7 upvotes before a moderator moved it into a comment below my original question….

His answer:

I would recommend you to watch Jimmy Bogard’s NDC 2012 session “Crafting Wicked Domain Models” on Vimeo. He explains what rich domain should be and how to implement them in real life by having behaviour in your entities. Examples are very practical and all in C#.

I took some notes to summarize the video for both my team’s benefit and to provide a little more immediate detail in this post. (The video is an hour long, but really worth every minute if you have time. Jimmy Bogard deserves a lot of credit for his explanation.)

  • “For most applications… we don’t know that they’re going to be complex when we start. They just become that way.”
    • Complexity grows naturally as code and requirements are added. Applications can start out very simple, as CRUD, but behavior/rules can become baked in.
    • “The nice thing is we don’t have to start out complex. We can start with the anemic domain model, that’s just property bags, and with just standard refactoring techniques we can move towards a true domain model.”
  • Domain models = business objects. Domain behavior = business rules.
  • Behavior is often hidden in an application — it can be in PageLoad, Button1_Click, or often in helper classes like ‘FooManager’ or ‘FooService’.
  • Business rules that are separate from domain objects “require us to remember” those rules.
    • In my personal example above, one business rule is WorkItem.StatusHistory.Add(). We’re not just changing the status, we’re archiving it for auditing.
  • Domain behaviors “eliminate bugs in an application a lot more easily than just writing a bunch of tests.” Tests require you to know to write those tests. The domain behaviors offer you the right paths to test.
  • Domain services are “helper classes to coordinate activities between different domain model entities.”
    • Domain services != domain behavior. Entities have behavior, domain services are just intermediaries between the entities.
  • Domain objects shouldn’t have possession of the infrastructure they need (i.e. IOfferCalculatorService). The infrastructure service should be passed in to the domain model that uses it.
  • Domain models should offer to tell you what they can do, and they should only be able to do those things.
  • The properties of domain models should be guarded with private setters, so that only the model can set its own properties, through its own behaviors. Otherwise it’s “promiscuous.”
  • Anemic domain model objects, that are just property bags for an ORM, are only “a thin veneer — a strongly typed version over the database.”
    • “However easy it is to get a database row into an object, that’s what we’ve got.”
    • ‘Most persistant object models are just that. What differentiates an anemic domain model versus an application that doesn’t really have behavior, is if an object has business rules, but those rules are not found in a domain model.
  • “For a lot of applications, there’s no real need to build any kind of real business application logic layer, it’s just something that can talk to the database and perhaps some easy way to represent the data that’s in there.”
    • So in other words, if all you’re doing is CRUD with no special business objects or behavior rules, you don’t need DDD.

Please feel free to comment with any other points that you feel should be included, or if you think any of these notes are off the mark. Tried to quote directly or paraphrase as much as possible.

3

Your question cannot be answered, because your example is wrong. Specifically, because there is no behavior. At least not in area of your domain. The example of AddStatusUpdate method is not a domain logic, but logic that uses that domain. That kind of logic does make sense to be inside some kind of service, that handles outside requests.

For example, if there was requirement that a specific work item can have only specific statuses, or that it can only have N statuses, then that is domain logic and should be part of either WorkItem or StatusHistory as a method.

The reason for your confusion is because you are trying to apply a guideline to code that doesn’t need it. Domain models are only relevant if you have lots of complex domain logic. Eg. logic that works on entities themselves and stems from requirements. If the code is about manipulating entities from outside data, then that is not, most probably, a domain logic. But the moment you get lots of ifs based on what data and entities you are working with, then that is domain logic.

One of the problems of true domain modeling is that it is about managing complex requirements. And as such its true power and benefits cannot be showcased on simple code. You need dozens of entities with tons of requirements around them to truly see the benefits. Again, your example is too simple for domain model to truly shine.

Finally, some OT thing I would mention is that a true domain model with real OOP design would be really hard to persist using the Entity Framework. While ORMs were designed with mapping true OOP structure to relational ones, there are still many problems, and the relational model will often leak into the OOP model. Even with nHibernate, which I consider much more powerful than EF, this can be a problem.

2

I realize this question is quite old so this answer is for posterity. I want to answer with a concrete example instead of one based on theory.

Encapsulate the “changing of work item status” on the WorkItem class like so:

public SomeStatusUpdateType Status { get; private set; }

public void ChangeStatus(SomeStatusUpdateType status)
{
    // Maybe we designed this badly at first ;-)
    Status = status;       
}

Now your WorkItem class is responsible for maintaining itself in a legal state. The implementation is pretty weak, however. The product owner wants a history of all status updates made to the WorkItem.

We change it to something like this:

private ICollection<SomeStatusUpdateType> StatusUpdates { get; private set; }
public SomeStatusUpdateType Status => StatusUpdates.OrderByDescending(s => s.CreatedOn).FirstOrDefault();

public void ChangeStatus(SomeStatusUpdateType status)
{
    // Better...
    StatusUpdates.Add(status);       
}

The implementation has changed drastically but the caller of the ChangeStatus method is unaware of the underlying implementation details and has no reason to change itself.

This is an example of a rich domain model entity, IMHO.

Your assumption that encapsulating your business logic associated with WorkItem into a “fat service” is an inherent anti-pattern which I would argue is not necessarily.

Regardless of your thoughts on the anemic domain model, the standard patterns and practices typical of a Line of Business .NET application encourage a transactional layered approach comprised of various components. They encourage the separation of business logic from the domain model specifically to facilitate communication of a common domain model across other .NET components as well as components on different technology stacks or across physical tiers.

One example of this would be a .NET based SOAP web service that communicates with a Silverlight client application that happens to have a DLL containing simple data types. This domain entity project could be built into a .NET assembly or a Silverlight assembly, where interested Silverlight components that have this DLL will not be exposed to object behaviours that may be dependent on components only available to the service.

Regardless of your stance on this debate, this is the adopted and accepted pattern put forth by Microsoft and in my professional opinion it is not a wrong approach but then an object model that defines its own behaviour is not necessarily an anti-pattern either. If you go forward with this design it is just best to realize and understand some of the limitations and pain points that you might run into if you need to integrate with other components that need to see your domain model. In that particular case perhaps you may want to have a Translator convert your object oriented style domain model into simple data objects that do not expose certain behaviour methods.

5

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật