Building Resilient Software: 10 Guidelines I Swear By
Jun 28, 2026
1. Fail Fast, Fail Loud
Validate inputs at the boundary. Throw early with clear messages. Silent failures become 3am bugs.
2. One Way to Do a Thing
Consistency reduces cognitive load. If you have two patterns for the same concern, delete one.
3. Logs Are Your First Debugger
Before adding a debugger, check the logs. If the logs are useless, fix the logs first. Structured logging with correlation IDs pays for itself in the first incident.
4. Dependencies Are Liabilities
Every library you add is code you don’t control. Before npm install, ask: can I do this in 20 lines? The answer is often yes.
5. Test Behavior, Not Implementation
A test that breaks on every refactor tests the wrong thing. Test the interface contract, not the internal variable.
6. Handle Partial Failure
Services degrade, databases lag, APIs return 500s. Your code should handle the case where one thing fails but everything else keeps working.
7. Make Illegal States Unrepresentable
Use types to encode invariants. If a field can’t be empty, don’t use a string — use a branded type or a dedicated class.
8. Prefer State Machines Over Booleans
Two booleans (isLoading, isError) have four states but only three are valid. A state machine (idle | loading | success | error) has four and all are valid.
9. Measure Before Optimizing
The slowest part of your app is never what you think. Profile before optimizing. Then profile again.
10. Write Code to Be Deleted
The best code is the code you can delete without worrying. Small functions, clear interfaces, and zero magic. Delete freely.