Beware of the Turing tar-pit (2004)
weblog.raganwald.com
weblog.raganwald.com
Solve the problem. Don't make new ones.
Works well for one chart from one dataset. But you want more than one chart, and pretty soon you find yourself repeating code, so you create functions, and you start thinking about data bindings and before you know it you’ve invented a generalized pipeline (or a buggy mess, depending how much forethought you put into it).
If you're thinking of writing it yourself, then you will probably need six months and a whole maintenance team, and who knows how well it's actually going to work or whether it is really needed or useful.
I think that it is good to view generalization as a tool. Like everything in software engineering, it is not an exact since and is influenced by many factors etc. But for me a guiding rule is: "When it is really clear that something will change in the future, then it makes sense to generalize. It is clear enough when you were willing to bet one week of your salary on that the need for generalization arises within X time." (where X is something less up to a year).
Mainly because this communicates intend to future code readers: "Beware, this thing will likely not be alone soon".
Unused abstraction makes reasoning about the codebase harder.
Meanwhile, if you can figure out small reasonable interfaces with potentially multiple implementers, then all the sudden things get a lot easier to deal with.
1. Engineering the generalized solution, then
2. Carrying the cognitive burden of this new indirection layer, and finally
3. Ripping out this premature -- and so likely wrong -- abstraction
Premature abstractions are like alcohol: fun borrowed from the future, and paid back later with interest. If unavoidable, choose the abstraction most narrowly scoped to your actual code base, not a future one. Humans suck at prediction. Ask me how I know.
The primary function of an interface is of course to swap out implementations. The first and most common use-case is generally for tests. You can do it other ways too, but they are usually more invasive.
That said, it’s easy to add interfaces later (which is one reason it’s a good abstraction). I would still defer it until needed.
As a push back ask them to raise an issue to request the interface. In the meantime fix the immediate problem only.
I don’t think your opionion is an outlier among people who have experience in maintaining software. But a lot of teaching make it seem as if abstraction is a goal in itself.
A driver for unnecessary abstraction is the idea that “it will be more difficult to abstract later” not realizing over-designing is a cause of this problem in the first place.
Great quote.
IMO that kind of long-term phrasing can sometimes backfire, because then the enthusastic junior engineer will go: "Ah! I'll impress everyone by making the most flexible configurable modular thingy!"
In other words, what TFA cautions against:
> The danger of the tar-pit is that instead of developing a solution to a problem, you develop a tool for solving problems. [...] situated right in the centre of some of the most attractive real-estate in your imagination. Tools that solve whole classes of problems in generic ways offer the potential for vast improvements is productivity.
Xsltproc segfaults on large files which is a bit dubious, and webassembly is refusing to run parts of libxml2 on the grounds that memory accesses go out of bounds. Browsers seem to have abandoned it.
I do want an extensible tree notation though and it does have a lot of existing tooling. Some of it quite good. Am I stuck in the mires of sunk cost, or am I wisely not implementing a DIY tree transform? Hard to see from here.