Contracts and Interfaces — How: The Method

The Contract Template

A well-defined contract has five components. Use this template every time:

CONTRACT: [Name]

ACCEPTS:
  - [input 1]: [type/shape] — [constraints]
  - [input 2]: [type/shape] — [constraints]

RETURNS:
  - [output]: [type/shape] — [guarantees]

ERRORS:
  - [condition] → [response]
  - [condition] → [response]

SIDE EFFECTS:
  - [what else occurs, if anything]

Designing Good Inputs

Be specific about shape

Not "a customer" — but "a customer ID (text, 8-12 alphanumeric characters)." Not "order data" — but "order containing: list of items (each with product_id and quantity), shipping address, and payment method."

Vague inputs create ambiguity. Ambiguity creates bugs.

Distinguish required from optional

Some inputs must always be present. Others have reasonable defaults. Make this explicit:

ACCEPTS:
  - search_query: text — required, 1-200 characters
  - page_number: number — optional, defaults to 1
  - results_per_page: number — optional, defaults to 20, maximum 100

Define constraints

What's valid? What's invalid?

  • "email: text — must contain exactly one @ symbol and at least one . after the @"
  • "quantity: number — must be a positive integer, maximum 999"
  • "date: text — must be in YYYY-MM-DD format, cannot be in the past"

Designing Good Outputs

Be explicit about guarantees

Don't just say "returns a list." Say:

  • "Returns a list of orders, sorted by date descending"
  • "Returns an empty list if no orders exist" (different from returning an error)
  • "Each order contains: order_id, date, total, and status"

Define the shape

RETURNS:
  - user:
    - id: text
    - name: text
    - email: text
    - created_date: text (YYYY-MM-DD format)
    - is_active: yes/no

Handle empty results explicitly

What happens when there's nothing to return?

  • Return an empty list?
  • Return nothing at all?
  • Return an error?

These are three different behaviors. The contract must specify which one.


Designing Good Error Cases

Errors are part of the contract, not an afterthought.

Be exhaustive

List every way the operation can fail:

ERRORS:
  - Input validation:
    - email is empty → error: "Email is required"
    - email format is invalid → error: "Invalid email format"
    - email already exists → error: "Email already registered"
  - Business rules:
    - account is suspended → error: "Account suspended"
  - System failures:
    - database unreachable → error: "Service temporarily unavailable"

Distinguish caller errors from system errors

Caller errors: "you sent me bad input" — expected, the caller should handle them System errors: "something is broken internally" — unexpected, needs investigation

Define recovery guidance

  • "If 'rate limit exceeded,' wait 60 seconds and retry"
  • "If 'session expired,' re-authenticate and retry"
  • "If 'item out of stock,' do not retry — display message to user"

Documenting Side Effects

A side effect is anything the operation does besides returning a value:

  • PlaceOrder returns the order ID, but also sends a confirmation email
  • DeleteAccount returns success, but also erases all stored data
  • Login returns a session token, but also logs the event and updates the last-login timestamp

If a side effect is not documented, someone will depend on it unknowingly.


The Contract Review Checklist

When evaluating a contract, ask:

  • Can a stranger implement this? Could someone who has never seen the system build a correct implementation from this contract alone?
  • Are all inputs fully defined? Shape, constraints, required vs. optional?
  • Are all outputs fully defined? Shape, guarantees, empty behavior?
  • Is every error case listed? Input validation, business rules, system failures?
  • Are side effects documented? Everything beyond returning the output?
  • Is the contract implementation-free? Does it say what without saying how?
  • Could this contract survive a rewrite? If internals were completely replaced, would it still make sense?

What to Look For in the Examples

The following pages show complete contract sets for three different systems. As you read:

  1. Notice the level of detail in inputs — every constraint, every edge case
  2. Notice how errors are categorized — caller errors vs. system errors
  3. Notice side effects you wouldn't have thought of — logging, notifications, state changes
  4. Notice how contracts chain together — the output of one becomes the input of the next
  5. Compare the same type of operation across different systems — a "create" operation in a library vs. a restaurant vs. a bank