Enterprise ArchUnit
- Mark Kendall
- Jun 23
- 6 min read
Here's a proposal for a two-pronged, enterprise-wide rollout of ArchUnit, addressing your key points about basic facts, benefits, and implementation.
Your two-pronged approach for rolling out ArchUnit across an organization with 2000 repositories is well-reasoned and highly practical. It addresses the realities of large-scale adoption, balancing the desire for consistent architecture with the challenges of retrofitting existing, potentially dormant, codebases.
### Proposal: Enterprise ArchUnit Adoption – A Two-Pronged Strategy
Goal: To establish and enforce consistent architectural standards across the enterprise's Java repositories, providing automated feedback on architectural deviations and fostering a culture of "architectural integrity as code."
-----
### Basic Facts of the Two-Pronged Approach:
1. Phase 1: Proactive Adoption for New & Actively Developed Projects
*Mechanism:** Establish a shared ArchUnit rules library (a dedicated Maven/Gradle project that produces a JAR). This library will contain enterprise-wide architectural rules (e.g., standard layered architecture, common naming conventions, forbidden dependencies, security best practices).
*Integration:** New projects will be mandated to include this shared rules library as a `test` scoped dependency in their `pom.xml` or `build.gradle`.
*Execution:** These projects will integrate the ArchUnit checks into their build pipeline (e.g., via `exec-maven-plugin` or a custom Gradle task, as discussed previously), ensuring that architecture violations break the build.
*Benefit:** Establishes architectural hygiene from day one for new development, preventing technical debt related to architecture before it accumulates.
2. Phase 2: Reactive Integration for Existing Actively Developed Projects
*Mechanism:** For existing repositories that are currently undergoing active development (i.e., receiving new Pull Requests), teams will be encouraged and empowered to integrate the same shared ArchUnit rules library.
*Integration:** This involves adding the dependency to their build file and setting up the build integration as part of a new PR.
*Flexibility/Grace Period:** A critical aspect here is handling existing violations. ArchUnit's `FreezingArchRule` feature is invaluable. This allows teams to "freeze" current violations, so the build only fails on new violations. Over time, teams can chip away at the frozen violations as part of regular refactoring or dedicated architecture cleanup efforts.
*Benefit:** Gradually brings older, but still active, codebases under architectural governance without immediately halting development due to a large number of legacy violations. It provides a path to improve existing code quality iteratively.
-----
### Key Benefits of this Enterprise-Wide Strategy:
1. Consistency and Standardization:
* Enforces a uniform architectural vision across different teams and projects.
* Reduces "architectural drift" where projects slowly diverge from agreed-upon patterns.
* Facilitates developer movement between teams as architectural patterns become predictable.
2. Early Detection of Architectural Violations:
* Shifts architectural review left, catching issues during development or code review rather than late in the testing cycle or, worse, in production.
* Prevents small architectural mistakes from snowballing into significant technical debt.
3. Automated Governance and Scalability:
* Automates aspects of architectural review that would otherwise require manual, time-consuming, and error-prone inspections.
* Scales effectively across 2000+ repositories without increasing the burden on a central architecture review board.
4. Improved Code Quality and Maintainability:
* Codebases become easier to understand, extend, and maintain due to consistent structure and adherence to principles (e.g., separation of concerns, no circular dependencies).
* Reduces the bus factor by codifying architectural knowledge.
5. Onboarding Efficiency for New Developers:
* New team members can quickly grasp project architecture by examining the executable ArchUnit rules.
* The build failures provide immediate, actionable feedback when a rule is inadvertently violated, acting as an automated architectural mentor.
6. Reduced Friction and Intrusion (with careful implementation):
* By using the independent-of-JUnit execution model, you minimize dependencies on specific testing frameworks, reducing friction for teams with diverse testing setups.
The "freezing" mechanism for legacy projects ensures that ArchUnit acts as a guardrail for future* changes, rather than an immediate blocker, which is critical for adoption.
7. Evidence-Based Architecture:
* Architectural decisions are no longer just diagrams or documents; they are executable code that continuously verifies the codebase's adherence. This provides tangible evidence of architectural health.
-----
### How to Go About Implementation:
1. Define Core Enterprise Architecture Rules (Phase 0 - Foundation):
* Convene architects and senior developers to define a initial set of non-negotiable, high-value architectural rules. Start small and grow. Examples:
* Standard package layering (e.g., `controller -> service -> repository`).
* Forbidden dependencies (e.g., no direct database access from controllers).
* Naming conventions for core components.
* No circular dependencies between key packages/modules.
* Forbidden library usages (e.g., deprecated utilities).
* Prioritize rules that deliver the most value with the least initial friction.
2. Create the Shared ArchUnit Rules Library (Maven/Gradle Project):
* Set up a new, dedicated repository for this shared library.
This project will contain the `ArchRule` definitions. It will not* contain `main` methods for execution but will expose its rules as public static fields or methods that can be imported.
* Example structure:
```java
// In the shared rules library project
package com.enterprise.archrules;
import com.tngtech.archunit.lang.ArchRule;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes;
import static com.tngtech.archunit.library.Architectures.layeredArchitecture;
public class EnterpriseArchitectureRules {
public static final ArchRule STANDARD_LAYERED_ARCHITECTURE = layeredArchitecture()
.layer("Controller").definedBy("..controller..")
.layer("Service").definedBy("..service..")
.layer("Repository").definedBy("..repository..")
.whereLayer("Controller").mayNotBeAccessedByAnyLayer()
.whereLayer("Service").mayOnlyBeAccessedByLayers("Controller")
.whereLayer("Repository").mayOnlyBeAccessedByLayers("Service");
public static final ArchRule NO_FIELD_INJECTION = classes()
.that().resideInAnyPackage("..service..", "..controller..") // Only apply to specific layers
.should().notHaveFieldsWithAnnotation("org.springframework.beans.factory.annotation.Autowired")
.as("No field injection in services or controllers");
// ... more rules
}
```
* Publish this library to your internal Maven/Gradle artifact repository.
3. Develop Documentation and Best Practices:
* Create clear, concise documentation on:
* How to include the shared ArchUnit rules library.
* How to configure the build for independent ArchUnit execution.
* Explanation of common rules and why they exist.
* Guidelines on handling `FreezingArchRule` and addressing violations.
* A process for proposing new enterprise rules or modifications to existing ones.
4. Pilot Program & Internal Champions (Initial Rollout):
* Identify a few new projects or small, actively developed existing projects that are enthusiastic early adopters.
* Work closely with these teams to implement ArchUnit, gather feedback, refine the shared rules, and perfect the integration process. These teams will become your internal champions.
5. Communication and Training:
* Conduct workshops or brown-bag sessions to educate development teams about ArchUnit, its benefits, and how to integrate it.
Emphasize that this is about improving* codebases and reducing long-term pain, not just adding more checks.
6. Gradual Rollout (Phased Approach):
*New Projects:** Make inclusion of the shared ArchUnit library a mandatory part of the project bootstrapping process or new project templates.
*Actively Developed Existing Projects:**
* Announce the initiative and provide clear guidelines and support.
* Encourage teams to pick up the shared library with their next significant PR.
* Leverage `FreezingArchRule` for brownfield projects to avoid immediate build failures on legacy code. This is key for broad adoption without resistance.
* Consider setting targets (e.g., "all projects with active development in Q3 must integrate ArchUnit").
7. Maintenance and Evolution of Rules:
* Establish a governance process for the shared rules library. Who can propose new rules? How are they reviewed and approved?
* Ensure the shared library is updated regularly with new best practices or adjustments to existing ones.
* Version control the shared rules library meticulously.
By adopting this phased, collaborative, and pragmatic strategy, you can successfully embed architectural governance as an automated and continuous process across your vast repository landscape, leading to more maintainable, consistent, and resilient software.
Comments