SOLID: principios, 5 reglas POO y aplicación en desarrollo

Autor: IT Sectr Publicado: 2026-05-11 Tiempo de lectura: 10 min

SOLID — cinco principios de la programación orientada a objetos formulados por Robert C. Martin (Uncle Bob) a principios de los años 2000. Según DigitalOcean, 2024, SOLID significa Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation y Dependency Inversion. Estos principios forman la base de Clean Architecture y se aplican en el desarrollo Android (MVP, MVVM, Clean Architecture) e iOS (VIPER, TCA).

Puntos clave

  • SOLID — acrónimo de cinco principios POO: SRP, OCP, LSP, ISP, DIP, formulados por Robert C. Martin para crear código flexible y mantenible.
  • SRP (Single Responsibility) — cada clase tiene una razón para cambiar, una responsabilidad por módulo.
  • OCP (Open-Closed) — las clases están abiertas para extensión pero cerradas para modificación, se implementa mediante herencia y polimorfismo.
  • LSP (Liskov Substitution) — los objetos de subclases deben reemplazar objetos de la clase base sin alterar la corrección del programa.
  • ISP (Interface Segregation) — los clientes no deben depender de interfaces que no utilizan, las interfaces deben ser estrechas y específicas.
  • DIP (Dependency Inversion) — los módulos de alto nivel no dependen de módulos de bajo nivel, ambos dependen de abstracciones.

¿Qué es SOLID? Visión general de los cinco principios

SOLID — acrónimo nemotécnico que representa cinco principios de diseño orientado a objetos. El término fue introducido por Robert C. Martin en el artículo «Design Principles and Design Patterns» (2000) y posteriormente popularizado en el libro «Agile Software Development: Principles, Patterns, and Practices» (2002). SOLID no es un framework ni una librería — es un conjunto de prácticas que hacen que el código sea menos acoplado, más testeable y fácil de modificar.

Según Clean Coder Blog, 2014, cada principio SOLID resuelve un problema de diseño específico: SRP combate las clases God, OCP previene cambios en cascada, LSP protege contra herencias incorrectas, ISP evita interfaces grandes y DIP reduce el acoplamiento fuerte. Juntos forman la base de Clean Architecture, que se utiliza en proyectos Android con MVP, MVVM y MVI.

SRP: Principio de Responsabilidad Única

Single Responsibility Principle (SRP) — principio de responsabilidad única. La formulación: «Una clase debe tener solo una razón para cambiar». Esto significa que cada módulo o clase es responsable de exactamente una funcionalidad o una entidad del dominio. Si una clase gestiona tanto usuarios como envío de correos — tiene dos razones para cambiar, violando SRP.

Según Robert C. Martin, 2002, SRP es el principio más importante y al mismo tiempo el más violado. En el desarrollo móvil, SRP se viola a menudo en Activity/Fragment al combinar lógica de UI, navegación, red y lógica de negocio. La solución es extraer cada capa en una clase separada: ViewModel para lógica de UI, Repository para datos, NavController para navegación.

Ejemplo SRP: Descomposición de UserManager

Considere la clase UserManager, que carga un perfil, guarda configuraciones y envía correos. Son tres responsabilidades distintas, cada una debe extraerse en una clase separada: UserProfileRepository (carga), UserSettingsStorage (guardado) y EmailService (envío). El código cliente (ViewModel) usa las tres mediante Dependency Injection, y cada clase se prueba fácilmente de forma aislada y cambia sin afectar a las demás.

kotlin
// ❌ Violación SRP: Activity conoce la red, BD y UI
class ProfileActivity : AppCompatActivity() {
    fun loadProfile() {
        api.getUser() // Llamada de red
        db.saveUser()    // Operación de BD
        updateUI()         // Actualización de UI
    }
}

// ✅ SRP cumplido: las capas están separadas
class ProfileViewModel : ViewModel() {
    private val repo = UserRepository()
    fun loadProfile() { repo.getUser() }
}

Señales de violación de SRP: una clase que supera las 200 líneas, tiene métodos de diferentes dominios, cambia con frecuencia por distintas razones. Para el desarrollo Android, la regla es simple: Activity solo maneja el ciclo de vida de la pantalla, ViewModel maneja el estado de UI, Repository maneja las fuentes de datos.

SRP y Arquitectura de Microservicios

El principio SRP se aplica no solo a clases sino también a la arquitectura a nivel de servicio. Cada microservicio maneja una entidad de dominio: UserService — solo usuarios, PaymentService — solo pagos, NotificationService — solo notificaciones. Esto permite escalar, desplegar y probar servicios de forma independiente. En aplicaciones móviles, SRP a nivel de microservicios se manifiesta en la separación de clientes API por dominio.

OCP: Principio Abierto/Cerrado

Open-Closed Principle (OCP) — las clases deben estar abiertas para extensión (se puede agregar nuevo comportamiento) y cerradas para modificación (el código existente no se cambia). Esto se logra mediante polimorfismo, clases abstractas e interfaces. En lugar de agregar if-else a un método existente, se crea una nueva implementación de interfaz.

Según Clean Coder Blog, 2014, OCP funciona mejor con el patrón Strategy. Por ejemplo, si una aplicación soporta diferentes métodos de pago (Google Pay, Apple Pay, PayPal), no es necesario agregar un switch-case al procesador de pagos. Cada método de pago implementa una interfaz común PaymentGateway, y un nuevo sistema de pago se agrega como una nueva clase sin modificar las existentes.

kotlin
// ✅ OCP: abierto para extensión, cerrado para modificación
interface PaymentGateway {
    fun processPayment(amount: Double): Boolean
}

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

// Nuevo sistema de pago — sin cambiar código existente
class ApplePayGateway : PaymentGateway {
    override fun processPayment(amount: Double) = true
}

LSP: Principio de Sustitución de Liskov

Liskov Substitution Principle (LSP) — principio de sustitución de Barbara Liskov. Si S es un subtipo de T, entonces los objetos de tipo T pueden ser reemplazados por objetos de tipo S sin alterar las propiedades del programa. Formalmente: una función que usa una clase base debe funcionar correctamente con cualquier subclase. Si una subclase lanza una excepción donde la clase base no lo hace — LSP está violado.

Según Robert C. Martin, 2002, LSP es el principio SOLID más difícil de entender. El ejemplo clásico de violación es la clase Square que hereda de Rectangle. Si setWidth en Square establece tanto ancho como alto, el código cliente que espera comportamiento de Rectangle obtiene un resultado inesperado. En el desarrollo móvil, LSP se viola a menudo al heredar ViewModel — cuando una ViewModel hija agrega dependencias obligatorias.

kotlin
// ❌ Violación LSP: Square rompe el comportamiento de Rectangle
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: Principio de Segregación de Interfaces

Interface Segregation Principle (ISP) — los clientes no deben depender de interfaces que no utilizan. En lugar de una única interfaz «gorda», cree varias interfaces estrechas y especializadas. Si una clase implementa una interfaz pero algunos métodos lanzan UnsupportedOperationException o quedan vacíos — es una señal clara de violación de ISP.

Según DigitalOcean, 2024, ISP es especialmente relevante en el desarrollo móvil al diseñar ViewModel y Repository. En lugar de una única interfaz UserRepository con todos los métodos CRUD, es mejor crear QueryUserRepository (solo lectura) y CommandUserRepository (escritura). Entonces un cliente de solo lectura (elemento UI) depende solo de la interfaz Query y no sabe nada sobre los métodos de escritura.

kotlin
// ❌ Interfaz grande — el cliente se ve forzado a implementar métodos innecesarios
interface UserOperations {
    fun getUser(id: String): User
    fun saveUser(user: User)
    fun deleteUser(id: String)
    fun exportUsers(): File
}

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

DIP: Principio de Inversión de Dependencias

Dependency Inversion Principle (DIP) — los módulos de alto nivel no deben depender de módulos de bajo nivel. Ambos deben depender de abstracciones (interfaces). Las abstracciones no deben depender de los detalles — los detalles deben depender de las abstracciones. Esto no es «Dependency Injection» (DI), aunque DI es una forma común de implementar DIP.

Según Robert C. Martin, 2019, DIP es la base de Clean Architecture. ViewModel (alto nivel) no debe crear directamente una instancia de RetrofitApi (detalle). En su lugar, ViewModel depende de una interfaz UserRepository, y la implementación concreta UserRepositoryImpl con Retrofit se pasa a través del constructor. En Android, DIP se implementa mediante Hilt/Dagger o Koin: todas las dependencias se proporcionan a través del contenedor DI.

kotlin
// ✅ DIP: Module depende de abstracciones, no de detalles
class UserRepositoryImpl(
    private val api: UserApi,   // Depende de la interfaz
    private val db: UserDao     // Depende de la interfaz
) : UserRepository {

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

// Hilt DI: los detalles se conectan a través del módulo DI
@Module
object NetworkModule {
    @Provides
    fun provideUserApi(retrofit: Retrofit): UserApi =
        retrofit.create(UserApi::class.java)
}

Aplicación de SOLID en desarrollo móvil

SOLID en desarrollo móvil se aplica en todos los niveles: desde la arquitectura de la aplicación hasta clases individuales. En proyectos Android, Clean Architecture divide el código en tres capas: domain (lógica de negocio — independiente de frameworks), data (repositorios, API, BD) y presentation (UI, ViewModel). La capa domain usa principios SOLID: casos de uso (SRP), interfaces de repositorio (DIP), clases de entidad (OCP + LSP).

Según Android Developers Guide, 2025, SRP en Android se manifiesta en la separación de ViewModel, Repository y Mapper. OCP — al agregar nuevas fuentes de datos a través de la interfaz DataSource. LSP — en el manejo uniforme de Result en diferentes repositorios. ISP — en el enfoque CQRS (separación de repositorios Read/Write). DIP — mediante Hilt/Koin para inyección de dependencias.

PrincipioProblema sin élSolución en proyecto móvil
SRPActivity de 1000+ líneasViewModel + UseCase + Repository
OCPswitch-case por tipo de pagoStrategy: interfaz PaymentGateway
LSPError al reemplazar BaseViewModelVerificar contrato de subclases
ISPUnsupportedOperationExceptionSeparación Reader / Writer
DIPViewModel crea Retrofit manualmenteContenedor DI Hilt / Koin

Errores comunes al aplicar SOLID

Errores de SOLID suelen estar relacionados con la sobrecomplicación excesiva del código. El primero — seguir los principios literalmente sin considerar el contexto. Dividir una clase UserService en 10 interfaces y 15 clases solo por un ISP «limpio» es sobreingeniería. SOLID es una herramienta, no un objetivo. El segundo error — confundir SRP con «un método = una responsabilidad». Una clase puede tener varios métodos si todos pertenecen a la misma área de responsabilidad.

Según Simple Thread, 2024, el tercer error — ignorar LSP al heredar ViewModel en Android. Si la ViewModel base espera LiveData pero la hija usa StateFlow — el código cliente suscrito a LiveData no recibirá actualizaciones. El cuarto — violar DIP por las pruebas: RepositoryImpl crea directamente una instancia de OkHttpClient, imposibilitando las pruebas unitarias.

La regla de oro: aplique SOLID cuando resuelva un problema real (cambios frecuentes, dificultad de pruebas, duplicación). Para pantallas CRUD simples, el cumplimiento estricto de los cinco principios es excesivo. Para lógica de negocio, cálculos financieros e interacciones con API, SOLID es esencial.

Conexión entre SOLID y Clean Architecture

Clean Architecture (Robert C. Martin, 2012) — aplicación directa de SOLID a nivel de capas de la aplicación. SRP define los límites de los casos de uso (cada caso de uso — una clase). OCP se implementa mediante interfaces de repositorio (Data Layer puede cambiar sin modificar Domain). ISP proporciona separación del caso de uso en límites de entrada/salida. DIP — dirección de dependencias hacia adentro de la capa Domain. LSP garantiza que cualquier implementación de repositorio sea reemplazable sin romper los casos de uso.

Preguntas frecuentes

¿Qué es SOLID en palabras simples?

SOLID — cinco reglas para escribir código fácil de cambiar, probar y entender. Cada letra es un principio: no escribas clases grandes (SRP), no cambies código existente — agrega nuevo (OCP), no rompas el comportamiento de las subclases (LSP) y otros.

¿Cuál es el principio SOLID más importante?

SRP (Single Responsibility) se considera el más importante porque su violación lleva a God classes — clases enormes difíciles de probar y modificar. Sin embargo, sin DIP (Dependency Inversion) el código permanece fuertemente acoplado, lo que también es crítico.

¿Es SOLID obligatorio para el desarrollo móvil?

No es obligatorio, pero es muy recomendable para proyectos comerciales con un ciclo de vida largo. Para aplicaciones simples (una pantalla, sin lógica de negocio), SOLID puede ser excesivo. Para proyectos con 50+ pantallas y 3+ desarrolladores, SOLID es un mínimo necesario.

¿Qué pasa si no se sigue SOLID?

Consecuencias: las clases se vuelven «gordas» (1000+ líneas), un cambio en un lugar rompe otros tres, es imposible escribir pruebas unitarias, agregar una nueva funcionalidad toma semanas en lugar de días. Con el tiempo, el código se convierte en un «Big Ball of Mud» — enredado y frágil.

¿Cómo verificar si se sigue SOLID en un proyecto?

Señales de cumplimiento: cada clase tiene menos de 200 líneas, cambiar una funcionalidad no afecta a 5+ archivos, las pruebas se escriben sin simular 10 dependencias, un nuevo desarrollador entiende la estructura en un día. Herramientas como SonarQube y detekt ayudan a identificar violaciones de SRP y DIP.

Resumen

  • SOLID — cinco principios POO (SRP, OCP, LSP, ISP, DIP) para crear código flexible y mantenible
  • SRP — cada entidad es responsable de una tarea, resuelve el problema de God classes
  • OCP — extensión mediante polimorfismo, no modificación de código existente
  • LSP — las subclases no deben romper el comportamiento de la clase base
  • ISP — interfaces estrechas en lugar de «navajas suizas» universales
  • DIP — dependencia de abstracciones, inyección mediante Hilt/Koin en Android
  • SOLID es esencial para Clean Architecture y proyectos móviles comerciales

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también