Abstractions are invaluable if you are dealing with a large codebase. Even the original author can’t keep everything in their head.
Indirections are invaluable if you want to be able to modify code in the future without making a gigantic mess — and potentially breaking compatibility in the process.
The wrong abstraction can be worse than no abstraction at all. And it can be non-obvious if you've got the "wrong" abstraction until much later when it's been in use for a while and had to be maintained -- and sometimes even then, we aren't good at recognizing that our pain is coming from the use of the wrong abstractions.
We often are, without necessarily realizing it, reluctant to refactor existing abstractions once there, preferring to alter them slightly or even more add new ones on top (which can make things worse in the long-run). And this isn't necessarily irrational, refactoring/removing existing abstractions is expensive, and with no guarantee you'll get it "right" this time either.
Sandi Metz says:
> prefer duplication over the wrong abstraction
https://www.sandimetz.com/blog/2016/1/20/the-wrong-abstracti...
Mechanically extracting things as in OP can often lead to "wrong" abstractions, which is what I get as the takeaway from the OP, which is a good reminder.
You are right that abstraction is the main tool we use as computer programmers, one way or another. Thinking in abstractions is the main thing we do that characterizes computer programming in contrast to other endeavors. So we certainly can't give it up entirely.
But this fact, I think, from my observations over my career, often leads us to over-abstraction ("over-engineering"), and the wrong abstractions. Because we are so taken with abstraction (it is neat, and you probably think so if you enjoy computer programming). It is good to be reminded that there is such a thing as too much as well as too little abstraction. Sometimes it's the "wrong" abstraction, but sometimes the "right" abstraction and the time it would take to arrive at it were unnecessary, and less/no abstraction would have served you just fine.
Take care pursuing things for their own sake and not for a reason (I suspect you do but impressionable people are reading along with us).
If the means of combination is not created, the abstraction will end up being big and complicated, and non-extensible.
As other people have voiced, there are concerns about following the plot.
I think it’s a bit like writing. I can paint a clear picture in your head or I can torture you slowly while relating the same four basic facts. While I have achieved the task in both you may not wish to work with me long if I only ever achieve the latter.
"Abstraction is used to reduce complexity."
My taxonomy: Abstractions hide complexity (bad), mental models simplify (good).
I'll consider how Shaw's worldview relates to my own.
"Indirection is used to reduce coupling or dependence."
My taxonomy: Indirection defers a design choice. A la Design Patterns.
One of my heuristics, when weighing alternatives, is to pick the design with the shallower stack depth. I'm just not smart enough to keep track of many moving parts.
FWIW: I see the 'isPrime' function more as macro (shorthand) done for legibility than a potent future cutpoint (eg Strategy).
Zed Shaw puts it well: "Abstraction and indirection are very different yet cooperating concepts with two completely different purposes in software development. Abstraction is used to reduce complexity. Indirection is used to reduce coupling or dependence."