Better programming: The Single Responsibility PrincipleJul 28, 2023
In this series of articles you will become familiar with the SOLID principles, which will help you write more modular, understandable, and maintainable code. SOLID is an acronym that encompasses the following principles:
- Single Responsibility Principle
- Open/Closed Principle
- Liskov Substitution Principle
- Interface Segregation Principle
- Dependency Inversion Principle
In this article, we will explore the first of these principles, called the Single Responsibility Principle. It states that a class or module should have only one reason to change or only one responsibility. This makes the software easier to implement and prevents unexpected side effects when modifications are made.
To learn Python and build the skills to land your first job, check out our Professional Python Developer Bootcamp.
How to Apply the Single Responsibility Principle
The key idea behind SRP is that each class or module should focus on doing one thing well. They should have a single, well-defined purpose within the overall application. This principle aims to separate concerns in your code so that it is easier to understand, maintain, and extend.
Let’s look at an example of a class with multiple mixed responsibilities and how you can reorganize your code to make it more robust and readable.
Imagine you work for an audio streaming application and you have to implement the player app. For this, you create a class called Song that is in charge of storing song details and also playing back its audio. The class could look like this:
This code does what you want at first, but will cause problems later on. To start, to test the play() and stop() methods you will have to involve other parts of your code, like the system that handles the downloads, etc. Any changes in these parts will make your Song class stop working properly.
In addition, if you are in charge of managing song information and a teammate is in charge of managing the streaming process, it is very likely that you will constantly make incompatible changes to the Song class.
On the other hand, if you use this song in other parts of the application (playlists, song details screen) you will force developers of those sections to deal with responsibilities that do not correspond to them. By changing the class, they can unnecessarily create problems in the streaming process.
To solve these problems, you can assign the Song class solely the responsibility of storing the corresponding song details, and create a new Player class that handles the streaming process:
Now, we can test our Song class without worrying about involving other app components related to the download process. On the other hand, if a teammate works on the streaming part, it is less likely that they will introduce incompatible changes in the Song class. Additionally, teammates who are in charge of other parts of the application do not have to deal with audio playback logic, limiting errors they can introduce in this part of the application, since the code is much better compartmentalized.
The Benefits of the Single Responsibility Principle
By using the single responsibility principle, you get the following benefits:
By having a single responsibility, our classes depend less on the rest of our code, so you will only have to change them when you want to modify or extend their behavior directly. Likewise, when you want to implement a change in your application, you will know which class(es) to change immediately.
When your teammates start working on your application, they will understand its structure and functionality more quickly, and will know in which class to look for a specific piece of code.
By not depending so much on other classes, it will be easier for you to test the functionality of your classes in isolation, and it will be easier for you to identify points of failure in your application when it does not pass the tests.
When you try to reuse a class with multiple responsibilities in a new context, it is most likely that you will only want to use part of its functionality, while the rest will be irrelevant. However, those other pieces of functionality may depend on other objects, which you will have to involve in this part of your code, making it more fragile and confusing.
When responsibilities are well separated, teams can work on different classes in parallel without affecting each other as much. Classes are decoupled from unrelated logic.
AI moves fast. We help you keep up with it.
Get a monthly selection of the most groundbreaking advances in the world of AI, top code repositories, and our best articles and tutorials.
We hate SPAM. We will never sell your information, for any reason.