The single responsibility principle (SRP) tells us that each module, class or even function should have one single responsibility It means that every class, or similar structure, in your code should have only one job to do. Everything in the class should be related to that single purpose. It is a simple and intuitive principle, bu it is sometimes hard to get right.
A lot of us developers seem to have an ill adjusted intuition for when it’s time to restructure our code. It’s far too easy to convince ourselves that we’ll go back and clean up at a later time. I convince myself about that a lot more often than I actually go back and refactor something.
We also seem to have an even worse intuition for what type code code that will be easy to maintain in the long run. A lot of us (again, that includes myself) gravitate towards code that pack too much functionality into one place. We tell ourselves that it’s a quicker way to get the job done.
However, there’s a price to be paid for going to quick at the beginning and that price is almost always that you go gradually slower and slower. The very things we did early on to increase speed has a huge risk of slowing us down in the long run.
The point with the single responsibility principle is to help us get things (more) right from the start. The SRP tells us to take the time up front to design our code in a way that helps us in the long run. Each group of functionality into it’s own encapsulated and isolated class or module. Don’t mix and match apples with rocket ships.
Single responsibility principle leads to Cleaner code
As with many things, you can take the single responsibility too far. It does not mean that your classes should only contain just one method. There may be many members as long as they relate to that single responsibility. It may be that when the a change occurs, multiple member functions of the class have to be updated. It’s even quite likely in many cases.
But the SRP does mean that we should try to separate code that might change for different reasons. A class that could change both because we want to modify front end HTML color scheme OR because we need change authentication method is most likely violating the SRP.
Working with the SRP is likely to have a tremendous effect on your code. You are going to get more but smaller classes in your design. Each of those classes will be a lot cleaner since they’re only concerned with one thing. You’re also going to have to be more diligent with how you name your classes and if you’re OK with letting go of PHP 5.2 (you should) you are going to benefit from using PHP namespaces and folders. You’re also being forced to think more about how each class interacts with the others since everything isn’t just available in the same class or even namespace any more.
A well thought out system design where classes are logically organized in folders and where each class is tightly focused on a single purpose sounds kind of appealing, doesn’t it? It also sounds a lot like what we call clean code.
(and clean code tends to be more testable and maintainable).
Finding the balance: Class Employee
There’s a classical example used to explain the only one reason to change idea, a class used to represent an employee in a system. The questions we’re supposed to ask is if it’s OK to have both functions to calculate the employee’s salary (business logic) and a set of functions that reads and writes employee objects to the database (persistence)?
The answer according to the SRP is no, the employee class should not mix business logic with persistence functionality. There are at least two reasons for the employee object to change, the first reason would be if we want to change the method used to calculate salary. The second reason to change would be if we decided to modify the database schema. Therefore according to the SRP, we should design our system with one class for employee business logic and another class for employee persistence. Different reasons for change means different classes.
But in a WordPress situation you could argue that this is a little bit over the top. Imagine a WordPress plugin that adds the custom post type to implement the Employee object and a third party tool like Advanced Custom Fields to define the various extra fields. We could still split the functionality in to two classes, one for business logic and one for database persistence.
The persistence mechanisms for a custom post type are largely decided by functions provided by the WordPress core and in this case, Advanced Custom Fields. Isolating persistence into an EmployeePersister class would simply mean that we create an additional layer between the WordPress database functions and the rest of our code. WordPress wraps the MySQL functions into an API and then we come along and wrap that API in another API. Does is make sense to create a separate class for 4-5 lines of code?
Well, it could make sense. If already know that we want to provide a Drupal version of that same plugin. Or perhaps we want to move away from using a custom post type to using our own database tables instead. If any of those two changes are actually realistic, we should go ahead and put the persistence specific code in a separate class.
But if you’re reasonably certain that such changes will not occur, then you can probably safely use the one Employee class for both types functions.
But then again, it could turn out that loading and saving the Employee internal state requires a lot of additional logic that is subject to change at a later time. In that case following the SRP and create a separate EmployeePersister class makes sense.
Applying the SRP requires us to find a balance between strict design and some sort of manageable reality. If we try too hard to look into the future and foresee every potential change, we’re probably going to end up with things we’re never going to need (YAGNI) which is bad in itself.
One way to understand the SRP is to consider the very opposite. A god-object, sometimes also called a god-class. We say that we have a a god object (or function) when a lot or even all of our code ends up in one really big class with lots methods, complex internal state, tons of dependencies and lots of responsibilities. Think of this one class as the god of your system, everything depends on it and it depends of nearly everything else. Even if the term god-object typically means the main class file of a system, god-objects are found in sub systems as well. In WordPress we can see an overall well designed plugin have local god-objects for certain things, I’ve seen a lot of Widgets implemented as de-facto god-objects.
The god object is a well known anti pattern (a common solution seen in system design that is usually ineffective and risky). A god-object often turns in to a maintenance nightmare, are difficult to debug and nearly impossible to test using standard tolls such as PHPUnit. We should avoid them.
A few signs that one of your classes might be trying to do too much:
- Your class is very long. If your class grows a lot beyond 1000 effective (not counting comments and white space) lines of code, you can probably split it into smaller classes with more distinct responsibilities
- One or many of the methods in your class grows beyond 100 effective lines of code. Large functions can usually be broken up into several smaller functions.
- The total number of methods (excluding getters and setters) grows too far beyond 25. This depends a lot on the specific class, but too many functions is an indication that your class is doing too many things.
- Your class declares a mix of static functions and instance functions. This is needed in some specific cases like to implement the singleton pattern. But if there’s a mix of static and non-static functions it usually means that the static functions has nothing to do with the object state and therefore could have been refactored into a separate class.
- Your class has functions that outputs HTML or CSS code directly (example). Following the SRP, a better option would be to separate HTML snippets and entire pages into their own files.
- Your class constructor have side effects on global state (state that is not part of your actual class). Typically via calls to add_action or add_filter (same example). This makes it a lot harder, sometimes impossible, to write unit tests for your class.
- Your main class file can’t even be included or required into a stand alone script without first loading WordPress. This is typically seen in cases where a developer mixes a class definition and old school procedural code into the same module. So that even loading that class have the side effect that a piece of procedural PHP code gets executed (same example again)
If your code does more than one of the above things there’s a chance that you will get long term benefits from splitting your class into smaller ones.
A great tool to get you started with analyzing your code is the PHP Mess detector. It’s a static code analyzer that checks your code for a number of metrics including the size of your classes and functions.
Example: The WordPress plugin boilerplate
A very pragmatic thing to do is to look at the specific real life case with a WordPress theme or plugin. A good place to look at is the WordPress plugin boilerplate written by Tom McFarlin’s WPPB foundation plugin (now maintained by Devin Vinson). It’s a foundation that many WordPress plugin are based on and it provides a good starting point of how to apply the SRP in a WordPress environment. From a birds eye perspective, the boilerplate is organized like this (lots of details excluded):
The main plugin file serves to bootstrap the rest of the plugin. It’s the only file that WordPress core really knows anything about and it’s what gets included in at every request to the server. The main job is to load the main class and hook it up to the WordPress init function.
The includes folder is where all common code is placed, including the main plugin file. Note that there are separate PHP modules for plugin activation and deactivation, each with a single responsibility. The boilerplate even uses a separate module to register all WordPress actions and filters needed by the plugin.
The admin folder is for all code that is related to the admin dashboard pages needed by this plugin. The one thing to note here is that the boilerplate encourages us to keep functionality in the main admin class but everything that renders HTML in a separate views folder (it’s actually called “partials” in real life).
The public folder has the exact same structure as the admin folder, but it’s intended for functionality and views that are used on the front end.
This basic structure of classes and folders provides an idea about how to separate different things into different folders and classes. Naturally, once you decide to base your plugin on this boilerplate, you will have plenty of opportunity to violate the SRP within this structure. Jamming all vital functionality into the main plugin class takes you right back to an evil god-object.
Look at the boilerplate as a starting point, as soon as your plugin gains in complexity, it’s your job to ensure that the code you add doesn’t pack too much into one place. Be generous with creating additional classes and make sure that similar functionality is keps grouped together and well isolated. Consider what types of reasons that could drive change in your project.
(note: There are some aspects of the plugin boilerplate that I think could be done differently to work better with other SOLID principles. Especially regarding dependency injection, but that’s a topic for another post)
Over to you
Do you have a specific question or do you just have something to add? Let me know in the comments below.