According to Conway’s law about software teams, your code ends up reflecting your organizational structure. One example of Conway’s law in action is the important—but somewhat terrifying—move from a monolith to a microservices/service-oriented architecture. Microservices split your code into small, manageable pieces that better reflect your multiple teams and different domains. They have a lot of benefits, like making your system more fault-tolerant, letting you reason about who owns which data, and speeding up your entire deployment process.
On the other hand, there are a few hurdles. The monolith inertia is hard to overcome. How do you know where to start, and how do you get cultural buy-in for the transition? As we’ve written in our blog about “taming” your microservices, there’s also the danger that you’ll create information silos and communication overhead if you don’t have the right processes in place.
But the pros greatly outweigh the cons here, and luckily there are safe ways to move from a monolith to microservices and look back on the project with zero regrets. Here are five things to keep in mind that we’ve learned from helping teams navigate this transition.
From what we’ve seen, teams often hesitate because they feel like they have to go from a monolith to dozens of microservices overnight. That’s simply a misconception. In reality, it’s possible and quite common to ease into the transition by moving to a few macroservices that can give you a happy medium between your monolithic architecture and going wild with Kubernetes.
Where can you start? You might try breaking out one team or a larger business domain into its own macroservice. For example, consider creating a service that handles your authentication flow with auth, identification, users, and groups. You can still deploy this as a monolith, but you’ll have all of your auth data in one place where you can easily manage, monitor, and protect it.
Another example might be your data science stack. Let’s say it’s Python-based while your monolith uses Java. Instead of trying to shoehorn this infrastructure into the monolith, run it as its own macroservice. You’ll be able to choose the right tools for each stack, which is another benefit of having a service-oriented architecture.
To make it easier to move to a service-oriented architecture, it can help to define the boundaries within your organization and your codebase well ahead of time. As an exercise, start by asking yourself: What are our business domains? Are there accountable owners? Essentially, try to imagine what your monolith would look like if it was a set of services.
Next, actually go about tactically adding abstractions around these domains within the monolith. Even if they’re all still hosted the same way, you can make these areas behave like independent services by creating separate data models, distinct boundaries, and an API layer. Then, when you want to rip out a certain chunk of your codebase and pull it in as a new service, most of the work will already be done.
One of the most important things to keep in mind here is that every service is going to need its own database and data models. Otherwise, as you add more and more services, you might end up just building a distributed monolith. If you ever catch yourself having to deploy your services in a certain order—first a, then b, then c—you’ll know you’re in this situation. You should be able to deploy microservices independently, and you can only do so if you decouple data from the monolith.
When you’re just starting to transition to new architecture, you’ll want to quickly get buy-in from the rest of the team. So while it might be tempting, it doesn’t make sense to invest a lot of time building a shiny new stack. Instead, remember that you’re in experimentation mode, and try to make do with what you have. If you’re on Heroku, just spin up a new Heroku service. But be sure to include the minimum pieces required to prove the benefit, like a CI/CD pipeline for doing builds.
We will recommend that you invest in tooling to make it easy to spin up new services. Once you get your team excited about one microservice, you want to be able to take advantage of that momentum and make sure that people are implementing future services in the right way. It’s hard to sell engineers on a project that takes longer than the current way of doing things. And often that’s the fear with microservices.
Service templates are a great tool for overcoming that hesitation. They make it so you can deploy services with one click and automatically set up your logging out of the box. They also help with versioning and providing runbooks for debugging your services. Having tooling like this in place helps your team feel confident in knowing that there’s an objective “right way” to deploy new services. To get an idea of what these templates can look like, check out cookiecutter or Spring Initializr.
You might believe that microservices are the future (and we’re with you)—but how do you convince everyone else in the organization? One way to do this is to break out a high-value, high-risk domain into a service, instead of starting with something small. In other words, make it clear that you’re serious about the transition. So instead of, say, an image-resizing service, kick off with something like your authentication flow.
To mitigate the risk, do a dry run. For a few weeks, while the monolith is still handling everything, start sending requests behind the scenes to your new service. This way you can make sure it’s behaving in the right way and have confidence when you decide to pull the trigger and switch everything over.
You want to make sure there’s a smooth transition for your team, too. Start by reviewing the status quo in your production readiness checklist. Check that everything engineers expect to be able to do with the monolith will still be possible with your new service. Keep in mind that a lot of your analytics and BI processes are probably tied to the monolithic database that contains all of your organization’s data. If you pull some of this into another service and the data isn’t in the DB anymore, your sales team isn’t going to be very happy. Bottom line: Make sure you aren’t breaking any data contracts.
Imagine you launch your high-impact project with a bang, and six months later, every team is off implementing their own microservices. Unfortunately, that’s where you could really start to see some problems. With a monolith, you can dig through the codebase and debug—but when things break in a service-oriented architecture, there’s no context. You might not even know who owns the service that’s breaking. And tech debt can grow exponentially because you have many services to manage instead of just one.
Why does this happen? When you put new infrastructure in place, it’s as if the organization has to create new muscles. The problem is that, left to their own devices, each team will come up with a different approach and build different kinds of muscles. Like in sports, you need to have standard drills, exercises, and playbooks in place from day one to ensure the organization acts like one cohesive unit.
It can be too early to invest in a lot of infrastructure, but it’s never too early to invest in a process. For example, you can:
It’s also a cultural change. Tribal knowledge accumulates really fast. So make sure you have documentation, tech talks, lunch and learns, and are generally always working to share context about your architecture. It takes a lot of organizational integrity to make this investment at the beginning, but trust us—it’s worth it.
Are you thinking about transitioning to a service-oriented architecture? Have any questions that we didn’t answer in this article? We’d love to help, even if it turns out Cortex isn’t the right fit—just reach out to firstname.lastname@example.org and chat with us any time.