Lesson 4.1.2 introduced a word that now gets its own lesson: fitness function, a test that does not check a function but a quality of the system. The first example was Q6, “the core knows no framework”, as a test in the build. Lesson 4.3.6 made it into the architecture test that holds the allowed directions between all modules, and lesson 4.10.6 (“Comparison, architecture tests and decision”) extended it so that it holds the chosen style of the code architecture.
The term comes from the literature on evolutionary architecture; the book “Building Evolutionary Architectures” by Neal Ford, Rebecca Parsons and Patrick Kua made it known. The idea is simple: an architecture lasts only as long as something checks it with every change. What stands only in a document decays with the third hurried pull request.
This lesson collects what the Kladde already checks, adds three kinds of checks that are still missing, and draws a line: what can be
checked automatically, and what remains a person's job? At the end stand three quality scenarios from docs/quality-goals.md, each with
an automatic check in the pipeline.
What a fitness function is, and when it runs
A fitness function has three properties: it checks a goal of the architecture, not a function; its result is objective, passed or not, or a number with a limit; and it runs by itself, again and again. Lesson 4.1.2 distinguished four kinds of check: test in the build, measurement in operation, probe, review. Fitness functions are the first two, and it is worth ordering them by time:
| Time | When | Good for | Limit |
|---|---|---|---|
| on every pull request | minutes, before merging | structure, contracts, dependencies, quick measurements | must be fast and stable, or it gets switched off |
| on a schedule | at night, weekly, before a delivery | load tests in Azure, long runs, checks against a running environment | a finding arrives hours or days after the change |
| continuously in operation | every minute to every day | response times of real requests, error rates, cost | finds what has already happened |
For the Kladde the collection looks like this. The column “since” names the lesson that built the check:
| Goal | Check | Time | since |
|---|---|---|---|
| Q6 The core knows no framework | architecture test: domain models know only .NET and the shared kernel | pull request | 4.1.2, 4.3.6 |
| Modules meet only through contracts | architecture test ModuleRulesTests |
pull request | 4.3.6 |
| the chosen style of the code architecture | extended architecture tests | pull request | 4.10.6 |
| every registration resolves | registration test | pull request | 4.3.5 |
| stored formats change only backward-compatibly | golden sample files | pull request | 4.4.6, 4.5.4 |
| the HTTP interface breaks no caller | contract test: the OpenAPI document against the checked-in version | pull request | K2 2.12.2 |
| Q2 Response time | load test with failure criteria in Azure Load Testing | on demand | K3 3.8.6 |
| Q2 Response time | p95 from Application Insights, alert | operation | 4.1.2 |
| Q5 Cost per office | budget with a warning on the forecast | operation, daily | 4.1.5, 4.7.7 |
| Q1 Several offices that never see each other | isolation tests | pull request | still open, built in the final project |
Three gaps stand out. There is no check of the packages, neither for known vulnerabilities nor for their licenses. Q2 is not checked at all in the pull request and otherwise only when someone starts the load test. And Q7, “fast tests without a network”, has carried the note “still open” since lesson 4.1.2. The following sections close these gaps as far as possible.