I just wanted to write a short note about Anders Hejlsberg:
“When you take something incredibly complex and try to wrap it in something simpler, you often just shroud the complexity. You don’t actually design a truly simple system.”
This is a profound and insightful observation.
It is often true of system coders that we like to say that we “hide” or “wrap” the complexity of a system, so that it can be used by the application coders to make products.
What Anders says is that such an approach can often lead to a system that overall has more complexity than otherwise. I don’t think he means that systems shouldn’t be complex, or that our APIs should be unsophisticated.
I think he means that as you go down a level of abstraction, the lower levels should be logically and practically simpler than the level above.
Actually acheiving this in real-world systems is, I think, the mark of a truly talented system programmer. I know I often fail at this, and my most recent efforts, while providing a “simple” top-level API, are far more complex underneath than perhaps they ought to be, or could be.
When I start a new system, I often start with the unit-tests. The idea is that once the tests pass, the system is a success. However, we can’t really write tests for all usages, so complexity creeps in as we make systems that attempt to deal with all possible future use-cases.
The result after a few iterations and mid-flow design changes is more complexity than there has to be. I pride myself on observing this “creeping complexity”, and also take pride in my willingness to do a deep, tedious and difficult cross-concern refactor in order to reduce it. But I think sometimes I don’t go far enough. I think I often make simplex systems.
Sometimes, it is only when a system is complete, and passes all tests, and works in the applciation space well enough, that you can see a better system underneath. A system that is simpler as you go down, rather than more complex as you go down. A system that better matches the application space.
However, it is at precisely that same time that you have the least amount of mental energy to do anything about it. The system works; the tests pass, and people are using it to make things. Why rock the boat?
Perhaps it is this indifference that is “the wall” for system coders. Overall, it’s a marathon, and you have to push through that last barrier, and be willing and able to do that last cross-cutting refactor that breaks everything for days or even weeks on end.
Only then can one reduce the complexity, remove the simplexity, and create a truly simple and useful system.