Code reusability vs. programming principles
Building an application with the use of object-oriented programming languages is a process during which you should remember a number of rules and principles. They are often collectively referred to as good practices, and their goal is to guide us towards writing code that is generally easy to maintain and extend. Sometimes, failure to follow some rules comes not from the lack of knowledge about their existence, but from our different approach to their application.
I think the best example of such a rule is the one that tells us to write reusable code. The rule appears to be clearly defined, however, it may be viewed as a requirement to write code that could be easily used anywhere in the application you are currently working on or other applications in the future. This often leads to a situation where code is much more complicated and poorly readable.
While writing this article, I analyzed some opinions found on the internet. There are provocative headlines stating that the reusability of code is overrated. You can read about the examples of creating complex code, whose number of abstraction levels is disproportionately large in comparison to the implemented functionality. This often leads to a situation where the time spent on preparing the functionality exceeds the original assumptions.
Even if you manage to get code that is highly reusable, it may turn out that the result is far from your intentions. Implementation of reusable code into another component or project causes many problems due to e.g. extensive parameterization. Additionally, the result is often the opposite to client’s expectations, as the extra time means higher costs of application development.
Basic programming principles
Making code reusable at all costs could run counter to other good practices, getting in the way of their implementation. Let’s have a look at some coding principles that might be affected by the misinterpretation of code reusability.
The KISS rule deserves our special attention here. It is an acronym derived from the English phrase “Keep It Simple, Stupid” that was formulated in the 1960s of the previous century and well known to American military engineers. The aim was to design airplanes in a way that enables even moderately skilled mechanics to do repair work in the field using simple tools. Over time, the rule has been transferred to other fields of science and engineering.
In terms of programming, the principle emphasizes the need for simplicity by avoiding unnecessary code complexity. Code should be as easy to read and understand as possible. It has been noted many times that a system is more stable if it is based on simplicity rather than excessive complexity. When you return to your code after a long break and it is difficult for you to work it out, it is a sign that you need to work harder on applying the KISS rule in practice.
A similar message is conveyed by the principle called “Code for the Maintainer”. According to that rule, you should write code for people who will be responsible for software maintenance afterwards. Modification of someone else’s code is often the most demanding and dominant part of a programmer’s job. We should not obstruct each other’s work. In sum, write code that you would like to receive yourself for modification from your colleague.
There is also a rule known as the “Boy scout rule”, according to which the scout should leave the camp cleaner than he found it. How does this relate to programming? Creating some additional code should not obfuscate the existing code. Additionally, if it is possible, the introduced changes should positively affect the readability of the code that you are modifying.
The question is how to follow the above-mentioned rules and write reusable code at the same time. Of course, I do not mean individual functions, but more extensive functionalities. It is often hard to say which piece of code will be reused as we don’t know the future. It happens at the design stage that we are not able to predict changes that may occur in the project. Therefore, the situation gets even more complicated.
In my opinion, it is extremely important to specify which part of the logic will probably be reused and skillfully separate the reusable logic from the accompanying code. What I mean is a fraction of code that helps to adjust the logic to the needs of the application you are currently working on. Let’s move to our use case below to focus on an example that inspired me to write this article.
Case study of code reusability
I worked on a project where the possibility to purchase and manage the subscription was one of the available functionalities. Since it is one of the most common types of application logic, there was an idea to create code that could be quickly adapted to other projects, assuming that their backend layer will be prepared in the same technology. The question was how to do it without affecting the estimate?
To achieve the goal, the logic responsible for the integration with the payment system at the design level was separated as a module. The code that was a bridge between the application and the module was located outside the module. However, all critical fractions of the logic always ended up inside the module. In this way the module code could be placed in a separate repository at a later stage.
We added a document fragment to the repository, facilitating integration with diagrams and description of key elements of the module. Moreover, we also added a script. When the script was invoked, the imported submodule was disconnected from the repository. This allowed us to make any code modifications without interfering with the repository. Additional support was provided with code comments and precise description of how to integrate the module with the application we are going to work on.
As already mentioned, I agree with the opinion that it is often not obvious at the design stage which part of the application logic should become reusable. However, it is always worth considering as it may be very time-consuming to extract code at a later stage of work on the application. One should remember about a common sense approach. When preparing reusable logic, you must not forget that code should be easy to extend and implement in another component.