More feedback! Quantity becomes quality
In David Bayles and Ted Orland's book, Art & Fear, there's a captivating story that has always stuck with me. This is a story that highlights a timeless argument: quantity versus quality. It goes like this:
"[A] ceramics teacher announced on opening day that he was dividing the class into two groups. All those on the left side of the studio would be graded solely on the quantity of work they produced, while those on the right would be graded solely on its quality...
Well, came grading time and a curious fact emerged: the works of highest quality were all produced by the group being graded for quantity. It seems that while the 'quantity' group was busily churning out piles of work — and learning from their mistakes — the 'quality' group had sat theorizing about perfection, and in the end had little more to show for their efforts than grandiose theories and a pile of dead clay."
This story isn't just about art. It's a lesson that extends to the realm of engineering, where quality and quantity are often perceived as opposing forces. Initially in my career, I thought achieving high-quality results required a significant investment of time. However, over time I discovered that the ceramics teacher's story can be applied to software engineering — a field that, much like art, is subjective and reliant on experience to distinguish "good code" from the rest.
Good code is more than just functional — it's maintainable, extensible, secure, and reliable. The best way to learn how to write such code is by either experiencing the consequences of poor code quality or learning from the experiences of others who have already learned those lessons.
In a previous role as a developer manager overseeing over 25 engineers, I witnessed a pattern that further reinforced the notion that quality and quantity are not necessarily at odds. Some engineers focused on perfection, aiming for flawless code. It's often said that "perfect is the enemy of good," and indeed, those engineers produced fewer lines of code but strived to maintain a high quality standard. On the flip side, some engineers were obsessed with producing and reviewing as much code as possible, quickly working through task lists. Those "quantity" engineers initially faced more bugs and required additional oversight, especially while getting started in their careers.
At first glance, it seemed like a classic case of quality versus quantity. However, what sets the two groups apart is the volume of feedback. What the ceramics teacher discovered in the story is the same story I saw with these engineers. The "quantity" group received abundant feedback because they produced and reviewed more work, ultimately improving their code quality over time much faster than the "quality" group.
It's not a battle of quality against quantity. Effectively, in software engineering, the more feedback you can receive, either through self-reflection or from others, the more you can learn and improve the quality of your work. There are also many ways to generate feedback. Here are some suggestions:
Do code reviews
Most people are used to addressing feedback on their own code. But when someone makes a comment, it is worth thinking about why the reviewer made that comment. It could be that the reviewer is leaning into some experience they can share. However, it is also important to get feedback on your ability to review code as well. Having two reviewers is an amazing tactic most teams can do. Not only does this provide additional feedback for the code writer, but it also gives an opportunity for the reviewers to get feedback from each other. Someone unfamiliar with an area of code might miss something, but when they can see someone else comment on it, it becomes an opportunity for both the reviewer and the writer to learn something.
Monitor deployed code
When your code goes out, how do you know it is working? And working well? It is always worth monitoring your features and looking for bugs and performance regressions, or just looking at adoption metrics. What you notice while monitoring can help you, the author, understand what slipped through so you can learn and improve. You can then share these learnings with your team and your code reviewers. Thinking about how you will observe whether things are working correctly or not ahead of time can also have a big impact on the quality of the code you write.
Debug unfamiliar areas of the code
In my experience, it is common for people unfamiliar with certain areas of the code to do what they can to avoid them altogether. Unfortunately, the end result of that tactic is the code area will stay unknown. Bugs, either discovered by your customers or error tracking software, can help guide you in where to explore. By jumping into unfamiliar areas of code, even if you do not "solve" the bug, you can learn new areas of the code, tricks for getting up to speed quickly, and debugging techniques. You might even identify where developer tooling is lacking. By stepping into an area that is a little outside of your comfort zone, your comfort zone will expand.
Create more pull requests
Pull requests don't need to happen at the end once all development is completed on a feature. Get your work in front of people fast. It is much easier to pivot early on than in the later stages. You can break a feature into small sections and ask for feedback on each piece, or get some eyes on your code early with a demo or code walkthrough. To go with the previous point, tackling bugs in unfamiliar areas of code is another way to start getting incremental feedback. And if you haven't gotten feedback on your work in a few days, then you should try to go gather some soon.
Keep in mind — the more complex a pull request is, the harder it is to review. The reviewer will need to maintain a lot of context which can lead to a shallow depth of the review. Or, it will take a long time to complete. The easier you make the pull request to review, the better feedback you are going to receive the easier it will be to find bugs.
Grouping pull requests on a single type of change is one way you can break large pull requests apart. One way to do this might be to have a single pull request that refactors a complex piece of code without modifying or changing the existing behavior, then a follow-up pull request with just the new changes. Another way might be to write up a pull request that is just a model and a database migration, then another for the controller and unit tests, followed by another with the UI and integration tests. Remember that pull requests can be stacked on top of each other. And just because it is a self contained piece doesn't mean that it is going to be deployed.
Share your mistakes
This isn't about blame or keeping a record of who messed up. By sharing your mistakes, your team might be able to identify and avoid those same mistakes too. Explaining what went wrong or what things you missed also helps to solidify your internal learning. Based on the lesson, you could share it at various levels — with the people who reviewed your code, your team, or the entire department.
Aiming for feedback quantity instead of quality might be a big shift. But in reality, you are still focusing on quality.
The goal is to use feedback, whether you give or receive it, to vastly increase your skills and the pace of your learning. Regardless of what you are working on, think about how and when you can get feedback on it. It is worth discussing with your team all of the various ways you can do this.
Engineering is a team effort that requires cooperation from everyone. But you can lead by example here. If you give solid feedback to others, you can supercharge your team's focus on quality. This can become a virtuous cycle where a supercharged teammate will provide great feedback to you or others in return. Everyone wins and everyone gets better.
At the end of the day, quality and quantity are desirable goals and they are both achievable. Churn out lots of code, learn from mistakes and the experiences of others, and you'll have high quality code too. That way, you can all have much more to show than grandiose theories and a pile of dead code.