Skip to content
Gustavo's Blog
Go back

SOLID — The Single Responsibility Principle

“A class should have only one reason to change.”

When developing software, we almost always need to create abstractions for the domain we are working on. In the OOP world, this means defining classes, interfaces, and assembling these code structures into something coherent.

During this process, we often encounter a familiar problem: classes that try to do too much.

The Rectangle Problem

Consider this diagram:

┌───────────────────┐         ┌─────────────────────┐
│  Computational    │         │                     │
│  Geometry App     │────────▶│     Rectangle       │◀──── Graphical App
└───────────────────┘         │  + draw()           │
                              │  + area(): double   │
                              └──────────┬──────────┘


                                       ┌─────┐
                                       │ GUI │
                                       └─────┘

The Rectangle class is serving two completely different purposes:

Why does this matter? Two reasons.

First, when a class handles multiple responsibilities, it may require changes for different reasons. A modification intended for one responsibility might inadvertently affect the other. If the rectangle’s constructor is modified to support drawing functionality, the computational geometry — which should remain independent — might also need to change, potentially breaking it.

Second, it becomes harder to understand the true purpose of the class. Is Rectangle responsible for drawing, or does it calculate the area?

Two issues, in summary:

  1. Domain Integrity — classes that combine responsibilities can compromise the clear structure of the domain.
  2. Unintended Side Effects — when responsibilities are intertwined, changes made for one purpose can inadvertently impact others.

There are many other issues beyond these two, but the main problem here is a human one. We struggle to understand code that mixes different responsibilities, which leads to bugs and extra time spent fixing them. The discussions around SOLID principles are ultimately meant to help developers fix bugs more easily and quickly.

If you look at Uncle Bob’s Clean Code, one of his early points is that we spend more time reading code than writing it. And if we’re going to spend so much time reading code, it should be pleasant and easy to understand. By following SRP, readability is greatly improved.

The Fix

Separate the rectangle into two classes. Create a low-level class GeometricRectangle that handles all geometric calculations, and another class Rectangle responsible for drawing. Rectangle can use composition to include a GeometricRectangle since it needs its geometric properties when drawing.

┌──────────────────┐    ┌──────────────────────┐    ┌─────────────────┐
│  Computational   │    │  Graphical           │    │                 │
│  Geometry App    │    │  Application         │    │                 │
└────────┬─────────┘    └──────────┬───────────┘    │                 │
         │                         │                │                 │
         ▼                         ▼                │                 │
┌────────────────────┐    ┌────────────────┐        │                 │
│ GeometricRectangle │◀───│   Rectangle    │───────▶│      GUI        │
│ + area(): double   │    │   + draw()     │        │                 │
└────────────────────┘    └───────────────┘        └─────────────────┘

With this refactoring, if GeometricRectangle changes the way it calculates the area, you don’t need to worry about the class that draws it. They are physically separated and logically distinct.

When Not to Apply It

There’s an important point here: we don’t always need to apply SRP. It depends on the domain and the problem you’re solving.

SRP should only be applied if changes actually happen. If a class rarely or never changes, and you know this from understanding your domain (by talking to business stakeholders), then there’s no real need to enforce it.

As Uncle Bob states in Agile Software Development:

“An axis of change is an axis of change only if the changes actually occur. It is not wise to apply the SRP, or any other principle for that matter, if there is no symptom.”

So be careful not to over-engineer and introduce unnecessary complexity into something that doesn’t actually need it.


The Single Responsibility Principle is a fundamental concept in software design that helps maintain clear, maintainable, and scalable code. By ensuring that a class has only one reason to change, we reduce the risk of unintended side effects.

Mixing responsibilities leads to unnecessary dependencies, making changes more complex and error-prone. Separating them creates more modular, flexible, and readable code.

But it’s essential to apply SRP with context in mind. Not every class needs to be split just for the sake of following a principle. Over-engineering leads to unnecessary complexity rather than solving real problems.

The goal of SRP is not to follow a rule — it’s to improve code maintainability and developer efficiency. Writing clean, modular, easy-to-read code makes software development more productive and enjoyable, helping us focus on solving real business problems rather than fighting complexity.

You’ll see that this is the core idea of all five SOLID principles. The next four are tools that help solve this same fundamental problem.


Share this post on:

Previous Post
SOLID — The Open/Closed Principle