It's amazing how many otherwise brilliant people dive headlong into project without considering these basic principals or even intentionally brush them aside.
I believe Saying simple > complex doesn’t actually mean anything because it’s effectively impossible to pin down definitions. They are totally in the eye of the beholder. Solutions that are simple in one axis almost always trade of complexity in other axes.
That's why I prefer the form "Do the simplest thing that could possibly work."
There's always going to be a minimum level of complexity. Sometimes that minimal level calls for throwing a PHP script up on some shared hosting provider somewhere. Sometimes that minimal level calls for an Enterprise-level design with ten layers of abstraction because you need to be able to individually unit test every aspect.
Being aware of where and when to introduce complexity is half the battle.
As a good illustration, consider FEniCS[1], where you can write a few lines of Python code which looks almost exactly like the math you're trying to solve, and have it compute the answer. Very simple!
Except to make that work there's a lot of infrastructure, including runtime-generated-and-compiled C++ code that gets dynamically loaded by said Python code to perform the actual calculations. Quite complex!
The true skill comes in finding the right balance between simplicity and complexity for a given situation.
In the case of FEniCS, the complexity is worth it because it allows the system to be used by less skilled programmers (who might know more about the math and physics), and the complexity handled by experienced programmers.
For our codebase we've got junior programmers who might need to read and understand my code if I'm on vacation and shit hits the fan, so I err on the side of making it easy to read and reason about. Which might not be the "simplest" for some measures of simplicity (like fewer lines of code).
I’d argue that FEniCs was a prime example of this in some ways, at least earlier in it’s history.
I started using it in about 2014. It was not exactly what I would call a simple project. It used to be an ordeal to build, could only easily be used via Docker, ported to Python 3 a long long time after most of it’s dependencies did, had an unstable C++ API that changes were not documented for but nonetheless you were required to use if you wanted for reasonable performance for some calculations, etc. The national supercomputing centre in my country managed to only get one version to build because it was so poorly specified at the time and basically only supported Ubuntu!
FEniCsX is considerably better usability wise, but that’s the result of hard lessons learnt.
People need to stop throwing around 'Premature optimization is the root of all evil'. Simple > Complex <--- Look at that. It's optimization! Complex != optimized
It need to be thrown around more. I cannot count on one hand the designs I came across that were needlessly complicated that rather than solving a pain point became a problem in themselves.
"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%."
And here's the deal, with more years in this industry, I've always found that the optimal performance almost always comes from a simple architecture.
And that performance optimization done prematurely often achieve complete opposite result. Meanwhile performance optimization done at necessity rarely have the same problem.
Simple > Complex.
It's amazing how many otherwise brilliant people dive headlong into project without considering these basic principals or even intentionally brush them aside.