Sandi Metz recently wrote an article proclaiming that duplication is cheaper than the wrong abstraction. This article raises valuable points about the costs of speculative generalization, but it’s part of a long line of articles detailing and railing against those costs. By now it should be old hat to hear someone criticize abstraction, and yet the meme persists.
The aspect of Sandi Metz’s article that I’d like to respond to in this post is the mindset it promotes or at least the mindset that has responded to it the most. This mindset is very common to see in comments – just get the task done, nothing more. Sometimes that’s appropriate and the right approach to take, but the problem here is that the costs of abstraction, especially when it’s gotten wrong, are obvious, and the costs of the “simplicity first” mindset aren’t as obvious. I won’t talk about the specific costs of duplicated code, as those are already well known. I will talk about the opportunity costs – the missed learning opportunities.
Good developers should be constantly learning, constantly honing their skills. There’s always room to improve. The skill that’s most important for developers to practice is recognizing profitable abstractions because doing so correctly relies on honed intuition. It takes seeing costs manifest over the long term, and it takes making mistakes. Developers should be constantly evaluating their past decisions and taking risks on new ones.
Opportunity cost is an often overlooked aspect of technical debt. The reason accumulating technical debt is the cheaper choice in the moment is that it takes a path for which the solution is already known. There’s nothing to learn, just implement the hack. That’s fine in small doses, but it forgoes the opportunity to learn things about the codebase, to discover missing abstractions and create conceptual tools that can help solve the problem.
So what the developers in Sandi Metz’s example should have done is noticed that this particular abstraction was costing them more than it was benefiting them. That’s a good thing to notice – it’s a valuable learning experience. What specific aspects of the abstraction were slowing down development? Which parts confused new developers and led them to make it worse? These are questions the developers should have asked themselves in order to learn from the experience.
Our development team has a weekly practice that we call “Tech Talks,” in which a developer talks about something they learned that week, some part of the codebase that was thornier than it should have been, and so on. This practice is invaluable for promoting a growth mindset, and the situation from Mz. Metz’s article would have been a perfect example to bring up.
Developers shouldn’t focus on just cranking out code. Those who limit their attention in such a way aren’t growing and will soon be surpassed by better tools. Instead, we should recognize that the job of a developer is to understand which abstractions will prove valuable for the codebase. The only way to learn that is through experience.