18. Herramientas y técnicas para detectar incumplimientos de SOLID

Detectar a tiempo los desvíos respecto de los principios SOLID evita que el sistema acumule deuda técnica. A continuación presentamos herramientas y técnicas que ayudan a monitorear la calidad del diseño en aplicaciones Java.

18.1 Métricas de diseño

  • Complejidad ciclomatica: clases con valores altos suelen violar SRP.
  • WMC (Weighted Methods per Class): un número elevado indica responsabilidades mezcladas.
  • DIT (Depth of Inheritance Tree) y NOC (Number of Children): sirven para revisar jerarquías sospechosas (LSP).
  • Fan-in / Fan-out: ayudan a detectar dependencias rígidas (DIP).

18.2 Análisis estático con SonarQube

SonarQube analiza el código y reporta olores relacionados con SOLID, como clases con demasiados métodos, acoplamientos excesivos o jerarquías complejas.

  • Reglas útiles: “God Class”, “Long Method”, “Switch statements should be replaced with polymorphism”.
  • Integración: se puede ejecutar en pipelines de CI/CD y revisar informes por sprint.

18.3 ArchUnit para validar arquitectura

ArchUnit permite escribir pruebas en Java que expresan reglas arquitectónicas. Es ideal para garantizar que los módulos dependan de interfaces y no de implementaciones concretas.

import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition;

@AnalyzeClasses(packages = "com.ejemplo")
public class ArquitecturaTest {

    @ArchTest
    static final ArchRule noHayDependenciasCiclicas =
            SlicesRuleDefinition.slices()
                .matching("com.ejemplo.(*)..")
                .should().beFreeOfCycles();
}

También se pueden definir reglas para que los servicios dependan de interfaces ubicadas en paquetes específicos.

18.4 Detectar olores con IntelliJ IDEA y Eclipse

Los IDE modernos incluyen inspecciones que señalan problemas comunes:

  • Clases demasiado grandes: sugiere extraer clases o métodos.
  • Constructores con muchos parámetros: pueden indicar violaciones a SRP o DIP.
  • Switch sobre tipos: sugiere reemplazar por polimorfismo.

18.5 Linting específico con PMD y Checkstyle

PMD y Checkstyle permiten crear reglas personalizadas. Por ejemplo, detectar métodos que exceden cierta cantidad de líneas o clases sin comentarios de intención.

18.6 Análisis de dependencias

Herramientas como Structure101, NDepend (para .NET) o el plugin Dependency Analyzer de IntelliJ ayudan a visualizar gráficamente las dependencias entre módulos.

  • Uso: identificar componentes muy utilizados y dependencias bidireccionales que violan DIP.
  • Beneficio: planificar refactorizaciones con foco en la modularidad.

18.7 Gestión de deuda técnica

Integrar sistemas como SonarQube Technical Debt o tableros en Jira/Trello para registrar deudas relacionadas con SOLID. Indicadores claves:

  • Clases con alta complejidad.
  • Interfaces que cambian con frecuencia.
  • Jerarquías extensas y difíciles de testear.

18.8 Revisiones de código dirigidas

Definir una checklist para code reviews orientada a los principios:

  • ¿Cada clase tiene una única responsabilidad?
  • ¿Las interfaces obligan a implementar métodos innecesarios?
  • ¿Hay instancias de instanceof que indiquen violaciones a LSP?
  • ¿Las dependencias se inyectan o se instancian internamente?

18.9 Pruebas de caracterización y cobertura

Los tests que ejercitan todo el contrato de una interfaz permiten detectar violaciones a LSP o ISP. Complementar con herramientas de cobertura (JaCoCo) ayuda a identificar clases críticas sin pruebas.

18.10 Monitorización continua

Para que las técnicas sean efectivas, es clave incorporarlas al ciclo de desarrollo:

  • Integración continua: ejecutar análisis estáticos y métricas en cada commit.
  • Dashboards de calidad: visualizar tendencias de complejidad, duplicación y deuda técnica.
  • Alertas tempranas: notificaciones cuando se supera un umbral (por ejemplo, complejidad > 15).

Las herramientas y técnicas presentadas funcionan mejor cuando se combinan con la disciplina cotidiana del equipo. El siguiente tema explorará conclusiones y próximos pasos para continuar profundizando en el diseño orientado a objetos.