S of SOLID: Single Responsibility Principle
SOLID is a well-known acronym in the software engineering field. Each of its letters stands for a principle to apply for writing maintainable and scalable software using object-oriented programming. In this series of articles, I will share my personal understanding and what I find valuable in each of these principles.
Single Responsibility Principle
The motto is: THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE.
The main keywords are cohesion, decoupling, and separation of concerns. Every class must be coherent at doing one thing and one must ensure maximal decoupling from other classes. Note that “doing one thing” is often misunderstood, it’s not about having a single method or function, but about serving a single actor/stakeholder.
The key interest is to prevent unexpected breaks in the software when modifying something else and ensure easy readability and maintenance.
Example of SRP Violation
Imagine this class:
# order.py
import pdflib
class Order:
order_id: int
amount: int
def ship_order():
...
def generate_pdf_invoice():
...
This breaks the SRP principle. Order has two responsibilities:
- Ship an order
- Generating order invoice
Also, these responsibilities are intended for different stakeholders:
- The department in charge of shipping orders
- The financial department
Each of these departments can have the need to change something in the class implementation, and changes from one shouldn’t impact the other.
Proper SRP Implementation
# order.py
class Order:
order_id: int
amount: int
# order_invoice.py
from order import Order
class OrderInvoice:
order: Order
def generate_pdf_invoice():
...
# order_shipping.py
import pdflib
from order import Order
class OrderShipping:
order: Order
def ship_order():
...
Advantages :
- The
ordermodule does not depend anymore on thepdflib - If changes are made to the PDF generation, only tests of the
OrderInvoiceclass need to be run - If someone makes any change to the
OrderInvoiceclass, we can be quite sure it won’t break theOrderclass. It simplifies the code review process.
Guidelines for SRP
Every class we write must gather code and data that:
- Are likely to change at the same time
- Are addressed to the same kind of users/stakeholders
- Respond to a single architectural/technical/functional decision
- Are called from the same other parts of the software
SRP applies at multiple levels:
- Methods
- Classes
- Modules
- Services
The Trade-off
Of course, it’s always a trade-off. Always ask yourself:
- Is it appropriate to write a new class instead of adding a new method in an existing one?
- Can it help decoupling?
- Do they have different responsibilities or serve different stakeholders?
- Will this separation make the code more maintainable or just add unnecessary complexity?
It’s not always clear how to respond. This is probably the essence of software engineering: making informed decisions about these trade-offs based on your specific context.
By Thomas Martin
Follow me or comment