Cloud-native computing rolls up domain-driven design, GitOps, and other modern software best practices. When implemented properly, these practices can reduce technical debt. The devil, however, is in the details.
Cloud-native computing is a new paradigm for enterprise IT that touches all aspects of modern technology, from application development to software architecture to the underlying infrastructure that keeps everything moving.
Cloud-native has thus given us an opportunity to clean house. We can take our newfangled, Kubernetes-empowered broom and sweep out all the dusty corners of our existing tech.
It would only be logical, therefore, to presume that cloud-native will finally put an end to all that technical debt that has been accruing lo these many years.
Logical, perhaps, but not realistic. Technical debt is notoriously persistent. Furthermore, given a dollar to spend, any CIO would rather spend it on something new rather than fritter it away on cleaning up some predecessor’s messes.
There are reasons to have hope, however. Cloud-native is certainly no magical broom, but its core practices can indeed help you reduce your technical debt, and deliver new software capabilities without accruing more – or at least, not as much debt as you would have otherwise.
Chipping Away at Legacy Technical Debt
Putting your organization through technical debt rehab so that you never accrue new debt is certainly part of the puzzle, but the more immediate concern is paying down existing, legacy technical debt.
Over the years, expedient shortcuts, ham-handed coding, and all manner of chewing gum and baling wire in the infrastructure has built up an impressive Gordian knot of complexity. As with the knot of legend, we may need the swing of a sword to untie it.
Cloud-native computing gives us a glimpse at such a sword: architectural refactoring based on domain-driven design.
Domain-driven design calls for breaking up complex enterprise software challenges (our Gordian knot) into separate business domains, each with a bounded context.
Such bounded contexts resolve business concepts like ‘customer’ or ‘invoice’ by restricting their context as per the needs of the business. For example, different divisions of a large enterprise may have different (perhaps overlapping) notions of a customer. Each one would represent a separate bounded context.
Early forays into microservice architectures led to a proliferation of interconnected microservices whose complexity limited their scalability. It soon became clear that organizing them by bounded context was the key to managing this complexity as well as delivering microservices-based solutions at scale.
Domain-driven design, therefore, has become a part of cloud-native computing – and furthermore, informs how we must approach the modernization of legacy assets following this new paradigm.
Once more, the Gordian knot metaphor applies. The first step in dealing with a legacy software challenge that exhibits high technical debt is to apply architectural refactoring, thus transitioning legacy (typically monolithic) architectures to modular elements with bounded context.
In other words, you must introduce modularization following business-driven bounded contexts in order to steer a path that reduces technical debt.
The devil, as per usual, is in the details. Based upon the business needs and the legacy challenges you face, you might leverage this architectural refactoring in any of several ways:
- You might find that the existing code within a bounded context doesn’t meet today’s requirements at all. In such instances, you might rewrite that code as microservices.
- There may still be value in the legacy business logic, which you then migrate to microservices (see my recent SiliconANGLE article on legacy code migration).
- You may expose legacy modules as APIs, either because they already have useful APIs, or because you have updated the legacy code to expose it via APIs.
- You may script the interactions with legacy modules using robotic process automation (RPA) bots.
Note that since you have previously reorganized and modularized the legacy software into bounded contexts, each of the four approaches above is now more straightforward than it would have been otherwise.
Furthermore, future refactoring, if necessary, is also more straightforward, since you have taken a ‘divide and conquer’ approach that compartmentalizes your technical debt. It’s more practical to pay off, say, four smaller debts over time than one large one.
This approach is also one of the best ways to reduce the brittleness of RPA bots. Without bounded context-driven architectural refactoring, such bots can break if anything changes anywhere in the application landscape. With the appropriate compartmentalization, such failures will be more manageable and easier to fix.
Preventing New Technical Debt
Preventing new technical debt is like asking your teenager to keep their room clean. Perhaps they will for a while, but then one thing leads to another, and it’s a mess once again.
What they need is more structure, am I right? At least in the cloud-native case, structure does help.
Cloud-native computing brings a broad set of best practices to the table, delineating how best to architect your software, configure your infrastructure, create and deploy your applications, and manage everything in production.
Certainly, if you follow all these suggestions, you’re less likely to layer on new technical debt – or at least, not as fast as dirty socks pile up in your teen’s bedroom.
One linchpin example: the ‘infrastructure as code’ (IaC) principle, and its ‘cattle, not pets’ mantra. Thou shalt not mess with servers in production, the IaC principle states. Instead, rework the software-based representation of the infrastructure as necessary and redeploy.
The IaC principle can certainly limit additional technical debt in production, as it provides a proactive approach for fixing production issues. Just one problem: IaC doesn’t go far enough.
The problem with IaC is that you have to write various programs (or scripts, or recipes, or whatever the term du jour is). You must then test, manage, and version those programs just like any other program – which means that technical debt can creep in just as it can with any other software.
Fortunately, cloud-native computing has moved several steps beyond IaC, where each step improves on the one before.
The first step: representing infrastructure via declarative configurations, which specify how the infrastructure should be configured without specifying how to achieve such configurations.
Declarative approaches reduce technical debt as compared to IaC because there is less room for shortcuts or sloppiness, but those representations – which typically appear in YAML files or other JSON-based formats – are still quite codelike, especially for complex, dynamic infrastructure configurations.
The second step: GitOps. GitOps brings Git-centric practices and processes to software release and management.
GitOps in many ways complements declarative approaches to infrastructure configuration, as it takes a declarative approach to software deployment. However, GitOps goes further by providing more structure to its processes – and the more structure, the fewer opportunities for technical debt to creep in.
The third step, however, is the current state of the art: intent-based computing.
Intent-based computing has three parts:
- A declarative representation of the software in question (either infrastructure, application code, or something else) in the form of technical policies.
- An abstraction of such technical policies as business policies that represent the business intent of the underlying configurations.
- A mechanism for ensuring the underlying software conforms to this business intent, not only at policy application, but on an ongoing basis – thus eliminating policy drift.
In other words, intent-based computing takes the declarative configuration approach and GitOps and adds additional structure, essentially ensuring that the entire cloud-native environment complies with the business intent over time.
Such compliance is the best sword we have for cutting through the Gordian knot of technical debt.
The Intellyx Take
Cloud-native computing lays out better practices and processes for handling software-based change than we’ve ever had before, and thus represents our best shot at reducing existing technical debt and preventing new debt from recurring.
However, people must still follow such practices and processes – and just like with your teenager, there’s no guarantee that they will.
At the heart of cloud-native computing is the goal of dealing with ongoing, rapid change at scale – and anytime there is change, people must be involved. And with people comes human error, the desire for shortcuts, and never-ending opportunities for sloppiness.
Rest assured, therefore, that technical debt is here to stay. The best we can do is cut pieces off the Gordian knot, and help our teenagers eventually become adults who never, ever, leave their dirty socks on the floor.
© Intellyx LLC. Intellyx publishes the Intellyx Cloud-Native Computing Poster and advises business leaders and technology vendors on their digital transformation strategies. Intellyx retains editorial control over the content of this document. Image credit: Intellyx.