This post is the first in a five-part series which will give an introduction to every principle. You may want to subscribe to Invisible to the eye feed if you want to stay tuned on new issues of this series.
Here are some examples of classes which does not follow the SRP:
- a Car which fills its fuel tank by itself
- a CreditCard which knows how to charge itself (the classic Misko Hevery's example)
- a CreditCardProcessor which knows how to do http requests
- a Comment which sends mails
A rule of thumb to make this decision is to describe the behavior of a class with a single phrase. If you cannot formulate such a phrase or it contains the word and or other connectives, probably the behavior should be divided in more simple parts.
Particularly, entity classes (in respect to service ones) should have only the purpose to maintain state along with their business, inherent behavior. That's why a Comment instance contains name, text and mail fields but not a method warnAuthor(), which sends mails, to call on subsequent comments insertion.
The advantages of religiously following SRP are:
- classes are more reusable, since you can pick only the one which implements a specific behavior without reusing a God class which can do everything and depends on everything.
- classes are shorter and simpler to maintain.
- design is more fine-grained, because every bit of behavior has its place in a small class. Knowing what you are going to modify it's half of the work in object-oriented development: with smaller classes, it will be obvious where a change belongs.
- writing small and cohesive classes leads to testable code, while writing God classes leads to a non-testable ball of mud. A maintainable system is composed by a graph of object whose classes depends on each other for collaboration: this picture is obtained with dependency injection techniques.
Now that we are inspired by the principle, let's factor out some responsibilities from our example classes:
- a GasStation or a GasPump will fuel a Car's tank
- a CreditCardProcessor should take care of charging a CreditCard
- a CreditService will insulate CreditCardProcessor from the Internet
- a CommentRepository will call a Mailer or a CommentSubscriber whenever a new Comment instance is add to it
* The object in the image at the top of the post is Bicycle Wheel from Marcel Duchamp, a surrealist artist. It is an artwork, but to me is a perfect symbol of an object that does too much.