The real problem is that software is bunches of little idiot savants glued together. They do their known role well but ONLY their known role. They are not flexible and have no common sense to adapt to new situations. They have to have an exacting or pre-known environment.
When we try to make software more flexible, it becomes unpredictable, often backfiring. Often it's better to keep it narrow and crash rather than have it "guess" and do something wrong because you may end up with a million wrong results before you catch it.
I remember a story about military battle simulation software being built in the early days of OOP. An Australian company wanted a customized version for Australia, so they asked the vendor to add Kangaroos to the simulation.
Rather than code up a Kangaroo from scratch, which would take a while, the developers made the Kangaroo class inherit from the already built "Human" class. It all worked fine until a group of simulated Kangaroo's were spooked by explosions and whipped out weapons and started fighting back. The "Human" class was tuned for military simulations, not general animals because that wasn't the vendor's original goal.
The story may be an urban myth, but it illustrates some of the pitfalls of "reuse". Unless you have full knowledge of what you are reusing, you may end up reusing unexpected and inappropriate sub-features.
It's probably an undeniable rule of the universe that you have to balance predictability against flexibility. No free lunch, at least not until "true" AI comes along such that software won't make stupid guesses anymore; but then we'd all be obsolete.