Software designers have always strived to design the perfect software. From the designing perspective, when all the possible inputs and outputs are well defined and speculated, this goal is not all that hard to achieve.
However, any software would never be perfect as long as it interacts with the real world. Any good design is subject to change as soon as the implementation cycle begins.
Furthermore, almost all companies (excluding a few of the startups) have some imperfect, legacy code. It is next to impossible to come up with a perfect design when all these are taken into the picture. Ironically, this very aspect that we live in a real imperfect seems to be a big surprise for many fellow developers. We often hear developers argue how to change existing systems while developing new systems to make the old systems function better. But given the expenses associated with software development, the proposal of changing the existing infrastructure almost could never pass your managers eyes.
Taken all the unknowns into the equation, an alternative is to treat the old systems like black boxes. We only assume, given the input to the original system, what is coming out of it, ignoring its particular implementations. This approach can dramatically reduce development time and create a new system no less robust then the original ones. It also can help concentrating development resources on the new project, and in some future time, the old system can be revisited and modified given that all the pre-determined boundaries are preserved. So, how do we achieve this? Here are some principal I use as guidelines when designing a new system that interacts with many existing ones (I call it the blackbox approach):
- Defining boundaries : When developing a new software system that interacts with the existing systems, the first thing to do is to define the boundaries. By defining the boundaries, it is far easier to develop the new portion of the system using the defined boundaries as a known portion (either input or output) to the new system.
- Encapsulate unknowns : It is always a reality that many aspects of the existing system (or new system to be designed) are unknown or only partially known to you at the design time. Encapsulating the unknowns is probably the most important aspect in development an enterprise solution. And this goes hand in hand with the next item that I will touch upon later (Loose coupling). For the many unknowns given to you at design time, the best you can do is to encapsulate them in a thin layer that interfaces your core design. This layer has to be thin enough that any future changes to it would be easy. The encapsulation has to be strong enough so that changes to this layer would not require much logical redesign of the layers that lie below it. As an example of a bad design, imagine that you speculate in your design that you need a field called customer invoice number in the database, you wrap it in a dataset (not strongly typed) and pass it all the way down to your core logic. If at a later time that you decide this field is not needed any more, you would have to comb through all your code to find out where this is used. Since the dataset you are using is not strongly typed, it means that compilation of the code would not give you confidence as to whether the conversion has been performed successfully. In this scenario, you would have to rely on some sort of code coverage mechanism to figure out whether all the references to the old code have been changed. This is always a great challenge in the real world.
- Loose coupling : Last but not least, loose coupling with the existing systems is almost always a good idea to put in your design whenever is possible. With loose coupling, the contract between your new system and all the existing systems are easier to maintain and thus the problems are more isolated and easier to track. The assumption throughout this article is that you wanted to model your existing systems and new systems like black boxes and only worry about the interfaces they exposed to the outside. The only drawback is that a loosely coupled system is less efficient in general. An XML based interface (or other methods for loose coupling) requires more processing and has almost no guarantee of timely execution. Sometimes this approach might not be possible given the business requirements. But developers should always strive to separate the system they are developing from the systems they depend on but have no control over to minimize later headaches.