El diseño estructural del software se mantiene estable cuando logra armonizar dos fuerzas: el acoplamiento, que mide la dependencia entre unidades, y la cohesión, que evalúa la unidad interna de cada componente. Más que opuestas, son complementarias: mejorar una afecta a la otra y el objetivo es alcanzar un equilibrio que favorezca la mantenibilidad.
En todo sistema las piezas necesitan colaborar. Reducir el acoplamiento a cero es imposible y, si se lograra, eliminaría cualquier coordinación. Del mismo modo, la cohesión absoluta aislada rompería los flujos de negocio. El equilibrio implica permitir colaboraciones controladas entre componentes altamente cohesivos para que la intención del código permanezca clara y sus cambios controlados.
El Principio de Responsabilidad Única, base del conjunto SOLID, refuerza la idea de cohesión: cada clase debe cambiar por un único motivo. Cuando se respeta esta premisa, el acoplamiento necesario se sostiene mediante contratos bien definidos, evitando dependencias implícitas o atajos que erosionan el equilibrio.
Los extremos suelen ser fáciles de reconocer:
Representar el dominio con diagramas de contexto ayuda a decidir qué componentes deben colaborar estrechamente y cuáles pueden mantener interfaces más abstractas. Al mapear las relaciones se identifica cuándo un servicio está asumiendo demasiadas responsabilidades, o cuándo un módulo necesita un canal de comunicación más directo para evitar complejidad accidental.
El siguiente fragmento muestra un servicio de facturación que coordina cuatro colaboradores. La cohesión del servicio es alta (solo calcula y confirma facturas), mientras el acoplamiento se mantiene bajo gracias a contratos explícitos.
class ServicioFacturacion {
private final RepositorioFactura repositorioFactura;
private final CalculadoraImpuestos calculadoraImpuestos;
private final ServicioInventario servicioInventario;
private final IntegracionContable integracionContable;
ServicioFacturacion(RepositorioFactura repositorioFactura,
CalculadoraImpuestos calculadoraImpuestos,
ServicioInventario servicioInventario,
IntegracionContable integracionContable) {
this.repositorioFactura = repositorioFactura;
this.calculadoraImpuestos = calculadoraImpuestos;
this.servicioInventario = servicioInventario;
this.integracionContable = integracionContable;
}
Factura emitir(Pedido pedido) {
servicioInventario.reservar(pedido);
Factura factura = Factura.desde(pedido, calculadoraImpuestos);
repositorioFactura.guardar(factura);
integracionContable.registrar(factura);
return factura;
}
}
Si en el futuro se agrega un nuevo medio de notificación, el servicio principal no debería modificarse. La extensión ocurre mediante la inyección de una nueva interfaz, preservando la cohesión y controlando el aumento del acoplamiento.
Algunas prácticas simplifican la construcción de sistemas sostenibles:
Monitorear el acoplamiento y la cohesión de forma conjunta permite detectar desequilibrios. Valores elevados de LCOM junto con un alto conteo de dependencias indican clases que necesitan particionarse y redistribuir sus colaboraciones. Herramientas como SonarQube, IntelliJ o Eclipse IDE ofrecen tableros que cruzan estas métricas para visualizar los puntos críticos.
Cuando el equilibrio se sostiene, los equipos perciben los beneficios: los cambios se localizan, la revisión de código se enfoca en decisiones de negocio y el despliegue reduce riesgos. Por el contrario, un desequilibrio se manifiesta en ciclos de liberación irregulares, deuda técnica acumulada y dificultad para incorporar nuevas personas al proyecto.
Antes de cerrar un incremento, conviene repasar la siguiente lista:
Mantener el equilibrio entre acoplamiento y cohesión es un trabajo continuo. Requiere observación, refactorizaciones frecuentes y una comprensión profunda del dominio de negocio. Al practicar estas ideas, la arquitectura se mantiene evolutiva y preparada para los desafíos futuros.