Most programmers have only a vague notion of how competent they are at what they do for a living.
Steve Yegge – Being the Averagest
As you can probably tell from most of the posts on this blog, I’m a huge fan of Steve Yegge’s blogs (they are incredible, seriously, go read them if you haven’t). But that above quote put into words something that had been bugging me for a long time before I read the post, and then has been on my mind ever since.
Over the last few months, I’ve read through The Phoenix Project, The Goal, and Toyota Kata, and I’m starting to get somewhere with a useful framework for figuring out a way to determine competency levels of programmers and a systematic way to improve.
or “What the hell are we doing here?”
To figure out how to become a better programmer, first we have to be able to define what exactly our goal is. What does it mean for one programmer to be “better” than another? If you can identify programmers as being better than one another, how does someone determine what those qualities are to focus on themselves or help others find ways to improve? Improve to what? Improve on what?
For engineers I’ve mentored in the past, it really bothered me that I didn’t really have a good framework for answering those questions, and I haven’t really gotten an answer that really satisfied me from anyone I’ve talked to. The best advice I’ve been able to come up with in the past has been essentially: find a co-worker who is noticeably better than you at something and learn from them on how to get better at it. In the absence of having a solid answer to what it means to be a good programmer that seemed like a useful method to improve, but there is a much more effective way of improving that doesn’t rely on the luck of having good teammates and randomly picking useful attributes.
So, with that said, lets move on to figuring out what that goal might be.
There are a handful of targets that I’ve seen people strive toward that seem like potential candidates for what our goal might be. If you have others, please let me know and I’ll add them here for discussion. As you can imagine, I don’t think these are the whole picture, but it is useful to talk through why that is.
To write the most elegant, beautiful, and clean code possible
When art critics get together they talk about form and structure and meaning. When artists get together they talk about where you can buy cheap turpentine. – Picasso/Renoir (apocryphal)
If you were to only read popular programming books and watch conference talks, you might be convinced that these things are what we should all be striving for. The measure of what makes a good programmer. What usually gets lost is that the advice you’re reading or listening to is usually a solution to a specific problem and not absolute commandments on what constitutes good code. Even Sandi Metz has said that her famous 5 Rules came about because the project she was on had “They had the classic ‘many things too big’ problem – ‘many things too connected’ problem.” If things are generally going well on your project, you aren’t a failure because you wrote a 6 line method. Sarah Mei also has a tweetstorm about Livable Code that I feel expresses better than I can.
I’m not saying the idea of “code quality” and all the different of it going around have no merit, but I do feel that it is mostly accomplishment theater. It is really easy to apply the “extract method” refactor or make a class conform to the command object pattern and get a sense that you accomplished something or “cleaned up” the code base without needing to do the hard part of figuring out if that actually makes things better. What metric are you using to determine if one code design is better than another? (that it complies with the style guide more than the other isn’t the right answer).
To write the most performant and scalable code
Pretty much all the runtime complexity knowledge you need is “don’t nest loops”
— Sarah Mei (@sarahmei) September 29, 2017
There are times and situations where this is important, but not only is a small percentage of your code actually performance sensitive, if you take Sarah Mei’s tweet above into consideration, even your performance sensitive areas are usually solved with relatively simple solutions. Some evidence has been found correlating a reduction in response time to an increase in sales, but you can find many companies in our industry who claim to hire great programmers and still end up having performance and scalability issues. You also have plenty of quotes all essentially saying that premature optimization is the root of all evil. So while this is a sliding scale and definitely a part of it, I can’t see having the idea of “10x programmers” floating around and being about people who write incredibly performant and scalable code if writing it only mattered a small percentage of the time.
To write completely, 100% bug free code
For anyone who feels bad about their product backlog, just remember that Outlook has been rendering smiley faces as “J” for eight years.
— James Archer (@jamesarcher) March 31, 2017
Can you name one product you’ve used where you’ve never encountered a bug? Facebook’s original mantra of “move fast and break stuff” comes to mind here. Facebook, a company that is known for and strives to hire great programmers wanted them to not worry about releasing bugs. If our ultimate goal were only about writing bug free code, they would be paying a lot of people a lot of money to ignore what makes them worth paying that amount of money if this were the case.
This is another sliding scale like performance. There’s a threshold where you begin to get diminishing returns on time spent. You need to be able to write code that hits these thresholds for your product’s situation (if you’re writing pacemaker software you’ve got a different bug threshold than if you were working on a social media site for example), but like the Facebook saying implies, sometimes there are better uses of your time.
“Productivity ‘N’ Quality (PNQ)” or “Done and Gets Things Smart”
These two come from Steve Yegge blog posts, “Being the Averagest” and “Done and Gets Things Smart“. I feel like they come really close to what it is we’re trying to do. We’re trying to be productive at a high quality level and we’re trying to be done while getting things smart. These start to talk more than just about the code itself and bring a delivery parameter into the discussion. I think where this falls apart, and Steve mentions it in both posts, is that they don’t really give you a framework for measuring the impact. How do I get better at being done and getting things smart? What does “getting things smart” even mean?
The Goal from The Goal
If the above options aren’t the goal, then what is? I have a strong feeling that there is a rewording of the goal that they define in The Goal that captures some of what Steve is saying in the two lines above and also gives us a useful framework for figuring out somewhat of a measurement system.
The goal from The Goal is to maximize throughput while minimizing inventory and operating expense. A big idea from the book is that where a lot of people focus on reducing operating expense, you can really only reduce it to $0. Throughput, on the other hand, is unbounded. New languages, ideas, frameworks, and libraries allow you to produce exponentially more than without them. You’re also able to use these tools to create new ones, faster, enabling the creation and creativity needed for even further enhancements.
Throughput is probably the easiest of the three to define, as we mostly already have rough measures for it. Most of us use tools like Pivotal Tracker, JIRA, Asana, etc at work and work on estimating complexity and/or time to complete a task. Even if estimation isn’t completely perfect, it is a measurement to start with that we improve on as we get further. It is also the one I think will produce useful insights if we focus on it.
To kick things off, I’ll throw out an MVP of an answer to the question posed in the title of this post:
Given the same complexity, and quality, bug rate, and performance output, the programmer who is “better” is the one who completes the work first.
This is a simplistic first version of an answer and makes a ton of assumptions, but it gives us somewhere to start. To illustrate this, lets look at this chart of 6 different programmers.
Like I said, there are a lot of assumptions baked in here like technical skills being the only things that matter, being able to define a quality threshold, being able to quantify the quality/bugs/performance values for work, and being able to quantify complexity enough that we can normalize it. It is also one dimensional, but my plan over the next few posts is to propose some ways to measure what we’re assuming are “measured” here enough to give us this simple chart, and ways to use this definition to help us find ways to improve technical ability as programmers.
Even if we weren’t going to assume that throughput is one of our biggest goals, it should be clear that everyone on the chart is a better programmer than F. C is also in bad shape, but probably only needs to spend more time focusing on areas that take them below the quality threshold, but the situation isn’t dire. A, B, and D are the high performers here, and any kind of additional factor could make the case for one of them to be “the best”.
What has me most excited about the above definition is that helping each one of these different programmers improve technically becomes drastically easier.
A, B, and D should focus on ways to complete their work in less time, maybe it is mechanical ability, becoming better at using their tools, automating repetitive tasks away, ore even creating a new abstraction to simplify their work.
C can take more time, maybe talking through their implementation, pairing with A, B, or D, or trying to find a common thread in the bugs that are found in their code.
F’s situation might look dire, but we all started out where F is on this chart. They need to work on everything A-D need to, and they’re probably overwhelmed. The trick is to pick one thing and have them focus on it. Finding what is taking so much time will likely have the biggest return, since it allows them to go through iterations on everything else much faster.
E likely either needs to study YAGNI and DTSTTCPW, or they need help becoming more confident in the code they’ve written. They are able to write very high quality code, well above the team’s threshold, but are taking much longer than everyone else to do it.
I could probably go on and on about this forever and in a lot of different directions, but I’ve been sitting on this post for months and this seems like a good place to stop. I have a bunch of ideas for future posts, and my rough outline for the next few posts is:
What does it mean to be a better programmer than another?
- Improving throughput in isolation
- Using throughput to find areas of improvement
- Where Inventory and Operating Expense come in
- Code quality, the why, the when, and some measurements
- The added complexities of a team, and some measurements
- Higher order goals and implications on traditional career ladders and interview practices
If any of these seem particularly interesting, I’d love to chat with you about them.