Simplify Refactoring Monoliths to Microservices with AWS and vFunction

Refactoring Effort diagram with vFunction Modernization Hub
Amir Rapson April 20, 2022

The Challenge to Modernize Complex Legacy Applications

With estimates that 80% of the world’s business systems still not cloud ready, executives have begun to mandate initiatives to modernize their legacy applications for the cloud. These legacy applications are usually large monolithic systems with years or decades of accumulated technical debt, making them difficult to change, expensive and risky to scale, and weighing down an organization’s capability to innovate.

For simple use cases, some teams begin modernizing their legacy stack by re-hosting some applications on a cloud platform like AWS. Though rehosting an application on AWS can bring immediate cost reductions, customers still have to manage and maintain these applications, which are often composed of tightly-coupled services which are difficult to change and face risks of downstream effects.

For very complex and large legacy monoliths however, enterprises quickly run into a wall with re-hosting alone. Put simply, the more lines of code, classes, and interdependencies, the less value we’ll get from lifting and shifting. To gain agility, these applications must be modularized, and that means refactoring, rearchitecting, or even rewriting critical legacy applications to be cloud native. 

Solution Overview: Analyze, Select, and Decompose Services

AWS Migration Hub Refactor Spaces is a modernization platform for developers working with applications that are not cloud native, or that are in the midst of their journeys to be cloud-native.. 

AWS Refactor Spaces provides the base architecture for incremental application refactoring to microservices in AWS, reducing the undifferentiated heavy lifting of building and operating AWS infrastructure for incremental or iterative refactoring. You can use Refactor Spaces to help reduce risk when evolving applications into microservices or extending existing applications with new features written in microservices.

vFunction, an AWS Partner, provides an AI-driven platform for developers and architects that intelligently and automatically transforms complex monolithic Java applications into microservices, restoring engineering velocity and optimizing the benefits of the cloud. Designed to eliminate the time, risk, and cost constraints of manually modernizing business applications, vFunction delivers a scalable, repeatable factory model purpose-built for cloud native modernization.

Using vFunction Platform and AWS Refactor Spaces together can solve the dual challenges of decomposing monolithic apps into microservices and then iteratively and safely stage, migrate, and deploy those microservice applications onto AWS environments. This lets enterprises breathe new life into their legacy applications, and refactor old code for new cloud environments.

Legacy system architects and developers start off with vFunction, which analyzes the complexity of monolithic apps using automation, artificial intelligence (AI), and patented analysis methods, allowing architects to automate and accelerate the re-architecting and rewriting of their legacy Java applications into microservices.

The Base Report – Static Analysis to Calculate Technical Debt

The Base Report from vFunction Assessment Hub

Within minutes of installing vFunction, we see the vFunction Base Report (image above). Using static analysis data, vFunction uses machine learning algorithms to calculate technical debt and quantify it. vFunction then enables architects and developers to begin building a business case for modernization. The primary goal of the Base Report is to help stakeholders make an informed decision about which apps and services to prioritize for modernization.

In the vFunction Platform, technical debt is calculated by looking at the complexity, calculated based on the number of entangled interdependencies that reflect tight-coupling between business domains, and the risk, calculated by the length of class-dependency chains that increase the impact of downstream changes to any part of the system.

As a result, vFunction is able to determine the “Cost of Innovation”, which is a metric that reveals how much per $1.00 invested is needed simply to manage your system’s technical debt, rather than innovating and building new functionality. In this case, the company will have to spend $2.80 (x2.8) to achieve $1.00 towards innovation. The Post-Refactor metric shows that by tackling the top 10 High Debt Classes alone, this can be reduced to $2.20 (x2.2). 

The Refactoring Effort – Dynamic Analysis to Determine Priorities

The Refactoring Effort Radar in vFunction Modernization Hub

We can now look at Refactoring Effort analysis in the image above. Adding to the static analysis performed earlier, vFunction now performs patented dynamic analysis that leverages AI to build a representation of the effort it would take to refactor the application. 

These parameters are based on vFunction analysis utilizing clustering algorithms and graph theory to measure complexity scores based on: 

  • Class Exclusivity
  • Resource Exclusivity
  • Service Topology 
  • Infra Percentage
  • Extracted Percentage

Class Exclusivity 

Class Exclusivity refers to the percentage of classes exclusive to specific services. A high class exclusivity score means that most services contain whole domains, indicating more bounded contexts and fewer interdependencies.

Resource Exclusivity

Resource Exclusivity refers to the percentage of application resources–like Java beans, DB tables, sockets, and files–that are exclusive to the services. Similar to class exclusivity, a high resource exclusivity score hints that the domain is encapsulated within the service, and that there are limited constraints for extracting the service.

Service Topology

Service Topology refers to the complexity of service-to-service calls required for the application to run. In this case, we want a lower service topology score, which indicates less chatter and communication overhead between services. In some applications, it is required to add more complexity to the communication between services in order to increase class and resource exclusivity. This is a decision that architects will be required to make in many complex applications. 

Infra Percentage Score

Infra Percentage refers to the number of overall classes that vFunction recommends be put  in a common library. A high infra percentage score indicates a low amount of infra classes found in common libraries, which helps us avoid tight coupling between services and limits technical debt.  

Extracted Percentage

The Extracted Percentage refers to the percentage of classes that can be safely removed from the monolith based on the target refactoring plan. A high percentage here indicates that it will be possible to eliminate any remainder of the original monolithic application.

Using these scored metrics above, we can then enter the Analysis pane (aka vFunction Studio) of the vFunction Platform dashboard to view the exact services identified, with drill down capabilities to better review the analysis. 

The Analysis pane in vFunction Modernization Hub lets your merge, split, and analysis different services

In the image above, we are looking at a sample application called Order Management System (OMS). This image shows a visual representation of the services and classes in this application. The size of the circle is determined by the number of classes called in each service. Green circles represent services with high class exclusivity (over 67%), and blue circles represent services with lower class exclusivity (between 33%-67%). The higher the class exclusivity, the easier it will be to extract it into a microservice architecture–it is less tightly-coupled and the number of interdependencies is lower.

Further interaction with the platform reveals interdependencies between beans, synchronization objects, database tables, database transactions, and more. You can drill down into a specific service to see entry points and call trees, classes that were found by the dynamic analysis or by the static analysis, tracked resources, and dead code classes. The platform allows you to refine the boundaries of the services and determine the architecture, while automatically recalculating the metrics of the designed architecture. Next, you can iteratively extract any service.

Create and extract a newly configured service in JSON with vFunction Modernization Hub

The image above shows vFunction extraction configuration of your updated single microservice to a target platform and source repository. The platform then generates human readable JSON files that includes all the information to create the service with the extracted code from the original monolith using vFunction’s Code-Copy utility, which we can then run in our terminal or IDE.

In the next section we’ll look at how to take your extracted services and use AWS Refactor Spaces to set up and manage the infrastructure to test, stage, deploy the new version of your service.

Solution Overview: Deployment to AWS

Now that we’ve looked at the vFunction Platform experience, let’s look more at the sample application architecture after service extraction and the beginning of modernization. 

The OMS example referenced above is a legacy Spring Framework application running on Apache Tomcat 9 and deployed on an AWS EC2 instance. In the image below, we see a system architecture in which the original monolithic OMS application is running on Tomcat 9 (bottom right).

Using AWS Refactor Spaces, we employed the familiar Strangler Fig Pattern on the OMS application, decomposing it into microservices with vFunction and deployed to AWS (top right). From a previously monolithic architecture, we’ve split the OMS into multiple services deployed with Kubernetes on AWS Elastic Kubernetes Service (EKS) using NGINX for exposing the REST API. 

We created a proxy for the OMS app, services, and routes. In this case, there are two services: one for the original monolith, and the other representing the microservice extracted by vFunction and now running on EKS with NGINX Ingress. This produces default routes to the service that represents the monolith, along with the URI path that routes API calls to the other controller service.

In the end, we’ve produced an API gateway that routes the API calls to a network load balancer and transit gateway. Some traffic continues to go to the monolith running on EC2, where we have the product and inventory data. Other traffic goes through NGINX–with the same URL, but with a different route–to the other controller in EKS. 

Conclusion – Start Decomposing Your Monolith

To conclude, enterprises that have been challenged by having to modernize highly complex legacy applications within their business landscape can now jump-start their journey to cloud native architecture, in a de-risked, methodical, and iterative way. 

With the vFunction Platform to assess, analyze and extract services from the monolith, and with AWS Refactor Spaces to route and manage traffic, architects and developers are now enabled to employ the Strangler Fig pattern to decompose a traditional application into services, and route requests to two different destinations: the original monolith, and the newly decomposed microservices.

Does this seem like a good fit for your modernization initiative? Contact vFunction to learn more about our products in a personal demo session with one of our engineers.