Writing the Perfect Piece of Software
What would it take to write the perfect piece of software in the modern SaaS paradigm? A paradigm in which the best products are able to constantly adapt to the changing demands of the market.
My immediate thought when considering this question is that the specific technical details of the software are less important than the team that builds it. Which programming language is used, which database technology, which cloud provider, all the nitty-gritty implementation details, are less important than the organizational structure, beliefs, values, and moral of the team behind it. To produce the perfect piece of software, you’ll need the perfect team.
The perfect piece of software must be delightful to use.
It should instill a sense of wonder in its users that has them thinking “This is fucking great”. The type of wonder you experienced the first time you used Google search. It should feel empowering. To achieve this it needs a target audience. If it tries to please everyone, it’ll please no one. Vim is a great text editor for programmers. But for your parents who are just trying to compose an email, it’s a needlessly complicated set of hotkeys, devoid of the buttons and icons they’re accustomed to. It’s unlikely a team will produce something delightful on their first attempt, so they’ll need to iterate based on feedback from their users. This requires a combination of courage and self-awareness. They need the courage to release something that isn’t perfect and the self-awareness to realize that they won’t produce perfection in a silo. They need to communicate with their users and be receptive to feedback, especially uncomfortable feedback. They need to think backwards from the user. Remaining constantly aware that they are in the business of producing software for an end-user, not writing code for the sake of writing code. And the only way this can be achieved is if they use the product they’re making. Successful brewmasters drink their own beer. If the team only interfaces with the code, they’ll forget about what it outputs, a program. They’ll fall into the trap of months-long internal changes that have no noticeable effect on the end-user, like changing a test framework or migrating to the hottest new programming language, while failing to realize the opportunity cost of neglecting features that users actually care about.
The perfect piece of software solves a problem.
And in a similar vein to the fallibility of trying to please everyone, it shouldn’t try to solve every problem. It should solve a single, well-defined problem, and solve it well. It should solve a problem that actually exists. Not a problem its founders invented. One way to ensure you’re solving a real problem is to pick one that members of the team have (shoutout Paul Graham), which comes with the added benefit of guaranteeing that the development team uses their product. To solve the problem well it’ll need many iterations, which adapt based on feedback from its users. A common pattern is arising: the importance of iteration and courage (courage is required for soliciting and thoughtfully considering feedback). To have many iterations you need lots of time or lots of speed. And in a competitive environment where demand is constantly changing, fortune favors the fast. The iteration speed of a software product has two main factors: the output of the team and the complexity of the system. The output of the team roughly equates to how much they work multiplied by the focus of that work. Depending on who you ask the output of this equation is maximal in a four-day workweek or the Chinese 996. The second part of the equation, complexity of the system, determines how efficient that output is. In a simple, well-architected system, entirely new features can be shipped in a few weeks, whereas in an overly complex system, the same change could take years. The complexity of a software system grows by default. The more code you write, the more opportunities there are for bugs to arise. Even if no code is being added to the system, its complexity grows as its dependencies become outdated and require patching. The only way to tame this ever-growing complexity is to constantly refactor. Members of the perfect team understand this. They strive to make the house a little cleaner every time they enter. They heed the advice of Douglas Crockford, creator of JSON and JSLint, and spend every sixth development cycle refactoring code.
The perfect piece of software has no bugs.
An achievement many believe to be impossible for any complex program, especially a SaaS. And maybe it is, but we can still try and describe the team and processes with the highest probability of achieving bug-free software. The code that composes bug-free software must be as simple as possible. The code must be written in such a way that it has “obviously no bugs”, as opposed to “no obvious bugs”. Simplicity and readability must be the north star of the dev team. The authors need to possess a healthy amount of skepticism towards the code they write and that of their teammates. They need to evaluate what the code actually does, not what someone says it does. They need to possess a mentality of quality assurance that manifests as a strong desire to find bugs in their own code. And they need to write tests upon tests to try and expose these bugs. The authors of the perfect piece of code practice strict code ownership. Code contributors are intimately familiar with the section of the code that they’re changing. And even then their changes are still reviewed by two members of equal familiarity. The perfect development team dismisses the idealistic notion that “everyone own’s everything” like they dismiss socialism. They know it doesn’t work.
The perfect piece of software can change fast, without introducing bugs.
A statement that sounds like a dichotomy when you consider Facebook’s early engineering motto of “Move fast and break things”. But If one had to describe the archetypal team capable of achieving this feat, they would describe a team that never bandages on features. A team that never rushes their implementation or skimps on unit tests to meet a deadline. A team that moves slow to move fast. By never compromising their principles in the face of short team goals, they’re able to move at a steady, some would even say “fast” pace in the long term. At a technical level, the enabler of moving fast is automation. Automated testing, automated releases, static code analysis, etc. Any and all processes that minimize the need for human intervention accelerate development speed while simultaneously reducing the errors that we are so prone to making.
The perfect piece of software is secure.
Only authorized users can modify and access the data that they are privy to while maintaining that unauthorized users can do no harm. The application data itself is uncorrupted and reliable, making extensive use of redundancy to ensure this quality. And lastly, the application and its data are highly available, think six nines or better. To ensure these qualities the development team must hold the three goals of security (confidentiality, integrity, and availability) in their heads at all times. They must design the system from the ground up with security in mind. They must stay up to date on the latest security trends, while also thinking critically of the potential vulnerabilities in their application and avoiding a checklist mentality. They must believe in Hammurabi's code, which calls for the builder of the bridge to sleep underneath it. They must not rely on some external party to evaluate the security posture of their application, for the builder knows more than the inspector and could easily hide flaws if he so chooses.