This phrase is, by now, common programmer knowledge, a reminder that the person first writing a piece of code shouldn’t buy convenience at the expense of the people who will have to read it and modify it in the future. More generally, code is read more than written conveys that it’s usually a good investment to make the code maintainable by keeping it simple, writing tests and documentation, etc. It’s about having perspective over the software development cycle.
Let me express this idea more succinctly:
maintainer > author
I think this line of thought can be extended beyond code-writing and used as a rule of thumb to identify problems and make decisions.
Code is a means to an end. Software should have a purpose, it’s supposed to provide a service to some user. It doesn’t matter how well written or maintainable the code is, nor how sophisticated the technology it uses if it doesn’t fulfill its purpose and provides a good experience to the user:
user > maintainer > author
Or, since we won’t need to distinguish between developer roles anymore:
user > dev
This is why, instead of guessing or asking what they need, it’s best to put the program in front of the users early and frequently and to incorporate what we learn from their feedback.
This is a strong mental model, just keeping the users in mind during development can get us quite far. It’s approximately how I learned the job and how I understood it for the first half of my career.
When I say “run” I don’t just mean executing a program; I mean operating it in production, with all that it entails: deploying, upgrading, observing, auditing, monitoring, fixing, decommissioning, etc. As Dan McKinley puts it:
It is basically always the case that the long-term costs of keeping a system working reliably vastly exceed any inconveniences you encounter while building it.
We can incorporate this idea into our little model:
user > ops > dev
It took me a while to fully grasp this because, in my experience, much of the software being built never really gets to production, at least not at a significant scale. Most software is built on assumptions that never get tested. But when you run your code in production, the KISS mantra takes on a new dimension. It’s not just about code anymore; it’s about reducing the moving parts and understanding their failure modes. It’s about shipping stuff and ensuring it works even when it fails.
I said that keeping the users in mind during development can get us very far. This works under the assumption that software that’s useful and works well, software of value to users, will be of value to the organization. It’s a convenient abstraction for developers: we produce good, working software, and the business deals with turning it into money. And it mostly works, especially for consumer and enterprise software. But, eventually, that abstraction proves to be an oversimplification, and we can benefit from incorporating some business perspective into our working process:
biz > user > ops > dev
The most obvious example is budget: we don’t have infinite resources to satisfy the user needs, so we need to measure costs and benefits. There’s marketing, there’s deadlines. There are stakeholders and investors. There are personal interests and politics at play. Decisions that make sense for our software, our team or our users considered in isolation, but not when we consider the organization as a whole. Sometimes, we need to work on what generates revenue, not what pleases the user. I’ll get back to this.
We arrived at a little model that expresses the relative importance of various factors in software development, one that can perhaps help us see the bigger picture and focus on what matters. Now I want to look at some common software development dysfunctions and see how they map to the model.
author > maintainer
This is where we started. This is clever and lazy code that turns into spaghetti and haunted forests, this is premature optimizations, this is only-carlos-can-touch-that-module, etc.
dev > user
Software from teams that don’t learn from their users or that put technology first. Over-engineered programs, “modernizations” that degrade the user experience, web apps that break the browser features, etc.
dev > ops
Software that wasn’t designed with its operation in mind. This is overly complicated software with lots of moving parts, fancy databases for small data loads, microservice ecosystems managed by a single small team. Software prematurely architected for scale. Software designed by different people than the ones woken up at midnight when it breaks.
dev > biz
Code considered as an end in itself. Software built by pretentious artisans, musicians of the Titanic, and Lisp Hackers.
dev > *
Software produced when there’s nothing at stake and developers get to do whatever they want.
biz > user >
ops > dev
This is software that’s built but rarely (or never) gets to production. I call this imaginary software. Charity Majors calls it living a lie.
user > ops > dev
Another kind of imaginary software is the one that doesn’t have users. (But scales). This is software that doesn’t solve a problem, or solves the wrong problem, perhaps nobody’s problem. Software that results from taking some hyped tech and hammering everything with it until something vaguely resembling a use case comes up.
biz > user > ops > dev
Venture-backed software without a business model or whose business model is grow-until-monopoly-then-exploit-users.
If you didn’t rage-close the browser tab yet, let me wrap up by going back to this:
biz > user
This one has ramifications that can be hard to swallow.
As I mentioned above, the way I learned the job, software was about solving problems for end users. This is summarized in one of the final tips of The Pragmatic Programmer, saying that our goal is to delight users, not just deliver code. But, since I started working as a programmer, and as software became ubiquitous, I’ve seen this assumption become increasingly hard to uphold.
There’s a lot of software being produced that just doesn’t care about its users, or that manipulates them, or that turns them into the product. And this isn’t limited to social media: as a user, I can’t even book a room, order food, or click on the Windows start button without popups trying to grab my attention; I can’t make a Google search without getting back a pile of garbage.
There’s a mismatch between what we thought doing a good job was and what a significant part of the industry considers profitable, and I think that explains the increasing discomfort of many software professionals. And while we can’t just go back to ignoring the economic realities of our discipline, perhaps we should take a stronger ethical stand not to harm users. Acknowledging that the user may not always come before the business, but that the business shouldn’t unconditionally come first, either:
user > ops > dev
biz > ops > dev
biz ≹ user