SOLID: Principles, 5 OOP Rules and Application in Development

Author: IT Sectr Published: 2026-05-11 Reading time: 10 min

SOLID — five principles of object-oriented programming formulated by Robert C. Martin (Uncle Bob) in the early 2000s. According to DigitalOcean, 2024, SOLID stands for Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion. These principles form the foundation of Clean Architecture and are applied in Android development (MVP, MVVM, Clean Architecture) and iOS (VIPER, TCA).

Key Takeaways

  • SOLID — an acronym for five OOP principles: SRP, OCP, LSP, ISP, DIP, formulated by Robert C. Martin for creating flexible and maintainable code.
  • SRP (Single Responsibility) — each class has one reason to change, one responsibility per module.
  • OCP (Open-Closed) — classes are open for extension but closed for modification, implemented through inheritance and polymorphism.
  • LSP (Liskov Substitution) — subclass objects should replace base class objects without altering program correctness.
  • ISP (Interface Segregation) — clients should not depend on interfaces they do not use; interfaces should be narrow and specific.
  • DIP (Dependency Inversion) — high-level modules do not depend on low-level modules; both depend on abstractions.

What is SOLID? Overview of the Five Principles

SOLID — a mnemonic acronym representing five principles of object-oriented design. The term was introduced by Robert C. Martin in the article “Design Principles and Design Patterns” (2000) and later popularized in the book “Agile Software Development: Principles, Patterns, and Practices” (2002). SOLID is not a framework or library — it is a set of practices that make code less coupled, more testable, and easier to change.

According to Clean Coder Blog, 2014, each SOLID principle addresses a specific design problem: SRP fights God classes, OCP prevents cascading changes, LSP guards against incorrect inheritance, ISP avoids fat interfaces, and DIP reduces tight coupling. Together they form the foundation of Clean Architecture, which is used in Android projects with MVP, MVVM, and MVI.

SRP: Single Responsibility Principle

Single Responsibility Principle (SRP) — a principle of single responsibility. The formulation: “A class should have only one reason to change.” This means every module or class is responsible for exactly one functionality or one domain entity. If a class manages both users and email sending — it has two reasons to change, violating SRP.

According to Robert C. Martin, 2002, SRP is the most important and simultaneously the most violated principle. In mobile development, SRP is often violated in Activity/Fragment by combining UI logic, navigation, networking, and business logic. The solution is to extract each layer into a separate class: ViewModel for UI logic, Repository for data, NavController for navigation.

SRP Example: Decomposing UserManager

Consider the UserManager class, which loads a profile, saves settings, and sends emails. These are three distinct responsibilities, each of which should be extracted into a separate class: UserProfileRepository (loading), UserSettingsStorage (saving), and EmailService (sending). The client code (ViewModel) uses all three through Dependency Injection, and each class is easily tested in isolation and changes without affecting the others.

kotlin
// ❌ SRP Violation: Activity knows about network, DB and UI
class ProfileActivity : AppCompatActivity() {
    fun loadProfile() {
        api.getUser() // Network call
        db.saveUser()    // Database operation
        updateUI()         // UI update
    }
}

// ✅ SRP followed: layers are separated
class ProfileViewModel : ViewModel() {
    private val repo = UserRepository()
    fun loadProfile() { repo.getUser() }
}

Signs of SRP violations: a class exceeding 200 lines, methods from different domains, frequent changes for different reasons. For Android development, the rule is simple: Activity only handles the screen lifecycle, ViewModel handles UI state, Repository handles data sources.

SRP and Microservice Architecture

The SRP principle applies not only to classes but also to service-level architecture. Each microservice handles one domain entity: UserService — only users, PaymentService — only payments, NotificationService — only notifications. This enables independent scaling, deployment, and testing of services. In mobile applications, SRP at the microservice level manifests in separating API clients by domain.

OCP: Open-Closed Principle

Open-Closed Principle (OCP) — classes should be open for extension (new behavior can be added) and closed for modification (existing code is not changed). This is achieved through polymorphism, abstract classes, and interfaces. Instead of adding if-else to an existing method, a new interface implementation is created.

According to Clean Coder Blog, 2014, OCP works best with the Strategy pattern. For example, if an app supports different payment methods (Google Pay, Apple Pay, PayPal), there is no need to add a switch-case to the payment processor. Each payment method implements a common PaymentGateway interface, and a new payment system is added as a new class without modifying existing ones.

kotlin
// ✅ OCP: open for extension, closed for modification
interface PaymentGateway {
    fun processPayment(amount: Double): Boolean
}

class GooglePayGateway : PaymentGateway {
    override fun processPayment(amount: Double) = true
}

// New payment system — without changing existing code
class ApplePayGateway : PaymentGateway {
    override fun processPayment(amount: Double) = true
}

LSP: Liskov Substitution Principle

Liskov Substitution Principle (LSP) — Barbara Liskov’s substitution principle. If S is a subtype of T, then objects of type T can be replaced with objects of type S without altering program properties. Formally: a function using a base class should work correctly with any of its subclasses. If a subclass throws an exception where the base class does not — LSP is violated.

According to Robert C. Martin, 2002, LSP is the hardest SOLID principle to understand. The classic violation example is the Square class inheriting from Rectangle. If setWidth on Square sets both width and height, client code expecting Rectangle behavior gets an unexpected result. In mobile development, LSP is often violated when inheriting ViewModel — when a child ViewModel adds required dependencies.

kotlin
// ❌ LSP Violation: Square breaks Rectangle behavior
open class Rectangle(open var width: Int, open var height: Int)

class Square(side: Int) : Rectangle(side, side) {
    override var width
        get() = super.width
        set(value) { super.setBoth(value, value) }
}

ISP: Interface Segregation Principle

Interface Segregation Principle (ISP) — clients should not depend on interfaces they do not use. Instead of a single “fat” interface, create several narrow specialized ones. If a class implements an interface but some methods throw UnsupportedOperationException or remain empty — that is a clear sign of ISP violation.

According to DigitalOcean, 2024, ISP is especially relevant in mobile development when designing ViewModel and Repository. Instead of a single UserRepository interface with all CRUD methods, it is better to create QueryUserRepository (read-only) and CommandUserRepository (write). Then a read-only client (UI element) depends only on the Query interface and knows nothing about write methods.

kotlin
// ❌ Fat interface — client is forced to implement unnecessary methods
interface UserOperations {
    fun getUser(id: String): User
    fun saveUser(user: User)
    fun deleteUser(id: String)
    fun exportUsers(): File
}

// ✅ ISP: segregated interfaces
interface UserReader { fun getUser(id: String): User }
interface UserWriter { fun saveUser(user: User) }
interface UserDeleter { fun deleteUser(id: String) }

DIP: Dependency Inversion Principle

Dependency Inversion Principle (DIP) — high-level modules should not depend on low-level modules. Both should depend on abstractions (interfaces). Abstractions should not depend on details — details should depend on abstractions. This is not “Dependency Injection” (DI), although DI is a common way to implement DIP.

According to Robert C. Martin, 2019, DIP is the foundation of Clean Architecture. ViewModel (high-level) should not directly create a RetrofitApi instance (detail). Instead, ViewModel depends on a UserRepository interface, and the concrete UserRepositoryImpl with Retrofit is passed through the constructor. In Android, DIP is implemented through Hilt/Dagger or Koin: all dependencies are provided via the DI container.

kotlin
// ✅ DIP: Module depends on abstraction, not on details
class UserRepositoryImpl(
    private val api: UserApi,   // Depends on interface
    private val db: UserDao     // Depends on interface
) : UserRepository {

    override suspend fun getUser(id: String): User {
        return api.fetchUser(id)
    }
}

// Hilt DI: details are wired through the DI module
@Module
object NetworkModule {
    @Provides
    fun provideUserApi(retrofit: Retrofit): UserApi =
        retrofit.create(UserApi::class.java)
}

Applying SOLID in Mobile Development

SOLID in mobile development is applied at all levels: from application architecture to individual classes. In Android projects, Clean Architecture divides code into three layers: domain (business logic — independent of frameworks), data (repositories, API, database), and presentation (UI, ViewModel). The domain layer uses SOLID principles: use cases (SRP), repository interfaces (DIP), entity classes (OCP + LSP).

According to Android Developers Guide, 2025, SRP in Android manifests in separating ViewModel, Repository, and Mapper. OCP — when adding new data sources through the DataSource interface. LSP — in uniform Result handling across different repositories. ISP — in the CQRS approach (separating Read/Write repositories). DIP — through Hilt/Koin for dependency injection.

PrincipleProblem Without ItSolution in Mobile Project
SRPActivity with 1000+ linesViewModel + UseCase + Repository
OCPswitch-case by payment typeStrategy: PaymentGateway interface
LSPBug when replacing BaseViewModelCheck subclass contract
ISPUnsupportedOperationExceptionReader / Writer separation
DIPViewModel manually creates RetrofitHilt / Koin DI container

Common Mistakes When Applying SOLID

SOLID mistakes are most often related to excessive code overcomplication. The first — following principles literally without considering context. Splitting one UserService class into 10 interfaces and 15 classes just for “clean” ISP is overengineering. SOLID is a tool, not a goal. The second mistake — confusing SRP with “one method = one responsibility.” A class can have several methods if they all belong to the same area of responsibility.

According to Simple Thread, 2024, the third mistake — ignoring LSP when inheriting ViewModel in Android. If the base ViewModel expects LiveData but the child uses StateFlow — client code subscribed to LiveData will not receive updates. The fourth — violating DIP for testing: RepositoryImpl directly creates an OkHttpClient instance, making unit testing impossible.

The golden rule: apply SOLID when it solves a real problem (frequent changes, testing difficulty, duplication). For simple CRUD screens, strict adherence to all five principles is overkill. For business logic, financial calculations, and API interactions, SOLID is essential.

SOLID and Clean Architecture Connection

Clean Architecture (Robert C. Martin, 2012) — a direct application of SOLID at the application layer level. SRP defines use case boundaries (each use case — one class). OCP is implemented through repository interfaces (Data Layer can change without modifying Domain). ISP provides separation of Use Case into input/output boundaries. DIP — dependency direction inward to the Domain layer. LSP guarantees that any repository implementation is replaceable without breaking use cases.

Frequently Asked Questions

What is SOLID in simple terms?

SOLID — five rules for writing code that is easy to change, test, and understand. Each letter is one principle: don’t write big classes (SRP), don’t change existing code — add new (OCP), don’t break the behavior of subclasses (LSP), and others.

Which SOLID principle is the most important?

SRP (Single Responsibility) is considered the most important because its violation leads to God classes — huge classes that are hard to test and change. However, without DIP (Dependency Inversion), the code remains tightly coupled, which is also critical.

Is SOLID mandatory for mobile development?

Not mandatory, but highly recommended for commercial projects with a long lifecycle. For simple apps (one screen, no business logic), SOLID may be overkill. For projects with 50+ screens and 3+ developers, SOLID is a minimum requirement.

What happens if you don’t follow SOLID?

Consequences: classes become “fat” (1000+ lines), changes in one place break three others, unit tests become impossible, adding a new feature takes weeks instead of days. Over time, the code turns into a “Big Ball of Mud” — tangled and fragile.

How to check if SOLID is being followed in a project?

Signs of compliance: each class is under 200 lines, changing a feature does not touch 5+ files, tests can be written without mocking 10 dependencies, a new developer understands the structure in a day. Tools like SonarQube and detekt help identify SRP and DIP violations.

Summary

  • SOLID — five OOP principles (SRP, OCP, LSP, ISP, DIP) for creating flexible and maintainable code
  • SRP — each entity is responsible for one task, solves the God class problem
  • OCP — extension through polymorphism, not modification of existing code
  • LSP — subclasses should not break the behavior of the base class
  • ISP — narrow interfaces instead of universal “Swiss Army knives”
  • DIP — dependency on abstractions, injection through Hilt/Koin in Android
  • SOLID is essential for Clean Architecture and commercial mobile projects

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.

Discuss the project

Read also