Write the Failure Case First
Most of us write the happy path first. The function that works when the input is clean, the network is up, and the database has the row we expect.
Then we sprinkle error handling on top like seasoning.
I've started flipping that order. Before I write the success path, I write what should happen when things go wrong: bad input, missing data, timeouts, permissions denied. Not every edge case in the universe — just the failures that are likely or expensive.
Why first? Because failure cases shape the interface. If you decide early that a missing user should return null versus throw, the rest of the function follows. If you invent that decision after the happy path is done, you end up with awkward returns, half-handled exceptions, or callers that guess.
A practical version of this:
- List the ways this can fail that you care about.
- Decide the contract for each (throw, return a Result, log and continue).
- Sketch those branches.
- Then write the success path into the space that's left.
You don't need a formal Result type or fancy error taxonomy. You need a clear answer to "what does the caller see when X goes wrong?" before the happy path hardens into something that can't say.
The bonus: reviewers ask fewer "what if" questions, because you already answered the important ones in the code.
Try it on your next small function. Failure first feels backwards for about ten minutes. After that, the happy path gets simpler, not harder.
