You can rewrite a module's body on a quiet afternoon. You cannot rewrite its interface without touching every caller, and the callers are the part you do not control. So the interface is where the decision actually gets made, and it gets made early, usually before anyone has seen the problem clearly enough to make it well.
What follows is what I do about that.
The first move is to ask what a deep module would look like here — one that hides enough behaviour that the caller can forget the rest.
Three questions, in order
What does the caller already know?
What would it have to learn to use this?
Is the difference worth the module existing?
The third question is the one that kills modules, and it should. A wrapper that renames its dependency has a cost and no depth — and a type alias like type Id = string is the same trade in miniature.
Three methods, and everything downstream is a pure function of them. The slug derivation, the canonical construction, the pagination, the consistency assertions — none of that appears here, which is the point.
A narrow interface is a promise you can keep.
What this rules out
Configuration objects that grow a field per caller
Optional parameters that change the return type
Anything named helpers
The two shapes, drawn to the same scale. Depth is the ratio, not the size.
The vocabulary here is John Ousterhout's, and the book is short enough to read in a sitting.
---
title: "The interface is the decision"
description: "Most of what a module will cost you is settled by its interface, before a line of its body is written."
url: "https://lateano.com/writing/the-interface-is-the-decision"
author: "Colin Lateano"
published: "2026-07-11"
updated: "2026-07-19"
tags:
- title: "How I work"
url: "https://lateano.com/tags/how-i-work"
---
# The interface is the decision
Most of what a module will cost you is settled by its interface, before a line of its body is written.
You can rewrite a module's body on a quiet afternoon. You cannot rewrite its interface without touching every caller, and the callers are the part you do not control. So the interface is where the decision actually gets made, and it gets made early, usually before anyone has seen the problem clearly enough to make it well.
## What follows is what I do about that.
The first move is to ask what a [deep module](/glossary/deep-module) would look like here — one that hides enough behaviour that the caller can forget the rest.
### Three questions, in order
1. What does the caller already know?
2. What would it have to learn to use this?
3. Is the difference worth the module existing?
The third question is the one that kills modules, and it should. A wrapper that _renames_ its dependency has **a cost and no depth** — and a type alias like `type Id = string` is the same trade in miniature.
> [!WARNING]
> A wide interface is not a style problem. It is a commitment to every caller that reaches through it, and you find out how many there were on the day you try to change it.
The signature carries the whole argument:
```ts title="src/graph/build.ts"
interface ContentGraph {
nodeAt(route: string): Node | null
incomingReferences(termSlug: string): Node[]
routes(): Route[]
}
```
Three methods, and everything downstream is a pure function of them. The slug derivation, the canonical construction, the pagination, the consistency assertions — none of that appears here, which is the point.
> A narrow interface is a promise you can keep.
## What this rules out
- Configuration objects that grow a field per caller
- Optional parameters that change the return type
- Anything named `helpers`

The vocabulary here is [John Ousterhout's](https://web.stanford.edu/~ouster/cgi-bin/aposd.php), and the book is short enough to read in a sitting.
[Interface depth explorer](https://example.com/fixtures/interface-depth-explorer)
> [!ASIDE]
> I have changed my mind about this once already. The earlier version of this argument said the body mattered more, and it was wrong for a reason worth its own post.
>
> What changed my mind was wanting a [seam](/glossary/seam) I had not left myself, which is a body problem you can only reach through the interface.