Por décadas, a indústria de software repetiu o mesmo mantra como se fosse axioma: "low coupling, high cohesion". A frase virou tatuagem cultural, está em livro de OO dos anos 90, em palestra de microserviços de 2015, em code review de 2026. O problema é que esse mantra é unidimensional, e quem tenta aplicá-lo como regra absoluta acaba produzindo arquiteturas que são piores do que o acoplamento que estavam tentando evitar: módulos cerimoniais que se comunicam por events assíncronos para resolver o que era uma chamada de função; microserviços que compartilham schema de banco escondido em uma biblioteca interna; shared kernels que viram cemitério de tipos.
Vlad Khononov, em Balancing Coupling in Software Design, propõe um modelo que recupera a complexidade real do problema. Acoplamento não é uma régua. É um sistema de três eixos: Strength (o quê é compartilhado), Distance (onde o acoplamento vive fisicamente) e Volatility (com que frequência os componentes mudam). Avaliar acoplamento sem os três eixos é como avaliar custo de viagem usando só a distância, ignorando velocidade, terreno e quantas vezes você precisa ir.
O eixo 1: Integration Strength, nem todo "compartilhar" custa o mesmo
Strength mede o que dois componentes compartilham. E aqui mora uma escala que a maioria dos times trata como binária quando é, na verdade, gradual. No extremo mais fraco, dois componentes apenas conhecem um contrato público estável, um endpoint REST versionado, uma fila com schema explícito, uma interface declarada. No extremo mais forte, eles compartilham estado interno, invariantes implícitos, ou suposições sobre representação em memória. Entre os dois extremos existem degraus: compartilhar um modelo de domínio, compartilhar uma estrutura de dados específica, depender de efeito colateral de uma implementação concreta.
O que importa para o engenheiro é o seguinte: quanto mais forte o acoplamento, maior o raio do estrago de uma mudança. Se o componente A muda e B compartilha apenas um contrato com A, B segue intacto até o contrato quebrar. Se A muda e B compartilha o modelo interno de A, qualquer ajuste em A é uma roleta russa em B. Strength é, portanto, o eixo que mede quanto da sua mudança vaza.
O eixo 2: Distance, onde o acoplamento mora fisicamente
Distance é o eixo mais subestimado da indústria. Mede a distância física e organizacional entre os pontos acoplados: dois métodos da mesma classe, duas classes do mesmo módulo, dois módulos da mesma aplicação, duas aplicações da mesma empresa, dois serviços de empresas diferentes. Cada degrau aumenta o custo de mudança coordenada, não pela mudança em si, mas por quem precisa estar envolvido, quanto tempo de comunicação, quantas barreiras de deploy.
O custo cresce de forma não-linear. Mudar duas funções no mesmo arquivo é um commit. Mudar dois módulos do mesmo serviço é uma PR coordenada. Mudar dois microserviços de squads diferentes é uma reunião, um RFC, um plano de release. Mudar dois sistemas de empresas diferentes é uma negociação contratual. Distance multiplica o custo de coordenação muito mais do que multiplica o custo do código. Times que ignoram distance tipicamente terminam em distributed monolith: muito acoplamento, espalhado por muita distância, o pior dos dois mundos.
O eixo 3: Volatility, o eixo que ninguém olha
Aqui está o eixo que praticamente nenhum manual de arquitetura discute com a profundidade necessária: com que frequência cada componente muda? Um helper de formatação de data que está estável há cinco anos pode ser fortemente acoplado com tudo no sistema e ninguém vai sentir. Um módulo de cobrança que muda toda sprint, acoplado fortemente com qualquer outro componente, é uma bomba-relógio. Acoplamento só dói quando algo muda. Se nada muda, o acoplamento é gratuito.
Isso inverte uma intuição comum. Engenheiros gastam orçamento de complexidade desacoplando partes do sistema que são, na prática, estáveis, pagam o preço da indireção em código que nunca vai precisar do benefício. Enquanto isso, deixam fortemente acoplados os módulos voláteis, porque "é só refatoração depois". A heurística correta é oposta: invista desacoplamento onde a volatilidade é alta, tolere acoplamento onde a volatilidade é baixa.
A fórmula: BALANCE = (STRENGTH XOR DISTANCE) OR NOT VOLATILITY
Lida em português engenharia: um design é balanceado quando a força do acoplamento e a distância são opostas, ou quando a volatilidade é tão baixa que o resto não importa. O XOR é o coração da fórmula. Significa que apenas um dos eixos pode estar "alto" sem desequilibrar o sistema:
- STRENGTH alta + DISTANCE baixa = coesão. Duas funções da mesma classe podem compartilhar estado interno. Está tudo bem. Isso é o que chamamos de módulo bem desenhado, partes intimamente relacionadas que vivem juntas e mudam juntas.
- STRENGTH baixa + DISTANCE alta = modularidade saudável. Dois microserviços de squads diferentes que se comunicam por um contrato público e versionado. Cada um evolui no seu tempo. É o que se espera de boa fronteira.
- STRENGTH alta + DISTANCE alta = distributed monolith. O pior cenário. Microserviços que compartilham schema de banco, ou serviços externos que dependem de detalhes internos de outro. Cada mudança vira projeto trimestral.
- STRENGTH baixa + DISTANCE baixa = cerimônia injustificada. Duas funções no mesmo arquivo se comunicando via event bus. Você pagou o preço da indireção sem ganhar nada, virou premature decoupling.
- NOT VOLATILITY = perdão universal. Se o componente está congelado, o resto pode estar errado e ninguém vai sentir. Mas confiar nisso é apostar que o futuro não vai chegar.
Os anti-patterns que a fórmula expõe imediatamente
A força do modelo é que ele nomeia patologias que antes circulavam como decisões de "boa arquitetura". Distributed monolith deixa de ser folclore e vira um quadrante do diagrama: alta strength + alta distance. Premature decoupling (aquela mania de injetar interface entre duas funções do mesmo módulo) deixa de ser "estilo pessoal" e vira um quadrante errado: baixa strength + baixa distance, pagando preço sem benefício. E o famoso "shared kernel que cresce sem governança" é um caso típico de strength alta + distance crescente, começa coeso, vira distributed monolith conforme os times que dependem dele se afastam organizacionalmente.
Sinais práticos de desequilíbrio
- Toda mudança "simples" exige PR em três repositórios: strength alta cruzando distance alta. Você tem um distributed monolith.
- Bug em um serviço aparece em outro por "efeito colateral": strength altíssima vazando entre fronteiras que deveriam isolar.
- Refatorar uma classe local exige tocar 7 arquivos de adapter: premature decoupling, você desacoplou antes da volatilidade justificar.
- Time A bloqueia time B toda sprint: distance alta com strength alta institucionalizada via dependência cruzada.
Como aplicar, auditoria de acoplamento em três passos
O modelo não exige ferramenta nova. Exige uma mudança de pergunta. Em vez de "isso está acoplado?", o time passa a perguntar três coisas. (1) Qual é a força do acoplamento? O que exatamente é compartilhado, contrato, modelo, estado, suposição? (2) Qual é a distância? Mesmo arquivo, mesmo módulo, mesmo serviço, mesma empresa, ou cruzando fronteira externa? (3) Qual é a volatilidade? Esse código muda toda sprint, toda quarter, todo ano, ou está congelado?
Com as três respostas, o passo final é olhar para o quadrante e decidir: está balanceado, ou estou pagando custo onde não preciso e tolerando risco onde deveria investir? A maioria dos refactorings que "melhoram arquitetura" e na prática só pioram entrega são exatamente erros de leitura desse diagrama, desacoplar onde não precisa, tolerar acoplamento onde a volatilidade vai cobrar.
O reframe que muda como você lê PRs
O ganho real do modelo de Khononov não é teórico. É operacional. Você passa a ler PRs com um olho diferente. Em vez de cair no reflexo de "essas duas classes estão acopladas demais", você pergunta: elas estão no mesmo módulo? mudam juntas? a força do acoplamento é proporcional à proximidade? Em vez de bloquear uma mudança por "princípio", você consegue nomear precisamente o desequilíbrio, ou aceitar que está balanceado e seguir.
Coupling não é vilão. Coupling desbalanceado é. O bug não é o acoplamento existir; é a combinação errada entre força, distância e volatilidade. Times que internalizam o modelo tridimensional param de gastar capital de complexidade na briga errada, e passam a investir desacoplamento onde, de fato, o futuro vai cobrar.
