design-by-contract

v2026.09.24

Design with explicit contracts — preconditions, postconditions, invariants, guard clauses. Use when designing a function/class, hardening a boundary, or adding assertions.

GitHub
安装命令
npx skhub add laurigates/design-by-contract
Markdown
SKILL.md

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 checkFinding 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 executableWriting the tests that exercise them → testing-plugin

Core Principle

Contract elementQuestion it answersFailure if omitted
PreconditionWhat must hold before the routine runs?Garbage-in produces silent garbage-out
PostconditionWhat does the routine guarantee after?Callers re-check or assume wrongly
InvariantWhat stays true across every public method?Object drifts into an impossible state
Guard clauseReject the invalid case early, at the topDeep 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

MistakeCorrect approach
Asserting on user/network inputAssertions are for impossible states; validate external input with errors
Re-validating clean data in every inner layerValidate once at the boundary; inner code assumes the contract
Vague preconditions ("valid input")Concrete, checkable conditions
Deep if nesting for edge casesGuard clauses at the top, flat happy path
Catching an exception you can't act onLet it propagate; a swallowed invariant violation hides the bug

Quick Reference

Input kindMechanismWhere
External / expectedError handling + actionable messageTrust boundary
Internal / impossibleAssertionWhere the invariant must hold
Invalid early-exit caseGuard clauseTop of the routine
Class consistencyInvariant established in ctor, preserved per methodEvery 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
发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.24

发布时间

Sep 24, 2026

分类

未分类

许可证

MIT

源路径

software-design-plugin/skills/design-by-contract

默认分支

main

最新提交

1668324

Tree SHA

b2d4cc3