8

Anemic domain model was criticized a long time ago by Evans and Fowler, since apparently it goes against object oriented principles, etc. The DDD community is clearly aligned with this statements.

However, in recent years there have been disagreeing voices claiming it's not an antipattern at all and that it is an example of following SOLID principles.

I have been working for so many years using Spring Framework. Every project in every company has always had a service layer containing the business logic, using repositories that operate on anemic models (JPA entities). Furthermore, most of the samples, even the official ones from the Spring guys, showcase this way of working.

My questions are: is anemic domain model still considered an antipattern? Have we all been doing things (regarding DDD) wrong? Don't you think that having Rich Domain models violates the SOLID principles?

closed as primarily opinion-based by amon, VoiceOfUnreason, gnat, David Arno, Daenyth Oct 23 '17 at 14:36

Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    "is anemic domain model still considered an antipattern?". By some, yes. By others, myself included, see it as the preferable way of writing code most of the time, but if the RDM suits you, use it. So voting to close this as purely opinion-based. – David Arno Oct 23 '17 at 10:46
  • 1
    This would be a fantastic question for a discussion/debate forum; but there isn't currently an authoritative answer. We prefer questions that can be answered, not just discussed. – VoiceOfUnreason Oct 23 '17 at 14:21
5

ADM is a good pattern for a solution of distributed services such a microservices. It fits many of today's web based business cases.

Consider if we have an Order Domain object. With an OOP approach we would add Order.Purchase() Order.Cancel() etc. It would work well in a desktop app, where we hold orders in memory and do multiple things to the same instance.

But if we have a distributed system, with programs which just to one thing, ie access a list of orders and purchase each one in turn, or get a list of orders and cancel each in turn then having both Methods on the same object makes no sense. We would have to have two Domains or Bounded Contexts:

PurchaseSystemOrder.Purchase()

and

CancelSystemOrder.Cancel();

The only thing these objects would share would be the data structure of properties.

As you add more and more microservices, you end up with dozens of types of Order. It no longer makes sense to talk about an Order as a Domain object, even though its the same conceptual order which is being processed by all these systems.

It makes far more sense to have an Anaemic model, Order, which just encapsulates just the data and to rename your services accordingly:

PurchaseService.Purchase(Order order)

Now we can talk about Order again and we can add whatever new services we think up to process the, without affecting the other currently deployed services.

Fowler and Co come from a monolith system background, in their world an ADM approach would mean a single app with all these separate services instantiated in memory and the OrderDTO being passed around and mutated. This would be far worse than putting the methods on a rich Order model.

But in a distributed system, there are many programs, each only requires a single Order method and runs it on multiple orders, loading each, running the method and then discarding it. It only requires a single Service and a stream of data objects.

Populating a rich model fully, worrying about the requirements and dependencies of all the Methods only to call a single one and then discard the object almost immediately is pointless.

Plus a change to a single one of the methods would require updating all the distributed components as they all depend on the Rich Model for their logic.

I have no room in my code base(s) for stuff they don't need

  • 2
    I downvoted because I think DDD is particularly well-suited to microservices precisely due to the bounded context concept. I think the problem with your answer is that you Order concept and class would be the same across each micro-service but I think that’s neither necessary nor accurate. – RibaldEddie Oct 22 '17 at 21:04
  • I don't disagree, ADM can be DDD if you call your PurchaseService CashRegister and make it part of your domain language – Ewan Oct 22 '17 at 21:08
  • can you elaborate? I always thought that YMMV when ADM and DDD were in a SOLID J2EE or .NET C# MVC EF codebase. – RibaldEddie Oct 22 '17 at 21:16
  • What I mean is that the bounded context Order, PurchaseSystemOrder.Purchase() will be pretty much identical code to CashRegister.Purchase(Order order) its just a naming change in your domain language. A rich domain model means having both Purchase and Cancel methods on the same class. – Ewan Oct 22 '17 at 21:24
  • ...where having Cancel and Purchase on the same class means that class will cross bounded contexts. – Ewan Oct 22 '17 at 21:25
4

SOLID and DDD are orthogonal to each other, meaning they are really going in different directions from each other. You shouldn’t say that one is used to the exclusion of the other, since they can and should probably exist together in the same codebase.

Anemic domain models only become an anti-pattern once your problem domain has lots of behavior and you have hundreds of service methods with lots of copy-pasted logic or dependencies where service layer methods have to call other service layer methods to get anything done.

DDD is an excellent paradigm for micro-services because of the bounded context concept.

Beware the temptation to see infrastructure code as part of your domain. Infrastructure code is anything that you didn’t write yourself or anything that is coupled to a framework or library that interacts with a third-party system. Database connections, SMTP mailers, ORM libraries, application server run times, all that stuff is infrastructure and you shouldn’t include or depend on it in your domain if you can avoid it.

SOLID principles are a set of general purpose OOP concepts that you can use to make better OOP code. You can write a good DDD codebase using them.

  • Regarding the separation of infrastructure code from the domain. So far I had considered JPA Entities my domain, having the following application layers: controller -> service - > repository -> domain (JPA Entities). What would be the right (or one of the right) ways of modelling it acording to your point? Something like: controller -> rich model -> x? How and where would I deal with transactionality? And what about JPA Mapping? Wouldn't we have to duplicate our rich model with separated JPA entities? – codependent Oct 22 '17 at 21:35
  • A JPA entity is a plain old Java object. The mapping is part of the infrastructure but the class itself doesn’t have to be. If you elect to treat it as part of the infrastructure then you should consider it as a data transfer object that is used in the Factory or Repository to create a domain Entity. – RibaldEddie Oct 23 '17 at 15:44
0

A rich domain is nice when done well. A nightmare when not. An anemic domain is always bad. But its a familiar comfortable kind of bad.

If an anemic domain is all you ever want you chose the wrong language when you chose a general purpose language. 4th generation languages specialize around a specific use. If anemic is good enough using them would have made your life easier.

Many frameworks worm their way into the language space until you can't advertise the job as a java job anymore. It's a Java/Spring job. What they're doing, besides making you depend on them, is turn a general purpose language into a bastard form of a 4th generation language.

Is that a best practice or an anti pattern? Well you boss mostly just cares about whether you can hire people to work on the code base. So if we have to pretend we're using a general purpose language to hire people we will.

If your ok with that then fine. You certainly aren't the only one.

But don't tell me that's how it has to be. Don't tell me it's doing anything for me more than it is. I know how to live without it. I know how to push it out so only a few things depend on it. If you're asking me to give in and let it take over everything just because fighting it is to hard then yeah I think that's bad.

I have no room in my code base for stuff it doesn't need.

As for SOLID and the other design principles I can largely follow those even in an anemic domain. Not following them causes a different kind of problem.

  • I appreciate your answer and absolutely agree that some frameworks such as Spring or JPA-Hibernate have conquered the Java landscape. However it's also undeniable that they have provided a bunch of good practices and simplifications that Java (JEE) didn't address at all or did wrongly.I'm really enthusiastic about DDD and would like to understand all the principles they tell.In your experience,what are the best platforms/languages/frameworks to work with pure DDD apps (with Rich Domain Models)?Any good Github sample you know? As you say I want to do things well, not conform with bad practises. – codependent Oct 22 '17 at 19:58
  • We don't do resource recommendations here. But I believe a proper infrastructure layer that deals with frameworks means you can use any kind you like. Just treat them like a library. Keep knowledge of them out of the domain. Also, don't rely on magic. Resist the urge to use things you couldn't make yourself. Cause some day you may need to. – candied_orange Oct 22 '17 at 20:06
  • Going back to the original point. What about SOLID principles? Rich domain models assume many responsibilities, persistence (JPA), business logic (having to deal with transactionality), etc. Anemic models on the other hand only care about persistence having separated services dealing with business logic. Sounds also easier to test. What's so wrong about it then? – codependent Oct 22 '17 at 20:23
  • The main thing is you start making design choices based on the systems needs rather than semantic needs. Its subtle, easy to ignore, the cost isn't obvious and hard to justify correcting. In short it's like arguing that power lines should be buried rather than on polls. Once people get used to the cheep alternative it's not likely to change. Even when hurricanes knock out the power. – candied_orange Oct 22 '17 at 21:26
  • I was going to give you the benefit of the doubt over your claim that "A rich domain is nice when done well. A nightmare when not." Maybe I've just never seen it done well, But then you make the nonsense claim that "An anemic domain is always bad." Opinionated nonsense rendering your answer worthless. -1 – David Arno Oct 23 '17 at 10:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.