Have you ever changed one part of your code... and suddenly, five unrelated things broke?
Or added a small feature... and ended up editing dozens of lines across a single class?
If yes, you’ve probably encountered a violation of one of the most important design principles in software engineering: The Single Responsibility Principle (SRP).
Let’s understand it with a problem and why it violates SRP.
Meet the classic God Class. You’ve probably seen it before. Maybe even written it.
At first glance, this may seem convenient — everything about an employee in one place.
But let’s pause and examine what this class is actually doing:
That’s four distinct responsibilities rolled into one class.
This class is tightly coupled to four different reasons to change. That’s a red flag.
A class should have one, and only one, reason to change. — Robert C. Martin (Uncle Bob)
In simple words: A class should do one thing and do it well.
The Single Responsibility Principle (SRP) is the 'S' in the famous SOLID principles of object-oriented design.
But what exactly is a "responsibility"?
It’s not a method. It’s not a function. It’s a reason for the class to change.
Ask yourself this:
How many reasons might someone need to update this class in the future?
If the answer is more than one — it’s likely breaking SRP.
Think of a restaurant.
Would you hire one person to do all of these?
Of course not. You’d hire:
Each with a single responsibility.
Why should your code be any different?
Time to fix our original Employee
God Class using SRP.
We’ll take each distinct responsibility from the original Employee
class and extract it into its own focused, well-named class.
They all deserve their own classes.
Employee
ClassLet’s start by slimming down Employee
into a simple data class:
This class now does one thing: represent an employee.It doesn’t calculate salary, store itself, or send emails. That’s the job of others.
This class handles just the logic of calculating an employee’s net pay.If payroll policy changes, we only update this class.
The responsibility for talking to the database belongs here. You can swap out JDBC for JPA or another data layer without touching the rest of the system.
This class handles the formatting and creation of a textual payslip. You can replace the output format later (PDF, HTML, JSON) without affecting the rest of your codebase.
This class is responsible only for sending emails. It doesn’t calculate anything. It doesn’t generate the report. It just sends it.
The mistake: Breaking a class into too many tiny classes that don't add real value.
Example:
Creating separate classes for TaxCalculator
, BonusCalculator
, BenefitsCalculator
, and SalaryAggregator
— when all of these could be grouped into a cohesive PayrollCalculator.
Why it’s a problem:
Focus on cohesion, not fragmentation. Group logic that changes together or belongs to the same business concern.
The mistake: Assuming each method must be its own class.
Example:
Some developers might try to split this into:
WelcomeEmailSender
PayslipEmailSender
Why it’s a problem:
Don’t confuse the number of methods with number of responsibilities. If the methods serve the same purpose (sending emails), it’s fine to keep them together.
The mistake: Thinking, “This class is small and works fine — no need to split it.”
Example: A utility class that starts off simple but quietly grows:
Why it’s a problem:
Watch for creeping responsibilities even in utility classes. Apply SRP early before small classes become unmanageable.
The mistake: Taking the "reason to change" definition too literally or too vaguely.
Bad interpretation: “I only ever change this class when a stakeholder asks for a change, so it has one reason to change.”
Why it’s a problem: SRP is not about who asks for the change, but what kind of change is being made.
Clarify the responsibility in terms of business logic or technical behavior. Ask: Is this logic cohesive, or are unrelated concerns bundled together?
Yes, you’ll likely end up with more classes — but that’s not a bad thing.
Instead of having one massive class doing everything poorly, you have smaller, focused classes doing one thing well. These classes are:
Think of it as managing complexity through separation, not increasing it. When responsibilities are clearly separated, your system becomes easier to reason about — even if the file count grows.
SRP helps reduce cognitive load, even if it increases the class count.
There’s no hard-and-fast rule. It depends on your domain and use case. But here’s a simple heuristic:
If you need to use the word “and” or “or” to describe what your class does, it probably has more than one responsibility.
Example:
Another tip: If the reasons for change are unrelated — say, a tax policy update vs. a new email template, your class is likely doing too much.
Absolutely. SRP can and should be applied across multiple levels:
SRP is a mindset: separate concerns to improve clarity and adaptability, no matter the scale.
When a class does only one thing, testing becomes straightforward.
You don’t have to:
You can focus on the specific input/output of a class without worrying about unrelated functionality baked into it.
Sometimes it’s okay to group closely related behaviors into one class.
For example, a EmailService
class that:
That’s fine — they all fall under the same responsibility: sending emails.
But if that class also starts doing PDF generation or user authentication, it’s time to split it up.
Think of SRP less as a strict rule and more as a guiding principle.
It won’t always be obvious where to draw the line, and that’s okay.
Use SRP to:
When used wisely, SRP becomes a tool to manage change and complexity, not a burden.