How Single Responsibility Principle relates to anemic/rich domain model?
Asked Answered
G

3

10

Currently in doing some code review of stuff taken over from another team and have one doubt about applying SRP and its relation to anemic or rich domain model (as defined by Martin Fowler). Rich domain model concept is to have intelligent object that can not only set/get their properties but also can perform some more complicated business logic. I wonder how it fits into SRP?

Say I have my model class having some properties that can expose those props and provide some simple calculations on its properies. Next requirement is to have possibility to store this object data in some storage object that is not under my control, like this:

class MyObject {
    // get set
    // parse sth
    
}

Store method in storage

   storage.store(key, object);

Doesn't it violate SRP if MyObject has store method like this

public void store(Storage storage) {
    storage.store('keyOne', fieldOne);
    storage.store('keyTwo', fieldTwo);
}

From this object's pov it is a good think to be able to store its state. Other way could be to introduce sort of service here and do this like that:

public StorageService {
    private Storage;
    // constructor here
    ....
    public void store(MyObject myobj);
}

Can you point me any links I can read about this problem? I've found one thread on SO here but it doesn't answer my question completely.

How is it resolved in DDD? Models in DDD are by definition rich and can be seen as having too many responsibilities.

Gerous answered 10/1, 2012 at 18:17 Comment(2)
That might be an overly literal interpretation of SRP. Ignore Uncle Bob and go for "cohesion".Fixation
As noted in my answer, if Storage is stable and abstract (say, some standard JSON, XML, RDB interface) then, IMO, there is absolutely no problem going for cohesion and putting it into the domain model.Hitandmiss
B
7

A rich domain model (RDM) means that the logic governing the model's behavior belongs within the model, as opposed to treating the model like data with getters/setters. This does not mean everything including persistence, security, how to display the model in the GUI, etc. needs to be within the model.

RDM and SRP go hand-in-hand, they do not conflict with each other.

Violating SRP/RDM:

Car {
   // possibly violates SRP
   storeInDatabase();  
   // smells like anemic domain model
   getEngineState();   
}

Following SRP/RDM:

// usings aspects to remove cross-cutting concerns from the model and follow SRP
@DatabaseSerializable 
Car {
   // rich domain model encapsulates engine state and exposes behavior
   drive();            
}
Boucicault answered 10/1, 2012 at 19:22 Comment(3)
If you have a Car with many other methods apart from just Drive(), for example SwitchOn(), SwitchOff(), Turn(), Brake(), PlanRoute(), you do have RDM, but you don't have SRP. The more rich your class is with behaviour, the more it goes against SRP. These ARE opposing ideas.Merrythought
RDM means that your model should contain domain logic. SRP means your classes should be responsible for one thing--in the case of the model it means 'containing domain logic', and not containing serialization code or code that opens a web connection, etc.Boucicault
I am aware of the meanings. JuanZe says it best: "Models in DDD are by definition rich and can be seen as having too many responsibilities". In other words, it's not easy to implement a truly rich entity without that entity having too many responsibilities (more than 1). Unless of course we inject single responsibility services/objects into it, in which case it's borderline ADM.Merrythought
A
4

"Models in DDD are by definition rich and can be seen as having too many responsibilities" is a simplistic interpretation of DDD. Always it depends in how good are your models. You could create bad models using DDD (for example creating objects with too many responsabilities or creating anemic models). DDD and SRP are two good practices too follow, as much as refactoring, TDD and many more, but you should complement their use with your experience and judgement (or someone else's). Everything has its pros and cons, don't be dogmatic about applying any practice.

Andria answered 10/1, 2012 at 19:3 Comment(0)
H
3

@Garrett Hall

I somewhat disagree with your statement "RDM and SRP go hand-in-hand, they do not conflict with each other." In my experience, when SRP is overemphasized, it leads to an anemic domain model. "No, we can't do or even help support any persistance, no, we can't do 21-CFR11, no, we can't even know what a GUI is..." and your class ends up doing nothing and just have an Anemic Domain Model.

And if RDM is overemphasized (that's the direction/error I tend to fall into) then SRP completely falls by the wayside and you eventually notice that your class has 100s of methods and is clearly doing too much.

You need to find a balance, the happy medium where both RDM and SRP are happening. And finding that balance is hard and often involves more gut-feelings and politics within your team than technical savvy or rules.

"Know thyself". If you are like me, and tend towards overly complex classes, be aware. And when you see somebody else's class that looks too complex even to you, that a big red flag. Likewise, if you know that you are pretty hardcore about SRP, and you see a class that looks anemic even by your standards, that's a major code smell.

Now, somewhat answering the OP's question about Storage, I think a lot depends on how stable, standard, and abstract Storage is. If Storage were some standard XML, CSV, or RDB abstraction, I have absolutely no problem with objects knowing how to store themselves.

Hitandmiss answered 10/1, 2012 at 20:58 Comment(1)
SRP says that a class shall have one reason to change, and it means one source of reason to change. So when different behaviors exists for an object they shall be separated into different classes and those classes (which are services in DDD) belong to domain model.Broke

© 2022 - 2024 — McMap. All rights reserved.