How to Migrate a Java Monolith to Microservices

Microservices help us build, scale, and deploy software faster. Here's how to migrate your monolith, without losing your mind.

How to Migrate a Java Monolith to Microservices

Build fast or die.

That’s the rule in software. And when I worked as a consultant, I saw the struggle for speed first hand.

I worked with a global bank that was building a credit approval application. It was massive – a mix of tens of services to ensure you were worthy of their APR.

But one day, their lead developer pulled me to the side and said,

“I’m afraid to make changes to our app. Because I know that something will break”

If he’s afraid to make changes, how fast do you think they’ll go?

Why do we use microservices?

Monoliths are large applications that are deployed as a single unit. They aren’t all bad, but as applications grow, monoliths become a nightmare to change. Development slows.

That’s why we use microservices.

A comparison of monoliths and microservices

Microservices help us build software fast. They are small services that we can build, change and scale quickly. And to get this speed, we can break down our monolith into a set of microservices.

But there are challenges on this journey.

How do we migrate a monolith to a microservices?

The most important part of a migration is to remember the goal. The “why” will dictate how we go about our migration. For us, it’s the need for speed.

To break our monolith into microservices, we’ll need to answer three questions:

  1. Which applications should we migrate first?
  2. How do we migrate our applications to microservices?
  3. How will we build, run, and manage these new microservices?

Which applications should we migrate first?

Not everything needs to be a microservice. To choose a good candidate application to migrate, we’ll try to maximize benefit and minimize risk. Think ROI. Here are signs of a good candidate.

Sign #1: The application changes frequently

This helps us get the most value of moving to microservices (and reduces most slowdown). Every time we make a change service, we’ll reap the speed benefits of our migration.

Sign #2: The application requires a low LOE to migrate

This may seem contrary to the first sign. But, monolithic applications that use modern runtimes or have well-defined boundaries require less refactoring and can be great candidates.

Applications with well defined boundaries

Sign #3: The application has few other ones depending on it

Avoid migrating a core application first. You’ll already be figuring how to build, deploy, and orchestrate new services. You don’t want to do that while getting tangled in a web of dependencies.

Applications with the fewest apps depending on it

Pro Tip: Use Application Migration Toolkit

What if we could visualize your entire application inventory, run a code level analysis and assess the best candidates for migration? That’s what Migration Toolkit does. If you only do one thing, run this.

Application Migration Toolkit

How do we migrate our application to microservices?

Note: I talk a lot about containers in the next sections. Microservices aren’t containers, but they’re a great way to deploy them.

Migrations are best done in stages. When teams try it in one go, it usually ends in frustration and scrapping the whole effort. For Java applications, we recommend three steps.

Step 1: Migrate to a modern application server

To make your migration efforts easier, move to an application server that is:

  1. Supported. Because, production.
  2. Conforms to open standards. Being locked in slows your ability to move fast. I’m looking at you, WebLogic and WebSphere.
  3. Can easily run on a container platform. This will help with future modernization efforts.

Full disclaimer: I work for Red Hat. But I’ll offer a shameless plug to JBoss EAP. It’s a lightweight, open source app server that meets all of the above criteria.

Pro Tip: The Migration Toolkit can give you a source level analysis of what needs to change if you’ve moving.

Step 2: Run your monolith on a container platform

If you did step one, you’ll be able to easily deploy your JBoss EAP application to a container platform. This isn’t our final destination, but running a monolith on a container platform has some speed benefits like:

  • Automatic Scaling,
  • Failover  
  • Zero Downtime Deployments

Pro Tip: For now, leave your existing database intact and connected to the monolith

Step 3: Break apart your monolith

This could be an article all on its own. Now that our app is on a container platform, we’ll start to break apart our monolith. Here are a few tips when creating microservices.

Start at the edge first. Similar to sign #3, start with services that don’t have a ton of dependencies.

An illustration of an edge service

Think capability, not code. Break things out in terms of business function. This helps us deploy independently, move fast, and it’s key to arranging teams that can manage end-to-end delivery.

Examples of well-defined microservices

Don't forget the data. To get full benefits of speed, each service should have it’s own datastore. You can expose the data for other services through an API or replicate it in the microservice's database.

Each service has it's own database

Pro Tip: Use messaging queue like AMQ to communicate with older apps without having to make drastic changes.

How will we build, run and manage our microservices?

To effectively build and run our new microservices, we’ll need a new runtime and a platform.

Container Native Java

You’ve probably realized that Java EE wasn’t built with microservices in mind. Loading a fat JVM is the opposite of “micro”. So we’ll need a runtime that can run well in a container. Enter Quarkus.

(Disclaimer: Quarkus is a RedHat brainchild)

Comparison of Java and Quarkus

It’s a container native java stack that helps developers go freaky fast. It’s the best part of Java, optimized for speed. You also may use other runtimes for different services:

  • NodeJS / Angular - for web application frontend
  • Vertx - building reactive microservices & real-time apps

Running Microservices

Microservices help us go fast. But we have some new problems like:

  • Deployment - How do we build & deploy five services instead of one?
  • Orchestration - How do we manage hundreds of tiny microservices running?
  • Communication - How will our services discover each other and communicate?

It's a waste of time to build this ourselves. Our best bet is to use a container platform to do all this for us. Like…OpenShift

An overview of OpenShift Container Platform

OpenShift automates deployment, orchestration, and service discovery for microservices. And it runs anywhere. So when your CTO mandates that you’re going to Azure, you don’t have to change how you work.

Best Practices

Migrations can be a lot of work, but you can make your life easier.

  1. Do your migration in stages. Use the Migration Toolkit to assess your portfolio and see where to start.
  2. Build Good Microservices. Start at the edge, focus on business function, and don’t forget the data.
  3. Use container runtimes and platforms

Recap

Monoliths slow development, but microservices help us build software fast. They are small services that we can build, scale, and deploy quickly.

To break down your monolith, look for signs of candidates, migrate in stages, and choose a good runtime and platform for your services.

Project Code & Links

Happy Coding,

-T.O