← Back to list
SW Engineering & Management
#진화형 아키텍처#피트니스 함수#아키텍처 거버넌스#점진적 변경#ArchUnit
Last updated · 2026-11-02

Evolutionary Architecture and Fitness Functions

1. Overview

An evolutionary architecture is one designed to support change — occurring across multiple dimensions — in a "guided, incremental" manner, and the core instrument of that "guidance" is the fitness function, which objectively measures an architectural quality attribute.

Software architecture long rested on the premise that "if you design it correctly up front, it will last." But as cloud, microservices, and continuous delivery became pervasive, requirements, technology, organizations, and regulations began to change on a weekly or daily cadence rather than quarterly, and the very premise of "completeness of the initial design" collapsed. In a world where change is constant, the success of an architecture shifted from "how perfectly it was designed" to "how safely it can keep changing." Evolutionary architecture is the approach that Rebecca Parsons, Neal Ford, Patrick Kua, and Pramod Sadalage systematized to answer exactly this question, with the 2017 first edition and the 2022 second edition of Building Evolutionary Architectures as its theoretical foundation.

The key insight is that it engineered "evolution" into something beyond a biological metaphor. Just as a genetic algorithm scores the fitness of each solution numerically every generation and applies selective pressure toward better directions, an architecture too can keep its intended characteristics while evolving if it automatically measures the fitness of quality attributes on every change and lets only acceptable changes pass. In other words, a fitness function reduces the question "is this change architecturally acceptable?" to an executable check rather than a human's subjective review.

The definition of evolutionary architecture decomposes into three properties. First, guided — fitness functions set the direction so that change does not occur in just any direction. Second, incremental — building and deploying in small units keeps the scope of change under control. Third, multiple dimensions — it preserves several quality axes simultaneously, not only technical but also data, security, operations, and performance. The higher-order concept binding these three properties is the mindset of "promoting change to a first-class design concern," and a professional engineer must be able to explain this in contrast to the traditional "design once" model.

2. Overall Structure: Guided Change, Incremental Change, Multiple Dimensions

The overall structure of an evolutionary architecture takes the form of a closed loop: "architectural goals → fitness functions → guided incremental change → operational system → observed feedback." The diagram below shows how quality-attribute requirements and the various characteristic dimensions converge into a set of fitness functions, how the result decides whether a change passes or is blocked, and how metrics collected in operation feed back into the fitness functions.

flowchart TB
    subgraph DIM["Architectural characteristic dimensions"]
        D1["Technical: coupling, cyclic refs"]
        D2["Security: dependency vulnerabilities"]
        D3["Operations: availability, scalability"]
        D4["Performance: response time p99"]
        D5["Data: schema evolution"]
    end
    GOAL["Architectural goals\n(quality attribute requirements)"] --> FF["Set of fitness functions\n(objective fitness measurement)"]
    DIM --> FF
    FF -->|pass| CHANGE["Guided incremental change\n(passes deployment pipeline)"]
    FF -->|fail| BLOCK["Change blocked, feedback"]
    CHANGE --> SYS["System in operation"]
    SYS -->|collect observed metrics| FF
    BLOCK -.->|fix and retry| CHANGE

Guided change is the principle of confining the degree of freedom of change within the fence of quality attributes. Developers change functionality freely, but the moment they cross a boundary a fitness function defines (e.g., "the presentation layer may not directly reference the persistence layer," "cyclic dependencies between services must be zero"), the change is automatically rejected. What matters here is that a fitness function is not a "prohibition list" but a "definition of the architectural characteristics that must be preserved." Declaring characteristics explicitly keeps the design intent alive inside the code and the pipeline as "living documentation," even after the responsible person changes over time.

Incremental change demands two aspects at once. On the development side, things must be built in small, testable units; on the operations side, they must be deployable and reversible safely in small units. The former is backed by modularity, low coupling, and automated tests; the latter by deployment mechanisms such as [[ci-cd-pipeline]], [[feature-flag]], canary, and blue-green. Without incrementality, no matter how good the fitness functions are, the risk of "big-bang changes" cannot be controlled, so incremental-change capability is a precondition of evolutionary architecture.

Multi-dimensional preservation reflects the fact that an architecture is not a single quality but a balance of several conflicting qualities. The table below lists representative dimensions and fitness functions commonly used in each.

Dimension Preserved characteristic Fitness function example Measurement means
Technical (code) Module boundaries, coupling "0 direct UI→DB dependencies," 0 cyclic refs ArchUnit, dependency-cruiser
Performance Response time, throughput "p99 latency < 100ms" load test, APM
Security Vulnerabilities, policy "0 Critical CVE dependencies" SCA, policy-as-code (OPA)
Operations Availability, resilience "SLO maintained under fault injection" chaos experiments
Data Schema compatibility "block backward-incompatible schema changes" schema registry validation

Declaring "what, at which threshold, with which tool" to protect for each dimension turns architectural governance from an abstract slogan into executable rules.

3. Classification and Operation of Architectural Fitness Functions

Fitness functions are not a single form but are classified along several axes, and their combination determines a governance strategy. The most widely used distinctions are atomic vs. holistic on the scope axis and triggered vs. continual on the cadence (execution timing) axis.

An atomic fitness function verifies a single architectural characteristic independently. A rule such as "service A may not import service B's internal package," for instance, looks at a single concern and so executes quickly, like a unit test. A holistic fitness function, by contrast, examines together the integration points where multiple characteristics interact. A verification like "when the authentication service and payment service operate together, does the whole transaction satisfy security and latency conditions simultaneously?" belongs here; it runs in an integrated environment, so it is costly but catches defects that surface only in combination.

On the cadence axis, triggered functions execute in response to a specific event such as a commit or deployment. Most atomic rules fall here and become stages of the deployment pipeline. Continual functions measure constantly during operation, independent of events. Monitoring p99 latency or availability in production and raising an alert when an SLO is violated is a typical example, and it couples with observability ([[opentelemetry-observability]]) infrastructure. Beyond these, there are temporal functions that run periodically independent of code (e.g., a monthly check for expiry/deprecation of cryptographic libraries), static (ending with static analysis) vs. dynamic (requiring execution), and manual (performed by humans) vs. automated distinctions. A real-world strategy defaults to "automated, atomic, triggered" and complements it with manual, temporal functions only for characteristics that are hard to automate.

The diagram below shows how these fitness functions are placed in the deployment pipeline and the operational environment to automate governance.

flowchart LR
    DEV["Developer commit"] --> VCS["Version control(Git)"]
    VCS --> CI["CI pipeline"]
    subgraph STAGE["Fitness function gate"]
        direction TB
        S1["Atomic, static\n(ArchUnit dependency rules)"]
        S2["Holistic, triggered\n(integration contract check)"]
        S3["Dynamic, continual\n(response time under load)"]
    end
    CI --> STAGE
    STAGE -->|all pass| DEPLOY["Deploy(canary)"]
    STAGE -->|violation| FAIL["Block merge, alert"]
    DEPLOY --> PROD["Production environment"]
    PROD -->|observability metrics| MON["Continual fitness function\n(availability, latency monitoring)"]
    MON -.->|SLO violation alert| DEV

Concretely, in the Java world one writes "the ..web.. package may not access the ..persistence.. package" as a JUnit test with ArchUnit and runs it on every PR. .NET's NetArchTest, Python's import-linter, and JavaScript's dependency-cruiser play the same role. When this test fails, the merge is blocked, so the design rule is enforced not as a wiki document but as the immediate signal of a build failure. This is the "Automating Architectural Governance" the second edition especially emphasizes, and it is fundamentally different from a quarterly Architecture Review Board (ARB) retroactively skimming hundreds of changes.

4. Architectural Quantum and Application Procedure

The key concept when discussing the unit of change in an evolutionary architecture is the architectural quantum. A quantum means the smallest unit that is independently deployable, has high functional cohesion, and has complete static and dynamic coupling. The smaller and more clearly bounded a quantum, the narrower the blast radius of a change, making evolution easier; conversely, when coupling is tangled — such as multiple services sharing a database — the quantum grows huge and evolution becomes as hard as in a "distributed monolith." Evolvability is therefore directly tied to aligning bounded contexts in [[domain-driven-design]] and to low-coupling design, and it meshes naturally with the strategy of incrementally replacing legacy via the [[strangler-fig-pattern]].

The application procedure usually follows this order. ① Agree with stakeholders on the architectural characteristics (quality attributes) to preserve and prioritize them — since not all can be protected, pick the "most important few." ② Translate each characteristic into a fitness function together with a measurable threshold. ③ Place the fitness functions in the pipeline/monitoring to run automatically. ④ Build and deploy changes in small units, receiving immediate feedback on violations. ⑤ Observe operational metrics and periodically re-examine the thresholds and the functions themselves.

What is often overlooked in this procedure is the last responsible moment principle and the paradox of excessive fitness functions. Because premature abstraction makes change harder, defer decisions until the moment they are needed, but once an important characteristic is decided, nail it down immediately as a fitness function. At the same time, if there are too many functions or thresholds are overly strict, even normal evolution is blocked, creating the paradox where "a device meant to aid change obstructs change." Also, exploiting the fact that, per Conway's Law, system structure comes to resemble organizational structure, running an "inverse Conway maneuver" that arranges teams to fit the desired architecture first makes evolution supported at the organizational level ([[team-topologies]]).

5. Comparison with Traditional Architectural Governance

The value of the evolutionary approach becomes clear when contrasted with traditional governance. Rather than a mere list of items, looking at "why the difference arises" reveals that the crux is that the timing, agent, and form of verification differ.

Category Traditional governance Evolutionary (fitness functions)
Verification timing Quarterly/semiannual after-the-fact review (ARB) Every commit, deployment, continuous
Verification agent Architect's manual review Automated executable check
Artifact Static design documents Living executable code
Feedback delay Weeks to months Minutes to real time
Attitude to change Suppress/freeze change Promote safe change

In the traditional model, design documents begin to diverge from the code right after they are written. A single quarterly review cannot keep up with the structural erosion (technical erosion) created by the hundreds to thousands of commits in between, and even when a violation is found, it is already so deeply entangled that it is hard to undo. A fitness function, by contrast, surfaces a violation "the moment it occurs" as a build failure, so it is corrected when the fix cost is dozens of times lower — exactly matching quality engineering's old rule of thumb that the cost of fixing a defect grows exponentially the later the stage. This difference governs the accumulation rate of [[technical-debt]].

As a concrete case, one global streaming company constantly verifies the resilience characteristics of hundreds of microservices with chaos-experiment-based continual fitness functions, guaranteeing even before deployment that a given instance failure does not cascade to the whole. As another case, a large platform organization embedded hundreds of ArchUnit rules in CI to block "disallowed inter-layer dependencies" at the merge stage, effectively converging design violations that a quarterly ARB used to catch after the fact to nearly zero. What these have in common is that they moved architectural characteristics from something "declared in documents and kept by people" to something "declared in code and enforced by the pipeline."

6. Deep Dive: Fitness Functions and Platformization in the Data/AI Era

A recent trend is to extend fitness functions beyond code structure into automated governance across the entire realm of data, ML, security, and operations. In the data realm, coupling with a schema registry blocks backward-incompatibility-breaking schema changes ([[schema-registry]]), or verifies compliance with data contracts ([[data-contract]]) in the pipeline. In the ML realm, "ML fitness functions" that block deployment when model drift ([[model-drift-monitoring]]) or fairness/performance metrics stray beyond thresholds enter the MLOps pipeline, and in generative AI, evolutionary thinking is spreading through the approach of constantly measuring qualities such as hallucination rate, toxicity, and prompt-injection defense rate as evaluation (eval) gates.

At the organizational level, platform engineering ([[platform-engineering]]) embeds fitness functions in the "golden path" by default so that every team automatically inherits common governance. Coupling with policy-as-code ([[policy-as-code]]) and DORA metrics ([[dora-metrics]]) makes it possible to observe and improve both the preservation of architectural characteristics and delivery performance on a single dashboard. This is a shift that redefines governance from a "cost of control" into a "capability that increases delivery speed," and in an environment where generative AI surges code output, the importance of automated architecture verification grows even larger.

That said, such extension demands the premise of measurability. A substantial part of "good architecture" consists of characteristics hard to measure automatically, such as readability and ease of understanding, so the greed of reducing everything to fitness functions instead breeds distortion. Therefore, distinguishing characteristics that can be automated from those requiring human judgment, and complementing the latter with manual/temporal functions and design reviews, remains a core task.

7. Considerations and Implications

From a professional engineer's perspective, adopting an evolutionary architecture is a problem of co-designing the trade-offs of technology, organization, governance, and cost.

  • Application strategy (incremental adoption): Rather than trying to turn all characteristics into fitness functions at once, automate from a few core characteristics prone to erosion (layer dependencies, cyclic references, key SLOs) and expand by maturity. For legacy, it is realistic to combine with the [[strangler-fig-pattern]] and apply functions first only to the replacement segment.
  • Trade-off (agility vs. control): The more fitness functions, the greater the control, but the degree of freedom of change and build time are sacrificed. Over-tightening the number of functions and thresholds falls into the paradox where a device meant to aid evolution blocks evolution, so one must keep failure rate and build time as metrics and periodically prune the function portfolio itself.
  • Organization/culture (inverse Conway maneuver): Automated governance presupposes a shift from a culture where "the architect is the gatekeeper" to one where "teams autonomously preserve characteristics." Exploit Conway's Law in reverse to align team boundaries with the desired architectural quanta, and let the stream-aligned teams of [[team-topologies]] own their own fitness functions.
  • Limits of measurement and complement: Complement non-automatable characteristics such as readability and design appropriateness with manual/temporal functions and reviews, running them alongside qualitative evaluation such as ATAM ([[architecture-tradeoff-analysis-method]]). Blind faith in automated measurement alone creates the bias where "only what is measured gets improved."
  • Outlook (codification of governance): Fitness functions extended into data, ML, AI, and security converge with platform engineering and policy-as-code into the "codification of governance." The more generative AI accelerates code production, the more the capability to safely absorb change through automated verification will become the core competitiveness that simultaneously determines an organization's delivery speed and quality.

References


In one line: Evolutionary architecture nails down the quality attributes to be preserved as executable fitness functions and evaluates them automatically on every change, so it safely and incrementally absorbs change across multiple dimensions and shifts architectural governance from after-the-fact document review to continuous automation.