Stackbook Logo
architecture-descriptionemerging · low operational burden

Architectural Fitness Functions

Also known as: fitness-functions, architecture-tests

Intent

Automate objective checks that guard architectural characteristics so they cannot silently erode.

Problem

Architectural intent such as layering, latency budgets, or dependency rules lives in documents. Code drifts from it unnoticed until a costly failure. Reviews cannot catch everything.

Forces

  • •Architecture degrades gradually through small changes
  • •Manual review does not scale
  • •Characteristics like performance and security need measurable thresholds
  • •Checks must be fast enough to run on every change

Solution

Overview

A fitness function is any mechanism that gives an objective assessment of how close a system is to an architectural goal. The term comes from evolutionary computing and was applied to architecture by Ford, Parsons, and Kua.

Fitness functions fall into several types: atomic versus holistic, triggered versus continuous, and static versus dynamic. A unit-level dependency check is atomic and triggered. A load test of a whole flow is holistic. A production latency alert is continuous.

How it works

Pair each characteristic with a measurable check and a place to run it.

// ArchUnit-style dependency rule
noClasses().that().resideInAPackage("..domain..")
  .should().dependOnClassesThat()
  .resideInAPackage("..infrastructure..");

# production check
alert: p99_latency_checkout > 400ms for 10m

Start with the two or three characteristics that would hurt most if lost, such as module boundaries, data residency, and tail latency. Add a function only when a violation is both plausible and costly, and give each function an owner and a documented reason it exists.

Pitfalls

  • Measuring what is easy rather than what matters
  • Letting failing checks stay red until people ignore them
  • Writing functions for every concern instead of the critical few
  • Forgetting to retire checks when the target architecture changes

Key takeaways

  • Tie each function to a stated architectural goal
  • Run structural checks in CI and operational checks in production
  • Keep the set small and trusted
  • Update thresholds deliberately, with an ADR

✓ When to Use

  • •Systems with defined layering or module boundaries
  • •Evolving systems where drift is a known risk
  • •Non-functional requirements with measurable targets

✗ When Not to Use

  • •Characteristics that cannot be measured objectively
  • •Prototypes with unstable structure
  • •Teams without CI discipline

Pros

  • +Turns architecture into executable guardrails
  • +Gives fast feedback on violations
  • +Documents intent as living tests

Cons

  • −Poorly chosen metrics create false confidence
  • −Maintenance cost when architecture changes
  • −Slow checks hurt CI times

Cost Profile

Infrastructure

Low - CI and monitoring reuse

Operational

Low to medium

Cognitive

Medium - choosing the right metrics

Failure Modes

  • Checks pass while the real characteristic degrades

  • Flaky functions get ignored or disabled

  • Thresholds never updated after intentional redesign

Real-World Examples

Alternatives

    Related Patterns

    • architecture-reviews
    • observability

    Competency Domains

    economics evolutionreliability ops