SOLID Foundations for Contemporary Software Engineering
Part 1: Enhancing Single Responsibility Principle
In a world where technology evolves at a breakneck pace, it’s valid to question the relevance of principles formulated decades ago, even more so when they were initially explicitly formulated for object-oriented programming.
However, the underlying concepts of SOLID—such as modularity, separation of concerns, and encapsulation—have broad applicability beyond just OOP.
SOLID principles are foundational to software engineering, the same as the laws of physics are for the physical world, and they can inspire best practices in other paradigms and on different levels of abstraction.
Microservices Architecture and Beyond
The Single Responsibility Principle (SRP), in its original definition, states:
There should never be more than one reason for a class to change.
This mindset naturally aligns with microservices. First, let’s alter the definition by swapping the word class with microservice.
There should never be more than one reason for a microservice to change.
In this form, the SRP aligns perfectly with the microservices architectural style. Each service is designed to perform a single function or handle a specific business capability. This allows for more manageable, scalable, and resilient systems. Microservices can be developed, deployed, and scaled independently, which enhances team agility and overall system maintainability.
But nowadays, even microservices have become an approach challenged by concepts such as right-sized service or function as a service. Even more so, the definition above narrows the SRP to be focused solely on the backend.
There should never be more than one reason for a component to change.
In this generalization, a component can be anything:
a class in OOP
a service in a decoupled system
a function in the functional paradigm or FaaS
a component in a single-page web application
an NPM module
etc.
But let’s not stop there. Even though we have captured almost any application entity now, we can expand the principle outside of the boundaries of a software system. Let’s name this principle:
Unified Change Principle (UCP)
There should never be more than one reason for a change in a component.
The Unified Change Principle (UCP) keeps the core objective of SRP — ensuring that each component is cohesive and focused enough that a singular concern drives any modification, but also adds guidance for use cases when a component represents:
a feature
a team’s (sprint) goal
an application behavior
Let’s look at a simple example of a feature request of adding a newsletter subscription functionality to a web application. This feature requires implementing a new modal variation with the subscription form, adding this subscription modal to a home page, and implementing an API and storage for e-mail addresses.
Such a standalone feature request, which represents one and only change in a component at a given time, can be broken down into more granular standalone change requests or tasks for frontend and backend teams, and those, in turn, implement those changes in the correct modules of their modular system adhering to the SRP.
One change at a time means smaller, more frequent commits and deployments that address specific issues or introduce individual features. This reduces the risk associated with deployments and makes identifying and rolling back changes easier if something goes wrong.
At the same time, this approach enables more frequent feedback loops and better adaptability in the development process.
The same approach can be used in refactoring efforts and managing technical debt by making isolated changes and addressing issues within a codebase easier by tackling them one at a time.
Quality Over Quantity
Both principles emphasize code quality and its long-term benefits over immediate output and short-term solutions.
These principles, as well as SOLID as a whole, shouldn’t be viewed as a rigid set of rules but as a set of guidelines to be interpreted and applied in the context of your specific challenges and applied in correct doses so they do not lead to over-engineering.
In Part 2 of this series, we will examine how the rest of the SOLID principles apply outside their originally defined scope. See you there!
What I’m reading
Tidy First? by Kent Beck beautifully pairs with the SRP and UCP as it shows how to make your code more readable and maintainable in small steps while working on a new change in your software.