Philosophy that cannot be verified is decoration. This is the audit I run against a real repository — one hour, no rewriting, only evidence.
Before you start
- Open the repository at the default branch, with CI green or known-red.
- Run the complexity tool and export the list of methods above 5.
- Generate the dependency graph (
deptrac,ArchUnit,jdeps,cmake --graphviz). - Time-box each section. You are collecting evidence, not fixing anything.
O — Discipline (rules 1–17)
- Complexity: no method above cyclomatic complexity 5.
- No method with two levels of indentation.
elsedoes not appear (search, then justify each hit).switch/casedoes not appear.- No magic numbers or strings.
- No class above 50 lines; no method above 20; no package above 10 classes.
- No class with more than two instance variables.
- No method or constructor with more than two parameters.
- No interface with more than two methods.
- No abbreviations in public names.
- Booleans start with
is/has/can/should; methods start with a verb. - Constants in
UPPER_SNAKE_CASE; properties and methods incamelCase.
T — Composition (rules 18–24)
- Every collection field is its own class.
- No call chain longer than one dot, except builders and fluent APIs.
- No static methods except factories and pure functions.
- Commands and queries are separated; value-returning methods have no side effects.
- No global state or singletons; dependencies arrive through the constructor.
- Use cases are classes with one public method.
- Wiring happens in a single composition root.
- The dependency graph has no cycles.
A — Armor (rules 25–31)
- No getters, setters or public mutable properties.
- Properties are private;
protectedonly for framework inheritance. - Classes are
finalorsealedby default. - No inheritance except framework base classes.
- Inputs validated in constructors and public methods.
- Preconditions fail fast, with a domain exception.
- Input parameters are never mutated.
- No domain file imports a framework, ORM, HTTP or database package.
- An architecture test enforces the layer rule in CI.
K — Silence (rules 32–36)
- Properties are immutable; methods return new instances.
- Collection-returning methods return empty collections, never
null. - Failure is explicit — Result/Either or exception — never
null. - No hidden dependencies, magic methods or implicit conversions.
- No SQL, HTTP or file paths in the domain.
- Repositories behave like collections; an in-memory implementation exists.
- Transactions are opened by infrastructure, not by the domain.
U — Contracts (rules 37–40)
- Primitives and strings that carry meaning are wrapped in value objects.
- No
mixed/array/objectoutside explicit serialization. - Every public method is declared in an interface.
- Comments explain why and live in contracts.
- A published contract exists (OpenAPI/IDL), is versioned and matches the vocabulary.
- Breaking changes are detected in CI (spec diff).
- No client reaches the database or an internal endpoint directly.
Scoring
| Score | Verdict | Action |
|---|---|---|
| 90–100% | Compliant | Keep the CI checks; re-audit quarterly. |
| 70–89% | Mostly compliant | Fix the failing sections in the next sprint; each failure must have an owner. |
| 40–69% | Partial | Pick one section per sprint. Do not start a rewrite. |
| < 40% | Not applied | The codebase is not OTAKU. Say so, then decide whether to migrate — honesty is cheaper than ceremony. |
CI hooks
| Check | PHP | C# | Java | C++ | TypeScript |
|---|---|---|---|---|---|
| Complexity ≤ 5 | PHP_CodeSniffer | CA1502 | PMD | clang-tidy | ESLint complexity |
| Size and style | PHP_CodeSniffer | StyleCop | Checkstyle | clang-tidy | ESLint |
| Dependencies | deptrac | NetArchTest | ArchUnit | CMake targets | ts-arch |
| Contract | spec diff + schema validation in integration tests | ||||
What to do with the result
Publish the score in the README, with the date and the audited commit. Not to shame anyone — to make progress visible. A repository that goes from 45% to 72% in one quarter is a success story, not a failure.