What Is Good Code?
(Epistemic status: I am not entirely satisfied with the Merchant here, but it's the closest I've been able to get so far.)
When managing developers, and when watching conversations between developers online, I sometimes notice them arguing past each other about what constitutes "good code". One group will assert that good code must adhere to specific programming practices. The other will assert that good code is code that makes money for its author.
In the worst cases, each camp derides the other. The first camp will say the other is immature and inexperienced, begging for trouble; the second camp that the other are mindless slaves to old dogmatism, and want everyone else in their chains. The first will say the other is dangerously unprofessional; the second will reply "Don't care: shipping and billing!"
In the course of trying to work through the arguments on each side, so that I can explain them to myself and others, I have started using the names "Priest" and "Merchant" as categories to help give me a handle on the attitudes expressed.
While the following descriptions are necessarily caricatures, I think they capture some recognizable qualities of the Priest and Merchant: what they care about most, their goals and focus, their time preferences, and their blind spots. In each case we start with the question, "What is good code?"
When you ask the Priest "what is good code?", his answers will have this flavor:
Good code is SOLID.
Good code is well-abstracted and well-encapsulated.
Good code is well-separated into appropriate layers and concerns.
Good code is cleanly organized and architected.
Good code has tests -- especially unit tests.
There are similar variations on these answers; they reveal that the Priest is program oriented. He cares first and foremost about the code for its own sake.
The overarching goal of the Priest is holiness -- sometimes known as "code quality," or "correctness," or "conformance to standards."
The Priest is focused on peer satisfaction -- that is, on the satisfaction of other Priests who review his code. It is other Priests who will determine how well he has achieved holiness in his code.
The Priest has a preference for the long-term time horizon. He is driven to make working with his code frustration-free for the many years he expects it to exist.
One problem with the Priest-like desire for holiness in code, is that it leads into holiness spirals. Priests engage in arguments about whether sufficient code holiness has been achieved -- and of course, the answer is always that the code is not holy enough.
Each Priest, to demonstrate his own holiness, is eager to point out how his code is holier than yours, and to explain how yours could become even holier than it is. There is always a way for your code to be more SOLID. There are ever more finely-tuned abstractions to implement. The testability, and the tests themselves, can always be improved. The spiral towards more-perfected holiness never ends.
The Priest recognizes no boundary or limiting principle to coding for holiness -- why would a Priest ever volunteer to be less holy than possible?
When you ask the Merchant "what is good code?", his answers will have a different flavor:
- Good code is code that makes money -- the sooner, the better!
This answer, and its variations, reveal that the Merchant is product-oriented. He cares first and foremost about the product being marketed, not about the code behind the product.
The overarching goal of the Merchant is market success -- whether in financial terms, or in terms of beating out competitors.
The Merchant is focused on customer satisfaction -- that is, the satisfaction of people who use the product, and do not ncessarily care about how the code behind the product operates. It is the customers who will determine the market success of his product.
The Merchant has a preference for the near-term time horizon. He is concerned with shipping code sooner rather than later, so that the product can achieve market success more quickly, and so that product iterations through the market are more responsive. Every minute of coding effort that does not line up directly with market success through customer satisfaction is a minute of coding effort to be avoided.
One problem with the Merchant-like desire for quick market success is that it leads quickly to technical debt. Speed in getting product to market means that little attention is paid to longer-term program concerns, which makes the product more difficult to improve over time. The codebase becomes resistant to change, which means the product cannot respond quickly to changed conditions for market success. This means living with the product and the pain it produces, abandoning the product and moving on to another one, or rewriting it entirely -- again, as quickly as possible.
The Merchant recognizes no boundary or limiting principle to coding for market success -- why would a Merchant ever volunteer for less market success than possible?
Which Is Better?
This is the old program-vs-product dichotomy again. In some ways it represents an argument about primacy: which mode is to dominate the other, the Priest-like or the Merchant-like?
The program-oriented developer (the Priest) wants a good codebase on which the product is founded. The product-oriented developer (the Merchant) wants a good product to present to the market.
But which approach is the right one? Or at least, which one is more pragmatic than the other -- which is the more practical approach?
Both the Priest and the Merchant will defend their attitude as being "practical." However, to quote Rand: "What is 'practical' depends on what you want to practice."
Obviously, says the Priest, coding for the long-term is practical. It helps to keep the codebase lower-cost in the end, even if it takes longer to ship to production. The venture will be better for it over all.
And obviously, says the Merchant, coding for the near-term is practical. The longer it takes to get the product to market, the longer it takes for the venture to succeed. There won't be a long-term if we don't make it through the near-term.
The Priest is OK with shipping later, to avoid foreseeable technical debt in advance, since avoiding technical debt is clearly a practical approach.
The Merchant is eager to ship sooner, and deal only with actually-realized technical debt later, since achieving market success earlier is clearly a practical approach.
The Priest wants to "do things the right way" to satisfy other Priests. The Merchant wants to "do things the right way" to satisfy the market.
The Priest will try to argue for excellence in the program according to various quality measures. The Merchant will argue that mass appeal in the market is itself a form of excellence in the product.
For just about any variation of these kinds of arguments, both the Priest and the Merchant have strong but conflicting cases.
Resolving The Conflict
What occurs to me is that both of these attitudes or aspects are simultaneously present in developers. The difference is not that one attitude or the other is present or absent, but that one aspect or the other is emphasized or de-emphasized by each developer to a different extent.
Stated differently: it is not that a developer is a Priest or a Merchant. It is that each developer emphasizes the Priest-like and Merchant-like aspects of his approach to different levels.
One developer may give the vast majority of emphasis to his Priest-like desires. Conversely, another will much more strongly emphasize the Merchant-like aspects of his personality. Even so, every Priest exhibits some Merchant behaviors once in a while, and every Merchant acts like a Priest sometimes. This is because doing so 100% either way leads to trouble.
On the Merchant side, if it's all product all the time, you end up with a program that is a mess, and the product cannot continue -- at least, not without greatly increased frustration and pain while working with the code.
On the Priest side, if it's all program all the time, you never get a product to market -- or at least, it takes more time than you have available, and the codebase is discarded when the venture fails.
A Priest-only developer would never ship a product, because the program can never be holy enough. A Merchant-only program would be entirely unreadable by others, since the program behind a successful product need not conform to the expectations of other developers.
Yet the Priest ships code to market (though perhaps not as early as the Merchant), and Merchant code conforms to expectations (though perhaps not as well as that from the Priest).
So it must be that every developer possesses at least some amount of each aspect. This means the two aspects are each in tension with each other. And whereas neither of the two aspects has a limiting principle of its own, each aspect can act as a limit on the other.
As an exercise, try to see which of those aspects you emphasize more strongly. Then, consciously practice consulting the other aspect -- in doing so, you may be able to more effectively evaluate tradeoffs when deciding when code is not yet holy enough, or for when it would be better to ship now and deal with technical debt later.
Then the Merchant aspect might be able to accept some more non-product efforts for the sake of the program. And the Priest aspect might be able to accept some more unholiness in the program for the sake of the product.
The "quality of product versus quality of program" topic looks like a running theme with me; here are some other posts on the subject.
- Different Definitions of Quality
- Crockford on Quality and Style
- Efficiency vs Quality in Software Development
- Quality, Features, and Schedule
- Framework Tradeoffs for Beginners
- Hacking, Refactoring, Rewriting, and Technical Debt
- Qualty: Program vs Product