← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Design by Contract

Code Quality Advanced
debt(d7/e5/b5/t5)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). While phpstan and psalm can detect some type-related contract violations, the core issue — undocumented assumptions, missing assertions, implicit contracts — requires careful code review to identify. Static analyzers catch type mismatches but cannot detect that a method assumes 'positive integer' when it only declares 'int'. Runtime assertions may catch violations, but missing contracts are invisible until integration bugs surface.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix suggests documenting and enforcing contracts with assertions, which sounds simple but requires examining each method's assumptions, adding docblock annotations, and inserting assertion calls. For a codebase that never practiced DbC, this is a component-wide refactor to retrofit contracts onto existing methods systematically.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). Design by contract applies across all contexts (web, cli, queue-worker) and becomes a persistent discipline — every new method needs contract documentation, every modification must preserve invariants. It's not architectural-defining (b7+) but it does create ongoing overhead that shapes how developers write and review code across the system.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap' (t5). The misconception field explicitly states that developers confuse DbC with defensive programming. This is a documented gotcha that most devs eventually learn — DbC assigns responsibility (caller meets preconditions, callee guarantees postconditions) while defensive programming validates everything regardless. The common mistake of 'checking preconditions inside a method that the caller is responsible for' directly reflects this trap.

About DEBT scoring →

Also Known As

DbC preconditions postconditions contract programming

TL;DR

Methods define formal preconditions (what callers must guarantee), postconditions (what the method guarantees), and invariants (what's always true).

Explanation

Design by Contract (Bertrand Meyer, Eiffel) treats method interfaces as contracts: the caller satisfies preconditions, the callee satisfies postconditions, and the class maintains invariants throughout. In PHP, contracts are implemented via assertions or guard clauses at method entry, return type declarations, and documented invariants. Enforcing contracts explicitly shifts debugging from 'something went wrong somewhere' to 'this specific contract was violated at this specific point', dramatically reducing the time to locate bugs.

Common Misconception

Design by contract is the same as defensive programming. DbC defines a formal agreement between caller and callee — if the caller meets the preconditions, the callee guarantees the postconditions. Defensive programming validates everything regardless of who is responsible.

Why It Matters

Design by contract formalises preconditions (what the caller guarantees), postconditions (what the method guarantees), and invariants (what always holds) — making contracts explicit prevents a whole class of integration bugs.

Common Mistakes

  • Checking preconditions inside a method that the caller is responsible for satisfying — the method should assert, not silently correct.
  • Not documenting contracts in docblocks when PHP lacks native contract syntax — implicit contracts are unknown contracts.
  • Disabling contract checks in production without profiling whether they are actually expensive.
  • Writing contracts that are too weak to catch real violations — a precondition of 'not null' when 'positive integer' is needed.

Code Examples

💡 Note
assert() checks can be disabled in production (zend.assertions=0) — use exceptions for runtime enforcement, assert() for developer-time contracts.
✗ Vulnerable
// No contract — accepts anything, fails unpredictably:
function divide(float $a, float $b): float {
    return $a / $b; // Division by zero if $b === 0.0 — precondition not enforced
}

// With contract:
function divide(float $a, float $b): float {
    assert($b !== 0.0, 'Precondition: divisor must not be zero');
    return $a / $b;
}
✓ Fixed
/**
 * @param positive-int $quantity   Precondition: must be > 0
 * @param float         $price      Precondition: must be >= 0
 * @return float                    Postcondition: return value >= 0
 */
function lineTotal(int $quantity, float $price): float {
    assert($quantity > 0, 'quantity must be positive');
    assert($price >= 0,   'price must be non-negative');

    $total = $quantity * $price;

    assert($total >= 0, 'total postcondition violated');
    return $total;
}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 80
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
1 ping S 1 ping M 0 pings T 0 pings W 0 pings T 1 ping F 1 ping S 1 ping S 0 pings M 0 pings T 1 ping W 0 pings T 2 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 1 ping F 0 pings S 1 ping S 0 pings M 0 pings T 1 ping W 1 ping T 0 pings F 1 ping S 0 pings S 0 pings M
No pings yet today
No pings yesterday
Amazonbot 10 Ahrefs 8 Perplexity 8 Scrapy 7 SEMrush 6 PetalBot 5 Unknown AI 3 Google 3 Bing 2 Majestic 1 Twitter/X 1 Applebot 1
crawler 54 pre-tracking 1
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Document preconditions (what caller must ensure), postconditions (what you guarantee on return), and invariants (what stays true always) — enforce them with assertions in development
📦 Applies To
any web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Functions with undocumented assumptions about input; no assertion checks in complex business methods
Auto-detectable: ✗ No phpstan psalm
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update


✓ schema.org compliant