While reviewing some code today, a principle of software design somehow distilled itself to clarity in my head.
When designing your system, think of every major system1 upon which your own system directly depends2 as a bug.
By “think of it as a bug,” I mean that sooner or later, you are going to come to truly hate this dependency. It won’t do what you want, or it will turn old and crufty, or it will get outdated, or your system will outgrow it. Perhaps it already stinks. And therefore, think about what you are going to have to do to take it out and replace it with something better, and possibly not even having similar API’s.
Yes, you should have your code sufficiently factored and modular that such a replacement will be minimally invasive. But more importantly: if that replacement requires any change in the API’s3 by which the outside world is using your system, then there is something wrong with your design. Stop and fix that immediately.
1Both external dependencies and major subsystems of your own code. Both will suck in time, I promise you.
2If the systems upon which you directly depend have done this properly, you don’t need to worry about your indirect dependencies. If they haven’t, then you should consider replacing them now, because you are obviously dealing with the work of madmen.
3Or UI’s, if your software is at the top of its software stack. UI’s are just API’s for communicating efficiently with humans. (Or perhaps API’s are just UI’s for communicating with computers?)