This article examines the validity, challenges and finally the approaches towards reusability of your deliverables. It digs deeper than usual slogans such as DRY and invites the reader to look into the consequences of adopting reusability approach!
Reusability Definition Problem
I am sure that title of the article would have surprised many, this is not something you hear often. There are bazillions of articles on the benefits of reusability, however literally just a handful giving the opposite perspective. Let me start with a personal story which I think almost everyone can relate to.
Anecdotal example on why reusability is difficult to articulate in terms of instructions.
More than a decade (14 years ago to be precise) ago, one of my colleagues decided to make my code reusable. She found a few similar looking log statements and refactored those into a utility method (log) which takes the Logger object, logging level and the message as the argument and invokes the passed logger with the same message and the level. The utility class where this method was refactored was famously called LogUtils.
So from now onwards I was supposed to invoke LogUtils.log, which internally invokes the Logger object (passed as a argument), which internally invokes Log4j native methods. But why?
Even though we were both fairly new to the IT at that time, my colleague was fairly bought into DRY principle. However, something seemed off about this whole process which was difficult to pin-point and articulate. What could be wrong about DRY principle? After all, it is on the internet and lot of authors sing its praises at every given opportunity both online and offline as well, even in my own organization!
It took me a while to think independently from internet-slogan-driven thought processes and come to following conclusions
- There is no limit to the number of ways different code statements can look similar.
- Hence there is no limit to the number of ways a code can be refactored.
Usability vs Reusability
Is the Construct even Valid?
Let's put the concept of 'Software Reusability' through the process of construct validity. If you are setting reusability as a goal for a developer, how would you measure that goal was achieved or not? One should be able to define and understand 'reusability' before it can be measured. However, it can be seen that there is a significant overlap between the definition and understanding of usability and reusability in the context of those things which are not meant for single use.Example from daily life!
If I am able to wear a shirt more than once, it can be called a reusable shirt. If I am able to wear the same shirt in different places like Gym, Office, Restaurant, etc. can it still be called a reusable shirt? The answer is obviously - No. Things like shirts are not meant to be used only once. Since they are meant to be used multiple times, that itself becomes there actual use. Reusability construct for Software.
Single-use material things like napkins are meant to be disposed off after use. Reusability's principle purpose was meant to give an alternate approach to throwing such things away. But how do you articulate the purpose of reusability for things like software, binaries or source code, which are not meant for a single use? One can argue that reusability will come into picture for a shirt once it has been disposed off. However, this doesn't apply to software paradigm since software doesn't go through wear and tear. You can discontinue using a software and then either forget about it or resume operations when needed. Example from software!
Aren't all public methods reusable? Definition problem!
If the reusability goals aren't precise then it creates another problem. If code reusability is defined as 'to be able to reuse a method wherever applicable or possible', then by this definition all public methods are reusable. How would you articulate against it without defining upfront what those applicable scenarios are? In other words, all methods are written to meet given requirements. Even if you try to be specific about it by saying code reusability is defined as 'to be able to reuse a method in pre-defined scenarios', still all public methods satisfy this criteria. Not linked to scenario statistics!
This simply implies that you cannot measure code reusability in terms of number of scenarios it covers and number of ways a method can be invoked. Also, you cannot put a number to how many scenarios are not covered, since you cannot possibly know all possible scenarios well in advance before designing the method. You can't even know all scenarios after/during testing the method either, which means you can't reliably set a reusability score of a method.
But does it mean that all those well-meaning experienced experts, who are suggesting the young developers to make their code more and more reusable, are wrong? Let's see different possible meanings or context of reusability.
Possible meanings of reusability Using an Industry Standard term!
Let's face it - reusability is an accepted term in the IT industry. Not very well understood though, but accepted nonetheless! Also, engineering and engineering management can be hard enough when you need to deal with stakeholders with a varied set of backgrounds and experiences! We've all used some or the other catch-all term to get out of distracting and futile conversations. 'Industry standard', for commonly used things like Spring-boot, is one such term I have seen most people use to indicate - This is what IT the community usually uses and I am not willing to argue pros and cons of a technical package with someone who has very little background in the same. Reusability is another such 'industry standard' term.
If someone is encouraging you to expand the scope of your current requirement and handle more scenarios than the immediate ask, so that your code is more reusable, then they are looking for extensibility!
If someone wants you to write your function/class as a component so that it can be invoked from anywhere, they are looking for decoupling or segregation of different aspects of functionality!
If the instruction is to not to repeat code as much as possible, then you want to explore how your code can be refactored further.
However, extensibility, decoupling and refactoring are not without their own challenges.
Challenges in Reusability
Let's examine the challenges in setting the general direction as making our code more extensible, achieve decoupling amongst various aspects and refactoring.
Goal/Boundary problem Scope the artifact!
Suppose you are tasked to write a reusable method/class/package, how would you decide to draw a line on what that method/class/package should accomplish and what it shouldn't? In other words, you need to define the scope of a code artifact. Process the scope!
Can you define those principles which will govern this boundary decision? In other words, not only do you need to decide exactly how extensible it should be, but also decide on how to arrive at the same conclusion. In the absence of such pre-defined principles this decision becomes person dependent, which means it is hard for your organization to put a process around it.But who should scope?
This has a domino effect on the engineering management process. In the absence of a clearly defined scoping process, it doesn't help that communicating such decisions to any decent sized team (medium or large) becomes another pain. In other words, leadership of the team has to decide on such matters since you cannot leave it to the individual developers to decide the scope or the scope setting process.Example!
However, the boundary is not just to limit or delimit the scope, it is also between different aspects of the code. How many different aspects of code you want to decouple is limited to your imagination and comprehension. For example, a log configuration not only defines different logging concerns, their configs, their locations and their levels, but also the format in which logging is done. Decision of whether a single log configuration should handle all the concerns or multiple ones will depend on who is designing the logging framework as their is no single universal approach on what to segregate and what not to segregate.
Capturing assumptions in business-functions methods vs technical methods.
Do you know what you are assuming!
Setting goals is hard enough for a technical components, it is way harder for a business component. Simply because you may not know the assumptions you are making while designing a business component. Reason why you may be unaware of the assumptions that you are making could be due to your lack of domain knowledge as well.Example!
For example, if you have not seen multiple OMSs (order management systems) in the industry or if you are not intimately aware of the business process of a given organization, then how can you know whether the order management system that you are designing right now will work for a given organization or not. Assumption leads to limitations!
If you take a certain decision while designing a business app based on your domain expertise, regardless of whether your experience is big or small, may prevent you from taking a certain decision in the future. For example, you may unknowingly assume, looking at various online ordering systems, that only one discount-coupon can be applied on an order. You may not realize that you even made this assumption till you encounter a use-case which is contrary to this assumption.
Possible Reusability Models and their drawbacks
This final section examines possible ways to achieve the target of supposed reusability. Let's analyze if we can do this via documentation, communication and governance, or if we need to adopt an entirely different approach or different expectations.
Goal Setting, Documentation, Communication and Governance. Is it worth it? Leadership hands-off Reusability Process!
Suppose your team is told to start documenting not just reusable methods, but also candidate-scenarios where this reusable methods can be used. Scope of each method is defined in detail, not just for the current delivery but also in terms of its future roadmap. Your team members are told to get this document reviewed by senior technical management for any misses, duplication, roadmap verification, etc. For the sake of convenience, all developers must make changes in the same document or segregate these methods in multiple documents based on some aspect. Adding a new method to the document should require design, code and roadmap review by the technical management team. All team members must keep themselves up to date with changes in the document. Viability of the process!
Not only is this going to add to development cycle, but more importantly it increases the length of the document overtime. Even if you are a part of small-to-medium size team (lets say 5 developers), your team is likely to be maintaining a document with 100s of such reusable methods in just a few months of development effort. Over a period of time, reviewing this document is going to take a significant cognitive effort from your leadership. Not to mention the frustration that it would cause to your product management leadership, since any small change could lead to significant impact analysis on the reusability design and changes to the document as well. Learnings!
In short, this method is simply not going to work!! It is likely to get shelved after a few quarters. And if your leadership doesn't learn from this exercise and understand that reusability (with hands-off leadership approach) comes at a significantly higher cost, then most likely months/years down the line some new genius (lets say a lateral hire) may come up with a brilliant idea of code-reusability and you'll be going through a similar process again!! You can either learn by trying this out yourself or you can save everyone's time by simply thinking this through!!
More leadership hands-on approachLeadership hands-on approach!
According to me, there is only one way your deliverable can be expected to work across multiple scenarios. That is - when requirements you have received have already captured those scenarios in the first place. All required business scenarios, immediate or future, must be documented and given as an input for a component design and entity-relationship design. Functional and non-functional requirements must be consolidated into a technical requirement before sharing with a senior developer or a low-level technical lead.Component/Framework, not the Methods/APIs!
Focus less on individual method or API reusability, focus more on component/framework level reusability. Technical requirements should be traced to the business ones (functional/non-functional) while keeping all the internal stakeholders in the loop on what your deliverables are going to achieve now and what your deliverables can achieve in future. You obviously need to communicate more to everyone on the same page, but that is the whole point of getting into reusability-space in the first place!! You wanted to sell how reusable your deliverables are, now there is a framework for the same. Finally
This approach basically calls for more a hands-on leadership approach. The idea is to share the component/framework requirements, translated form business one, instead of the direct business requirements. In fact, immediate use case(s) becomes test case(s) for the reusable component or framework that you are going to put together. This also means any impact on the framework requires considerable brainstorming and analysis, but that is the price you must be willing to pay for so called reusability!!