Acoplamiento (Coupling) en el desarrollo móvil — conceptos clave, tipos y cómo reducirlo

Autor: IT Sectr Publicado: 2026-05-13 Tiempo de lectura: 9 min

El acoplamiento (coupling) es una métrica que muestra cuánto depende un módulo de la aplicación de otro. Según Wikipedia, el acoplamiento débil (low coupling) es una señal de un sistema bien diseñado, donde los módulos se pueden cambiar sin romper los vecinos. Gestionar el coupling es una de las principales tareas del arquitecto al diseñar aplicaciones móviles.

Puntos Clave

  • Coupling — el grado de dependencia entre módulos: alto = acoplamiento fuerte, bajo = acoplamiento débil
  • Content coupling — el peor tipo, cuando un módulo modifica datos internos de otro módulo
  • Data coupling — el mejor tipo, cuando los módulos intercambian solo datos simples a través de parámetros
  • Dependency Injection — la herramienta principal para reducir el coupling en el desarrollo móvil
  • Interfaces y abstracciones — el mecanismo principal para reducir el acoplamiento entre capas de la aplicación

Qué es el Coupling

Coupling (acoplamiento) es una métrica que determina qué tan estrechamente un módulo o clase está conectado con otro. Cuanto más sabe un módulo sobre la estructura interna de otro, mayor es el coupling y más difícil es cambiar el sistema. En una arquitectura bien diseñada, el coupling debe ser mínimo: los módulos interactúan solo a través de interfaces estrictamente definidas.

Existen dos aspectos del coupling: aferente (dependencias entrantes — cuántos módulos dependen de este) y eferente (dependencias salientes — de cuántos módulos depende este). Analizar estas métricas ayuda a identificar puntos críticos en la arquitectura donde el cambio de un módulo afectaría a muchos otros. Herramientas como IntelliJ Dependency Analyzer y Xcode Graph visualizan estas conexiones.

Es importante entender que el coupling cero es imposible — los módulos deben interactuar de alguna manera, de lo contrario no es un sistema sino un conjunto de programas aislados. La tarea del arquitecto es hacer que el coupling sea manejable y transparente. El ideal: los módulos interactúan solo a través de interfaces y pasan solo datos simples, sin conocer la estructura interna del otro. Esto se llama acoplamiento débil (loose coupling).

Tipos de acoplamiento de débil a fuerte

Seis tipos de coupling forman una escala del mejor al peor. Comprender esta escala ayuda a evaluar el código existente y elegir la dirección de la refactorización. La mayoría de los proyectos móviles tienen tipos mixtos de coupling, y la tarea del arquitecto es reemplazar progresivamente los tipos fuertes por los débiles.

Data coupling — el mejor tipo

Data coupling (acoplamiento de datos) — los módulos intercambian solo datos simples a través de parámetros de métodos. El módulo A llama al método del módulo B, pasando primitivos o estructuras simples, y recibe un resultado. El módulo A no sabe cómo está implementado B internamente. Este es el tipo de coupling más deseable: minimiza el impacto de los cambios.

Ejemplo: EmailValidator.isValid(email: String): Boolean. La clase consumidora pasa una cadena y recibe un Booleano, sin tener idea de las expresiones regulares o reglas de validación dentro del validador. Cambiar la lógica de validación no requiere cambiar el consumidor — el coupling es mínimo. El data coupling es el objetivo para todas las interfaces públicas en una aplicación.

Stamp coupling — aceptable pero no ideal

Stamp coupling (acoplamiento por sello) — los módulos intercambian objetos compuestos pero usan solo una parte de sus campos. El módulo A pasa un objeto User al método calculateDiscount, que usa solo user.status. El problema: si la estructura de User cambia (se agrega un campo obligatorio), el módulo calculateDiscount no cambia, pero el consumidor que crea el objeto User sí cambia.

En la práctica, el stamp coupling es inevitable y aceptable si el objeto pasado es un modelo de datos estándar (Entity). El problema surge cuando un módulo recibe un objeto completo solo por un campo. En tales casos, es mejor pasar el valor específico directamente (data coupling). La solución es analizar el uso de campos por parte del receptor.

Control, External, Common y Content coupling

Control coupling — un módulo pasa una bandera a otro que controla su comportamiento (calculate(useNewAlgorithm: Boolean)). Esto es peor que stamp coupling porque el módulo consumidor debe conocer las variantes internas de funcionamiento del módulo llamado. Solución: dividir el método en dos — calculateWithNewAlgorithm() y calculateWithLegacyAlgorithm().

External coupling — los módulos dependen de un protocolo externo, formato de datos o API. Todos los módulos que analizan el mismo JSON o trabajan con la misma base de datos tienen external coupling. No se puede evitar completamente, pero se puede aislar: crear una capa de mapeo entre el formato externo y los modelos internos. Common coupling — los módulos comparten un estado global común. Content coupling — el peor tipo, cuando un módulo modifica directamente los datos internos de otro módulo.

Tipo de couplingNivelDescripción
DataMejorPaso de datos simples a través de parámetros
StampAceptablePaso de objetos con uso parcial
ControlMedioControl del comportamiento mediante banderas
ExternalAltoDependencia de protocolo/formato externo
CommonMuy altoEstado global compartido
ContentInaceptableModificación directa de datos internos del módulo

La escala de coupling desde data (ideal) hasta content (desastre) es una herramienta práctica para las revisiones de código. Si ves common o content coupling en un proyecto — son objetivos prioritarios de refactorización. Los data y stamp coupling son aceptables y están presentes en cualquier proyecto, pero su cantidad debe controlarse.

Por qué el coupling es crítico en el desarrollo móvil

El coupling alto convierte el desarrollo en un proceso lento donde cada cambio requiere verificar decenas de módulos potencialmente rotos. Esto es especialmente crítico en el desarrollo móvil: las plataformas se actualizan anualmente (Android API Level, iOS SDK), las bibliotecas trimestralmente y los requisitos de negocio continuamente. El acoplamiento débil es la única forma de manejar este flujo de cambios sin regresiones constantes.

Ejemplo práctico: una aplicación móvil donde todas las pantallas importan directamente NetworkingManager y DatabaseManager. Al reemplazar el cliente HTTP de Retrofit a Ktor (Android) o de URLSession a Alamofire (iOS), el desarrollador tendría que modificar cada pantalla. Con acoplamiento débil, basta con cambiar una implementación oculta detrás de la interfaz NetworkDataSource — los consumidores no notarán el reemplazo.

El impacto del coupling en las pruebas unitarias también es enorme. Una clase con coupling alto (creación directa de dependencias en el constructor) no se puede probar de forma aislada — arrastra consigo la base de datos, la red y la UI. Para probar dicha clase, hay que iniciar un emulador y esperar las pruebas de integración. Una clase con coupling bajo acepta dependencias mediante inyección en el constructor y se puede simular fácilmente.

kotlin
// Alto coupling — la clase crea sus propias dependencias
class ProfileViewModelHigh {
    private val api = RetrofitApi()
    private val db = RoomDatabase.getInstance()
    private val cache = MemoryCache()
}

// Bajo coupling — las dependencias se pasan a través del constructor
class ProfileViewModelLow(
    private val api: ApiService,
    private val db: DatabaseService,
    private val cache: CacheService
)

En el primer caso, ProfileViewModelHigh está estrechamente vinculado a implementaciones específicas — reemplazar Retrofit por Ktor requiere cambiar el código de ViewModel. En el segundo caso, ProfileViewModelLow depende solo de interfaces, cuyas implementaciones se proporcionan externamente. Probar la segunda clase es trivial: pasar implementaciones simuladas y verificar la lógica sin emulador.

Patrones para reducir el coupling

Principio de Inversión de Dependencias (D en SOLID) es la base para reducir el coupling. El principio dicta depender de abstracciones, no de implementaciones concretas. En lugar de que una clase cree directamente un objeto RetrofitApi, debe recibir una interfaz ApiService. Esto traslada la dependencia de una biblioteca específica al nivel de abstracción, que se puede reemplazar sin cambiar el consumidor.

Patrón Observer (o sus versiones reactivas — StateFlow, Combine Publishers) reduce el coupling entre la fuente de datos y los suscriptores. El suscriptor no sabe de dónde provienen los datos, simplemente reacciona a los cambios. Esto desacopla al emisor y al receptor: se puede agregar una nueva fuente de datos sin cambiar los suscriptores existentes. EventBus y SharedFlow funcionan bajo el mismo principio.

Patrón Bridge separa la abstracción de la implementación, permitiendo que cambien de forma independiente. En el desarrollo móvil, Bridge se utiliza, por ejemplo, para módulos dependientes de la plataforma: una interfaz común ImageLoader con diferentes implementaciones para iOS (Kingfisher, Nuke) y Android (Glide, Coil). El código que trabaja con ImageLoader no depende de la biblioteca elegida y puede reemplazarla simplemente cambiando la implementación.

Dependency Injection como herramienta de gestión del coupling

Dependency Injection (DI) es la herramienta más práctica para reducir el coupling en el desarrollo móvil. En lugar de que una clase cree sus propias dependencias, un contenedor DI (Hilt, Koin, Dagger para Android; Swinject, Factory para iOS) las proporciona desde fuera. La clase recibe las dependencias mediante inyección por constructor, método o propiedad, sin conocer las implementaciones concretas.

La DI documenta explícitamente las dependencias de la clase: basta con mirar el constructor para entender con qué módulos interactúa la clase. Si el constructor acepta 8 parámetros de diferentes capas — es una señal de coupling excesivo que requiere refactorización. Una buena práctica es no más de 3-4 dependencias por clase. Más indica una violación del Principio de Responsabilidad Única y coupling excesivo.

La DI también simplifica las pruebas: para cada prueba se crea una clase con dependencias simuladas, sin requerir una base de datos o red real. En Flutter, la DI se implementa mediante Provider, Riverpod o GetIt. Independientemente del framework, el objetivo es uno: reducir el acoplamiento entre módulos haciendo que las dependencias sean explícitas y reemplazables. El uso de DI en un proyecto móvil ha sido el estándar de facto desde la década de 2020.

swift
// El contenedor DI construye el grafo de dependencias
protocol AuthServiceProtocol {
    func login(email: String, password: String) async throws -> User
}

final class AuthService: AuthServiceProtocol {
    func login(email: String, password: String) async throws -> User {
        // implementación
    }
}

// ViewModel no conoce el servicio específico — solo el protocolo
final class LoginViewModel {
    private let auth: AuthServiceProtocol

    init(auth: AuthServiceProtocol) {
        self.auth = auth
    }
}

// DI Container es el único lugar donde se crean los tipos concretos
final class DIContainer {
    lazy var authService: AuthServiceProtocol = AuthService()
    lazy var loginViewModel: LoginViewModel {
        LoginViewModel(auth: self.authService)
    }
}

Aquí, LoginViewModel depende solo del protocolo AuthServiceProtocol, no de un AuthService específico. Reemplazar la implementación (por ejemplo, cambiar de Firebase Auth a un servidor personalizado) requiere cambios solo en DIContainer. Todos los consumidores de AuthServiceProtocol permanecen intactos — el coupling se minimiza mediante abstracción y DI.

Preguntas Frecuentes

¿En qué se diferencia el coupling de la cohesión?

La cohesión mide la consistencia interna de un módulo, mientras que el coupling mide la interconexión externa entre módulos. Una buena arquitectura busca alta cohesión y bajo coupling. Estas métricas son inversamente proporcionales: aumentar la cohesión generalmente reduce el coupling, y viceversa.

¿Qué tipo de coupling es aceptable en código de producción?

Data y stamp son normales y están presentes en cualquier proyecto. El control coupling es aceptable en escenarios limitados (por ejemplo, patrón strategy). El external coupling es inevitable al trabajar con APIs externas, pero debe aislarse tras una capa de mapeo. El common y content coupling son señales de problemas arquitectónicos que requieren refactorización inmediata.

¿Cómo medir el coupling en un proyecto?

Herramientas de análisis estático: IntelliJ IDEA Dependency Matrix, Xcode Graph, informe de dependencias de Gradle, SonarQube. Métricas: coupling aferente (Ca), coupling eferente (Ce), Inestabilidad (Ce/(Ca+Ce)). Una Inestabilidad alta (cercana a 1) significa que el módulo es fácil de cambiar y pocas cosas lo referencian — esto es bueno.

¿Puede ser perjudicial un coupling bajo?

Un coupling extremadamente bajo puede significar un número excesivo de abstracciones e interfaces que complican la navegación del código. Si se crea una interfaz separada para cada clase, el programador pierde tiempo saltando entre archivos. Equilibrio: interfaces para la API externa del módulo, pero no para cada clase auxiliar interna.

¿Cómo reducir el coupling al trabajar con código heredado?

Utiliza la técnica Strangler Fig — reemplaza gradualmente las llamadas directas con interfaces. Comienza extrayendo interfaces para las clases más referenciadas. Luego introduce un contenedor DI. Cubre el código aislado con pruebas de caracterización para asegurarte de que la refactorización no cambie el comportamiento del sistema.

Resumen

  • Coupling — métrica de dependencia entre módulos: el acoplamiento débil es el objetivo de una buena arquitectura
  • Data coupling — el mejor tipo, content coupling — el peor, inaceptable en código de producción
  • Inversión de Dependencias e interfaces — los mecanismos principales para reducir el acoplamiento
  • Dependency Injection — herramienta práctica que hace las dependencias explícitas y reemplazables
  • Coupling alto hace el código frágil: un cambio rompe muchos módulos
  • Coupling bajo simplifica las pruebas: cada módulo se simula independientemente sin emulador
  • Equilibra entre coupling y abstracciones — el exceso de interfaces complica el código

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