Is it an Omelette?!
You can’t turn an omelette into spaghetti once it’s made. Most of the time, people expect to change a software behaviour or add new functionality. As a chef as long as you have not decided on the output you have lots of options in front of yourself to go with. But once you have chosen what to cook, based on the ingredients and what stage you’re in you might have a few options (though you should be a chef)!
A closer look
Software might look like cooking, but if we take a closer look it’s not. To make a certain dish we need certain ingredients with limited flexibility, so the decision is finalized once the food is selected. One of the main differences between cooking and software is the ability to reverse or modify decisions. Most of the time, we can alter the functionalities, or be asked to add more features. We always have some degree of flexibility based on the decision we have tried to defer which can help to keep the choices open to us. At the beginning of the project, we live in an ambiguous world with plenty of unanswered questions and unknowns, which will gradually be revealed. As we go forward, our knowledge will be increased and we can see the hidden aspects of what we are working on. It’s no surprise for experienced developers/architects that changes are inevitable, especially in the early stages of development.
Assumptions will kill us
This brings us to the challenges we face in system development. As a system developer working with operating systems and embedded systems, I’ve faced these issues firsthand. Each operating system has officially some certain Inter-Process communication being provided to the process running on it. So, that’s not difficult to consider all of them when you need one of them. On top of that, we might have some libraries/frameworks being implemented by utilizing the IPCs. I would say usually the option won’t go beyond 7-10!
Having said that, the IPC solutions don’t have the same footprint, way of working with or even the same constraints. It means moving from one to another will have enough complexity and pain. But the point is, we need to develop, we can’t stop for a long time to ensure that solution A fits fine. We have two options: take a chance by choosing a solution based on our assumptions, or defer the decision to a later time. Now the question is “How do we manage it“?!
Overcoming by abstraction …
The best idea in these cases is to implement an abstraction on top of them to enable proceeding with the development and not blocking it. Of course, implementing an abstraction will come with some drawbacks such as time to implement, losing performance, etc. However, the advantages weigh more. First of all, we will be able to continue in development. Next, at any time, we can change the lower layer without being worried about breaking other modules. Then we can use the abstraction to test the whole layers/modules above without involving the low-level implementation which usually is based on the operating system. Most of the time, the degree of flexibility that will be brought to the project is more than enough to ignore the drawbacks. (Especially with C/C++ code by utilizing Smart Pointers we can reduce the impact of the abstraction).
Just to give you an idea of how it might look, not as the final solution.
The analogy between cooking and software development is clear enough so I used it as an example. The next time you can consider deferring the decision by abstraction and not blocking the project.
Any idea how we can use abstraction in cooking?! 🙂