Dave Farley On What Makes High Quality Code
This morning, on the latest episode of the Engineering Room podcast, Dave Farley said something about code quality that really connected with the way in which I see software development. In the past, I've talked about the importance of writing code that's easy to find and easy to delete. But, both of these concepts tactically roll-up in a higher-level strategy that Dave identifies: write code that's safe and easy to change:
The more traditional approaches start off assuming that we have to get things right at the beginning. But we start off assuming that whatever we do is going to be wrong, it seems to me, in profound ways. And so we work in ways that allow us to be wrong safely. And easily correct it when we find it. (57:30)
.... So I've come to the belief that the only definition of quality in code that makes any sense is our ability to change the code. If it's easy to change, it's high quality; if it's hard to change, it's not. (59:30)
This notion that hard-to-change code is low quality code hits me in the gut. This is so much of what I've been wrestling with lately. Every choice that I'm making in my application architecture has, to some extent, been going through this lens: is the choice I'm about to make going to make my life easier or harder?
I'm sure that some people will have the reaction that such an outlook is nothing more than an excuse for not doing things the "right way". But, I think that's exactly what I love about this insight—that it separates out the academia of software development from the pragmatic realities of the world. Sometimes, the sub-optimal way is actually the way that makes the code easiest to work with. And, that's 100% awesome.
Reader Comments
100% agree with this. Thanks for sharing Ben.
I will state my conclusion first. Quality in code serves as a euphemism for skills issue. When we encounter code that we find hard to read or change, we might call the code unreadable or low-quality, but we actually mean "The programmers who wrote this code did a poor job," or "I don't have the skills needed to understand this code." If we don't recognize the problem as our own lack of skills we blame the code. Whichever framing applies, putting the blame on the code rather than the author or the reader prevents hurt feelings and bruised egos.
Dave Farley gives a definition of code quality that kind of kicks the can down the road, and at the same time has little value except in hindsight. "If it's easy to change, it's high quality; if it's hard to change, it's not." But "easy to change" defies easy definition and measurement just as much as "quality" does. If we don't discover (or judge) code to have low quality until we need to change it, how does that help us write quality code to begin with?
How easy or hard a programmer thinks changing some code might get depends mainly on the programmer. An inexperienced programmer will find most code hard to read and change (and thus low quality by Farley's definition), whereas an experienced and skilled programmer will not have the same difficulty. A skills issue, in other words.
As programmers gain experience they usually internalize a vague set of heuristics by which they judge code quality. At the same time the range of code they can read and confidently change expands. Some programmers will get stuck in the "expert beginner" loop [1] and stop improving. Some programmers get hung up on aesthetic trivia and dismiss code as unreadable because of indentation or naming conventions. Many programmers arrive at some style or paradigm for development that works for them -- a local maxima -- then judge everyone else according to their metrics. Farley's podcast dealt with Extreme Programming, and he relentlessly promotes CI/CD. If you don't do XP, CI/CD, OOP, functional, "Clean Code," take your pick, your code must lack quality, because you didn't use some version of "best practices."
Brian Kernighan and P.J Plauger wrote The Elements of Programming Style [2] back in 1974. That book summarized many of the heuristics experienced programmers had come to use for writing quality code, and judging the quality of code. Kernighan focused on writing code, not so much on system design or how to organize projects, but I think he did put his finger on a lot of what we think we mean when we talk about code quality. Kernighan also gave the nicest and clearest illustration of code readability, or quality, as a skills issue in The C Programming Language (2nd Edition) in chapter 5.5, when he walks through multiple implementations of
strcpy
from beginner to expert, while explaining pointers.I listened to the podcast and couldn't tell what Farley meant when he referred to "more traditional approaches," but in context it seems he means any development style other than XP and/or CI/CD/TDD. I think saying that those "traditional approaches... start off assuming that we have get things right at the beginning" caricatures up-front planning and design, drawing a false dichotomy between so-called waterfall (traditional, I suppose) and agile and XP. Farley looks old enough to know better. Software development embraced the reality of software changing over time, and new requirements driving ongoing development and maintenance, way back before I started programming over 40 years ago. The concepts of modules, cohesion, and coupling -- central to designing and implementing readable and maintainable software -- got described back in the 1960s by Larry Constantine [3] at the beginning of the structured design phase of the industry trying to grapple with large-scale software development and maintenance lifecycles.
No serious software designer ever started out assuming they had to, or could, get everything right at the beginning. Waterfall never worked that way either, it always had feedback and iterations, formal or informal, and programmers understood the necessity of iterating and checking in with users and stakeholders back in the olden days. Maybe Farley meant to contrast with some other tradition that I don't know about.
[1] https://daedtech.com/how-developers-stop-learning-rise-of-the-expert-beginner/
[2] https://en.wikipedia.org/wiki/The_Elements_of_Programming_Style
[3] https://en.wikipedia.org/wiki/Coupling_(computer_programming)
@Greg,
What a truly wonderful and thoughtful response. Thank you so much for taking the time to write it down. And, I think you accurately hit on a big part of what makes this all such a challenge to discuss: that so much of it is relative to the people both writing and then later reading the code. And, to your point, it's a shame that we have to judge the code quality in hindsight. Yes, as we gain experience, we can build up a set of heuristics; but, we're all still learning as we go (at least, I hope we are).
It reminds of a critique, or rather a clarification, of a common phrase: "the right tool for the job". I once heard someone expand on it saying that it's actually "the right tool for the job given your team at this moment in time." The expansion there being that "right" is actually a highly contextualized concept.
It reminds also of another quote from Donald Knuth: "Programs are meant to be read by humans and only incidentally for computers to execute." Again, a perspective that stresses the fuzzy, touchy-feel qualities of code.
Ha, and also George Carlin's bit about driving just popped to mind: "Have you ever noticed that anybody driving slower than you is an idiot, and anyone going faster than you is a maniac?"
To be clear, I'm not pushing back on anything you're saying—really, I'm only underscoring how subjective so much of programming is. Much of my internal struggle over the last few years has been trying to come to terms with this very notion. For many years, I was worried about the "one right way" to do things. But, I think this often sends us down a path of folly, stressing trade-offs that don't benefit us, but rather benefit some idealized concept of what "good" programming is.
And maybe I'm just not experienced enough yet to have the right set of heuristics. Which is exactly why quotes like this (from Dave Foley) connect with me. It gives me another tool in my decision making tool-belt. The next time I'm at a fork in the road and I have to make a decision about how I want to proceed, it's just another question I can ask myself before writing the code: will this make it easier/safer or harder/dangerous to change in the future?
Actually, this framing just helped me settle a point of contention that I've had for a long time: application code vs. stored procedures. When I was coming up in the programming world, there were two groups of people: those who loved stored procedures and those who hated stored procedures. I've always been in the latter camp; but, I could never articulate why. I "knew" that stored procedures were a bad idea; but, I didn't have the cognitive tools to understand my gut feelings / instinct.
To now be able to frame it in terms of ease/safety to change, it's much easier to understand my initial aversion. Moving logic out of the database (stored procedures) and into the application code makes the logic easier and safer to change. Especially with techniques like feature flags, where application control flow can be gradually altered.
So all to say, yes as we gain experience our notion of what is / isn't good code evolves. And, a lot of that is the changing set of heuristics that we have access to. And, for me, the framing of choices in terms of ease of change is really just one more of those heuristics.
@Ben Nadel,
Thank you for posting the original article and your reply. I agree that George Carlin hit it on the head. I can't count how many times I've heard programmers call someone else's code crap or cryptic; they alone occupy the sane middle ground.
You don't have to spend much time with programmers, in person or online, to hear them throw around words like "quality," "readable," "maintainable," "clean code," "best practice," "productive," "optimal," etc. But when pressed you won't get a good definition or a metric. Maybe they repeat something they read, a rule like DRY or technique like dependency injection that makes sense in some contexts. The software business falls prey to fad, fashion, and cargo cults more than we like to admit.
Of course Knuth got it right too, but what counts as human readable for Knuth would baffle a lot of junior programmers. I have actually read criticisms of Knuth's books complaining that he made up an assembly language for his examples -- why can't he rewrite with examples in Python or Javascript?
We would all benefit from remembering the strongly subjective nature of things we casually talk about as objective properties of software -- quality, readability, maintainability. That would let us focus on helping each other level up our skills and arrive at a shared set of heuristics we can teach and learn, rather than criticizing the ephemeral artifacts.
As for stored procedures in SQL... it depends. You find that more in larger enterprise environments for a few good reasons. From my own experience in enterprise-scale logistics, stored procedures give the organization a single place to implement core business logic, which makes more sense if you think about application software developed over many years, by different teams, and in different languages. You don't want ten versions of a function to check for low inventory levels, you want that in one place. DRY applies to business logic, in other words, not just to chunks of code. At this point someone will comment that you can do that in an application layer. Yes, and you see that in enterprise systems as well. Logically equivalent approaches, with performance or cost deciding one way or the other.
Another reason: atomicity. You can implement atomic operations more safely (and usually with a lot less code) in the database. Think about financial transactions that update multiple ledgers -- all of the updates must succeed or fail together.
For programmers who haven't worked in such environments and who (barely) learned SQL with a less capable RDBMS such as MySQL, stored procedures seem clunky, hard to read, hard to manage in version control, and yet another language to learn and remember. If you use Oracle or SQL Server or DB/2 you will find those problems solved, and stored procedures offer a lot of safety, maintainability, and performance. When I see people dismissing stored procedures as a bad practice I can safely bet they come from a Rails or Node.js or PHP/Laravel background, accustomed to ORMs and query builders, the database supporting one application and code base, with MySQL or Postgres acting as a dumb object store. Don't even get me started with so-called NoSQL, which mostly don't even support stored procedures.
Not trying to promote my own site, but I do have a couple of relevant articles. Free, no ads, popups, affiliate links.
What does code readability mean?
Why don't software development methodologies work?
@Greg,
Thanks for the links, will check them out. Also, your comment here really hits home for me:
As I've gotten farther into my career, this is more and more the mindset that I'm trying to achieve. I've always enjoyed learning in public and trying to create a conversation (such as this one); but, it is only in my recent years that I've come to truly understand how differently everyone sees the world. And, how just different everyone's experience is. And, that what works well for me may have nothing to do with what works well for others (and vice-versa).
This, to me, is the great irony of trying to remove the human element from software development. It's a fundamentally human endeavor.
To that point, I just want to emphasize that I wasn't dismissing stored procedures as "bad practice"—only that when viewed through the lens of "ease of change", it helps me understand the feelings I was having when deciding where to put logic.
To echo a quote I just recently heard on a podcast (I think it was on Lenny's Podcast somewhere):
Anyway, this is all great food for thought. I really appreciate you Yes-and'ing my original post.
@Ben @Greg,
I very much enjoyed your exchange here! And I'm clearly out of my depths with the wealth of ideas being shared here, but I care very much about code craftsmanship. I hold Ben's code examples in very high regard and find them extremely easy to read/understand. In my opinion, that is a mark of great code. And I totally get that this may be because his mental model agrees in large parts with my own. It's also probably because I frequent this blog and he's played a large role in shaping my coding outlook and style.
I try to write code that is readable, understandable, safe to change, and safe to delete. We all probably do. Sometimes we succeed. Sometimes we fail. I can't tell you how often I've gone back to code I've written in the past and wondered to myself...what was I thinking? It's easy to not see the trees for the forest when you're mired in the details at the 100ft view, which obscures your ability to make the "more reasonable" trade off from the 50k ft view.
@Chris,
First off, thank you for the kind words - I'm glad that we are simpatico. Second, I love the fact that I can look back at code that I wrote a while ago and feel a twinge of shame. To me, that's a good sign that I'm continuing to grow as a programmer. When I look back and everything feels great for too long, it will probably be because I've given up 😄 not because I've written the best code.
@Ben Nadel, @Chris,
After 40+ years writing code I still look at stuff I wrote and think I could have done better. That just comes with the territory — we learn new and better techniques constantly. No shame in that. It means we have advanced our skills and not got stuck. Over time we experience that less and less. That's what I meant by internalizing heuristics over time.
I spent the day rewriting a lot of error handling code, replacing my own code from a few years ago. And I had the thought, why didn't I do it the "right way" to begin with? Back then I thought I knew the right way but today I have a more robust approach. Still, very likely I will revisit it again in a few years and wonder what I was thinking.
"Error handling" is definitely one of the areas of application development that I'm continually refining.
Post A Comment — ❤️ I'd Love To Hear From You! ❤️
Post a Comment →