---
title: "Architecture checklist: all 65 rules · Agent Wranglers"
url: https://agentwranglers.se/playbook/architecture/checklist
updated: 2026-10-20
licence: "All rights reserved"
---

# Architecture checklist

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

Every rule in the architecture playbook, by chapter, required rules first. Each links to its own page with how we built it and how to check it.

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers architecture playbook: https://agentwranglers.se/playbook/architecture/checklist`.

## Code review

- [ ] **Required** [Review the whole change against its base](https://agentwranglers.se/playbook/architecture/code-review/review-against-the-base): Review a branch as one solution, compared with the branch it will merge into. Never review only the changed lines.
- [ ] **Required** [Check that it solves a named problem](https://agentwranglers.se/playbook/architecture/code-review/solves-a-named-problem): Every change must solve a problem someone can name, or add clear value to the codebase. Code without a reason is cost without return.
- [ ] **Required** [Keep it simple to maintain](https://agentwranglers.se/playbook/architecture/code-review/simple-to-maintain): Choose the simplest design that solves today's problem. A new developer or agent must understand a change without asking its author.
- [ ] **Required** [Name the principle and the fix in every finding](https://agentwranglers.se/playbook/architecture/code-review/name-principle-code-fix): Every finding names the broken principle, the exact file and line, and a concrete fix. "This feels messy" is not a finding.
- [ ] **Required** [Stay consistent with the codebase](https://agentwranglers.se/playbook/architecture/code-review/consistent-with-the-codebase): New code follows the patterns the codebase already uses for the same job. Two ways to do one thing doubles what every reader must learn.
- [ ] **Required** [Write code that agents can parse](https://agentwranglers.se/playbook/architecture/code-review/readable-for-agents): Write code that people and AI agents can read in one pass, with clear names, small files, types and a predictable structure.
- [ ] **Required** [Answer every question by number](https://agentwranglers.se/playbook/architecture/code-review/answer-every-question-by-number): Answer every review question with its number, even when the answer is "no problems found". A skipped number counts as not reviewed.
- [ ] **Required** [Verify every finding from scratch](https://agentwranglers.se/playbook/architecture/code-review/verify-with-fresh-agents): Check each finding again with a reviewer who starts fresh, such as a second person or a new AI agent. Drop findings that don't hold up.
- [ ] **Recommended** [Prefer the patterns the industry knows](https://agentwranglers.se/playbook/architecture/code-review/industry-standard-patterns): Solve common problems with the patterns and libraries most developers already know. Invent a new pattern only when the known ones fail.
- [ ] **Recommended** [Report problems beyond the diff](https://agentwranglers.se/playbook/architecture/code-review/look-beyond-the-diff): When the review finds other code that breaks the same rules, report it too, as a separate list.

## Names and functions

- [ ] **Required** [Name things for what they mean](https://agentwranglers.se/playbook/architecture/names-and-functions/intention-revealing-names): Every name says why the thing exists, what it does and how it is used. A reader should never need a comment to learn what a name means.
- [ ] **Required** [Never let a name mislead](https://agentwranglers.se/playbook/architecture/names-and-functions/no-disinformation): A name must never suggest a type or behaviour the code does not have. Calling a set a list, or a lookup a getter that writes, misleads every reader.
- [ ] **Required** [Keep functions short](https://agentwranglers.se/playbook/architecture/names-and-functions/small-functions): Keep each function at 20 lines or fewer. A longer function nearly always does more than one thing.
- [ ] **Required** [Keep nesting shallow](https://agentwranglers.se/playbook/architecture/names-and-functions/shallow-nesting): Nest blocks at most two levels deep in business logic. Deep nesting hides which branch runs and when.
- [ ] **Required** [Pass few arguments](https://agentwranglers.se/playbook/architecture/names-and-functions/few-arguments): Give a function at most three arguments. When it needs more, pass one named object that groups them.
- [ ] **Required** [Make each function do one thing](https://agentwranglers.se/playbook/architecture/names-and-functions/one-thing-per-function): Each function does one thing at one level of detail. A function either changes something or answers a question, never both.
- [ ] **Recommended** [Use names you can search for and say aloud](https://agentwranglers.se/playbook/architecture/names-and-functions/searchable-names): Use whole words that people can pronounce and search for. Replace magic numbers and strings with named constants.
- [ ] **Recommended** [Split blocks into named functions](https://agentwranglers.se/playbook/architecture/names-and-functions/extract-and-name): When a block of code needs a moment of thought, move it into a function whose name says what it does.

## Comments

- [ ] **Required** [Refactor clever code instead of explaining it](https://agentwranglers.se/playbook/architecture/comments/refactor-clever-code): When a block needs a comment to be understood, rewrite it so it reads plainly. Never leave a puzzle with a note beside it.
- [ ] **Required** [Delete commented-out code](https://agentwranglers.se/playbook/architecture/comments/no-commented-out-code): Never commit code that is commented out. Delete it, because version control already keeps every old line.
- [ ] **Recommended** [Let the code explain itself](https://agentwranglers.se/playbook/architecture/comments/self-documenting-code): Name things so the code explains itself, and write a comment only for a reason the code cannot show.
- [ ] **Recommended** [Keep change history out of comments](https://agentwranglers.se/playbook/architecture/comments/no-journal-comments): Keep change logs, author names, dates and ticket histories out of the code. Version control records who changed what and why.
- [ ] **Recommended** [Say why, not what](https://agentwranglers.se/playbook/architecture/comments/comments-say-why): A comment states a reason the code cannot show, such as a bug in another system, a legal rule or a measured trade-off. It never repeats what the code does.
- [ ] **Recommended** [Keep docblocks only for what types cannot say](https://agentwranglers.se/playbook/architecture/comments/useful-docblocks): Write a docblock only when it adds a type, a contract or a unit the language cannot express. Delete docblocks that repeat the signature.
- [ ] **Recommended** [Link every TODO to a ticket](https://agentwranglers.se/playbook/architecture/comments/todos-with-tickets): A `TODO` or `FIXME` comment names a ticket, or it is not merged. Loose notes in the code are never planned and never found.

## Errors and nulls

- [ ] **Required** [Throw exceptions instead of returning error codes](https://agentwranglers.se/playbook/architecture/errors-and-nulls/exceptions-not-error-codes): Signal failure with an exception or a typed result. Never return a magic value such as `-1`, `false` or an error string that callers must remember to check.
- [ ] **Required** [Never return null](https://agentwranglers.se/playbook/architecture/errors-and-nulls/never-return-null): Collections return empty, services use a Null Object, and lookups return one consistent "absent" value. A caller should never crash because it forgot a check.
- [ ] **Required** [Never pass null into a function](https://agentwranglers.se/playbook/architecture/errors-and-nulls/never-pass-null): Never call a function with `null` to mean "use the default" or "skip this". Give the function a clear variant or an options object instead.
- [ ] **Required** [Make fields required unless absence is valid](https://agentwranglers.se/playbook/architecture/errors-and-nulls/required-fields): Every constructor argument and data object field is required and non-nullable, unless "not there" is a valid state of the business.
- [ ] **Required** [Never swallow errors](https://agentwranglers.se/playbook/architecture/errors-and-nulls/never-swallow-errors): Never catch an error and carry on as if nothing happened. Handle it, add context and rethrow it, or let it reach the edge.
- [ ] **Required** [Release every resource you open](https://agentwranglers.se/playbook/architecture/errors-and-nulls/release-resources): Close every file, connection, lock and handle with the language's scoped construct, so it is released on success and on error.
- [ ] **Required** [Await every async call](https://agentwranglers.se/playbook/architecture/errors-and-nulls/await-every-promise): Await every promise, task or future, or hand it to code that handles its errors. A call that nobody waits for loses its errors without a trace.
- [ ] **Recommended** [Use typed domain exceptions](https://agentwranglers.se/playbook/architecture/errors-and-nulls/domain-exceptions): Give each kind of failure its own exception type with a clear name and the data needed to handle it. Never throw a bare generic error with only a message.

## Coupling

- [ ] **Required** [Talk only to your direct neighbours](https://agentwranglers.se/playbook/architecture/coupling/law-of-demeter): A function calls methods on its own object, its arguments and the objects it creates. It never reaches through one object to steer another, as in `a.getB().getC().doSomething()`.
- [ ] **Required** [Make the order of calls impossible to get wrong](https://agentwranglers.se/playbook/architecture/coupling/no-hidden-temporal-coupling): If methods must run in a set order, the code must enforce it. Never rely on callers remembering to call `init()` first.
- [ ] **Required** [Pass state in instead of sharing globals](https://agentwranglers.se/playbook/architecture/coupling/no-global-state): Never share changeable data through globals, singletons or module-level variables when it changes how code behaves. Pass state in, and return new state out.
- [ ] **Recommended** [Tell objects what to do](https://agentwranglers.se/playbook/architecture/coupling/tell-dont-ask): Give an object a command instead of reading its state and deciding for it. The rule that uses the data lives next to the data.
- [ ] **Recommended** [Keep internals private](https://agentwranglers.se/playbook/architecture/coupling/private-internals): Each module exports only what its callers need. Everything else stays private, so it can change without breaking anyone.

## SOLID and DRY

- [ ] **Required** [Keep each piece of knowledge in one place](https://agentwranglers.se/playbook/architecture/solid-and-dry/dry): Every rule, value and decision lives in one place in the code. Repeated text is fine. Repeated knowledge is not.
- [ ] **Required** [Give each module one reason to change](https://agentwranglers.se/playbook/architecture/solid-and-dry/single-responsibility): Each class, module or function serves one actor and has one reason to change.
- [ ] **Required** [Keep the contract in every subtype](https://agentwranglers.se/playbook/architecture/solid-and-dry/liskov-substitution): A subtype must work everywhere its parent type works. It may not demand more, promise less or throw "not supported".
- [ ] **Required** [Build only what is needed now](https://agentwranglers.se/playbook/architecture/solid-and-dry/no-speculative-abstraction): Do not add interfaces, factories, options or layers for needs that do not exist yet.
- [ ] **Recommended** [Extend code without editing it](https://agentwranglers.se/playbook/architecture/solid-and-dry/open-closed): Add new behaviour by adding a new type or strategy, not by editing a growing switch or if chain.
- [ ] **Recommended** [Prefer composition over inheritance](https://agentwranglers.se/playbook/architecture/solid-and-dry/composition-over-inheritance): Reuse behaviour by holding an object that does the job, not by extending a class. Inherit only when the child truly is a kind of the parent.
- [ ] **Recommended** [Keep interfaces small](https://agentwranglers.se/playbook/architecture/solid-and-dry/interface-segregation): Split large interfaces into small role interfaces, so no class has to implement methods it does not use.
- [ ] **Recommended** [Depend on abstractions at the edges](https://agentwranglers.se/playbook/architecture/solid-and-dry/dependency-inversion): Business rules depend on small interfaces they own. Databases, payment providers and email services implement those interfaces.

## Data shapes

- [ ] **Required** [Use typed objects instead of loose arrays](https://agentwranglers.se/playbook/architecture/data-shapes/typed-data-objects): Pass data between functions as a named type, such as a DTO or value object. Never use `object`, a plain dictionary or an untyped array that says nothing.
- [ ] **Required** [Never type anything as mixed or any](https://agentwranglers.se/playbook/architecture/data-shapes/no-mixed-or-any): No `mixed`, `any` or untyped value in signatures, properties or docblocks. Each one turns off the type checker for everything it touches.
- [ ] **Required** [Convert to arrays and JSON only at the edge](https://agentwranglers.se/playbook/architecture/data-shapes/convert-at-the-edge): Keep typed objects inside the app. Turn them into arrays, JSON or strings only where data leaves, such as an HTTP response or a database write.
- [ ] **Required** [Parse input once at the boundary](https://agentwranglers.se/playbook/architecture/data-shapes/parse-at-the-boundary): Turn outside input into a typed, valid object as soon as it arrives. Code after that point trusts the type and does not check again.
- [ ] **Required** [Use enums instead of magic strings](https://agentwranglers.se/playbook/architecture/data-shapes/enums-not-strings): Give every fixed set of values an enum or union type. Never compare against loose strings such as `"paid"`.
- [ ] **Required** [Give each function one return type](https://agentwranglers.se/playbook/architecture/data-shapes/one-return-type): A function or endpoint always returns the same shape. It never returns an object in one case, an array in another and `false` in a third.
- [ ] **Required** [Insert text literally when you replace](https://agentwranglers.se/playbook/architecture/data-shapes/literal-replacement): When you insert outside text with a replace function, make sure the text goes in exactly as written. Many replace functions treat parts of the replacement as commands.
- [ ] **Recommended** [Wrap domain values in their own types](https://agentwranglers.se/playbook/architecture/data-shapes/value-objects): Give each domain value with its own rules a small type, such as `EmailAddress`, `OrderId` or `Money`. Never pass it around as a bare string or number.
- [ ] **Recommended** [Make data objects immutable](https://agentwranglers.se/playbook/architecture/data-shapes/immutable-data): Make DTOs and value objects read-only. Create a new object for a change instead of editing one that others may hold.
- [ ] **Recommended** [Model each state as its own type](https://agentwranglers.se/playbook/architecture/data-shapes/states-as-types): When an object moves through states, give each state its own type with only the fields it has. Never pair a status field with optional fields that some states leave empty.

## Dead code

- [ ] **Required** [Delete code that nothing uses](https://agentwranglers.se/playbook/architecture/dead-code/delete-unused-code): Remove unused functions, classes, exports, parameters, routes and files as soon as they stop being used.
- [ ] **Required** [Remove flags that never change](https://agentwranglers.se/playbook/architecture/dead-code/remove-stale-flags): Delete a feature flag once it is fully on or fully off, along with the branch that no longer runs.
- [ ] **Required** [Remove unused dependencies](https://agentwranglers.se/playbook/architecture/dead-code/remove-unused-dependencies): Uninstall packages that no code imports. Each one adds install time, attack surface and update work.
- [ ] **Required** [Delete tests with their feature](https://agentwranglers.se/playbook/architecture/dead-code/delete-tests-with-feature): When you remove a feature, remove its tests, fixtures and settings in the same change.

## Structure

- [ ] **Required** [Point dependencies inward](https://agentwranglers.se/playbook/architecture/structure/layers-point-inward): Business rules never import the web framework, the database or other outside services. Outer layers depend on inner ones, never the reverse.
- [ ] **Required** [Allow no dependency cycles](https://agentwranglers.se/playbook/architecture/structure/no-dependency-cycles): No module may depend on itself through a chain of imports. Cycles make code impossible to test, load or change on its own.
- [ ] **Required** [Format all code with one tool](https://agentwranglers.se/playbook/architecture/structure/one-formatter): Format every file with one automatic formatter, with its settings in the repository. Nobody formats by hand, and reviews never discuss layout.
- [ ] **Recommended** [Group code by feature](https://agentwranglers.se/playbook/architecture/structure/group-by-feature): Put the code for one feature together, such as `orders/` or `invoices/`, instead of spreading it across folders named `controllers/`, `models/` and `services/`.
- [ ] **Recommended** [Name files after what they hold](https://agentwranglers.se/playbook/architecture/structure/consistent-file-names): Use one naming style for files and folders, and name each file after its main export.
