Skip to content
matthewcm.dev

    ↑ ↓ move · ↵ open · tab scopeopen graph →

    Architecture Fitness Functions

    Automated checks that fail the build when the architecture drifts, like a service importing a database driver directly. Cheap feedback that keeps a codebase on the shape it was designed for.

    Seedtended planted 1 min read

    🌱 A rough idea, planted recently. Expect rough edges — it will grow.

    On this page

    A fitness function is a test of an architectural property rather than a behaviour: coupling, layering, which modules may depend on which. When the architecture drifts, the build fails, instead of the drift quietly piling up.

    A one-file example

    The rule: the service layer talks to repositories, never to the datastore directly. The simplest version just looks for forbidden imports in each layer:

    # test_architecture.py: services never import datastores directly
    from pathlib import Path
    
    FORBIDDEN_IN_SERVICES = ["sqlalchemy", "pymongo", "boto3", "psycopg2"]
    
    def test_service_layer_isolation():
        for service_file in Path("src/services").glob("*.py"):
            source = service_file.read_text()
            for forbidden in FORBIDDEN_IN_SERVICES:
                assert forbidden not in source, f"{service_file.name} imports '{forbidden}' directly"

    It’s crude (a string match, not a dependency graph), but it runs in milliseconds and it catches the mistake on the pull request where it happens. Grown-up versions exist for most ecosystems: ArchUnit for Java, dependency-cruiser for JavaScript and TypeScript, import-linter for Python.

    Why bother

    Drift is the default. Plenty of projects start with a clean, well-layered architecture and slowly lose it under delivery pressure. That’s understandable: deadlines are real. A fitness function doesn’t stop you shipping; it makes the shortcut visible and pulls you back on track without a big-bang rewrite.

    They also keep the people side honest. If the layers map to teams (product teams on top, platform teams underneath, as in The Platform Relevance Gap), enforcing the boundaries in code keeps each team working at the right layer.

    Run them in CI next to everything else: they’re the architectural end of Shift Left Testing.

    Through a training lens

    It’s like seeing a physio when something starts to feel off, or asking a coach to check your technique. You can usually coach yourself through a programme, but outside feedback, or simply filming your sets, gives you the small corrections that keep you progressing instead of slowly grooving a bad pattern. A fitness function is that video, recorded on every commit.

    From chapter 3 of Domain-Driven Platform Engineering.

    • #architecture
    • #fitness-functions
    • #ci
    • #coupling
    • #domain-driven-design

    ↪ Links to (2)