Over-engineering is a bet on a future you can't see
The simplest thing that works looks junior, so smart engineers skip it. Why over-engineering bets on a future you can't see, and simple stays cheap to change.

Every over-engineered system I have seen was built by someone smart. That is the part that took me years to understand. Over-engineering is not a junior mistake. Juniors write code that is too simple and breaks. It is the capable engineers, the ones who can hold a whole system in their head, who reach for the framework, the abstraction layer, the configurable everything, and quietly build a cathedral to serve a shed.
Why smart engineers over-engineer
We tell ourselves a story about why. We are being forward-thinking. We are building for scale, for the requirements that are surely coming, for the flexibility future-us will thank us for. It sounds like foresight. Mostly it is something less flattering: complexity is more interesting than simplicity, and it looks more like expertise. The simplest thing that could possibly work looks junior on the page, so the people most able to build something clever are the least willing to build something plain.
Complexity is a bet on a specific future
Here is the reframe that changed how I build. Every abstraction you add today is a prediction. The plugin system predicts you will need plugins. The generic interface predicts a second implementation. The config knob predicts someone will want it turned. You are not writing flexible code, you are placing a bet on one particular version of the future, and paying for it now, in the currency of every change you make from here on.
And the house edge is brutal, because most predictions are wrong. The second implementation never arrives. The plugin nobody builds. The scale that was surely coming plateaus at a tenth of the design target. Now you maintain the machinery for a future that did not happen, and worse, the real future, the one you could not see, shows up and does not fit the shape you guessed. The wrong abstraction is more expensive than no abstraction, because you have to unwind it before you can move.
Why the simplest thing wins
The simplest thing that could possibly work has one property that beats all of that: it stays cheap to change. It makes no bet. When the real requirement arrives, and it always arrives in a shape you did not predict, simple code bends to meet it because there is less of it holding an opinion. You did not prepay for flexibility you never used, so you still have the budget to build the flexibility you actually need, now that you can finally see it.
This is not an argument for dumb code or ignoring the future. It is an argument for humility about forecasting. You cannot see the future clearly enough to build for it, so buy the option that costs least to change once the future tells you what it actually wanted. That option is almost always the simple one. It is why dugalaxy fills an empty database with deterministic templates and nothing more, and the restraint is the feature, not a limitation we have not gotten around to fixing.
Do the simplest thing. Then let reality, not your imagination, tell you what to complicate.
Complexity is a bet on a future you cannot see. Simplicity is the option that stays cheap when you are wrong.