Saturday, February 28, 2009

Anti-Pattern: Anemic Domain Model

Here is an anti-pattern Martin Fowler will agree with. In fact, it’s Martin Fowler that first described this anti-pattern in November 2003. Like Fowler said, it looks like a model, it smells like a model but there is no behaviour inside.

The basic symptom of an Anemic Domain Model is that at first blush it looks like the real thing. There are objects, many named after the nouns in the domain space, and these objects are connected with the rich relationships and structure that true domain models have. The catch comes when you look at the behavior, and you realize that there is hardly any behavior on these objects, making them little more than bags of getters and setters.

The problem with the anemic domain model is that all the logic is not with the associated object. It’s located in the objects that use them. See the problem? So unless you are using the objects that have the behaviours, having the anemic domain model won’t bring you any good. In fact, they just getters and setters with barely enough behaviour to call them objects.

Of course, you gain a good separation of concerns and a gain in “flexibility” of behaviours if ever needed. You also gain the ability to generate those domain models from a modeling tools without having to break a sweat. If there is so many benefits, where’s the catch?

3 times nothing! You just need to separate the business logic multiple time so that every part of the business get their own. Objects can’t self validate since the validation logic is located outside of the object. Everyone need a reference to that specific model DLLs and any shared entities which increase the coupling of the classes. It also increase the code duplication since many part of the business will essentially reuse many parts that other part of the business need. Don’t forget the maintenance! Since the business logic is spread across the business, all the common business logic will need to be updated all at once and validated against their respective service and validation. And that, is if this part of the business want to update. It’s like dealing with many mini-companies within the same companies.

Got enough? So put some business logic inside your domain model and make it easy to understand. If a certain part of the business need so “special” behaviour, it will have to be incorporated inside the main domain model.

But what if you have to maintain an anemic domain model and you want to fix this anti-pattern? Of course you can always rewrite the software but it’s an expensive solution. The solution is that every time a new requirements arrive, put it inside the domain model and DO NOT put it inside the many service class. This is what Greg Young described as “making bubbles”. By making bubbles of great code that is going to be easy to maintain/reuse, and by maintaining the current system, you will finish by replacing everything.

Anything worth doing is worth doing well.

Submit this story to DotNetKicks

10 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. (Deleted my first reply, boy was it not what I intended to write)

    I strongly disagree here. I don't speak C#, but you'll likely get my gist if I speak Java.

    Imagine if the Double class had everything under Math. Everything under serialization packages, like SOAP, JMS, REST, JSON, etc... Java would require more libraries do to this. It'd tightly couple.

    Imagine a bank switching a formula. In your world, switch the domain model and it propagates through. But what if I'm still using V1 and your V2 hasn't made its way to me. It's the same problem. Your point shifts the problem to upgrading a different library.

    This doesn't jibe at all.

    ReplyDelete
  3. I completely understand your point. But think for a second that you have a domain model that have relationships to other objects, properties to hold information but... nothing else. No method to validate itself (Product have a positive price, Order have LineItem, Taxes are positive, etc.) or that the whole domain model doesn't have any behaviour like adding a Product to a Shopping cart. Think about having to do that inside a Service object. THAT is anemic. Of course, I respect YAGNI. But when everything is in the service, as you increase the amount of service, you increase code duplication. Domain Model also break SRP in the sense that it doesn't take its own responsibility. An object should be able to validate itself (up to a point of course) and interact with other objects inside the same model. What do you think?

    ReplyDelete
  4. I would agree for a single app. But I think in a distributed evironment an anemic model + a set of services to operate on it are almost a requirement.

    In an "enterprise" environment, the same services are often accessed from multiple places. Take the example of adding a product to a shopping cart. This may be done from the web, from a POS machine, through a mainframe greenscreen operated by a CSR, etc.

    With an anemic domain model, the same domain objects can be converted back and forth from a variety of formats (Java objects, C# objects, XML data, etc) and passed into a service through whatever transport is appropriate (RMI, SOAP, etc). If they have logic attached, you lose that flexibility.

    ReplyDelete
  5. The assessment of a software model that I value is making it easy to create and maintain a robust implementation.

    Following from this, keeping things simple, avoiding duplication, managing coupling and maximizing cohesion can be helpful guides, but not rules to be slavishly followed.

    > The problem with the anemic domain model is that
    > all the logic is not with the associated object.
    > It’s located in the objects that use them.

    Is this poor logic? "if it is not here it must be there", What about somewhere else?

    Why in the user of the object and not in a service or strategy related to the logic rather than the object.

    The overall coupling and cohesion might be better minimized in ways other than bloated god objects in the domain.

    Much interesting business logic is not associated with one domain object but with many. The decision to locate the logic in one or the other domain object can create a more tangled domain.

    I will find the object oriented model more worthy of consideration if I could *just* have one. However I am compelled to develop an SQL model. SQL not relational, SQL databases are not relational in significant ways. Maintaining two models and a mapping is simply a disaster.

    I will happily dump either model and I just can't make SQL one die so lets kill domain objects and go with a simple anemic mapping of the SQL model.

    ReplyDelete
  6. I think that the problem when the domain self validation requires access to many other domain objects ,so preparing the data to validate the self-object requires using many finders.

    Also if the validation requires comparing a new and old domain object states, then adding the validation in the domain object is not valid.

    I just need to brainstorm if having a validation layer is better or trying to restrict to DDD principles.

    ReplyDelete
  7. I think that moving the behavior to a set of services allows much more scalability in an enterprise environment. Your services classes act as a facade so that you may change the implementation of the data retrieval at any time. The anemic model allows raw contracts for any caller to agree to without caring about how the data is to be delivered. This allows the for SOC in my opinion. Java has already learned this which is why they've moved away from bloated EJB's in favor of POJO's.

    ReplyDelete
  8. A services layer allows for better SOC and much easier maintainability because the behavior can change at any time without the callers having to know or care about the mechanics of the data retrieval. C#'ers should learn from java's shift from bloated EJB's in favor of POJO's. We have a tendency to want to make single classes for everything which makes it "easier" to understand but a nightmare to maintain in a larger team. Testability also comes into play as services classes are very easy to mock and allows for more maintainable unit tests in a larger team.

    ReplyDelete
  9. just bumped into this ...

    I wrote a post on why anemic domain models can also be patterns http://codebetter.com/blogs/gregyoung/archive/2009/07/15/the-anemic-domain-model-pattern.aspx

    ReplyDelete
  10. With anemic domain models all you get is getters and setters all over. You are doing procedural programming and lose the benefits of OO, period.

    ReplyDelete

Please try to keep comments relevant to the topic. All comments after 1 month will be moderated.