During a discussion about how to best implement our domain objects when applying DDD, which has recently become more and more popular, a colleague pointed me to Martin Fowler's article about Anemic Domain Models (2003). Martin is one of my heroes; I try to read as many of his writings and watch as many of his talks as I can, because they give me deep insight and a balanced understanding of all options available, which I consider essential to making smart software design decisions . In the aforementioned article, Martin uses rather opinionated language to say that the Anemic Domain Model is an anti-pattern 'robbing yourself blind'. So he must have (or at least must have had) good reasons to be so strongly opposed to it; just as Eric Evans, whom Martin cites several times.
Now, in 2019, I have difficulties seeing it as universally problematic, even after rereading the article several times. So I think I should maybe add my two cents, even if it may upset the DDD community.
What are Anemic Domain Models?
In Martin's seminal P of EAA book (2002), a Domain Model is defined as 'an object model of the domain that incorporates both behavior and data'. This clearly sets it apart from Entity Objects, which are object representations of only the data stored in a database (relational or not), while the behavior is located in separate classes instead. Note that this divide is not really a layering, it’s just procedures working with pure data structures. This is the only way to work in procedural languages like C.
So putting the different terminology aside and simplifying things, an Anemic Domain Model is basically just another word for using pure-data Entity Classes, with the behavior extracted to what we might call Operation Classes .
What’s wrong with pure Entities + Operations?
In the article, Martin acknowledges that, while true, it’s not sufficient to just declare that the Entity/Operation dichotomy is not OO, while Domain Models are. The main pain he sees is the 'awkwardness of mapping to a database'; he views this as only worthwhile if the objects being mapped to actually utilize their potential.
Two factors may have invalidated his premise, though: (a) ORM tools like JPA have improved considerably; you can also directly store objects and its dependencies as a document into e.g. MongoDB. It’s actually much easier as well as cleaner to simply map an Entity to/from a database than to work directly with e.g. JDBC result sets, or manually map the data. (b) Much more importantly, nowadays the DB model is generally controlled by a single application only; luckily teams mostly stopped integrating via databases by sharing their tables with other teams. So if the domain model needs to evolve, the DB schema can be migrated without any coordination ceremony; and we can work with a unified, or even ubiquitous, model .
Nonetheless: having the business methods directly on the business objects has an indisputable elegance; you should not push that aside too easily.
Can Entities be real Domain Objects?
Bean validation is a natural fit to add constraints to your Entities: you can simply add, for instance, a
@Past annotation to the
LocalDate born field of a
Person entity and the validation is automatically done whenever you want to store it. This can be seen as an extension to the type system you use for e.g.
LocalDate. No extra code, pure domain logic: nice.
You can also create custom constraints, e.g.
@Name to prevent smileys and other inappropriate characters in people's names; the validator you’ll need to write is also pure domain logic code. And bean validators can deal with substantial complexity: you can (a) validate multiple fields in combination; (b) use validation groups, e.g. for different states of the entity; and (c) inject helper classes for repositories and others. This allows you to check, for example, that the real estate agent has the legally required certifications to sell a specific building, depending on its location and other factors. Pure domain logic: nice.
JPA Entity classes can also have additional domain methods, e.g. our
Person class can have a method
getAge that calculates the current age of the person from the
born field; or creating a
Customer object may automatically set the first registration date. Pure domain logic: nice.
Some domain methods require repositories or other helpers; e.g. when (re)calculating the sum of an order, we may have to fetch the article prices. We could inject all the helpers we needed into our entities ; but it’s a good Clean Code practice to move complex interactions out of an Entity into an Operation class; esp. if multiple entities are involved; testing gets much easier in this way, too.
Note that these Operation Classes are still part of the Domain Model: they should be pure domain logic and probably reside in the same package as the entities. Only the invocation is different: instead of calling
order.calculateTotalPrice(), you have an
OrderOperations class where you call
calculateTotalPrice(order) . I think that’s not too bad.
Fully blown business transactions sometimes get seriously complex. For example, closing a sale of an insurance may have to trigger many other processes; we may even have to span multiple Bounded Contexts. This is often rightfully extracted into a separate application layer (some call it Service Layer) that 'only coordinates tasks and delegates work'; you may call it a Transaction Script. But the line between core domain and application logic is often blurry and different people draw it at different locations.
When building a Backend For Frontend where the frontend has to display additional data, e.g. the ratings of an article when adding it to an order, that’s clearly application logic; or a multi-step creation operation, where every step should be persisted, is also clearly application logic: the decisions are about UX, which is completed by the visual decisions that I’d define to be a presentation layer: a web application often differs from a desktop application in how it looks, but it probably has the same application logic ; the application logic can easily be unit-tested with subcutaneous tests, while testing the presentation requires serious integration setup.
Martin cites Eric Evans' statement that the application layer 'does not contain business rules or knowledge'. But isn’t the coordination of the processes involved in a business transaction also business domain knowledge? Doesn’t it implement business rules? I find the distinction between application and domain logic difficult to draw out of thin air. I prefer to postpone the creation of design artifacts like layers until a specific need arises.
Separating data from behavior triggers memories of the old-school thinking of databases defining the constraints, and fat frontend applications doing the actual work. I can understand why OO purists like Martin disregard this approach. But it also has its strengths: when we separate only complex behavior, it may not be clear where we should look for a specific operation; we’d need additional conventions to define when we do one thing and when we do the other. When we separate all the behavior — validation logic as well as calculations and complex operations — from the data, things are more uniform and may be easier to grasp … and to test!
And it’s not at all old-school: when brought to an internet scale, it may result in things like the SOLID project, where your personal data (pictures, blogs, etc.) is strictly separated from the applications you use to work with it (Facebook, Twitter, etc.), so you can easily switch to other applications without losing your data. This is not only about re-implementation of the same type of application; it’s about different types of applications working on the same data. This would not be possible without an Anemic Domain Model.
I agree that it’s a smell to prematurely start with an Anemic Domain Model and to declare this as a best practice; but I disagree that OO purity is a hard requirement for qualifying as a Domain Model. It’s a valid solution to separate Operation Classes from Entity Classes; just keep them in the same Domain Model layer! Sometimes there are compelling reasons to separate logic from data; and sometimes it’s better not to. Software developers must be (en)able(d) to see for themselves when it’s better to do one or the other. And they should know how to use bean validation, for example.
Naming things is one of the hard things in Computer Science, and it’s truly important; one could argue that we should not call something a Domain Model when the objects are anemic. But saying that DDD only works with a pure OO paradigm excludes and denies not only the pragmatic approaches described above, but also, e.g., functional programming; and that would be a big loss. I think that an Anemic Domain Model still qualifies to be called a proper Domain Model — and it’s good to have it as a valid tool in your belt.
What do you think? Am I completely wrong? Please comment!
@Entityare not really part of a pure Domain Model, they are not hard runtime dependencies either: you can simply ignore them in tests; and what most developers don’t know, even when the annotations are not on the classpath, classes using them load just fine! So it’s basically a matter of taste: do you dislike such a 'pollution'? Or do you shun the extra mapping code required to make it 'pure'? Purity doesn't directly add value; the mapping code qualifies to be called anemic itself. Some NoSQL databases can even store Entity classes that have no annotations at all, but real DDD purists may still not like the fact that annotations might become necessary one day.
fromRüdiger zu Dohna
Test-Fixtures: Wozu denn überhaupt?
Für uns Softwareentwickler ist der ultimative Endgegner immer die Komplexität. Wir haben zahlreiche, teils ziemlich mächtige Waffen gesammelt, um in diesen Kämpfen bestehen zu können: Dinge wie Modularisierung, Abstraktion, Lean Development, iteratives...
- Test Driven Development
Rüdiger zu Dohna
12.5.2023 | 18 Minuten Lesezeit
GraphQL business error responses revisited
GraphQL excels by suggesting to think more from the actual client requirements than from the sometimes prematurely abstract server-side grand conceptualizations. It's essential to strike the right balance between the perspectives of all stakeholders,...
Rüdiger zu Dohna
7.8.2022 | 10 Minuten Lesezeit
RFC-7807 problem details with Spring Boot and JAX-RS
Application specific problems, e.g. a missing field in a client request, have to be handled properly with machine readable and human friendly custom business error codes — in RESTful web services using JAX-RS, Spring Boot, or any other technology. Only...
- Open Source
Rüdiger zu Dohna
10.1.2020 | 16 Minuten Lesezeit
Structured JUnit 5 testing
Automated tests, in Java most commonly written with JUnit, are critical to any reasonable software project. Some even say that test code is more important than production code, because it's easier to recreate the production code from the tests than the...
Rüdiger zu Dohna
28.9.2018 | 15 Minuten Lesezeit
Dein Job bei codecentric?
Agile Developer & Consultant (w/d/m)
An allen Standorten
More articles in this subject area
Discover exciting further topics and let the codecentric world inspire you.
Event Storming – Gemeinsam die Domäne entdecken
In der Praxis treten innerhalb von Projekten häufig Schwierigkeiten auf, die auf unklare oder unscharfe Abgrenzung von Fachlogik zurückzuführen sind. Ursache häufig: die Problemdomäne ist für den Kunden nicht immer klar, oder von vornherein wurde die...
13.8.2019 | 11 Minuten Lesezeit
Domain-driven API-first Design mit Schema.org
APIs sind längst mehr als technische Schnittstellen zwischen Backend und Frontend. Für viele Unternehmen werden APIs zum Kern des Geschäftsmodells. Unter den Stichworten „API as a Product“ und „API-first“ rücken disruptive Unternehmen APIs in den Fokus...
5.3.2019 | 7 Minuten Lesezeit
Shared Code in Microservices
Microservices sind schon lange kein Hype-Thema mehr. Unzählige Blogartikel, Bücher, Best Practices, Tweets und War Stories aus konkreten Projekten zeugen von einem gelebten Architektur-Stil. Es gibt kaum eine Frage, die nicht bereits mehrfach von allen...
16.7.2018 | 10 Minuten Lesezeit
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Rüdiger zu Dohna
IT Consulting Expert
Do you still have questions? Just send me a message.