Refactoring to microservices, Part 3: Roadmap to microservices adoption
Step by step, move your applications from a monolith to a set of microservices
In Part 1 of this series, I introduced some key reasons and recommendations for restructuring your code for a microservices-based approach. And in Part 2, I described the kinds of problems you can solve with a microservices-based refactoring of your data.
Now to conclude the series, I’ll put that advice into a 4-phase roadmap for transforming your applications from a monolith to a set of microservices. As I’ve helped customers adopt microservices, I’ve rarely seen a customer jump all the way to a full microservices strategy all at once. Instead, most are successful in following a stepwise approach to migrating to microservices.
Macroservices are the initial step in your journey. A macroservice is what most customers see when they look at their existing landscape of “SOA services.” The Web services may be implemented to use RESTful protocols, but it’s just as common to find service implementations in SOAP.
Your starting point is to adopt one common protocol for service access: REST. (Asynchronous services using a messaging system are a special case that I won’t cover here in order to keep it simple). So once you agree to standardize on REST, if you have existing Web services already supporting REST, you’re done with this step — great!
But if you have a complete monolith without any Web services at all, then begin there and see if you can separate out your business logic into RESTful Web services.
Or if you do have Web services, but they are based on SOAP, you’ll need to refactor your functional-based SOAP interfaces to entity-based REST interfaces.
Once you’ve refactored to REST, you’ll want to make sure that you can document and catalog your REST services. This is where description formats like Swagger are helpful, especially in conjunction with tools in IBM Cloud like API Connect, which can take in Swagger documents and generate individual IBM Cloud services tiles for binding and invoking those RESTful services.
After agreeing on REST and documenting your interfaces, the next step is to begin splitting the services apart. Make sure that you’re doing your best to follow functional decomposition and work toward achieving one container per service. Remember to follow the decomposition guidelines in Part 1 of this series.
It may take a while to get there. The microservices architecture requires a level of operational discipline that many teams are not ready to adopt. Adopting the “one container per service” strategy may require you to adopt supporting technologies like Cloud Foundry or Docker in IBM Cloud. Many team may want to take this step slowly.
Similarly, the “one container per service” strategy may require you to move from traditional middleware like WebSphere® ND to WebSphere Liberty. Take your time and make sure you set up the right infrastructure for monitoring and logging to be able to support this approach. In IBM Cloud, you could use the Monitoring service or another related service. In any case, you’ll want to standardize on one approach for tracking how your services are being used and how they are performing.
A full microservices architecture isn’t achieved until you’ve addressed not only how you deploy your services, but how you build them as well. In this step, you’ll want to work toward achieving a full independent continuous integration/continuous delivery (CI/CD) pipeline for each service. Tools like the IBM Continuous Delivery Pipeline can help you achieve that.
At this point in your journey, you can also starting thinking about independent scaling of your microservices. Features like Container Groups in the IBM Cloud Container service or the Auto-Scaling for IBM Cloud service will help you. With Auto-Scaling, the number of application instances is adjusted dynamically based on the scaling policy that you define.
Microservices at scale
The final step is moving to a fully scaled-out microservices approach. Many teams never need to take this step! In my experience, most projects will ultimately have only a few — usually fewer than 10 — microservices.
At this step, you’ll have to consider the questions of service discovery: How do you discover your services, and how do you set up routing rules? Service Discovery in IBM Cloud can help you there. Service Discovery can locate microservices by logical names instead of hardcoded network addresses, and it can remove unhealthy microservices automatically.
Finally, you may want to consider what happens if you have downstream services failures. In this case, something like Netflix Hystrix can run in the IBM Cloud Kubernetes Service on IBM Cloud.
Now that you’ve seen the roadmap to get from where your applications are now to the final microservices “nirvana,” you can begin your journey! You can see how each step builds on the other, and honestly, it’s okay to stop short of the final destination if you need to.
Just be sure to remember my warnings in Part 1 and Part 2— don’t just adopt microservices to be the cool kid on the block. Make sure that the problem you’re solving is one to which a microservices architecture is well suited, and only adopt microservices as part of an overall process of adding business value to your application.