Automating the Strangler Pattern with Microlithic Development
Introduction
In today’s tech landscape, developer agility and service scalability are paramount. As companies scale and adapt, one of the biggest questions they face is: “How do we convert a monolith to microservices?” The answer isn’t straightforward, as each approach has its benefits and limitations. This is compounded by the fact that it isn’t simple to make those large refactoring changes and revert in the middle of the effort — you can’t know if transitioning architectures will be good for you until you try it out. This is the idea behind the strangler pattern.
However, a new paradigm — microlithic development — aims to bridge the gap, enabling companies to transition smoothly while automating much of the heavy lifting. In this post, we’ll explore how the microlith addresses issues in traditional software architectures and how it powers a seamless journey from monolith to microservices while allowing you to test the split each step of the way, allowing you to revert and change where the split happens anytime.
What are Microservices?
Microservices architecture divides a larger application into small, modular services that operate independently. Each “microservice” can be developed, deployed, and scaled separately based on usage, allowing for higher agility and adaptability. Imagine a vast e-commerce platform; instead of one gigantic application, you have independent services — like user accounts, product catalogs, and payment processing — working together seamlessly.
This approach enables rapid development, easier updates, lower chance of downtime impacting all users, and, crucially, tailored scaling of services. But this flexibility comes at a cost, especially for organizations with legacy codebases or for those trying to scale quickly.
What are the Issues with Monoliths at Scale?
A monolithic architecture is a single, unified codebase where all application components are tightly coupled. For many organizations, monoliths were the default choice — reliable and straightforward. But as a company scales, so does the monolith, and maintaining it becomes increasingly complex.
Some common issues include:
- Limited Flexibility — Changes in one part of the system can impact others, making it hard to innovate or adapt to new needs.
- Deployment Challenges — Even minor updates require redeploying the entire application, slowing down the release cycle.
- Scalability Issues — Monoliths can’t scale individual components independently, leading to inefficient use of resources and potential performance bottlenecks.
Despite these challenges, monoliths aren’t without their strengths: they’re simpler to manage, understand, and secure. This is a large part of the recent internet hate of microservices, but the rigidity at scale is hard to ignore. Not to mention a quote from a recent conversation I had with the technical founder of a Techstars F24 startup:
Once you take a monolith to production, all your dependencies and language versions will likely be frozen in time.
Regardless of the technical approach taken, there will be large trade-offs. Let’s look at an approach that captures the best of both worlds.
Enter the Microlith: A Bridge Between Monoliths and Microservices
A microlith takes a hybrid approach, allowing companies to selectively refactor and modularize parts of a monolith into smaller, manageable services at deploy time. This enables developers to continue to move fast by writing in their existing monolith while gaining the scalability of microservices at runtime. Think of it as a scalable “strangler pattern” that doesn’t require abandoning the original architecture. We call this strangler-on-the-fly approach “code-splitting”.
With a microlith, you retain the simplicity and reliability of a monolith, while gaining the flexibility and scalability of microservices — without the all-or-nothing investment of a full microservices transformation.
How Microliths Solve the Shortcomings of Both Approaches
Microliths create a middle ground. Here’s how they address the limitations of both monolithic and microservices architectures:
- Selective Isolation — Instead of dividing everything into separate services, the microlith allows companies to isolate only high-impact parts of the codebase through annotations in the code, like frequently updated or resource-intensive components.
- Easier Deployment — With microlithic development, you can update individual services without disrupting the rest of the application, enabling faster deployment cycles.
- Scalability Where Needed — With a microlith, only critical components need to scale, preserving resources and optimizing performance. Other components or even individual endpoints can scale to zero.
- Reduced Overhead — Unlike full microservices, which require complex service orchestration, microliths keep much of the code together, minimizing the operational burden.
- Improved Robustness — When a bug slips into production in a monolithic endpoint it runs the risk of taking the entire service down for everyone. In Microlithic development, only the deployed microservice or endpoint will go down.
- Per-endpoint Scaling — Deploying your services as a swarm of individual endpoints has never been possible before from a purely organizational perspective. How would developers maintain these individual codebases? How would they handle keeping them DRY and not copying functionality across repos? By splitting the code at deploy time this all becomes possible.
In essence, a microlith offers the best of both worlds, providing a modular approach that’s tailored to each company’s unique needs.
How Do Microliths Work?
Microliths work through simple tooling that perform analysis on the codebase and take the following actions:
- Trace the code and build an Annotated Execution Tree (AET) that represents the code as it exists in the codebase.
- Based on the annotations the user has added, the tree can be split into microservices or even one endpoint services.
- The algorithm then shakes the resulting code to remove “dead” execution branches.
- Finally, the tree is resolved back to a codebase that has been simplified “in-place”, without editing the code of your monolith.
This approach has many benefits, but the largest is allowing for refactoring on the fly without worrying about black-box approaches like AI refactoring tools. If your code works now, it will continue to work after the build.
The Benefits of Microliths for Legacy Codebases
For companies with legacy codebases, a microlith can make the transition from monolith to microservices far less daunting. Rather than rearchitecting everything, legacy applications can remain largely intact while selectively integrating new services.
This gradual migration is beneficial because it enables:
- Incremental Modernization — Developers can slowly refactor parts of the legacy codebase, leaving the rest of the application stable and operational.
- Less Risk, More Reward — Instead of an all-in migration, a microlith reduces the risk of technical debt and instability in production by allowing for different splits to be tested out in the lower environments without too much developer effort.
- Seamless Scaling — As you gradually migrate services, scaling is painless — essential parts of the system can be expanded without impacting the rest.
How NanoAPI Enables Microliths with Seamless Tooling
To realize the potential of microlithic development, companies need robust tools. NanoAPI simplifies the path to microliths by automating the code refactoring needed to break down and isolate legacy components without losing monolithic stability. With NanoAPI, developers can:
- Easily isolate and refactor components within a monolithic application into microliths with automated refactoring tools and a no-code style UI overview of the APIs.
- Visible and accessible tooling ensures that the system and its effects can be studied before running it on your monolith.
- Gain deeper understanding of what your code is doing today without worrying about out of date documentation or OpenAPI files.
If you’re intrigued by the microlithic approach and how NanoAPI powers it, star us on Github ⭐️ to join the community and help us make refactoring legacy codebases easier, faster, and more reliable.
Conclusion
Transitioning from monoliths to microservices is one of the most challenging projects for growing tech companies. The microlith offers a practical middle ground that combines the benefits of both architectures, making the journey less disruptive. Microlithic development becomes an accessible and powerful solution, allowing developers to scale without sacrificing stability.
While microlithic development is still young, the input and experience of the community can help to make this a viable approach to solve many of the pain points of bad tradeoffs made in the past.