Durante décadas, la industria del software repitió el mismo mantra como si fuera un axioma: "low coupling, high cohesion". La frase se volvió un tatuaje cultural, está en libros de OO de los años 90, en charlas de microservicios de 2015, en code reviews de 2026. El problema es que ese mantra es unidimensional, y quien intenta aplicarlo como regla absoluta termina produciendo arquitecturas que son peores que el acoplamiento que estaban tratando de evitar: módulos ceremoniales que se comunican por events asíncronos para resolver lo que era una llamada de función; microservicios que comparten schema de base de datos escondido en una biblioteca interna; shared kernels que se vuelven un cementerio de tipos.
Vlad Khononov, en Balancing Coupling in Software Design, propone un modelo que recupera la complejidad real del problema. El acoplamiento no es una regla graduada. Es un sistema de tres ejes: Strength (el qué se comparte), Distance (dónde vive físicamente el acoplamiento) y Volatility (con qué frecuencia cambian los componentes). Evaluar el acoplamiento sin los tres ejes es como evaluar el costo de un viaje usando solo la distancia, ignorando la velocidad, el terreno y cuántas veces necesitas ir.
El eje 1: Integration Strength, no todo "compartir" cuesta lo mismo
Strength mide lo que dos componentes comparten. Y aquí vive una escala que la mayoría de los equipos trata como binaria cuando es, en realidad, gradual. En el extremo más débil, dos componentes apenas conocen un contrato público estable, un endpoint REST versionado, una cola con schema explícito, una interfaz declarada. En el extremo más fuerte, comparten estado interno, invariantes implícitos, o suposiciones sobre la representación en memoria. Entre los dos extremos existen escalones: compartir un modelo de dominio, compartir una estructura de datos específica, depender de un efecto colateral de una implementación concreta.
Lo que importa para el ingeniero es lo siguiente: cuanto más fuerte el acoplamiento, mayor el radio del estrago de un cambio. Si el componente A cambia y B comparte apenas un contrato con A, B sigue intacto hasta que el contrato se rompa. Si A cambia y B comparte el modelo interno de A, cualquier ajuste en A es una ruleta rusa en B. Strength es, por lo tanto, el eje que mide cuánto de tu cambio se filtra.
El eje 2: Distance, dónde vive físicamente el acoplamiento
Distance es el eje más subestimado de la industria. Mide la distancia física y organizacional entre los puntos acoplados: dos métodos de la misma clase, dos clases del mismo módulo, dos módulos de la misma aplicación, dos aplicaciones de la misma empresa, dos servicios de empresas diferentes. Cada escalón aumenta el costo del cambio coordinado, no por el cambio en sí, sino por quién necesita estar involucrado, cuánto tiempo de comunicación, cuántas barreras de deploy.
El costo crece de forma no lineal. Cambiar dos funciones en el mismo archivo es un commit. Cambiar dos módulos del mismo servicio es una PR coordinada. Cambiar dos microservicios de squads diferentes es una reunión, un RFC, un plan de release. Cambiar dos sistemas de empresas diferentes es una negociación contractual. Distance multiplica el costo de coordinación mucho más de lo que multiplica el costo del código. Los equipos que ignoran distance típicamente terminan en un distributed monolith: mucho acoplamiento, esparcido por mucha distancia, lo peor de los dos mundos.
El eje 3: Volatility, el eje que nadie mira
Aquí está el eje que prácticamente ningún manual de arquitectura discute con la profundidad necesaria: ¿con qué frecuencia cambia cada componente? Un helper de formateo de fecha que está estable desde hace cinco años puede estar fuertemente acoplado con todo en el sistema y nadie lo va a sentir. Un módulo de cobro que cambia cada sprint, acoplado fuertemente con cualquier otro componente, es una bomba de tiempo. El acoplamiento solo duele cuando algo cambia. Si nada cambia, el acoplamiento es gratis.
Esto invierte una intuición común. Los ingenieros gastan presupuesto de complejidad desacoplando partes del sistema que son, en la práctica, estables, pagan el precio de la indirección en código que nunca va a necesitar el beneficio. Mientras tanto, dejan fuertemente acoplados los módulos volátiles, porque "es solo una refactorización después". La heurística correcta es la opuesta: invierte en desacoplamiento donde la volatilidad es alta, tolera el acoplamiento donde la volatilidad es baja.
La fórmula: BALANCE = (STRENGTH XOR DISTANCE) OR NOT VOLATILITY
Leída en español de ingeniería: un diseño está balanceado cuando la fuerza del acoplamiento y la distancia son opuestas, o cuando la volatilidad es tan baja que el resto no importa. El XOR es el corazón de la fórmula. Significa que solo uno de los ejes puede estar "alto" sin desequilibrar el sistema:
- STRENGTH alta + DISTANCE baja = cohesión. Dos funciones de la misma clase pueden compartir estado interno. Está todo bien. Eso es lo que llamamos un módulo bien diseñado, partes íntimamente relacionadas que viven juntas y cambian juntas.
- STRENGTH baja + DISTANCE alta = modularidad saludable. Dos microservicios de squads diferentes que se comunican por un contrato público y versionado. Cada uno evoluciona a su tiempo. Es lo que se espera de una buena frontera.
- STRENGTH alta + DISTANCE alta = distributed monolith. El peor escenario. Microservicios que comparten schema de base de datos, o servicios externos que dependen de detalles internos de otro. Cada cambio se vuelve un proyecto trimestral.
- STRENGTH baja + DISTANCE baja = ceremonia injustificada. Dos funciones en el mismo archivo comunicándose vía event bus. Pagaste el precio de la indirección sin ganar nada, se volvió premature decoupling.
- NOT VOLATILITY = perdón universal. Si el componente está congelado, el resto puede estar mal y nadie lo va a sentir. Pero confiar en eso es apostar a que el futuro no va a llegar.
Los anti-patterns que la fórmula expone de inmediato
La fuerza del modelo es que nombra patologías que antes circulaban como decisiones de "buena arquitectura". El distributed monolith deja de ser folklore y se vuelve un cuadrante del diagrama: alta strength + alta distance. El premature decoupling (esa manía de inyectar una interfaz entre dos funciones del mismo módulo) deja de ser "estilo personal" y se vuelve un cuadrante equivocado: baja strength + baja distance, pagando un precio sin beneficio. Y el famoso "shared kernel que crece sin gobernanza" es un caso típico de strength alta + distance creciente, empieza cohesionado y se vuelve un distributed monolith conforme los equipos que dependen de él se alejan organizacionalmente.
Señales prácticas de desequilibrio
- Todo cambio "simple" exige una PR en tres repositorios: strength alta cruzando distance alta. Tienes un distributed monolith.
- Un bug en un servicio aparece en otro por "efecto colateral": strength altísima filtrándose entre fronteras que deberían aislar.
- Refactorizar una clase local exige tocar 7 archivos de adapter: premature decoupling, desacoplaste antes de que la volatilidad lo justificara.
- El equipo A bloquea al equipo B cada sprint: distance alta con strength alta institucionalizada vía dependencia cruzada.
Cómo aplicarlo, auditoría de acoplamiento en tres pasos
El modelo no exige una herramienta nueva. Exige un cambio de pregunta. En vez de "¿esto está acoplado?", el equipo pasa a preguntar tres cosas. (1) ¿Cuál es la fuerza del acoplamiento? ¿Qué exactamente se comparte, un contrato, un modelo, estado, una suposición? (2) ¿Cuál es la distancia? ¿Mismo archivo, mismo módulo, mismo servicio, misma empresa, o cruzando una frontera externa? (3) ¿Cuál es la volatilidad? ¿Este código cambia cada sprint, cada quarter, cada año, o está congelado?
Con las tres respuestas, el paso final es mirar el cuadrante y decidir: ¿está balanceado, o estoy pagando un costo donde no lo necesito y tolerando riesgo donde debería invertir? La mayoría de las refactorizaciones que "mejoran la arquitectura" y en la práctica solo empeoran la entrega son exactamente errores de lectura de ese diagrama, desacoplar donde no hace falta, tolerar acoplamiento donde la volatilidad va a cobrar.
El reencuadre que cambia cómo lees los PRs
La ganancia real del modelo de Khononov no es teórica. Es operacional. Pasas a leer los PRs con otro ojo. En vez de caer en el reflejo de "esas dos clases están demasiado acopladas", preguntas: ¿están en el mismo módulo? ¿cambian juntas? ¿la fuerza del acoplamiento es proporcional a la proximidad? En vez de bloquear un cambio por "principio", puedes nombrar con precisión el desequilibrio, o aceptar que está balanceado y seguir.
El coupling no es el villano. El coupling desbalanceado lo es. El bug no es que el acoplamiento exista; es la combinación equivocada entre fuerza, distancia y volatilidad. Los equipos que internalizan el modelo tridimensional dejan de gastar capital de complejidad en la pelea equivocada, y pasan a invertir en desacoplamiento donde, de hecho, el futuro va a cobrar.