16

I want to be clear on this. When I say domain anaemia, I mean intentional domain anaemia, not accidental. In a world where most of our business logic is hidden away behind a bunch of services, is a full domain model really necessary?

This is the question I've had to ask myself recently since working on a project where the "domain" model is in reality a persistence model; none of the domain objects contain any methods and this is a very intentional decision.

Initially, I shuddered when I saw a library full of what are essentially type-safe data containers but after some thought it struck me that this particular system doesn't do much but basic CRUD operations, so maybe in this case this is a good choice. My problem I guess is that my experience so far has been very much focussed on a rich domain model so it threw me a little.

The remainder of the domain logic is hidden away in a group of helpers, facades and factories which live in a separate assembly.

I'm keen to hear what people's thoughts are on this. Obviously, the considerations for reuse of these classes are much simpler but is really that great a benefit?

skaffman
  • 398,947
  • 96
  • 818
  • 769
EightyOne Unite
  • 11,665
  • 14
  • 79
  • 105
  • Also for note (6 years later), a Domain Model isn't a Persistence Model. An "Entity" is a Persistence Model, and a Domain Model, even in SOA, is never really Anemic. Though it's heavy lifting is moved to Services, it still handles its own validation as a "Value Type". Apart from my answer below, I also define the difference between an Entity and Domain Model here: http://stackoverflow.com/a/35494560/1831054 – Suamere Sep 06 '16 at 20:19
  • Several related threads: (1) [Anemic Domain Model vs Domain Model](https://stackoverflow.com/questions/1156644/anemic-domain-models-vs-domain-model-in-a-simple-domain-driven-design) (2) [Rich Domain Model and ORM](https://stackoverflow.com/questions/14372065/rich-domain-model-and-orm) (3) [Anemic Domain Model vs Domain Model](https://stackoverflow.com/questions/1805641/anemic-domain-model-versus-domain-model) – jaco0646 Oct 12 '18 at 18:27

7 Answers7

6

I would agree a full domain model may not be necessary. However, I do think it's more painful to write tests for services with mocked data access objects than it is to write tests for non-anemic domain objects. I'm working on a project now where domain logic exists everywhere except in the domain model, scattered around in helpers and strategies and mediators, and the whole thing has become an unmanageable pile of legacy code even before it's gotten to production.

Thinking back to previous projects I do remember one that used anemic domain objects, it had a lot of issues, including a terrible homegrown xml database, but because it did take a service-based approach it was easy to take on the problems one at a time and make real headway. On the current project they tried to be clever and tie the domain objects to the database, ActiveRecord-style, and didn't make any efforts to control their dependencies. The tight coupling of domain objects to the database, overuse of static methods, and a spaghetti-like web of dependencies has been a big part of what has caused this codebase to become a prematurely brittle, inflexible, and untestable ball of mud. So I think while persistence-ignorant rich domain objects make testing of business logic much easier, the essential thing is to manage your dependencies.

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
  • 1
    This is my concern. If the domain objects are responsible for nothing then you can easily end up with a collection of 'god' classes and break SOLID OO principle all over the place. In fact, I'm not even sure you could call it OO anymore. So whilst it may not be necessary, it's possibly still appropriate. – EightyOne Unite May 04 '10 at 17:44
5

I believe that an anemic domain while an OO anti pattern is in fact a SOA pattern. The rules have changed a bit as we have elevated our level of abstraction.

I am exploring further in a series i am writing, i also had a rant about it on my log last year. https://metallemon.blogspot.com/2008/07/soa-and-anemic-domains.html

http://hubpages.com/hub/Building-Service-Orientated-Architecture

knittl
  • 246,190
  • 53
  • 318
  • 364
MetalLemon
  • 1,390
  • 11
  • 16
5

Six years later, this needs a major update.

The simple answer is yes. But the complex answer is no.

No, SOA doesn't require Anemia. But at the same time, an enterprise system isn't required to be written using SOA. And similarly, architecture isn't a requirement at all for any code. It would be a nightmare, but you could package every bit of functionality into one module if you wanted.

Simply put: OO was originally defined by how it was different from its predecessors. More specifically: C++ was defined by how it was different from C. But the definition of OO has changed. We now have a multitude of OO Principles.

Disclaimer: Many of these principles were partially or wholly created prior to OO, and were simply claimed or updated during the OO revolution. Also, I realize OO has been around for LONG-Before C++, but that doesn't change my statement:

Encapsulation, Inheritence, Polymorphism, Separation of Concerns, Persistence Ignorance, High Cohesion/Low Coupling, S, O, L, I, D, and many more.

Not only that, but if you follow DDD and/or TDD while following these principles, you almost don't have to architect at all. Just by following these principles, you naturally end up with a Service-Oriented Architecture that uses Anemic Domain Models.

Think about it. If you have an Employee class with Save(), SendMessage(), and PayEmployee()... you are breaking so many rules of the current OO Principles.

When you analyze and pull out certain responsibilities into different services, repositories, commands, factories, etc... You Can't Help but have an Empty Employee Class... sort of.

Sort of?

In honesty, you need to keep the idea of Value Objects in mind. Not only has the definition of OO evolved, but the definition of "Anemic" has evolved also. The Employee class should certainly not be empty. It can have plenty of "Business Logic" in it.

The Employee class can have:

  • A parameterized constructor, where the parameters are validated
  • Readonly Properties that calculate fields
  • Employee.ToString(), Employee.TryParse(), and similar object methods
  • Possibly others, specific to the Employee

In essence, the Employee is still anemic. There will certainly never be any algorithms or code-flow logic in a domain model. But there isn't just one kind of Business Logic.

When Martin Fowler said Anemic Domain Models were an Anti-Pattern over a decade ago, it was already becoming more and more viable. His reasoning was twofold, and both folds are old news.

His first fold first was that his defending definition of OO was that the Code and Data were married, or "combine data and process together", opposed to old procedural style. This is only true in bad code, unfortunately. If we follow Inheritence and Polymorphism, we know that functions don't REALLY live in the class. They live at pointers so that inherting classes can override and move them around. But... do they live in the code to increase readability? They certainly shouldn't! They should be defined in Interfaces and Abstractions, and only implemented in the classes. Sorry Martin, but while you were right that the Code/Data marriage was a huge original selling point for OO 2 decades ago, it isn't so much the matter-at-hand now.

His second fold was that he disqualifies SOA as being done incorrectly, and points to some descriptions that closely resemble what we call N-Tiered Architecture today. Granted, I realize this isn't new technology, but definitions have changed over the years.

Not only Martin Fowler, but many others after him had immediately cited his article and therefore said SOA was, itself, an Anti-Pattern because it required Anemic Models, which Fowler says is an Anti-Pattern.

So we're down to this...

Anemic Domain Models aren't really as Anemic as people believe. And SOA is required, we can't discount it. Unfortunately, this is just simply the way things are.

Why is SOA required? - This is getting too descriptive. But long-story-short: In the 90's domain software ran on PC's and Servers... and hardware "Plugged-Into" those monoliths. These days we have literally trillions of "computers" all around us. Smoke-Detectors, Refrigerators, Watches, Phones... These days The Computers Plug Into The Things. So every idea, department, CONCERN, and object is its own small domain. We require SOA to write them up into their own little services, and even sub-services.

Therefore: Applications now plug into Services (Instead of Services plugging into Applications). To create SOA, we simply follow the current rules of OO, such as SOLID and Separation of Concerns. And when we do so, we naturally arrive at Anemic Domain Models... sorta.

So no, Anemic Domain Models aren't required for SOA. They are a natural result of following current principles and standards.

Community
  • 1
  • 1
Suamere
  • 5,691
  • 2
  • 44
  • 58
3

This is exactly what I could not understand about people getting so excited about web services. Don't get me wrong, some good ideas there, but I see no difference to procedural programming here. Look at your architecture. What you describe is just using all the OOP stuff to make it perfectly procedural. How easier would it be to use plain data structures, algorithms and modules? I do not know your situation, but consider how easier it might be using relational database with stored procedures and some bindings to web services. One other answer seems to agree with me in a sort of a way... I would like to hear what you think, if it would make more sense in your situation and if not why? Am I mistaken about the procedural nature of web services?

Gabriel Ščerbák
  • 18,240
  • 8
  • 37
  • 52
2

I guess your architecture is SOA based and implemented using messaging, then the domain model should lay inside your the service layer. That means it is not necessary to force the entire architecture to be formed into domain model but you can apply that in the sub-architecture.

zs2020
  • 53,766
  • 29
  • 154
  • 219
1

I've found that most programmers just don't grok OOP. When it was introduced everyone rejoiced about how we'd no longer program yet another address data structure and how these Classes would marry code to data so that we wouldn't have to write more validation code.

Then, reality set in: My idea of an address doesn't always jive with someone else's. Worse, my concept of an address may change depending on the system I happen to be working on today. And that's a simple one.

And, it got even worse. Inheritance? What's that? Abstract, virtual, .. just keywords to put in the code to shut the compiler up.

And worse: code patterns. Need to validate an object? just use this helper pattern over here...

So we arrive at the point where most people believe a "class" is either a struct or a dumping ground for random functions that might be related in some way but god forbid you put the actual code for the class with the data defined by it.

NotMe
  • 87,343
  • 27
  • 171
  • 245
  • Agreed,..most programmers don't understand OOP. I feel like I'm at least well on my way to saying I do but I'm still open to advice and when I see an architecture like this, designed by people I KNOW probably know more than me I feel I should get second and third opinions. Just to be clear, are you saying domain anaemia is never appropriate? It feels fundamentally wrong to me but, like I say, I'm open to other opinions. – EightyOne Unite May 05 '10 at 08:07
  • I believe that when you have business logic that deals with particular data, then that logic needs to be with the data. Most of the logic I deal with either handles "in flight" processing or during persistence. An example of "in flight" is a user changing their password. In this case the User object should handle validation of requirements. By persistence I'm referring to the act of storing that User object into the database. In this case it should handle making sure the person making the change is authorized to do so AND that referential integrity is maintained. – NotMe May 05 '10 at 20:44
  • When the business logic is scattered, then you tend to lose out on class reuse. In the case of the User object, I now have to take not just the User class definition, but also all of these other classes. This means that I may very well miss something. Further by having all of those "helper" classes, the whole object model becomes complicated to the point that it's easier to start from scratch than reuse it. – NotMe May 05 '10 at 20:47
1

Here are some resources that explain it better.

SOA Design Pattern

Achieving Integrity in a SOAD

Why your SOA should be like a VW Beetle

MetalLemon
  • 1,390
  • 11
  • 16