Indeed. There is a balance to be found. Over-engineering and using the wrong abstractions hurts. Working with an “organic design” that has no useful separation of concerns, or forever reimplementing the basic data structures and algorithms of whatever domain you’re working in instead of doing creative work that is going to solve your real problem, also hurts. Too far towards either extreme and development progress slows to a crawl while quality plummets.
I wish we had a bit less emphasis in the industry on always using the latest shiny tools and a bit more on learning good fundamentals like data structures, algorithms and design patterns. Of course abstractions sometimes need to evolve as requirements do, but identifying which abstractions are helpful at present or when an existing abstraction isn’t helping any more and should be removed or replaced is absolutely a skill that can be developed with knowledge and experience, and it pays huge dividends to those who cultivate it.
So I was told this as bluntly as possible by someone 15 years ago - "you don't have to code all parts of your design".
Every line of code you write makes it harder to replace it. That the feature is an asset, the code is a liability. That the goal they had set out for me was to write as little as possible, but achieve the same result.
The only reason to rewrite a system out of tech debt, which is what I was doing then & getting lost in a sort of second system "this is the last rewrite" effort, is to write the next feature with less code - even if the next system needs you to rewrite bits you just wrote.
This might sound simplistic, but I've seen that work over and over again.
Plus, it was much easier to hand over the code to the next person when I wanted to do something new and interesting, if it was functionally complete and not full of half designed extension points all over.
That's an excellent articulation of what I think as "invisible seams" when I write code: they're soft points of extensions that don't need a separate interface/function/class _yet_. Sometimes I just mark them for myself with an extra newline within a function.
I would say that's more false then true.
Why? Because the design you haven't coded is a fantasy design. I'll give you a counter-quite, and excuse the military context: "No plan survives contact with the enemy" (simplification of a longer quote by Helmuth von Moltke.)
I have yet to make any non-trivial design which does not require significant changes while it is being coded. Perhaps some design geniuses with much deeper insight can make this happen - but those are very few. Most people probably need several rounds of implementation and user interaction before reaching an acceptable design.
So those parts of your design which you haven't coded are likely partially irrelevant and un-implementable.
This is not to say that you should write huge amounts of code. But - try to avoid designing much beyond what you actually code.
I still find it funny that the place to optimize is generally for 'rip-out-and-replace', rather than 'extend' (caveat emport, not always the case, but seems to be a better design to optimize for replaceable than it is to optimize for abstract & extensible)
I would disagree that "generalized" equates to simple. Generalized means generic and usually abstract.
- https://en.wikipedia.org/wiki/Rule_of_three_(computer_progra...
- https://blog.codinghorror.com/rule-of-three/ "It is three times as difficult to build reusable components as single use components"
I think implicit in the point, most code does not go on to be used thousands of time (let alone dozens or even more than once). Even if some code is used more than once, making it the same and shared has significant costs as well.
Now we advise people to build the simplest and most obvious version for the problem you are looking at right now and if in the future you need it all over the place, replace it with a reusable one.
The exception seems to be React components, those generally seem to be very easy to identify as reusable UI and can be made generic from day one.
There's the problem.
Depending on the use case, this may not obviate the necessity of plain-text/wiki documentation; but I do note a tendency for many wikis, documentation web sites, etc, to be incomplete and/or woefully out of date. Half-assed docs can almost be worse than no docs; if it’s a priority, then it has to be folded into the entire SDLC, or have its own dedicated staff.
If you write clean code that is easy to groc and easy to replace, then its also easy to extend once you know where you want to extend to.
I don't think it's quite as widespread, I would posit that this has changed to: - (1) YAGNI, build the simplest solution you can for the problem at hand. That will make it as easy as possible to change when future requirements are presented. (2) Design your code to be replaced, not extended. Design your modules in a way that someone can rewrite one without having to rewrite the whole system.
Points (1) & (2) really contradicts the generalized solution approach. The generalized solution tends to be very abstract, hard to understand, and because there are layers - not very modular (which makes it hard to re-write)