---
name: codebase-design
description: Use when designing or changing a module's interface, deciding where a seam goes, judging whether code is too shallow to be worth its surface, making something testable, or when another skill needs the deep-module vocabulary.
---

# Codebase Design

Design **deep modules**: a lot of behaviour behind a small interface, placed at a clean seam,
testable through that interface. The aim is leverage for callers, locality for maintainers, and
testability for everyone. This is the reference for that language; it is consulted, not run.

## Glossary

Use these terms exactly. Do not substitute "component", "service", "API", or "boundary": the
consistent language is the whole point, because a shared word is what lets a design discussion stay
about the design.

**Module**: anything with an interface and an implementation. Deliberately scale-agnostic: a
function, a class, a package, or a tier-spanning slice. *Avoid*: unit, component, service.

**Interface**: everything a caller must know to use the module correctly. The type signature, but
also invariants, ordering constraints, error modes, required configuration, and performance
characteristics. *Avoid*: API, signature, which are too narrow because they name only the type-level
surface.

**Implementation**: what is inside a module, its body of code. Distinct from **adapter**: a thing can
be a small adapter with a large implementation (a Postgres repository) or a large adapter with a
small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic,
"implementation" otherwise.

**Depth**: leverage at the interface. The amount of behaviour a caller or a test can exercise per
unit of interface it has to learn. A module is **deep** when a large amount of behaviour sits behind
a small interface, **shallow** when the interface is nearly as complex as the implementation.

**Seam** *(Michael Feathers)*: a place where you can alter behaviour without editing in that place;
the *location* at which a module's interface lives. Where to put the seam is its own design decision,
separate from what goes behind it. *Avoid*: boundary, which is overloaded with DDD's bounded context.

**Adapter**: a concrete thing that satisfies an interface at a seam. Names a *role*, the slot it
fills, not its substance.

**Leverage**: what callers get from depth. More capability per unit of interface learned. One
implementation pays back across N call sites and M tests.

**Locality**: what maintainers get from depth. Change, bugs, knowledge, and verification concentrate
in one place instead of spreading across callers. Fix once, fixed everywhere.

## Deep vs shallow

A **deep module** is a small interface over a large implementation:

```
┌─────────────────────┐
│   Small interface   │  ← few entry points, simple params
├─────────────────────┤
│                     │
│ Deep implementation │  ← complex logic hidden
│                     │
└─────────────────────┘
```

A **shallow module** is a large interface over a thin implementation, and is the thing to avoid:

```
┌─────────────────────────────────┐
│        Large interface          │  ← many entry points, complex params
├─────────────────────────────────┤
│  Thin implementation            │  ← mostly passes through
└─────────────────────────────────┘
```

When designing an interface, ask: can I reduce the number of entry points, simplify the parameters,
or hide more complexity inside?

## Principles

- **Depth is a property of the interface, not the implementation.** A deep module can be internally
  composed of small, swappable parts; they simply are not part of the interface. A module can have
  **internal seams**, private to its implementation and used by its own tests, as well as the
  **external seam** at its interface.
- **The deletion test.** Imagine deleting the module. If complexity vanishes, it was a pass-through.
  If complexity reappears across N callers, it was earning its keep.
- **The interface is the test surface.** Callers and tests cross the same seam. Wanting to test
  *past* the interface means the module is probably the wrong shape.
- **One adapter means a hypothetical seam. Two adapters means a real one.** Introduce a seam only
  when something actually varies across it.

## Designing for testability

Good interfaces make testing natural.

**Accept dependencies, do not create them:**

```typescript
// Testable: the seam is a parameter
function processOrder(order: Order, gateway: PaymentGateway) {}

// Hard to test: the dependency is welded in
function processOrder(order: Order) {
  const gateway = new StripeGateway();
}
```

**Return results, do not produce side effects:**

```typescript
// Testable: the outcome is the return value
function calculateDiscount(cart: Cart): Discount {}

// Hard to test: the outcome is a mutation
function applyDiscount(cart: Cart): void {
  cart.total -= discount;
}
```

**Keep the surface small.** Fewer entry points mean fewer tests; fewer params mean simpler setup.

## Relationships

- A **module** has exactly one **interface**, the surface it presents to callers and tests.
- **Depth** is a property of a **module**, measured against its **interface**.
- A **seam** is where a **module**'s **interface** lives.
- An **adapter** sits at a **seam** and satisfies the **interface**.
- **Depth** produces **leverage** for callers and **locality** for maintainers.

## Rejected framings

- **Depth as the ratio of implementation lines to interface lines** (Ousterhout): rewards padding the
  implementation. Depth-as-leverage is the definition used here.
- **"Interface" as the TypeScript `interface` keyword, or a class's public methods**: too narrow. The
  interface includes every fact a caller must know, including the ones the types cannot carry.
- **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**.

## Going deeper

- **Deepening a cluster given its dependencies**: [DEEPENING.md](DEEPENING.md) covers the dependency
  categories, seam discipline, and replace-don't-layer testing.
- **Exploring several interfaces for one module**: [DESIGN-IT-TWICE.md](DESIGN-IT-TWICE.md) covers
  the parallel design pattern, and the gate for when it is worth the ceremony.
