The Single Responsibility Principle (SRP) is defined by wikipedia as every object should have a single responsibility, and that all its services should be narrowly aligned with that responsibility.
Although the origins of this concept are someone disputed, most believe it was originally developed by Tom DeMarco in his book Structured Analysis and Systems Specification but was later popularized by Robert Martin in his book Agile Software Development: Principles, Patterns, and Practices. The principle simply states that a given class should have one and only one responsibility. And that the behavior of the class should be narrowly aligned with that single responsibility.
The essence of this concept has to do with the reason to change a class. If a class has more than one responsibility, it may have different reasons to change, each of which are independent of one another. Take for example a class that both imports data from a file and saves the data to a persistent storage mechanism. The single class needs to be modified for any change to the incoming file format as well as any change to the underlying data storage mechanism structure. These changes should not be connected. By modifying the class to adjust the file format, you risk introducing a bug to the file persistence code. In a hurry, without the safety net of automated unit tests (gasp!), developers tend to only test code that is related to a given change.
If your classes follow SRP, you probably can get away with only testing related code (although thorough automated unit tests are always the best course of action). If you violate SRP, you need to be extra cautious when considering the ripple effect from changes to your code. I believe SRP is so fundamental that it can make the difference between a system that is easy to maintain and one that is your worst nightmare to maintain.
Sounds simple right? Well it is, but it is common while designing and refactoring to find SRP violations. But let’s face it. Most software stinks and I have seen countless convoluted designs. Many of these designs (not designed by me of course) had a systemic SRP issue. SRP in one class in your system is not big deal, but SRP in most of your classes is sure recipe for disaster and a system that is very difficult to maintain.
When I have difficulty getting a design to feel right, I try to ask myself whether the classes in that portion of the system are following SRP. Many times, I find the core design issue stems from one or more classes with more than one responsibility.
There are many ways to deal with SRP violations. The most common are:
- Delegation – To put behavior in another class and leverage a pattern such as Strategy
- Aggregation – To push the behavior out to another class and reference this new class