Acoplamento (Coupling) no desenvolvimento mobile — conceitos-chave, tipos e como reduzir

Autor: IT Sectr Publicado: 2026-05-13 Tempo de leitura: 9 min

Acoplamento (Coupling) é uma métrica que mostra o quanto um módulo de uma aplicação depende de outro. De acordo com a Wikipedia, baixo acoplamento (low coupling) é sinal de um sistema bem projetado, onde os módulos podem ser alterados sem quebrar os vizinhos. Gerenciar o coupling é uma das principais tarefas do arquiteto ao projetar aplicações mobile.

Pontos Principais

  • Coupling — grau de dependência entre módulos: alto = acoplamento forte, baixo = acoplamento fraco
  • Content coupling — o pior tipo, quando um módulo modifica dados internos de outro módulo
  • Data coupling — o melhor tipo, quando os módulos trocam apenas dados simples através de parâmetros
  • Dependency Injection — a principal ferramenta para reduzir o coupling no desenvolvimento mobile
  • Interfaces e abstrações — o principal mecanismo para reduzir o acoplamento entre camadas da aplicação

O que é Coupling

Coupling (acoplamento) é uma métrica que determina o quão fortemente um módulo ou classe está conectado a outro. Quanto mais um módulo sabe sobre a estrutura interna de outro, maior o coupling e mais difícil é alterar o sistema. Em uma arquitetura bem projetada, o coupling deve ser mínimo — os módulos interagem apenas através de interfaces estritamente definidas.

Existem dois lados do coupling: aferente (dependências de entrada — quantos módulos dependem deste) e eferente (dependências de saída — de quantos módulos este depende). Analisar essas métricas ajuda a identificar pontos críticos na arquitetura onde a alteração de um módulo afetaria muitos outros. Ferramentas como IntelliJ Dependency Analyzer e Xcode Graph visualizam essas conexões.

É importante entender que o coupling zero é impossível — os módulos precisam interagir de alguma forma, caso contrário não é um sistema, mas um conjunto de programas isolados. A tarefa do arquiteto é tornar o coupling gerenciável e transparente. O ideal: módulos interagem apenas através de interfaces e passam apenas dados simples, sem conhecer a estrutura interna um do outro. Isso é chamado de baixo acoplamento (loose coupling).

Tipos de acoplamento do fraco ao forte

Seis tipos de coupling formam uma escala do melhor ao pior. Compreender essa escala ajuda a avaliar o código existente e escolher a direção da refatoração. A maioria dos projetos mobile tem tipos mistos de coupling, e a tarefa do arquiteto é substituir progressivamente os tipos fortes pelos fracos.

Data coupling — o melhor tipo

Data coupling (acoplamento de dados) — os módulos trocam apenas dados simples através de parâmetros de métodos. O módulo A chama o método do módulo B, passando primitivos ou estruturas simples, e recebe um resultado. O módulo A não sabe como B é implementado internamente. Este é o tipo mais desejável de coupling: minimiza o impacto das mudanças.

Exemplo: EmailValidator.isValid(email: String): Boolean. A classe consumidora passa uma string e recebe um Booleano, sem ideia das expressões regulares ou regras de validação dentro do validador. Alterar a lógica de validação não requer alterar o consumidor — o coupling é mínimo. Data coupling é o objetivo para todas as interfaces públicas em uma aplicação.

Stamp coupling — aceitável, mas não ideal

Stamp coupling (acoplamento por carimbo) — os módulos trocam objetos compostos, mas usam apenas parte de seus campos. O módulo A passa um objeto User para o método calculateDiscount, que usa apenas user.status. O problema: se a estrutura de User mudar (um campo obrigatório for adicionado), o módulo calculateDiscount não muda, mas o consumidor que cria o objeto User muda.

Na prática, o stamp coupling é inevitável e aceitável se o objeto passado for um modelo de dados padrão (Entity). O problema surge quando um módulo recebe um objeto inteiro apenas por um campo. Nesses casos, é melhor passar o valor específico diretamente (data coupling). A solução é analisar o uso de campos pelo lado receptor.

Control, External, Common e Content coupling

Control coupling — um módulo passa uma flag para outro que controla seu comportamento (calculate(useNewAlgorithm: Boolean)). Isso é pior que stamp coupling porque o módulo consumidor precisa conhecer as variantes internas de operação do módulo chamado. Solução: dividir o método em dois — calculateWithNewAlgorithm() e calculateWithLegacyAlgorithm().

External coupling — os módulos dependem de um protocolo externo, formato de dados ou API. Todos os módulos que analisam o mesmo JSON ou trabalham com o mesmo banco de dados têm external coupling. Não pode ser completamente evitado, mas pode ser isolado: criar uma camada de mapeamento entre o formato externo e os modelos internos. Common coupling — os módulos compartilham um estado global comum. Content coupling — o pior tipo, quando um módulo modifica diretamente os dados internos de outro módulo.

Tipo de couplingNívelDescrição
DataMelhorPassagem de dados simples por parâmetros
StampAceitávelPassagem de objetos com uso parcial
ControlMédioControle de comportamento por flags
ExternalAltoDependência de protocolo/formato externo
CommonMuito altoCompartilhamento de estado global
ContentInaceitávelModificação direta de dados internos do módulo

A escala de coupling de data (ideal) a content (desastre) é uma ferramenta prática para revisões de código. Se você vir common ou content coupling em um projeto — esses são alvos prioritários de refatoração. Data e stamp coupling são aceitáveis e presentes em qualquer projeto, mas sua quantidade deve ser controlada.

Por que o coupling é crítico no desenvolvimento mobile

Alto coupling transforma o desenvolvimento em um processo lento onde cada alteração requer verificar dezenas de módulos potencialmente quebrados. Isso é especialmente crítico no desenvolvimento mobile: as plataformas são atualizadas anualmente (Android API Level, iOS SDK), as bibliotecas trimestralmente e os requisitos de negócio continuamente. O baixo acoplamento é a única maneira de lidar com esse fluxo de mudanças sem regressões constantes.

Exemplo prático: um aplicativo mobile onde todas as telas importam diretamente NetworkingManager e DatabaseManager. Ao substituir o cliente HTTP de Retrofit para Ktor (Android) ou de URLSession para Alamofire (iOS), o desenvolvedor teria que modificar cada tela. Com baixo acoplamento, basta alterar uma implementação escondida atrás da interface NetworkDataSource — os consumidores não notarão a substituição.

O impacto do coupling nos testes unitários também é enorme. Uma classe com alto coupling (criação direta de dependências no construtor) não pode ser testada isoladamente — ela arrasta consigo o banco de dados, a rede e a UI. Para testar tal classe, é necessário iniciar um emulador e esperar pelos testes de integração. Uma classe com baixo coupling aceita dependências através de injeção no construtor e pode ser facilmente simulada.

kotlin
// Alto coupling — a classe cria suas próprias dependências
class ProfileViewModelHigh {
    private val api = RetrofitApi()
    private val db = RoomDatabase.getInstance()
    private val cache = MemoryCache()
}

// Baixo coupling — as dependências são passadas através do construtor
class ProfileViewModelLow(
    private val api: ApiService,
    private val db: DatabaseService,
    private val cache: CacheService
)

No primeiro caso, ProfileViewModelHigh está fortemente ligado a implementações específicas — substituir Retrofit por Ktor requer alterar o código da ViewModel. No segundo caso, ProfileViewModelLow depende apenas de interfaces, cujas implementações são fornecidas externamente. Testar a segunda classe é trivial: passar implementações simuladas e verificar a lógica sem emulador.

Padrões para reduzir o coupling

Princípio da Inversão de Dependência (D no SOLID) é a base para reduzir o coupling. O princípio determina depender de abstrações, não de implementações concretas. Em vez de uma classe criar diretamente um objeto RetrofitApi, ela deve receber uma interface ApiService. Isso desloca a dependência de uma biblioteca específica para o nível de abstração, que pode ser substituído sem alterar o consumidor.

Padrão Observer (ou suas versões reativas — StateFlow, Combine Publishers) reduz o coupling entre a fonte de dados e os assinantes. O assinante não sabe de onde os dados vêm — ele simplesmente reage às mudanças. Isso desacopla o remetente e o receptor: uma nova fonte de dados pode ser adicionada sem alterar os assinantes existentes. EventBus e SharedFlow funcionam no mesmo princípio.

Padrão Bridge separa a abstração da implementação, permitindo que mudem independentemente. No desenvolvimento mobile, Bridge é usado, por exemplo, para módulos dependentes de plataforma: uma interface comum ImageLoader com diferentes implementações para iOS (Kingfisher, Nuke) e Android (Glide, Coil). O código que trabalha com ImageLoader não depende da biblioteca escolhida e pode substituí-la simplesmente alterando a implementação.

Dependency Injection como ferramenta de gerenciamento de coupling

Dependency Injection (DI) é a ferramenta mais prática para reduzir o coupling no desenvolvimento mobile. Em vez de uma classe criar suas próprias dependências, um contêiner DI (Hilt, Koin, Dagger para Android; Swinject, Factory para iOS) as fornece externamente. A classe recebe as dependências através de injeção por construtor, método ou propriedade, sem conhecer as implementações concretas.

A DI documenta explicitamente as dependências da classe: basta olhar o construtor para entender com quais módulos a classe interage. Se o construtor aceita 8 parâmetros de diferentes camadas — este é um sinal de coupling excessivo que requer refatoração. Boa prática é não mais que 3-4 dependências por classe. Um número maior indica violação do Princípio da Responsabilidade Única e coupling excessivo.

A DI também simplifica os testes: para cada teste você cria uma classe com dependências simuladas, sem precisar de banco de dados ou rede real. No Flutter, a DI é implementada através de Provider, Riverpod ou GetIt. Independentemente do framework, o objetivo é um: reduzir o acoplamento entre módulos tornando as dependências explícitas e substituíveis. O uso de DI em projetos mobile tem sido o padrão de fato desde a década de 2020.

swift
// O contêiner DI constrói o grafo de dependências
protocol AuthServiceProtocol {
    func login(email: String, password: String) async throws -> User
}

final class AuthService: AuthServiceProtocol {
    func login(email: String, password: String) async throws -> User {
        // implementação
    }
}

// ViewModel não conhece o serviço específico — apenas o protocolo
final class LoginViewModel {
    private let auth: AuthServiceProtocol

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

// DI Container é o único lugar onde os tipos concretos são criados
final class DIContainer {
    lazy var authService: AuthServiceProtocol = AuthService()
    lazy var loginViewModel: LoginViewModel {
        LoginViewModel(auth: self.authService)
    }
}

Aqui, LoginViewModel depende apenas do protocolo AuthServiceProtocol, não de um AuthService específico. Substituir a implementação (por exemplo, mudar de Firebase Auth para um servidor personalizado) requer alterações apenas no DIContainer. Todos os consumidores de AuthServiceProtocol permanecem intactos — o coupling é minimizado através de abstração e DI.

Perguntas Frequentes

Como o coupling difere da coesão?

Coesão mede a consistência interna de um módulo, enquanto o coupling mede a interconexão externa entre módulos. Uma boa arquitetura busca alta coesão e baixo coupling. Essas métricas são inversamente proporcionais: aumentar a coesão geralmente reduz o coupling, e vice-versa.

Qual tipo de coupling é aceitável em código de produção?

Data e stamp são normais e estão presentes em qualquer projeto. Control coupling é aceitável em cenários limitados (por exemplo, padrão strategy). External coupling é inevitável ao trabalhar com APIs externas, mas deve ser isolado atrás de uma camada de mapeamento. Common e content coupling são sinais de problemas arquiteturais que requerem refatoração imediata.

Como medir o coupling em um projeto?

Ferramentas de análise estática: IntelliJ IDEA Dependency Matrix, Xcode Graph, relatório de dependências do Gradle, SonarQube. Métricas: coupling aferente (Ca), coupling eferente (Ce), Instabilidade (Ce/(Ca+Ce)). Alta Instabilidade (próxima de 1) significa que o módulo é fácil de alterar e poucas coisas o referenciam — isso é bom.

O baixo coupling pode ser prejudicial?

Coupling extremamente baixo pode significar um número excessivo de abstrações e interfaces que complicam a navegação no código. Se uma interface separada for criada para cada classe, o programador perde tempo saltando entre arquivos. Equilíbrio: interfaces para a API externa do módulo, mas não para cada classe auxiliar interna.

Como reduzir o coupling ao trabalhar com código legado?

Use a técnica Strangler Fig — substitua gradualmente as chamadas diretas por interfaces. Comece extraindo interfaces para as classes mais referenciadas. Em seguida, introduza um contêiner DI. Cubra o código isolado com testes de caracterização para garantir que a refatoração não altere o comportamento do sistema.

Resumo

  • Coupling — métrica de dependência entre módulos: baixo acoplamento é o objetivo de uma boa arquitetura
  • Data coupling — o melhor tipo, content coupling — o pior, inaceitável em código de produção
  • Inversão de Dependência e interfaces — os principais mecanismos para reduzir o acoplamento
  • Dependency Injection — ferramenta prática que torna as dependências explícitas e substituíveis
  • Alto coupling torna o código frágil: uma mudança quebra muitos módulos
  • Baixo coupling simplifica os testes: cada módulo é simulado independentemente sem emulador
  • Equilibre entre coupling e abstrações — interfaces excessivas complicam o código

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também