Simplifying APIs
Intent
Section titled “Intent”The simplifying APIs family is about the outside of a function: the part every caller has to read and reason about. A function can have a flawless body and still be painful to use because its name lies, its argument list is a mile long, or a stray boolean silently changes what it does. These refactorings tidy the call site so the interface advertises exactly what it offers.
The smell
Section titled “The smell”You can usually feel a bad interface at the call site. You squint at an argument list and cannot remember which true means what. You find two functions that are ninety percent identical and only differ by a hard-coded number. You keep passing the same three values together, in the same order, to every function in a module. None of these are bugs — the code works — but each one taxes everyone who reads the call.
flowchart TD
A["A function that is awkward to call"] --> B{"What makes it awkward?"}
B -->|"The name misleads or hides intent"| C["Rename Function/Variable"]
B -->|"Two near-clones differ by a value"| D["Parameterize Function"]
B -->|"Too many arguments travel together"| E["Introduce Parameter Object"]
B -->|"A boolean flips behaviour"| F["Remove Flag Argument"]
B -->|"The constructor is too rigid"| G["Replace Constructor with Factory"]
C --> H["An interface that explains itself"]
D --> H
E --> H
F --> H
G --> H What this module covers
Section titled “What this module covers”Nine refactorings that make function and method interfaces clearer and easier to call:
- Rename Function/Variable — when a name misleads or under-explains, rename it and update every caller. Names are the cheapest documentation you will ever write.
- Parameterize Function — when two near-identical functions differ only by a literal value, merge them into one function that takes that value as a parameter.
- Introduce Parameter Object — when a clump of arguments always travels together, group them into a single object so the relationship becomes explicit.
- Remove Flag Argument — when a boolean argument switches behaviour, split the function into two clearly-named functions.
- Replace Constructor with Factory Function — when a constructor is too limiting, wrap it in a factory function that can pick a subtype and carry a meaningful name.
- Separate Query from Modifier — when a function both returns a value and changes state, split it into a pure query and a separate command.
- Preserve Whole Object — when a caller unpacks several fields from an object just to pass them along, hand over the whole object instead.
- Replace Parameter with Query — when a parameter is derivable from data the function already has, drop it and compute it inside.
- Remove Setting Method — when a field should be fixed at construction, delete its setter to make the object immutable.
Each lesson shows the same before-and-after in TypeScript, Python, Go, and Rust, then walks through safe, ordered mechanics — running your tests between every step.