bulletproof-functions
Bulletproof Functions
This reference features a language-agnostic set of highly opinionated guidelines on writing robust bulletproof functions and abstractions that will survive the test of maintainability, testability, and production-grade durability.
Why do we even write functions to begin with?
This is worth asking because fundamentally, machine codes do not care about functions and only operate on assembly instructions. Functions are not hardware-level mechanisms for correctness, performance, or reliability; it has no bearing on the theoretical capabilities of the model of computation.
A shallow view is that functions are meant to deduplicate logic for code reuse, hence style guides dogmatically enforcing the DRY principle (i.e., extraction upon n > 1 occurrences). This is an unfortunately limited perspective because functions serve to abstract implementation details first and foremost. Functions are "bricks" that are laid out so that callers needn't zoom into the details anymore. Code reuse is a second-order effect of this abstraction, but should not be the primary motivation.
We thus fundamentally agree on the following principles:
- DRY-ness and code reuse are neither sufficient nor necessary conditions for extraction.
- Local reasoning, testability, and abstraction are the primary motivations for extraction, even for an audience of
n = 1consumers. - Functions are human-first communication devices for expressing the intent of the code. They must serve the human reader in abstracting complexity.
A function boundary does not require a file. Typically, extract a utility file because meaningful sans-I/O behavior needs a separate colocated test, even with one production consumer. Keep both files under their owner; do not invent tests for trivial glue or count tests as shared ownership.