Although an experimented programmer and architect, the same old basic problem comes back recurrently. I have my own religion about it, but I need some authoritative source.
Are anemic data models ( (c) Martin Fowler?) inherently bad? Should a cake be able to bake itself? Should an invoice know how (and when it should allow) to add lines to itself, or should another layer do that? rabbit.addToHole(hole) or hole.addRabbit(rabbit)? Has it been proved that an ADM is more bug-prone, or easier to maintain, or anything?
You can find a lot of claims on the web, but I'd really want some authoritative quotes, references or facts, if possible from both sides.
See this stackoverflow answer for enlightment.
And this is my opinion:
ADM (Anemic Domain Model) cannot be represented with class diagram UML
Anemic domain model is bad, only in terms of full oop. It is considered as bad design, mainly because you cannot create UML classes and relations with embedded behavior inside it. For example, in your Invoice class with Rich Domain Model (RDM):
Class Name: Order
Implemented: ICommittable, IDraftable, ...
Attributes: No, UserId, TotalAmount, ...
Behavior: Commit(), SaveDraft(), ...
The class is self-documented and self explaining about what it can do and what can't.
If it is anemic domain model, it does not has the behavior, and we need to search which class is responsible for Committing and Saving Draft. And since the UML class diagram only shows the relation between each classes (one to many / many to many / aggregate / composite), the relation with service class cannot be documented, and Martin Fowler has his point right.
In general, the more behavior you find in the services, the more
likely you are to be robbing yourself of the benefits of a domain
model. If all your logic is in services, you've robbed yourself blind.
This is based on class diagram UML in OOAD book by Lars Mathiassen. I don't know if newer class diagram UML can represent service class.
SRP
In ADM's point of view and compisition over inheritance, RDM (rich domain model) violates SRP. It may be true, but you can refer to this question for discussion.
Shortly, in ADM's point of view, SRP equals one class doing one thing and one thing only. Any change into the class has one and only one reason.
In RDM's point of view, SRP equals all responsibility related to and only to the interface itself. As soon as the operation involve other class, then the operation need to be put into other interface. The implementation itself may vary, as such if a class can implement 2 or more interfaces. It is simply said as if an operation in interface need to be changed, it is for and only for one reason.
ADM tend to be abused with static methods and dirty hacks may apply
ADM is very easy to be abused with static methods - service class. It can be done with RDM too, but it need another layer of abstraction and not worth it. Static methods are usually a sign of bad design, it reduced testability and may introduce race conditions, as well as hiding the dependency.
ADM can has many dirty hacks because the operations are not being constrained by the object definition (hey, I can create another class for this!). In hand of bad designer, this can become catastrophic. In RDM it is harder, please read next point for information.
RDM's implementation usually cannot be reused and cannot be mocked. RDM require to know the system's behavior beforehand
Usually RDM's implementation cannot be reused and mocked. In TDD manner, it reduced testability (please correct me if there is RDM which can be mocked and reused). Imagine a situation with this inheritance tree:
A
/ \
B C
If B need logic implemented in C, it cannot be done. Using composition over inheritance, it can be achieved. In RDM, it can be done with a design like this:
A
|
D
/ \
B C
In which introduce more inheritance. However, in order to achieve neat design early, you will need to know the system flow firsthand. That said, RDM require you to know the system's behavior before doing any design, or you won't know any of the interfaces named ISubmitable, IUpdateable, ICrushable, IRenderable, ISoluble, etc, suitable for your system.
Conclusion
That's all my opinion about this kind of holy war. Both has pros and cons. I usually go for ADM because it seems like higher flexibility even has less reliability. Regardless of ADM or RDM, if you design your system bad, the maintenance is hard. Any type of chainsaw will only shines when held by skillful carpenter.
I think the accepted answer to this question is one best answering your question too.
Things that I think are esential to remember:
ADM is adequate for CRUD applications, and since most apps start out this way, it's OK as a starting architecture; you can evolve from there via refactoring, if needed, but there's no point of over-designing an application right from the start
once complexity starts to grow - once business rules start to pile up - it's less convenient to keep the model anemic - separating the rules from the objects they act upon makes it hard to remember all rules that apply when you look at the object
if the rules are in the domain objects, they are also conducive to writing tests, if they're elsewhere (say in stateless services), you don't know what a domain object can do and what all constraints that apply to it are, to write proper tests for it (think orthogonal rules modelled in distinct services)
there's a distinction to be made between really simple applications and anemic domain models: in a really simple application, there is not much business logic, in an anemic domain model the logic exists, but is kept separately from the domain model
Related
I was trying to find tutorials and good examples which would explain difference between those two, but not able to find any information.
Pure fabrication and indirection acts to create and assign responsibilities to intermediate object, so could anyone explain what is difference between those design patterns?
Thanks!
You use Indirection if you want to create a lower coupling between components. The example Larman suggests in Applying UML and Patterns is a class TaxCalculatorAdapter. In order to shield clients from having to know inner workings of a possible adapter, he hides them with an indirection, only exposing the required API. This Indirection will be highly coupled to the adaptees, but only loosely coupled to the clients.
The PersistentStorage from Pure Fabrication is indeed an Indirecton (Larman states so in the book) in that it provides lower coupling. Pure Fabrication goes beyond that though in that it creates objects that are not part of your Domain Model.
The example Larman gives is a domain class Sale. Since Sale has all the data to save, it would be a candidate to hold the logic for saving a Sale as well (Information Expert). However, persistence logic is not related to the concept of a Sale, hence the class would become incohesive. Also, by coupling the Sale to a particular DB API, you limit reuse (Indirection to the rescue). And because saving is a general activity, you would likely also duplicate code in objects which also need to be saved. To avoid this, you make something up (the pure fabrication), meaning you create something that is not part of the Domain model (here: a PersistentStorage), but still captures an essential activity in your application.
As such, Pure Fabrication it is a specialization or rather a variant of Indirection.
Pure fabrication and indirection both are principles from GRASP.
Following examples in this dzone article might clear your concept about pure fabrication and indirection.
Pure Fabrication:
We know the domain model for a banking system contains classes like Account, Branch, Cash, Check, Transaction, etc. The domain classes need to store information about the customers. In order to do that one option is to delegate data storage responsibility to domain classes. This option will reduce the cohesiveness of the domain classes (more than one responsibility). Ultimately, this option violates the SRP principle.
Another option is to introduce another class which does not represent any domain concept. In the banking example, we can introduce a class called, PersistenceProvider. This class does not represent any domain entity. The purpose of this class is to handle data storage functions. Therefore PersistenceProvider is a pure fabrication.
Indirection:
This principle answers one question: How do you cause objects to interact in a manner that makes bond among them remain weak?
The solution is: Give the responsibility of interaction to an intermediate object so that the coupling among different components remains low.
For example, a software application works with different configurations and options. To decouple the domain code from the configuration a specific class is added - which shown in the following listing:
Public Configuration{
public int GetFrameLength(){
// implementation
}
public string GetNextFileName(){
}
// Remaining configuration methods
}
In this way, if any domain object wants to read a certain configuration setting it will ask the Configuration class object. Therefore, the main code is decoupled from the configuration code.
If you have read the Pure Fabrication Principle, this Configuration class is an example of pure fabrication. But the purpose of indirection is to create de-coupling. On the other hand, the purpose of pure fabrication is to keep the domain model clean and represent only domain concepts and responsibilities.
Many software design patterns like Adapter, Facade, and Observer are specializations of the Indirection Principle.
Pure fabrication class is a type of class ,which does not concept in a problem domain designed ,This class is assigned with high cohesion ^,low coupling & reuse.
Indirection
It solves the problem of assigning the responsibility of avoiding direct coupling between things.it also ensures low coupling between the objects & maintains higher reside capabilities.
Let's say there are two classes related to each other via some relations. For example, a Student maintains a list of the Classes he takes, and each Class has a list of Students taking it. Then I am afraid of letting the Student directly being able to modify its set of Classes, because each modification would have to be followed by a similar modification of a Class's list of Students, and vice versa.
One solution is to have a class whose sole purpose is to keep track of Class-Student relations, say Registrar. But then if some method in Student requires knowledge of its Class list, the Student needs to be passed the Registrar. This seems bad. It seems Student shouldn't have access to the Registrar, where it can also access other Students. I can think of a solution, creating a class that acts as a mediator between Student and Registrar, showing the Student only what it needs to know, but this seems possibly like overkill. Another solution is to remove from Student any method that needs to access its classes and put it instead in Registrar or some other class that has access to Registrar.
The reason I'm asking is that I'm working on a chess game in Java. I'm thinking about the Piece-Cell relations and the Piece-Player relations. If in the above example it wasn't OK for a Student to have access to the Registrar, is it OK here for a Piece to have access to the Board, since a Piece needs to look around anyway to decide if a move is valid?
What's the standard practice in such cases?
If relations can be changed - classes should be decoupled as much as possible, so along with each class create an interface, do not introduce tied relations between classes.
High level of separation you can achieve using intermediate services/helpers which encapsulates logic of communication between classes, so in this case you should not inject one class to an other even both are abstracted by interfaces, basically Student does not know anything about Class, and Class does not know anything about Student. I'm not sure whether such complexity is makes sense in your case but anyway you can achieve it.
Here is you may find a useful design pattern Mediator which can encapsulate interaction logic between two decoupled entities, take a look at it.
With the mediator pattern, communication between objects is
encapsulated with a mediator object. Objects no longer communicate
directly with each other, but instead communicate through the
mediator. This reduces the dependencies between communicating objects,
thereby lowering the coupling.
What I think you have found in your pretty nice example and explanation is that OO does not solve all problems well. As long as the responsibility is well shaped and sharp, everything is fine. And as long each responsibility fits in exactly one bucket (the class), it is pretty easy to design. But here you have a tradeoff:
If I define for each responsibility a separate class, I will get a bloated design that is pretty difficult to understand (and sometimes to maintain).
If I include for each separate responsibility at least one interface, I will get more classes and interfaces than I need.
If I decide that one of the two classes is responsible for the relation as well, this one object has more knowledge than usual about the other.
And if you introduce in each case a mediator or something similar, your design will be more complex than the problem.
So perhaps you should ask the questions:
What is the likelihood that the relation between the 2 objects will change?
What is the likelihood that the relation will exist between more 1 type of objects at each end?
Is that part of the system a highly visible part, so that a lot of other parts will interface it (and therefore will be dependent on it)?
Take the simplest solution that could possibly work and start with that. As long as the solution is kept simple, it is only your code (you don't design a library for others), there are chances that you can change the design later without hassle.
So in your concrete case,
the board field should have access to the whole board XOR
the figure on the field should have the responsibility of moving XOR
there should be an object type (ChessGame?) that is responsible for the overall knowledge about moving, blocking, attacking ...
I do think that all are valid, and it depends on your special "business case" which one is the most valid.
In the SRP, a 'responsibility' is usually described as 'a reason to change', so that each class (or object?) should have only one reason someone should have to go in there and change it.
But if you take this to the extreme fine-grain you could say that an object adding two numbers together is a responsibility and a possible reason to change. Therefore the object should contain no other logic, because it would produce another reason for change.
I'm curious if there is anyone out there that has any strategies for 'scoping', the single-responsibility principle that's slightly less objective?
it comes down to the context of what you are modeling. I've done some extensive writing and presenting on the SOLID principles and I specifically address your question in my discussions of Single Responsibility.
The following first appeared in the Jan/Feb 2010 issue of Code Magazine, and is available online at "S.O.L.I.D. Software Development, One Step at a Time"
The Single Responsibility Principle
says that a class should have one, and
only one, reason to change.
This may seem counter-intuitive at
first. Wouldn’t it be easier to say
that a class should only have one
reason to exist? Actually, no-one
reason to exist could very easily be
taken to an extreme that would cause
more harm than good. If you take it to
that extreme and build classes that
have one reason to exist, you may end
up with only one method per class.
This would cause a large sprawl of
classes for even the most simple of
processes, causing the system to be
difficult to understand and difficult
to change.
The reason that a class should have
one reason to change, instead of one
reason to exist, is the business
context in which you are building the
system. Even if two concepts are
logically different, the business
context in which they are needed may
necessitate them becoming one and the
same. The key point of deciding when a
class should change is not based on a
purely logical separation of concepts,
but rather the business’s perception
of the concept. When the business
perception and context has changed,
then you have a reason to change the
class. To understand what
responsibilities a single class should
have, you need to first understand
what concept should be encapsulated by
that class and where you expect the
implementation details of that concept
to change.
Consider an engine in a car, for
example. Do you care about the inner
working of the engine? Do you care
that you have a specific size of
piston, camshaft, fuel injector, etc?
Or, do you only care that the engine
operates as expected when you get in
the car? The answer, of course,
depends entirely on the context in
which you need to use the engine.
If you are a mechanic working in an
auto shop, you probably care about the
inner workings of the engine. You need
to know the specific model, the
various part sizes, and other
specifications of the engine. If you
don’t have this information available,
you likely cannot service the engine
appropriately. However, if you are an
average everyday person that only
needs transportation from point A to
point B, you will likely not need that
level of information. The notion of
the individual pistons, spark plugs,
pulleys, belts, etc., is almost
meaningless to you. You only care that
the car you are driving has an engine
and that it performs correctly.
The engine example drives straight to
the heart of the Single Responsibility
Principle. The contexts of driving the
car vs. servicing the engine provide
two different notions of what should
and should not be a single concept-a
reason for change. In the context of
servicing the engine, every individual
part needs to be separate. You need to
code them as single classes and ensure
they are all up to their individual
specifications. In the context of
driving a car, though, the engine is a
single concept that does not need to
be broken down any further. You would
likely have a single class called
Engine, in this case. In either case,
the context has determined what the
appropriate separation of
responsibilities is.
I tend to think in term of "velocity of change" of the business requirements rather than "reason to change" .
The question is indeed how likely stuffs will change together, not whether they could change or not.
The difference is subtle, but helps me. Let's consider the example on wikipedia about the reporting engine:
if the likelihood that the content and the template of the report change at the same time is high, it can be one component because they are apparently related. (It can also be two)
but if the likelihood that the content change without the template is important, then it must be two components, because they are not related. (Would be dangerous to have one)
But I know that's a personal interpretation of the SRP.
Also, a second technique that I like is: "Describe your class in one sentence". It usually helps me to identify if there is a clear responsibility or not.
I don't see performing a task like adding two numbers together as a responsibility. Responsibilities come in different shapes and sizes but they certainly should be seen as something larger than performing a single function.
To understand this better, it is probably helpful to clearly differentiate between what a class is responsible for and what a method does. A method should "do only one thing" (e.g. add two numbers, though for most purposes '+' is a method that does that already) while a class should present a single clear "responsibility" to it's consumers. It's responsibility is at a much higher level than a method.
A class like Repository has a clear and singular responsibility. It has multiple methods like Save and Load, but a clear responsibility to provide persistence support for Person entities. A class may also co-ordinate and/or abstract the responsibilities of dependent classes, again presenting this as a single responsibility to other consuming classes.
The bottom line is if the application of SRP is leading to single-method classes who's whole purpose seems to be just to wrap the functionality of that method in a class then SRP is not being applied correctly.
A simple rule of thumb I use is that: the level or grainularity of responsibility should match the level or grainularity of the "entity" in question. Obviously the purpose of a method will always be more precise than that of a class, or service, or component.
A good strategiy for evaluating the level of responsibility can be to use an appropriate metaphor. If you can relate what you are doing to something that exists in the real world it can help give you another view of the problem you're trying to solve - including being able to identify appropriate levels of abstraction and responsibility.
#Derick bailey: nice explanation
Some additions: It is totally acceptable that application of SRP is contextual base.
The question still remains: are there any objective ways to define if a given class violates SRP ?
Some design contexts are quite obvious ( like the car example by Derick ) but otherwise contexts in which a class's behaviour has to defined remains fuzzy many-a-times.
For such cases, it might well be helpful if the fuzzy class behaviour is analysed by splitting it's responsibilities into different classes and then measuring the impact of new behavioural and structural relations that has emanated because of the split.
As soon the split is done, the reasons to keep the splitted responsibilities or to back-merge them into single responsibility becomes obvious at once.
I have applied this approach and which has lead good results for me.
But my search to look for 'objective ways of defining a class responsibility' still continues.
I respectful don't agree when Chris Nicola's above says that "a class should presents a single clear "responsibility" to it's consumers
I think SRP is about having a good design inside the class, not class' customers.
To me it's not very clear what a responsability is, and the prove is the number of questions that this concept arises.
"single reason to change"
or
"if the description contains the word
"and" then it needs to be split"
leads to the question: where is the limit? At the end, any class with 2 public methods has 2 reasons to change, isn't it?
For me, the true SRP leads to the Facade pattern, where you have a class that simply delegades the calls to other classes
For example:
class Modem
send()
receive()
Refactors to ==>
class ModemSender
class ModelReceiver
+
class Modem
send() -> ModemSender.send()
receive() -> ModemReceiver.receive()
Opinions are wellcome
I'm in a project that takes the Single Responsibility Principle pretty seriously. We have a lot of small classes and things are quite simple. However, we have an anemic domain model - there is no behaviour in any of our model classes, they are just property bags. This isn't a complaint about our design - it actually seems to work quite well
During design reviews, SRP is brought out whenever new behaviour is added to the system, and so new behaviour typically ends up in a new class. This keeps things very easily unit testable, but I am perplexed sometimes because it feels like pulling behaviour out of the place where it's relevant.
I'm trying to improve my understanding of how to apply SRP properly. It seems to me that SRP is in opposition to adding business modelling behaviour that shares the same context to one object, because the object inevitably ends up either doing more than one related thing, or doing one thing but knowing multiple business rules that change the shape of its outputs.
If that is so, then it feels like the end result is an Anemic Domain Model, which is certainly the case in our project. Yet the Anemic Domain Model is an anti-pattern.
Can these two ideas coexist?
EDIT: A couple of context related links:
SRP - http://www.objectmentor.com/resources/articles/srp.pdf
Anemic Domain Model - http://martinfowler.com/bliki/AnemicDomainModel.html
I'm not the kind of developer who just likes to find a prophet and follow what they say as gospel. So I don't provide links to these as a way of stating "these are the rules", just as a source of definition of the two concepts.
Rich Domain Model (RDM) and Single Responsibility Principle (SRP) are not necessarily at odds. RDM is more at odds with a very specialised subclassof SRP - the model advocating "data beans + all business logic in controller classes" (DBABLICC).
If you read Martin's SRP chapter, you'll see his modem example is entirely in the domain layer, but abstracting the DataChannel and Connection concepts as separate classes. He keeps the Modem itself as a wrapper, since that is useful abstraction for client code. It's much more about proper (re)factoring than mere layering. Cohesion and coupling are still the base principles of design.
Finally, three issues:
As Martin notes himself, it's not always easy to see the different 'reasons for change'. The very concepts of YAGNI, Agile, etc. discourage the anticipation of future reasons for change, so we shouldn't invent ones where they aren't immediately obvious. I see 'premature, anticipated reasons for change' as a real risk in applying SRP and should be managed by the developer.
Further to the previous, even correct (but unnecessary anal) application of SRP may result in unwanted complexity. Always think about the next poor sod who has to maintain your class: will the diligent abstraction of trivial behaviour into its own interfaces, base classes and one-line implementations really aid his understanding of what should simply have been a single class?
Software design is often about getting the best compromise between competing forces. For example, a layered architecture is mostly a good application of SRP, but what about the fact that, for example, the change of a property of a business class from, say, a boolean to an enum has a ripple effect across all the layers - from db through domain, facades, web service, to GUI? Does this point to bad design? Not necessarily: it points to the fact that your design favours one aspect of change to another.
I'd have to say "yes", but you have to do your SRP properly. If the same operation applies to only one class, it belongs in that class, wouldn't you say? How about if the same operation applies to multiple classes? In that case, if you want to follow the OO model of combining data and behavior, you'd put the operation into a base class, no?
I suspect that from your description, you're ending up with classes which are basically bags of operations, so you've essentially recreated the C-style of coding: structs and modules.
From the linked SRP paper:
"The SRP is one of the simplest of the principle, and one of the hardest to get right."
The quote from the SRP paper is very correct; SRP is hard to get right. This one and OCP are the two elements of SOLID that simply must be relaxed to at least some degree in order to actually get a project done. Overzealous application of either will very quickly produce ravioli code.
SRP can indeed be taken to ridiculous lengths, if the "reasons for change" are too specific. Even a POCO/POJO "data bag" can be thought of as violating SRP, if you consider the type of a field changing as a "change". You'd think common sense would tell you that a field's type changing is a necessary allowance for "change", but I've seen domain layers with wrappers for built-in value types; a hell that makes ADM look like Utopia.
It's often good to ground yourself with some realistic goal, based on readability or a desired cohesion level. When you say, "I want this class to do one thing", it should have no more or less than what is necessary to do it. You can maintain at least procedural cohesion with this basic philosophy. "I want this class to maintain all the data for an invoice" will generally allow SOME business logic, even summing subtotals or calculating sales tax, based on the object's responsibility to know how to give you an accurate, internally-consistent value for any field it contains.
I personally do not have a big problem with a "lightweight" domain. Just having the one role of being the "data expert" makes the domain object the keeper of every field/property pertinent to the class, as well as all calculated field logic, any explicit/implicit data type conversions, and possibly the simpler validation rules (i.e. required fields, value limits, things that would break the instance internally if allowed). If a calculation algorithm, perhaps for a weighted or rolling average, is likely to change, encapsulate the algorithm and refer to it in the calculated field (that's just good OCP/PV).
I don't consider such a domain object to be "anemic". My perception of that term is a "data bag", a collection of fields that has no concept whatsoever of the outside world or even the relation between its fields other than that it contains them. I've seen that too, and it's not fun tracking down inconsistencies in object state that the object never knew was a problem. Overzealous SRP will lead to this by stating that a data object is not responsible for any business logic, but common sense would generally intervene first and say that the object, as the data expert, must be responsible for maintaining a consistent internal state.
Again, personal opinion, I prefer the Repository pattern to Active Record. One object, with one responsibility, and very little if anything else in the system above that layer has to know anything about how it works. Active Record requires the domain layer to know at least some specific details about the persistence method or framework (whether that be the names of stored procedures used to read/write each class, framework-specific object references, or attributes decorating the fields with ORM information), and thus injects a second reason to change into every domain class by default.
My $0.02.
I've found following the solid principles did in fact lead me away from DDD's rich domain model, in the end, I found I didn't care. More to the point, I found that the logical concept of a domain model, and a class in whatever language weren't mapped 1:1, unless we were talking about a facade of some sort.
I wouldn't say this is exactly a c-style of programming where you have structs and modules, but rather you'll probably end up with something more functional, I realise the styles are similar, but the details make a big difference. I found my class instances end up behaving like higher order functions, partial functions application, lazily evaluated functions, or some combination of the above. It's somewhat ineffable for me, but that's the feeling I get from writing code following TDD + SOLID, it ended up behaving like a hybrid OO/Functional style.
As for inheritance being a bad word, i think that's more due to the fact that the inheritance isn't sufficiently fine grained enough in languages like Java/C#. In other languages, it's less of an issue, and more useful.
I like the definition of SRP as:
"A class has only one business reason to change"
So, as long as behaviours can be grouped into single "business reasons" then there is no reason for them not to co-exist in the same class. Of course, what defines a "business reason" is open to debate (and should be debated by all stakeholders).
Before I get into my rant, here's my opinion in a nutshell: somewhere everything has got to come together... and then a river runs through it.
I am haunted by coding.
=======
Anemic data model and me... well, we pal around a lot. Maybe it's just the nature of small to medium sized applications with very little business logic built into them. Maybe I am just a bit 'tarded.
However, here's my 2 cents:
Couldn't you just factor out the code in the entities and tie it up to an interface?
public class Object1
{
public string Property1 { get; set; }
public string Property2 { get; set; }
private IAction1 action1;
public Object1(IAction1 action1)
{
this.action1 = action1;
}
public void DoAction1()
{
action1.Do(Property1);
}
}
public interface IAction1
{
void Do(string input1);
}
Does this somehow violate the principles of SRP?
Furthermore, isn't having a bunch of classes sitting around not tied to each other by anything but the consuming code actually a larger violation of SRP, but pushed up a layer?
Imagine the guy writing the client code sitting there trying to figure out how to do something related to Object1. If he has to work with your model he will be working with Object1, the data bag, and a bunch of 'services' each with a single responsibility. It'll be his job to make sure all those things interact properly. So now his code becomes a transaction script, and that script will itself contain every responsibility necessary to properly complete that particular transaction (or unit of work).
Furthermore, you could say, "no brah, all he needs to do is access the service layer. It's like Object1Service.DoActionX(Object1). Piece of cake." Well then, where's the logic now? All in that one method? Your still just pushing code around, and no matter what, you'll end up with data and the logic being separated.
So in this scenario, why not expose to the client code that particular Object1Service and have it's DoActionX() basically just be another hook for your domain model? By this I mean:
public class Object1Service
{
private Object1Repository repository;
public Object1Service(Object1Repository repository)
{
this.repository = repository;
}
// Tie in your Unit of Work Aspect'ing stuff or whatever if need be
public void DoAction1(Object1DTO object1DTO)
{
Object1 object1 = repository.GetById(object1DTO.Id);
object1.DoAction1();
repository.Save(object1);
}
}
You still have factored out the actual code for Action1 from Object1 but for all intensive purposes, have a non-anemic Object1.
Say you need Action1 to represent 2 (or more) different operations that you would like to make atomic and separated into their own classes. Just create an interface for each atomic operation and hook it up inside of DoAction1.
That's how I might approach this situation. But then again, I don't really know what SRP is all about.
Convert your plain domain objects to ActiveRecord pattern with a common base class to all domain objects. Put common behaviour in the base class and override the behaviour in derived classes wherever necessary or define the new behaviour wherever required.
Information-Expert, Tell-Don't-Ask, and SRP are often mentioned together as best practices. But I think they are at odds. Here is what I'm talking about.
Code that favors SRP but violates Tell-Don't-Ask & Info-Expert:
Customer bob = ...;
// TransferObjectFactory has to use Customer's accessors to do its work,
// violates Tell Don't Ask
CustomerDTO dto = TransferObjectFactory.createFrom(bob);
Code that favors Tell-Don't-Ask & Info-Expert but violates SRP:
Customer bob = ...;
// Now Customer is doing more than just representing the domain concept of Customer,
// violates SRP
CustomerDTO dto = bob.toDTO();
Please fill me in on how these practices can co-exist peacefully.
Definitions of the terms,
Information Expert: objects that have the data needed for an operation should host the operation.
Tell Don't Ask: don't ask objects for data in order to do work; tell the objects to do the work.
Single Responsibility Principle: each object should have a narrowly defined responsibility.
I don't think that they are so much at odds as they are emphasizing different things that will cause you pain. One is about structuring code to make it clear where particular responsibilities are and reducing coupling, the other is about reducing the reasons to modify a class.
We all have to make decisions each and every day about how to structure code and what dependencies we are willing to introduce into designs.
We have built up a lot of useful guidelines, maxims and patterns that can help us to make the decisions.
Each of these is useful to detect different kinds of problems that could be present in our designs. For any specific problem that you may be looking at there will be a sweet spot somewhere.
The different guidelines do contradict each other. Just applying every piece of guidance you have heard or read will not make your design better.
For the specific problem you are looking at today you need to decide what the most important factors that are likely to cause you pain are.
You can talk about "Tell Don't Ask" when you ask for object's state in order to tell object to do something.
In your first example TransferObjectFactory.createFrom just a converter. It doesn't tell Customer object to do something after inspecting it's state.
I think first example is correct.
Those classes are not at odds. The DTO is simply serving as a conduit of data from storage that is intended to be used as a dumb container. It certainly doesn't violate the SRP.
On the other hand the .toDTO method is questionable -- why should Customer have this responsibility? For "purity's" sake I would have another class who's job it was to create DTOs from business objects like Customer.
Don't forget these principles are principles, and when you can et away with simpler solutions until changing requirements force the issue, then do so. Needless complexity is definitely something to avoid.
I highly recommend, BTW, Robert C. Martin's Agile Patterns, Practices and principles for much more in depth treatments of this subject.
DTOs with a sister class (like you have) violate all three principles you stated, and encapsulation, which is why you're having problems here.
What are you using this CustomerDTO for, and why can't you simply use Customer, and have the DTOs data inside the customer? If you're not careful, the CustomerDTO will need a Customer, and a Customer will need a CustomerDTO.
TellDontAsk says that if you are basing a decision on the state of one object (e.g. a customer), then that decision should be performed inside the customer class itself.
An example is if you want to remind the Customer to pay any outstanding bills, so you call
List<Bill> bills = Customer.GetOutstandingBills();
PaymentReminder.RemindCustomer(customer, bills);
this is a violation. Instead you want to do
Customer.RemindAboutOutstandingBills()
(and of course you will need to pass in the PaymentReminder as a dependency upon construction of the customer).
Information Expert says the same thing pretty much.
Single Responsibility Principle can be easily misunderstood - it says that the customer class should have one responsibility, but also that the responsibility of grouping data, methods, and other classes aligned with the 'Customer' concept should be encapsulated by only one class. What constitutes a single responsibility is extremely hard to define exactly and I would recommend more reading on the matter.
Craig Larman discussed this when he introduced GRASP in Applying UML and Patterns to Object-Oriented Analysis and Design and Iterative Development (2004):
In some situations, a solution suggested by Expert is undesirable, usually because of problems in coupling and cohesion (these principles are discussed later in this chapter).
For example, who should be responsible for saving a Sale in a database? Certainly, much of the information to be saved is in the Sale object, and thus Expert could argue that the responsibility lies in the Sale class. And, by logical extension of this decision, each class would have its own services to save itself in a database. But acting on that reasoning leads to problems in cohesion, coupling, and duplication. For example, the Sale class must now contain logic related to database handling, such as that related to SQL and JDBC (Java Database Connectivity). The class no longer focuses on just the pure application logic of “being a sale.” Now other kinds of responsibilities lower its cohesion. The class must be coupled to the technical database services of another subsystem, such as JDBC services, rather than just being coupled to other objects in the domain layer of software objects, so its coupling increases. And it is likely that similar database logic would be duplicated in many persistent classes.
All these problems indicate violation of a basic architectural principle: design for a separation of major system concerns. Keep application logic in one place (such as the domain software objects), keep database logic in another place (such as a separate persistence services subsystem), and so forth, rather than intermingling different system concerns in the same component.[11]
Supporting a separation of major concerns improves coupling and cohesion in a design. Thus, even though by Expert we could find some justification for putting the responsibility for database services in the Sale class, for other reasons (usually cohesion and coupling), we'd end up with a poor design.
Thus the SRP generally trumps Information Expert.
However, the Dependency Inversion Principle can combine well with Expert. The argument here would be that Customer should not have a dependency of CustomerDTO (general to detail), but the other way around. This would mean that CustomerDTO is the Expert and should know how to build itself given a Customer:
CustomerDTO dto = new CustomerDTO(bob);
If you're allergic to new, you could go static:
CustomerDTO dto = CustomerDTO.buildFor(bob);
Or, if you hate both, we come back around to an AbstractFactory:
public abstract class DTOFactory<D, E> {
public abstract D createDTO(E entity);
}
public class CustomerDTOFactory extends DTOFactory<CustomerDTO, Customer> {
#Override
public CustomerDTO createDTO(Customer entity) {
return new CustomerDTO(entity);
}
}
I don't 100% agree w/ your two examples as being representative, but from a general perspective you seem to be reasoning from the assumption of two objects and only two objects.
If you separate the problem out further and create one (or more) specialized objects to take on the individual responsibilities you have, and then have the controlling object pass instances of the other objects it is using to the specialized objects you have carved off, you should be able to observe a happy compromise between SRP (each responsibility has handled by a specialized object), and Tell Don't Ask (the controlling object is telling the specialized objects it is composing together to do whatever it is that they do, to each other).
It's a composition solution that relies on a controller of some sort to coordinate and delegate between other objects without getting mired in their internal details.