¿Por qué son importantes las pruebas de arquitectura en un mundo polyrepo?

En Netflix, el ecosistema JVM tiene decenas de miles de repositorios Java. Sin una forma centralizada de aplicar reglas arquitectónicas, la deuda técnica se acumula silenciosamente — especialmente en APIs obsoletas o internas. El desafío: ¿cómo evitar que consumidores downstream usen APIs que los autores pretenden eliminar?

Las herramientas tradicionales de análisis estático (PMD, SpotBugs) se quedan cortas para la creación de reglas personalizadas. Sus lenguajes de reglas (XPath, XML) son opacos, difíciles de probar y específicos del lenguaje. ArchUnit, construido sobre análisis de bytecode ASM, ofrece una API Java fluida que es type-safe y fácil de probar unitariamente. Pero ArchUnit por sí solo está diseñado para un solo repositorio. Nebula ArchRules cierra esa brecha, permitiendo que organizaciones definan, publiquen y ejecuten reglas ArchUnit en cientos o miles de proyectos Gradle.

Caso de estudio: Gestión del ciclo de vida de APIs a escala

Después de un incidente causado por la eliminación de código obsoleto (deprecado por años, pero aún usado downstream), el equipo de Java Platform en Netflix necesitaba una solución sistemática. Introdujeron un conjunto de anotaciones de ciclo de vida de API:

  • @Deprecated (Java estándar)
  • @Public — para uso downstream
  • @Experimental — API inestable
  • Sin anotación = interno

Los autores de librerías podían marcar sus APIs, pero ¿cómo sabrían qué proyectos downstream las usaban incorrectamente? La respuesta: Nebula ArchRules.

Cómo funciona Nebula ArchRules

1. Escribiendo reglas compartibles

El ArchRules Library Plugin agrega un source set separado archRules. Implementas la interfaz ArchRulesService, devolviendo un Map<String, ArchRule>. Ejemplo:

public class GuavaRules implements ArchRulesService {
    static final ArchRule OPTIONAL = ArchRuleDefinition.priority(Priority.MEDIUM)
        .noClasses()
        .should()
        .dependOnClassesThat()
        .haveFullyQualifiedName("com.google.common.base.Optional")
        .because("Java Optional es preferible a Guava Optional");

    @Override
    public Map<String, ArchRule> getRules() {
        Map<String, ArchRule> rules = new HashMap<>();
        rules.put("guava optional", OPTIONAL);
        return rules;
    }
}

Las reglas se empaquetan en un JAR separado con el classifier arch-rules, publicado junto con la librería principal. Hay dos sabores:

  • Librerías de reglas standalone: contienen solo reglas (ej.: “no uses APIs @Deprecated”). Útiles para APIs OSS o Java core.
  • Librerías de reglas bundled: incluyen código principal y reglas específicas del paquete de la librería. Se aplican automáticamente cuando proyectos downstream dependen de la librería.

2. Ejecutando reglas entre repositorios

El ArchRules Runner Plugin descubre y evalúa reglas automáticamente. Para reglas standalone, agrégalas a la configuración archRules:

dependencies {
    archRules("com.netflix.nebula:nebula-archrules-deprecation:1.0.0")
}

Las reglas bundled se evalúan automáticamente. El plugin crea un classpath separado para cada source set, combinando el runtime classpath con la variante arch-rules. Una Gradle work action ejecuta ArchUnit con aislamiento de classpath, y las violaciones se serializan en un archivo binario.

3. Personalización y reportes

Puedes sobrescribir prioridades de reglas, deshabilitar reglas en ciertos source sets o definir umbrales de fallo:

archRules {
    ruleClass("com.netflix.nebula.archrules.deprecation") {
        priority("HIGH")
    }
}

Dos reportes nativos: JSON (legible por máquina) y consola (legible por humanos con apuntado de línea). Reportes personalizados pueden leer los archivos binarios directamente.

Netflix's polyrepo architecture with thousands of Java microservices managed by Nebula Gradle plugins Software Concept Art

Impacto real: 358 reglas, 5,000+ repos, 1 millón de problemas detectados

Netflix ejecuta actualmente 358 reglas en más de 5,000 repositorios, detectando casi 1 millón de problemas. Alrededor de 1,000 son violaciones de alta prioridad. Los datos fluyen al Portal Interno de Desarrolladores de Netflix, dando visibilidad a los autores de librerías sobre exactamente qué consumidores downstream usan APIs obsoletas o experimentales.

Ejemplo: Detectando uso de APIs obsoletas

ArchRuleDefinition.priority(Priority.MEDIUM)
    .noClasses()
    .that(resideOutsideOfPackage(packageName + ".."))
    .should()
    .dependOnClassesThat(resideInAPackage(packageName + "..")
        .and(are(deprecated())))
    .orShould()
    .accessTargetWhere(targetOwner(resideInAPackage(packageName + ".."))
        .and(target(is(deprecated()))
            .or(targetOwner(is(deprecated())))))
    .allowEmptyShould(true)
    .because("APIs obsoletas están sujetas a eliminación");

Esta regla captura tanto dependencia directa en clases obsoletas como acceso a métodos o campos obsoletos — todo con alcance al paquete de una librería específica.

Limitaciones y precauciones

  • Solo Gradle: El plugin depende de Gradle Module Metadata y configuraciones personalizadas. Maven u otros sistemas de build no son compatibles.
  • Bytecode ≠ Código fuente: ArchUnit analiza bytecode compilado, lo que puede perder código escondido por azúcar sintáctico (ej.: funciones inline de Kotlin que expanden a bytecode sin anotaciones).
  • Rendimiento: Ejecutar 358 reglas en miles de repos requiere un diseño cuidadoso del pipeline de CI. Netflix lo ejecuta en cada build de rama principal, lo que añade overhead.
  • Mantenimiento de reglas: Las reglas deben mantenerse actualizadas con los cambios en las librerías. Una regla desactualizada que señala una API irrelevante genera ruido.

Próximos pasos

Netflix está explorando automatización de corrección combinando los reportes detallados de fallo de ArchUnit con herramientas como OpenRewrite (determinístico) y LLMs (no determinístico). El objetivo: corregir violaciones automáticamente cuando sea posible. También planean mostrar violaciones de ArchRule como inspecciones en la IDE.

Si estás construyendo una organización JVM polyrepo, empieza pequeño: escribe algunas reglas bundled para tus librerías principales, habilita el runner en CI e itera. Las librerías de reglas OSS (nullability, buenas prácticas Gradle, seguridad) son un excelente punto de partida.

Para más sobre el uso responsable de IA en código, checa nuestra guía sobre cómo aprovechar agentes de IA de forma responsable. Y si estás evaluando herramientas de IA para tu flujo de trabajo, lee Beyond the Hype: Una Guía para Desarrolladores Responsables sobre Herramientas de IA.

ArchUnit bytecode analysis engine detecting deprecated API usage across JVM projects Dev Environment Setup

Diferencias clave

AspectoArchUnit + Nebula ArchRulesAnálisis estático tradicional (PMD/SpotBugs)
Creación de reglasAPI Java fluida, type-safe, testeable unitariamenteStrings XPath/XML, sin soporte de IDE
Soporte de lenguajesNivel de bytecode (cualquier lenguaje JVM)Basado en AST (específico del lenguaje)
ComparticiónGradle Module Metadata + variante arch-rulesEcosistema de plugins, sin compartición estandarizada
Escalabilidad5,000+ repos, 358 reglasTípicamente repositorio único
PersonalizaciónSobrescritura de prioridad, exclusión de source setsLimitada a la configuración del plugin

Conclusión

Nebula ArchRules transforma ArchUnit de una librería de pruebas de un solo repositorio en una plataforma de enforcement de arquitectura en toda la flota. Combinando la facilidad de creación de reglas con descubrimiento y reportes automatizados, Netflix redujo el riesgo de cambios que rompen y visibilizó la deuda técnica a escala. El enfoque es pragmático: empieza con unas pocas reglas, itera basado en incidentes reales y deja que los datos guíen tus prioridades.

Este artículo está basado en el post original del Netflix Tech Blog por John Burns y Emily Yuan. Para detalles técnicos completos, consulta el artículo original.

ArchRules violation report showing high-priority technical debt in a large-scale Java codebase Developer Related Image

Este contenido fue redactado con la asistencia de herramientas de IA, basándose en fuentes confiables, y fue revisado por nuestro equipo editorial antes de su publicación. No reemplaza el asesoramiento de un profesional especializado.