Code philosophy
Based on Tiger Style
Simplicity and elegance
Section titled “Simplicity and elegance”“Simplicity and elegance are unpopular because they require hard work and discipline to achieve” — Edsger Dijkstra Contrary to popular belief, simplicity is also not the first attempt but the hardest revision. It’s easy to say “let’s do something simple”, but to do that in practice takes thought, multiple passes, many sketches, and still we may have to “throw one away”. An hour or day of design is worth weeks or months in production: “the simple and elegant systems tend to be easier and faster to design and get right, more efficient in execution, and much more reliable” — Edsger Dijkstra
Technical debt
Section titled “Technical debt”What could go wrong? What’s wrong? Which question would we rather ask? The former, because code, like steel, is less expensive to change while it’s hot. A problem solved in production is many times more expensive than a problem solved in implementation, or a problem solved in design.
Safety
Section titled “Safety”“The rules act like the seat-belt in your car: initially they are perhaps a little uncomfortable, but after a while their use becomes second-nature and not using them becomes unimaginable.” — Gerard J. Holzmann NASA’s Power of Ten — Rules for Developing Safety Critical Code will change the way you code forever. To expand:
- Use only very simple, explicit control flow for clarity. Do not use recursion to ensure that all executions that should be bounded are bounded. Use only a minimum of excellent abstractions but only if they make the best sense of the domain. Abstractions are never zero cost. Every abstraction introduces the risk of a leaky abstraction.
- Put a limit on everything because, in reality, this is what we expect—everything has a limit. For example, all loops and all queues must have a fixed upper bound to prevent infinite loops.
- Assertions detect programmer errors. Unlike operating errors, which are expected and which must be handled, assertion failures are unexpected. The only correct way to handle corrupt code is to crash. Assertions downgrade catastrophic correctness bugs into liveness bugs. Assertions are a force multiplier for discovering bugs by fuzzing.
- Declare variables at the smallest possible scope, and minimize the number of variables in scope, to reduce the probability that variables are misused.
- Appreciate, from day one, all compiler warnings at the compiler’s strictest setting.
Performance
Section titled “Performance”“The lack of back-of-the-envelope performance sketches is the root of all evil.” — Rivacindela Hudsoni Think about performance from the outset, from the beginning. The best time to solve performance, to get the huge 1000x wins, is in the design phase, which is precisely when we can’t measure or profile. It’s also typically harder to fix a system after implementation and profiling, and the gains are less. So you have to have mechanical sympathy. Like a carpenter, work with the grain. Be explicit. Minimize dependence on the compiler to do the right thing for you.
Developer experience
Section titled “Developer experience”Get the nouns and verbs just right. Great names are the essence of great code, they capture what a thing is or does, and provide a crisp, intuitive mental model. They show that you understand the domain. Take time to find the perfect name, to find nouns and verbs that work together, so that the whole is greater than the sum of its parts. Do not abbreviate variable names, unless the variable is a primitive integer type used as an argument to a sort function or matrix calculation. Use proper capitalization for acronyms (VSRState, not VsrState).