SRP (Single Responsibility Principle) — the first principle of SOLID, which states: each class or module should have exactly one reason to change. This principle was formulated by Robert Martin in the book Clean Architecture (2017) and became the foundation of modular design. According to this book, applying SRP directly reduces component coupling and eliminates cascading changes when modifying functionality.
Key Takeaways
SRP (Single Responsibility Principle) is the single responsibility principle that states: every class or module should have exactly one reason to change. This does not mean a class should perform exactly one operation. It refers to a group of related actions united by a single responsibility to one actor.
Robert Martin redefined SRP in terms of actors: a class should change only at the request of one stakeholder or one group of people. If two different actors require changes to the same class, the responsibility is incorrectly divided.
For example, an Employee class that both calculates salary (accounting department request) and generates reports (management request) violates SRP. Changing calculation rules could affect report generation and vice versa.
A module should have one and only one reason to change. The reason for change is determined by an actor — a person or system initiating the requirement. If requirements from different actors lead to changes in one module, the module violates SRP.
The concept of the actor makes SRP a practical tool for architectural analysis rather than an abstract recommendation. When designing a system, simply ask: “Who will ask to change this code?” — if the answer includes more than one stakeholder, the responsibility should be separated.
Single responsibility is implemented by grouping methods that change for one reason. A class becomes a “collection point” for related logic rather than a “Swiss Army knife” for all occasions. This simplifies code understanding: a developer sees the class and immediately understands its purpose.
The mechanism of SRP is based on the single axis of change rule. If functionality can change for independent reasons, it should be extracted into separate classes. Connections between these classes are built through composition or delegation.
Violating SRP manifests in “God Objects” — classes that contain dozens of methods working with different data. Such a class is difficult to test — testing one method requires setting up the environment for all others. Changing one responsibility can break another, making the code fragile.
In practice, SRP helps developers answer the question “where is this code?” If each responsibility is separated into its own class, finding the right file takes seconds. In an Android project with MVVM architecture, this means UserViewModel is only responsible for the user screen state, and UserRepository for data retrieval. A developer looking for caching logic goes to UserCacheRepository, not ViewModel. Such code organization speeds up onboarding of new team members and reduces the number of errors during refactoring.
Mobile development places special demands on code modularity. An Android Fragment or iOS ViewController often becomes a “magnet” for logic: handling taps, calling APIs, parsing responses, updating UI — all in one class. SRP requires separating these responsibilities.
In Android architecture, SRP is embedded in Google’s Jetpack recommendations: ViewModel is responsible for screen state, Repository for data, UseCase for business logic. Each component has one reason to change. In iOS development, the MVVM and Coordinator patterns follow the same logic.
Following SRP in mobile projects yields measurable benefits: 40-60% reduction in class size, less time spent on code reviews, and fewer regression bugs when adding new functionality. Isolated modules are easier to cover with unit tests and reuse across other screens.
Unit testing of classes that follow SRP requires fewer mock objects and less configuration. If a class has one responsibility, its dependencies are limited. The test checks one behavior rather than a combination of multiple unrelated scenarios.
According to the Google Testing Blog report (2023), classes with a single responsibility show 35% higher test coverage compared to aggregator classes. Developers are more willing to write tests for small, understandable modules.
Let’s look at a typical Android class that violates SRP — it loads data, parses the response, and updates the UI. After refactoring, each responsibility is separated into its own component.
// SRP violation: one class does everything
class BadUserProfileActivity {
fun loadUser(userId: Int) {
// HTTP request
// JSON parsing
// UI update
// Database save
}
}
// After applying SRP
class UserRepository {
fun getUser(userId: Int): User
}
class UserViewModel {
private val repo: UserRepository
fun loadUser(userId: Int) { }
}
class UserProfileFragment {
fun render(user: User) { }
}
A similar example in iOS Swift with separation of the network layer and display:
// SRP violation: ViewController manages data and UI
class BadProfileViewController: UIViewController {
func viewDidLoad() {
// URLSession request
// Decode JSON
// Label update
}
}
// After applying SRP
protocol UserServiceProtocol {
func fetchUser(id: Int) async throws -> User
}
class ProfileViewModel {
private let service: UserServiceProtocol
func loadProfile(id: Int) { }
}
class ProfileViewController: UIViewController {
func display(user: User) { }
}
SRP refactoring does not complicate architecture — it redistributes responsibility. The amount of code may even decrease by eliminating duplication. Each new class has a clear purpose and can be developed independently.
Composition helps maintain SRP where inheritance creates unnecessary coupling. Instead of a superclass with a dozen methods, a subclass receives a set of specialized objects through the constructor. Each object is responsible for its own functionality.
In Android development, the Decorator pattern allows adding responsibilities without modifying the original class. In iOS, a Middleware chain in the networking layer separates logging, caching, and authentication into individual modules.
The most common violation is a “God Class”: a class that manages the database, sends notifications, generates reports, and handles user input. Such a class becomes a project bottleneck — any change requires full regression testing.
In mobile development, SRP violations are caused by mixing business logic and UI logic in Activity, Fragment, or ViewController. When an onClickListener simultaneously validates data, calls an API, and updates button visibility — that is a direct violation of the single responsibility principle.
The consequences of violating SRP include: difficulty in parallel development (conflicts in one file), hindered unit testing, high cost of making changes, and reduced code readability. Projects with systematic SRP violations require 2-3 times more time to add new functionality.
SRP violations can be identified by indirect signs: a class exceeds 200 lines, imports modules from different application layers (UI + network + database), has more than 5 public methods on different topics. Cohesion metric is a statistical indicator: low cohesion of methods within a class points to an SRP violation.
To detect SRP violations, use static analysis tools: for Android — Detekt with the TooManyFunctions rule, for iOS — SwiftLint with the file_length rule. These utilities highlight classes exceeding size and complexity thresholds.
Refactoring classes that violate SRP is done through Extract Class or Extract Delegate: a group of related methods is extracted into a separate class, and the original class delegates calls to them. Gradual application of such refactorings turns a “God Class” into a set of loosely coupled modules, each with a single responsibility. This approach allows improving architecture without stopping development — refactoring is done iteratively, one module at a time.
Frequently Asked Questions
No. SRP is not about the number of methods, but about the number of reasons for change. A class can have a dozen methods if they all serve one responsibility to one actor. One method is the opposite extreme, leading to excessive code fragmentation.
They are the same principle. Single Responsibility Principle translates to both “edinstvennaya otvetstvennost” and “edinstvennaya obyazannost.” The term “responsibility” more accurately reflects the essence: it is about responsibility to an actor, not a technical function.
Repository is a direct result of applying SRP to the data layer. Instead of spreading data access logic across ViewModel or UseCase, Repository takes on a single responsibility: providing data with source abstraction. This is a classic SRP implementation in mobile architecture.
Yes, SRP does not prohibit dependencies. A class with a single responsibility can delegate part of the work to other classes through composition. The key is that these delegated tasks are part of the same responsibility, not an independent reason for change.
Ask the question: “Which actors could require changes to this class?” If the answer contains more than one actor, SRP is violated. Additionally: try to describe the class’s purpose in one sentence without the conjunction “and.” If you cannot, the class does too much.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also