In his novel Sourdough, Robin Sloan juxtaposes a cutting-edge robotic arm with an ancient sourdough starter as the main character learns the art of bread-making. One is created with generations of knowledge and practice passed down in the form of food; the other is a futuristic device made by a fictional Silicon Valley startup with ambitions to “make repetitive labor obsolete.” Reading the book, I began to see both as technologies imbued with the ideas of each person who has contributed to them. As my organization has moved to remote work in 2020, I’ve realized that code is no different. Code is sourdough.
Sourdough starter, or culture, as it’s biologically known, is a collection of cells that must be cultivated in order to thrive. Cultivation involves routinely feeding it flour and water. At all times, it’s a combination of every past decision the cultivator made, whether experimenting with its diet or feeding it a tried-and true-mixture. Context is omnipresent in every batch. Even when a piece is cut off to be shared, the new mixture inherits the decisions of the past. Every new line of code cultivates a codebase in the same way.
A codebase is a history of past decisions, assumptions, and compromises.
A codebase is a history of past decisions, assumptions, and compromises. At The New York Times, where I’m a software engineer, my team navigates a number of codebases, some shared throughout the organization, some solely owned by us. Like many companies, we shifted to remote work this year, and deliberations and huddles that would normally have happened in the office or via spontaneous Zoom calls (for distributed teammates) started taking place asynchronously over Slack and in Google Docs. As a result, I was able to participate in far more discussions across the company and gain new insight into the decisions that would eventually be translated into code.
Every document and discussion adds history and context to the codebases we work in. Each addition, big or small, changes the mixture, like a baker altering sourdough starter by feeding it a different brand of flour or adding dashes of yogurt or honey to the dough. I’ve come to recognize this same history and context when reading through codebases and code reviews. I’m able to understand trade-offs and compromises, subtle disagreements and constraints; I can surmise what fed the decision for an engineer to, for instance, build a new component rather than use the existing standardized version. I see too that legacy code, maligned as it can be, amounts to a collective history that we can learn from.
With no reliance on meeting rooms and physical gathering spaces, communication has become more flexible: It’s never been easier to hop on a call with a team member to gain insight into their train of thought. There are engineers I’ve never met in person, yet I’ve learned the types of problems they like to solve and how they might approach an issue that arises from their code. I’m able to devote more time and emphasis not only to the solution, but to the underlying factors and the history behind it. I’m able to understand why some team members prefer stability and consistency, while others are willing to take risks in the name of experimentation.
Every piece of new code adds to the culture and cultivates our shared understanding.
Like a sourdough starter passed through the hands of many bakers—some novices, some experienced—a codebase reflects how teammates communicate with one another. It’s a snapshot of our thinking and our best attempts at codifying norms and assumptions. It’s a conversation in which each person contributes and is in conversation with those who came before them. With each new feature or bug report, we understand our code better. We identify areas where new logic doesn’t quite fit with existing logic. We’re constantly in touch with our own past decisions and those of our coworkers. We’re working together, trying to harmonize and match one another’s thinking patterns and assumptions. We trust one another to make decisions for the good of the team and the organization. Every piece of new code adds to the culture and cultivates our shared understanding.
If code is sourdough, we have an opportunity to better appreciate the histories and context that have gone into it. In software, we tend to think of legacy code as something that should be thrown away or rewritten, often conflating a codebase’s age with its health and viability. But code doesn’t age in a vacuum. If sourdough can be passed down from person to person over decades, then so can code. The preservation of decisions and experience is tied to the preservation of our codebase. Even when the code itself is no longer being updated, documentation around the logic or the underlying platform and adjacent technologies can keep a codebase and its culture vibrant. You can then pass that culture on for another team to bake with. It might just taste better than you’d expect.