Design by Contract
From Code Complete (McConnell) and Meyer's contract model: a routine's
correctness is a contract between caller and callee — the caller guarantees
the preconditions, the callee guarantees the postconditions, and the
object preserves its invariants across every public operation. Making that
contract explicit (guard clauses, assertions, documented expectations) is a
proactive design technique: it decides where each error is caught and whose
responsibility each check is, before the bug exists.
This is the design-time complement to code-quality-plugin:code-hidden-failures,
which detects error-swallowing after the fact. Here the goal is to place the
checks so failures are loud, attributable, and caught at the right layer.
When to Use This Skill
| Use this skill when... |
Use something else instead when... |
| Designing a function/class and deciding what it may assume vs must check |
Finding existing swallowed errors → code-quality-plugin:code-hidden-failures |
| Hardening a trust boundary (public API, parser, deserialization) |
A full correctness/security pass → code-quality-plugin:code-review |
| Deciding where a validation belongs (caller vs callee) |
Diagnosing a specific live bug → code-quality-plugin:debugging-methodology |
| Adding assertions/invariants to make assumptions executable |
Writing the tests that exercise them → testing-plugin |
Core Principle
| Contract element |
Question it answers |
Failure if omitted |
| Precondition |
What must hold before the routine runs? |
Garbage-in produces silent garbage-out |
| Postcondition |
What does the routine guarantee after? |
Callers re-check or assume wrongly |
| Invariant |
What stays true across every public method? |
Object drifts into an impossible state |
| Guard clause |
Reject the invalid case early, at the top |
Deep nesting; the happy path is buried |
Errors vs assertions — the load-bearing distinction. Validate external,
expected input (user, network, file, untrusted caller) with real error
handling at the boundary; assert internal, impossible conditions (a
violated invariant, a precondition another part of your code must have
guaranteed) to fail fast in development. Do not validate what an assertion
should catch, and never let an assertion guard external input.
Parameters
Parse $ARGUMENTS:
- Target (optional, first positional) — a function, class, module, or diff
to give contracts. If absent, default to the current change (
git diff HEAD +
staged) and say so.
Execution
Execute this contract design pass:
Step 1: Classify each input boundary
For the target, list every input and classify it external/expected (validate
with error handling) or internal/impossible (assert). State which layer owns
each check — push validation outward to the trust boundary so the core can
assume clean data.
Step 2: State the contract
For each public routine, write its precondition(s), postcondition(s), and — for a
class — the invariant the constructor establishes and every method preserves.
Make them concrete and checkable ("amount > 0 and currency is ISO-4217"),
not vague ("valid input").
Step 3: Place the checks
- Guard clauses at the top: reject invalid/edge cases early, return or throw,
keep the happy path flat and un-nested.
- Boundary validation: real errors with actionable messages for external bad
input — never an assertion, never a swallowed exception.
- Assertions: internal impossibilities and preserved invariants, so a logic
bug fails loudly in dev instead of corrupting state.
Step 4: Report
Emit per routine: the contract (pre/post/invariant), each check's placement and
kind (validate vs assert), and any input currently checked at the wrong layer or
not at all. Flag every spot where an external input is only assert-guarded
(a production hole) or an internal impossibility is handled as a recoverable
error (noise that hides real bugs).
Anti-patterns
| Mistake |
Correct approach |
| Asserting on user/network input |
Assertions are for impossible states; validate external input with errors |
| Re-validating clean data in every inner layer |
Validate once at the boundary; inner code assumes the contract |
| Vague preconditions ("valid input") |
Concrete, checkable conditions |
Deep if nesting for edge cases |
Guard clauses at the top, flat happy path |
| Catching an exception you can't act on |
Let it propagate; a swallowed invariant violation hides the bug |
Quick Reference
| Input kind |
Mechanism |
Where |
| External / expected |
Error handling + actionable message |
Trust boundary |
| Internal / impossible |
Assertion |
Where the invariant must hold |
| Invalid early-exit case |
Guard clause |
Top of the routine |
| Class consistency |
Invariant established in ctor, preserved per method |
Every public method |
Related
code-quality-plugin:code-hidden-failures — detects swallowed errors; this
skill places checks so failures stay loud (design-time complement)
code-quality-plugin:code-review — broader correctness/security review
code-quality-plugin:debugging-methodology — when a contract was violated and
you're tracing how
software-design-plugin:design-deep-modules — a deep module's contract is part
of its small, honest interface
1---
2name: design-by-contract
3description: Design with explicit contracts — preconditions, postconditions, invariants, guard clauses. Use when designing a function/class, hardening a boundary, or adding assertions.
4args: "[target]"
5argument-hint: "function|class|module|diff to give contracts; omit for current change"
6allowed-tools: Read, Grep, Glob, Bash(git diff *), Bash(git log *), TodoWrite
7created: 2026-06-23
8modified: 2026-06-23
9reviewed: 2026-06-23
10---
11
12# Design by Contract
13
14From *Code Complete* (McConnell) and Meyer's contract model: a routine's
15correctness is a **contract** between caller and callee — the caller guarantees
16the **preconditions**, the callee guarantees the **postconditions**, and the
17object preserves its **invariants** across every public operation. Making that
18contract explicit (guard clauses, assertions, documented expectations) is a
19*proactive design* technique: it decides *where* each error is caught and *whose*
20responsibility each check is, before the bug exists.
21
22This is the design-time complement to `code-quality-plugin:code-hidden-failures`,
23which *detects* error-swallowing after the fact. Here the goal is to place the
24checks so failures are loud, attributable, and caught at the right layer.
25
26## When to Use This Skill
27
28| Use this skill when... | Use something else instead when... |
29|---|---|
30| Designing a function/class and deciding what it may assume vs must check | Finding existing swallowed errors → `code-quality-plugin:code-hidden-failures` |
31| Hardening a trust boundary (public API, parser, deserialization) | A full correctness/security pass → `code-quality-plugin:code-review` |
32| Deciding where a validation belongs (caller vs callee) | Diagnosing a specific live bug → `code-quality-plugin:debugging-methodology` |
33| Adding assertions/invariants to make assumptions executable | Writing the tests that exercise them → `testing-plugin` |
34
35## Core Principle
36
37| Contract element | Question it answers | Failure if omitted |
38|---|---|---|
39| **Precondition** | What must hold *before* the routine runs? | Garbage-in produces silent garbage-out |
40| **Postcondition** | What does the routine guarantee *after*? | Callers re-check or assume wrongly |
41| **Invariant** | What stays true across every public method? | Object drifts into an impossible state |
42| **Guard clause** | Reject the invalid case early, at the top | Deep nesting; the happy path is buried |
43
44**Errors vs assertions** — the load-bearing distinction. Validate **external,
45expected** input (user, network, file, untrusted caller) with real error
46handling at the **boundary**; assert **internal, impossible** conditions (a
47violated invariant, a precondition another part of *your* code must have
48guaranteed) to fail fast in development. Do not validate what an assertion
49should catch, and never let an assertion guard external input.
50
51## Parameters
52
53Parse `$ARGUMENTS`:
54
55- **Target** (optional, first positional) — a function, class, module, or diff
56 to give contracts. If absent, default to the current change (`git diff HEAD` +
57 staged) and say so.
58
59## Execution
60
61Execute this contract design pass:
62
63### Step 1: Classify each input boundary
64
65For the target, list every input and classify it **external/expected** (validate
66with error handling) or **internal/impossible** (assert). State which layer owns
67each check — push validation **outward** to the trust boundary so the core can
68assume clean data.
69
70### Step 2: State the contract
71
72For each public routine, write its precondition(s), postcondition(s), and — for a
73class — the invariant the constructor establishes and every method preserves.
74Make them concrete and checkable ("`amount > 0` and `currency` is ISO-4217"),
75not vague ("valid input").
76
77### Step 3: Place the checks
78
79- **Guard clauses** at the top: reject invalid/edge cases early, return or throw,
80 keep the happy path flat and un-nested.
81- **Boundary validation**: real errors with actionable messages for external bad
82 input — never an assertion, never a swallowed exception.
83- **Assertions**: internal impossibilities and preserved invariants, so a logic
84 bug fails loudly in dev instead of corrupting state.
85
86### Step 4: Report
87
88Emit per routine: the contract (pre/post/invariant), each check's placement and
89kind (validate vs assert), and any input currently checked at the wrong layer or
90not at all. Flag every spot where an *external* input is only assert-guarded
91(a production hole) or an *internal* impossibility is handled as a recoverable
92error (noise that hides real bugs).
93
94## Anti-patterns
95
96| Mistake | Correct approach |
97|---|---|
98| Asserting on user/network input | Assertions are for impossible states; validate external input with errors |
99| Re-validating clean data in every inner layer | Validate once at the boundary; inner code assumes the contract |
100| Vague preconditions ("valid input") | Concrete, checkable conditions |
101| Deep `if` nesting for edge cases | Guard clauses at the top, flat happy path |
102| Catching an exception you can't act on | Let it propagate; a swallowed invariant violation hides the bug |
103
104## Quick Reference
105
106| Input kind | Mechanism | Where |
107|---|---|---|
108| External / expected | Error handling + actionable message | Trust boundary |
109| Internal / impossible | Assertion | Where the invariant must hold |
110| Invalid early-exit case | Guard clause | Top of the routine |
111| Class consistency | Invariant established in ctor, preserved per method | Every public method |
112
113## Related
114
115- `code-quality-plugin:code-hidden-failures` — *detects* swallowed errors; this
116 skill *places* checks so failures stay loud (design-time complement)
117- `code-quality-plugin:code-review` — broader correctness/security review
118- `code-quality-plugin:debugging-methodology` — when a contract was violated and
119 you're tracing how
120- `software-design-plugin:design-deep-modules` — a deep module's contract is part
121 of its small, honest interface