Reusability
REUSABILITY
TTM | ROI | Sellability | Agility | Reputation |
Reusability (or reuse) is one of the most sought-after of engineering qualities. It's something that engineers aspire to achieve, yet it can be difficult to realise.
Reusability is a way to use the same software component(s) on different projects, products, or within different contexts. Rather than repeatedly rebuilding the same functionality for different solutions, it is expedient (and, in most cases, sensible), to reuse a set of software units.
QUALITIES & REUSE
There's a general premise in software engineering that the more a solution is used, the higher its quality is likely to be. By exposing a solution to a wider, more diverse group of consumers, we are more likely to flush out bugs (and other weaknesses), sooner, and thus get them resolved. It's the same principle used in NFL, or soccer games, by the officials. The more eyes, the more failings will be found and rectified.
Thus, the greater the number of integrations (and the earlier they are undertaken), the sooner we can gain confidence in a solution.
The key benefits of reuse are:
- Improved ROI. Enhances developer productivity as reinvention is unnecessary.
- Improved Maintainability. Specific functionality resides in a single location.
- Improved TTM. There is no implementation effort, only integration effort. The functionality already exists, creating efficiencies.
- A laser focus on the problem domain. We want our talent to work on business problems, not on unnecessary (solved) problems.
REAL-WORLD EXAMPLES
There are numerous examples of reuse in the software world - for instance, consider the Spring framework, Java Enterprise (JEE) platform, or Node's package management. Or more plainly, SAAS-based solutions.
The JEE platform encompasses a plethora of frameworks and APIs, enabling developers to reuse functionality already built (and tested) - such as transaction, security, and thread management.
These libraries are standardised, reusable, and are understood (and used) by many. This makes good sense because:
- They provide useful functionality.
- They deter the creation of proprietary implementations that may be less flexible, or of inferior quality (contain bugs) to the solution being mimicked.
- They are more likely to have been rigorously tested through a mixture of specialist knowledge (on the part of the implementer), breadth of time (in use), consumer diversity (many different types of consumers using the solution for different intents), and scale (hopefully used by a large number of diverse consumers).
However, building reusable software can also be challenging. The software must be specific enough to solve a particular problem (i.e. be useful), yet generic enough (and sufficiently decoupled) to be reused in different contexts, and (potentially) in ways not yet conceived. Building reusable software can also take longer, as careful consideration is needed to truly achieve generic use across other products or projects.
REUSE & RELIABILITY
I've already described how highly (re)used software is generally more reliable than software that sees very little reuse. By exposing a solution to a wider, more diverse group of consumers, we are more likely to flush out bugs (and other weaknesses), sooner.
However, reusing software isn't without risk. The discovery of a major bug or vulnerability in a reused unit - after it has been embedded within many other services or products - has the potential to inflict damage, both in terms of the impact on existing business activities (e.g. failures, security vulnerabilities), and on the necessary release activities as each project is rebuilt, regression tested (Regression Testing), and then re-released.
REUSE RISK
At the tail end of 2021, a vulnerability was discovered in (several versions of) a Java-based open-source logging library called Log4j, a dependency prevalent in many Java-based software solutions [1]. Under the right conditions, the vulnerability allows remote execution of potentially malicious code that may then be used to disclose sensitive information. Many businesses and organisations were forced to rush out remediation (during the Christmas holidays) to mitigate the risk.
Now, your first instinct - after such a major impact - might be to question the value of reuse. After all, you wouldn't face this attack vector had you built your own logging solution. This thinking though, is neither practical, nor entirely accurate. Were you to attempt to write your own (logging) libraries, not only would it require your engineers to become logging experts, but it would divert you from your real goal - building value for your customers. You'd be “rebuilding the wheel”, but that wheel would likely be a poorer imitation of what others can currently offer (you introduce your own weaknesses, but the safety net of sharing it with many others to identify weaknesses is gone).
My point then is that reuse is a critical aspect of building out good quality software, quickly, but you should also be aware of the (occasional) consequences of relying upon others to support your solution.
Consequently, only reliable software modules should be reused. Of course this is harder to achieve in practice - software dependencies also evolve, often more quickly than your own solution, and a dependency can rapidly transition from a reliable state (no known vulnerabilities [2]) to a vulnerable one.
REUSE & MAINTAINABILITY
When specific functionality only resides in a single location, developers need only change that one area. This promotes ROI and Agility - we can make a single change and then reuse it in many different places.
Software design patterns like the Facade demonstrate such benefits. We can wrap complexity that might otherwise reside in multiple consumers in a single place - allowing many consumers to reuse it, and creating consistency. And when a change is needed, we do it once, and only once.
PILLARS AFFECTED
TTM
What's the quickest way to deliver value to the market? Well, assuming that the integration effort is reasonable, then the quickest route is to deliver what you already have; i.e. to reuse.
Reusable software enables us to apply the same solution to a range of other problems. It creates a Known Quantity - a familiarity that builds confidence, enabling developers to focus their efforts in other areas, but also creating a more efficient delivery lifecycle.
ROI
Reuse is an obvious contender for the ROI crown. Reusing the same solution again and again in different contexts is cost-effective and can attract a significant financial return. However, please use caution - a poor fit may create more problems than it solves (The Sensible Reuse Principle).
REUSE SHOEHORNING
Some are tempted to shoehorn a new solution into an existing system, regardless of its compatibility or appropriateness, typically for ROI or TTM needs.
A common form of shoehorning is building a “system-of-systems” (Frankenstein's Monster Systems), by marrying up functionality from a range of different systems (never intended to collaborate with one another, often doing the same things, and built using vastly divergent technologies, principles, and practices), linking and aggregating them together, and then selling it as one. Whilst it seems like a sound business strategy, it's often technically flawed, promotes short-term return (rather than the long-term), and eventually leads to poor TTM, ROI, Agility, Reputation, and Sellability.
SELLABILITY
Reuse is closely linked to Productivity and Releasability (e.g. it's easier to release something you're already familiar with, or that's already released). The ability to reuse a solution in different contexts is also a good sales enabler, because:
- It suggests good TTM / turnaround time.
- The solution is already “proven” (i.e. Stakeholder Confidence), and therefore believable (creating trust).
- It enhances the sales team's confidence that the solution meets the customer's needs, and they can leverage this information to increase the likelihood of the sale.
It's easier to sell an existing solution (a Known Quantity), which does most of what you need it to do, than to suggest an alternative that is both unknown and untested in this context.
AGILITY
As mentioned, reuse enables us to use an existing solution in different contexts. It supports Agility by enabling us to successfully use (and sell) the same solution in different contexts. Yet it also allows us to upgrade and modernise software with a single code change (and some regression) - Don't Repeat Yourself (DRY). Finally, reusable components help us to quickly identify solutions, and thus respond quickly to customer needs.
However, there are downsides. For instance, an important quality of Microservices is their fierce independence - they have little reliance upon others. Yet, reusing components across microservices implies a loss of control (Control) - we tie all of our service's life cycles to a single change, and create potential Evolvability challenges.
REPUTATION
Reuse can also impact reputation, such as in our ability to support customer changes, or in the perceived reliability of our solutions.
We construct (and reuse) software from a range of different sources, both internal and external. In order to protect our reputation, we must control how (and when) we introduce these components, and ensure they're regularly verified.
WHO'S TO BLAME?
Most customers don't care where your software originates from, as long as it does what they need it to do, it's sufficiently usable, and it's safe for them to use. If you introduce a vulnerable component from outside of your organisation, do you think they'll care that it originated from an external source, or that you introduced it without undertaking sufficient due-diligence?
SUMMARY
Reuse is one of the best ways to achieve good TTM and ROI. A software component that is highly reusable may be used across many other projects, systems, and contexts, making it a valuable asset. We reuse to: (a) use existing functionality that we either can't build ourselves, we don't want to (it's not in our problem domain), or we don't need to (e.g. we've already built it), and (b) to introduce a level of quality into our systems that we can't easily replicate. Yet it is not without concerns.
Shoehorning new features that seemingly fit into an existing solution (but in reality don't) is both easy and tempting. It causes us to inject lots of unnecessary complexity into an area where it doesn't belong. The more functionality you add, the greater the number of assumptions (Assumptions) embedded within a component, and therefore the less likely it can be widely reused (paradoxical isn't it?).
Secondly, we must also be rigorous with our dependencies, ensuring the components we reuse are both capable (functionally and non-functionally) and devoid of (exploitable) weaknesses that could cause reputational damage.
FURTHER CONSIDERATIONS
- [1] - Log4J/Log4shell Vulnerability - https://www.ncsc.gov.uk/information/log4j-vulnerability-what-everyone-needs-to-know
https://www.ncsc.gov.uk/news/apache-log4j-vulnerability
https://nvd.nist.gov/vuln/detail/CVE-2021-44228 - [2] - No known vulnerabilities isn't the same as no vulnerabilities - it simply means we're unaware of the existence of any vulnerabilities at this stage.
- Assumptions
- Control
- Frankenstein's Monster Systems
- Known Quantity
- Microservices
- Regression Testing
- The Sensible Reuse Principle
- Stakeholder Confidence