The Single Responsibility Principle, the most pervasive idea in software engineering and simplest way to improve your code
3 min read
The Single Responsibility Principle (SRP) is one of those simple ideas that enlight developers and scientists as well.
When correctly following the Single Responsibility Principle, your code will be faster to develop, simpler to debug and other people will find it easy to navigate it. Hence, it will be simpler for you to share it with your colleagues and for them to enhance it or to modify it.
The SRP introduces a simple rule so that you can have a very quick and easy to check test to immediately see if your code is well written or if something should change.
If you violate the Single Responsibility Principle, most likely you should re-think about your code, however, if you don’t violate it, it does not mean that your code is perfect.
The Single Responsibility Principle
The Single Responsibility Principle roughly states that:
A module should have only one reason to change
Here a “module” can be interpreted as a class, or as a set of classes, or as a function or even as a part of your single file.
Making it concrete
While the SRP is well-known between software engineers, it can sound strange at first to scientist or junior alike. A more useful view of the SRP simple will state that each part of your system should do one thing and one thing only.
Being responsible for only a single functionality.
Suppose your software needs to read data from a file, and then it needs to do some calculation and finally print the results.
Following the SRP, there will be three part in your software.
The first part, the
input-handler will be responsible to read the files and package all the information in a suitable data structure (list, arrays, dictionary, map, etc…) for the calculation.
The second part, the
compute will be responsible for reading the data structure coming from the
input-handler, do the necessary computation, and return the result.
The third part, the
output-handler will be responsible to read the data from the
compute and print them to the screen.
If the format of the file changes, then, only the input-handler will need to change. Crucially the new
input-handler will need to create a data structure that the
compute know how to handle. Most likely, the new
input-handler will need to create the same data structure of the old.
input-handler will need to respect the same interface, of the old
If instead of reading from a file we start to read from a database, similarly, as long as we pass a suitable data-structure to the
compute part, the
input-handler is free to change to fit the needs of your analysis.
Same approach to the
compute part, as long as it can read the data that comes from the
input-handler and pass suitable data to the
output-handler it can internally change to fit your needs. Maybe you don’t need anymore to compute the average, but you need the median.
output-handler, as long as it can read the data from the
compute part, it does not really matter what it does. When you are starting your analysis it could be sufficient to just print to screen the results, but if your analysis get more complex you may want to start creating plots.
Deeper than it sound
While our example seems very simple and easy to implement, the SRP is a driving force in software engineering.
It can be applied on both the architecture of the code, but also in smaller parts. If your simulation or analysis is composed of several steps, is vital to correctly applying the SRP. Both for speeding up the developing time, to make it simpler to find error, and to make it simpler to share it with your colleagues.