Software Guidelines
A small collection of guidelines on writing software.
Programs must be written for people to read,
and only incidentally for machines to execute.— Gerald Jay Sussman
We believe that to be a good developer, you must be able to understand and reason about both the technical details as well as the user needs. To be a great developer, though, you need to understand that the quality of any of your work is determined by the reader, never the writer.
Unfortunately, this is something that everyone has to experience at some point. You can write the most compact code, if your colleague does not understand it, it is not useful code. Similarly, if an end user does not understand the sign up workflow you worked on, they are (most likely) not using it wrong.
As frustrating as discussions with readers can be, they can be easily prevented by following common guidelines that we have collected or created over the years. Some of which are inspired by John Ousterhout's "A Philosophy of Software Design".
Reduce Cognitive Load
Increased cognitive load is the number one symptom of sub-optimally designed programs. It appears in many forms, is hard to eliminate and easy to introduce. It creeps into a codebase as a slow but steady productivity killer.
Fighting cognitive load is a long-term investment, where benefits are aligned with those of developers, clients and end-users. While sometimes abstract, there are concrete guidelines to prevent cognitive load from entering our codebases.
-
Define once. As soon as there is more than one source of truth, you introduce cognitive load.
-
Eliminate unknown unknowns. Effects of changes should be enforced by a compiler, not by conventions. Unknowns should be explicitly incorporated into the codebase, and as a last resort, documented close to the source.
-
Reason locally and rely on types. External assumptions can safely be encoded into a type system and invariants can be enforced by validators and compilers.
-
Describe the why, not the how. The how is explained deterministically in code that is uninteresting. The powerful part is the why, which is captured in comments and wikis.
-
Acknowledge that programming requires empathy. When making a contribution, try to place yourself in the head of your colleagues. Even thinking about coming back to this code in a few months yourself will most likely make you a better programmer.
Play Multiple Roles
The above guidelines sound interesting, but focusing on them alone can seriously harm one's productivity. As programmers we recognize that it is necessary to enter a "flow state". Not the coffee-fed all-nighter ones, but those that are based on the healthy momentum that you build up and should maintain when tackling the problem at hand.
Maintaining the flow state and delivering good code are not mutually exclusive. As Matthias Endler (at corrode) puts it: "I would argue that 'writing code' and 'refactoring code' are two different modes of programming. During writing mode, you want to focus on getting the idea down and stop your inner critic, which keeps telling you that your code sucks. During refactoring mode you take the opposite role: that of the critic. You look for ways to improve the code by finding the right abstractions, removing duplication and improving readability."
It is important to play both roles well, and to know when to play them. No strict rules exist, but the moment you start introducing others to your project, both roles should be explored. By the time your contributions will undergo testing and code review, both roles should be played out.
Using LLMs
Undoubtedly, LLMs have stirred up the software development landscape, and thus our work. In an effort to dominate the market, AI tools are made available at appealing low prices, facilitating the generation of code to be faster, cheaper and more accessible than ever before. As engineers, we know that writing syntax has never been the main task, and it might feel uncomfortable to see public perception change about the value of often carefully crafted and meticulously tested code. Though it would be naive to discard LLMs out of skepticism or fear. Where innovation has traditionally forced manual labor jobs to reorganize, it now forces the previously largely untouched base of desk job workers to adapt.
In doing so, we take Oxide's RFD 567 as inspiration, recognizing that LLMs perform meaningfully well at reading and processing documents while refraining from anthropomorphizing them. We experiment with LLMs to write code with clear guardrails and oversight and follow their development closely. We do not use LLMs to write texts, but do deploy them as editors, asking for feedback on our writings. As LLMs keep changing, so does our stance, and new insights will be reflected in this very RFD.