This does a lot to find pragmatic tradeoffs between performance and abstraction. It also pushes you away from the over-abstraction that leads to the Second System Effect, as coined by The Mythical Man-Month.
This does a lot to find pragmatic tradeoffs between performance and abstraction. It also pushes you away from the over-abstraction that leads to the Second System Effect, as coined by The Mythical Man-Month.
If you have three distinct examples, and you need to do something that requires a fourth, you won’t be able to justify spending time writing an abstraction. You should just copy it again. The three existing examples don’t use an abstraction, and they work just fine, so there’s clearly no need for an abstraction… or so the argument goes. In the unlikely event that you’re allowed to write the abstraction, you definitely won’t be allowed to reimplement the existing examples to use it now, because those modules are not in scope and we don’t have the budget to test them again.
If you don’t create the abstraction up front, you’ve lost the chance to have an abstraction.
It's not the only way of working, but it tends to suit the challenges faced by very large teams with high turnover, diffuse/negligent code ownership, many juniors/early-career contributors, and low trust.
It also produces software that resembles papier maché -- increasingly thick, disordered, and glutinous, with poor visibility and low durability.
If your team isn't subject to the challenges that make papier maché coding necessary, encourage people to escape its cargo cult. Small teams of people who trust each other, where code has long-term owners who can speak to its purpose and direction, can dynamically sculpt and rework code more like clay. And you get better software when that can be done.
If you end up having a poorly fitting abstraction, then you'll be spending extra effort on doing things "properly", but not really getting any benefit out of it. You just loose the agility of hacking things quick'n'dirty, or you end up hacking around the bad abstraction, and get worst of both worlds.
The rest depends on having management that understands trade-offs between doing things properly and efficiently long-term vs getting stuff out of the door quickly (if you're a startup with a short runway, or racing to be the first to win some opportunity, shipping ugly hacks now may be the only way to survive to even have "later" to worry about).
That may be true, but it’s still a problem if you can never create new abstractions, because that prevents you from creating good abstractions too, not just bad ones.
If you need to repeat yourself, first copy and paste. If you need to a third time, then you can pull it into a function to generalize.
But like nearly everything with programming, hard and fast rules are bad, but it’s a good rule of thumb
The One created the Two
The Two created the Three
The Three created the Ten Thousand Things
Chapter 42 of the Daodejing
The Second System Effect has nothing to do with over-abstraction of code - it has nothing to do with code at all. The basic premise is:
First System: We barely did anything we dreamed of and can see 100s of ways to improve things, but we had to get something to market.
Second System: We’ve learned so much! Revenue enables big picture thinking! Everything we ever dreamed of let’s design and build!
It’s fundamentally a mistake at a business/product design level. That feeling of success leads to a release of constraints and then trying to bite off far more than can be chewed.
The fact that the business mistakes are easiest to spot from outside doesn't mean that the coding mistakes aren't there. Even though that level of detail is only visible from inside of the system.