Microservices Are a Team Decision First
Most of the microservices conversations I hear are about technology, like containers and service discovery. The reason to split up a system is organizational. Small teams that can each ship a change on their own find out what customers want, and react to it, faster than one large team releasing everything together. If your teams still coordinate every release, you’ve taken on the costs of a distributed system and kept the speed of a monolith.
Speed of learning is the goal
I recently shared an article from the NGINX blog, Microservices at Netflix: Lessons for Team and Process Design. One line from it stuck with me. The goal, as the article puts it, is “learning about your customers and giving them what they want at a faster pace than your competitors.”
That sentence doesn’t mention services at all. It describes a loop. You have an idea about what customers want. You build the smallest version of it, ship it, and watch what people do with it. Then you adjust and go around again.
The team that goes around that loop more often learns more. Each pass is a chance to be wrong cheaply and correct course. A team that ships once a quarter gets four chances a year. A team that ships every day gets a few hundred.
Architecture matters here because it sets how long each pass takes. A monolith that a team can deploy twenty times a day is closer to that goal than fifty services that go out together once a month.
Services cost something every day
A method call becomes a network call. Network calls are slower, and they fail in ways a method call doesn’t: timeouts, partial failures, a dependency that’s up but taking eight seconds to answer. Every caller now has to decide what to do about that.
Data that used to live in one database, behind one transaction, is now spread across several. You give up joins and atomic updates across those boundaries and start reasoning about eventual consistency.
Then there’s the operational side. Each service needs its own build, deploy pipeline, monitoring, logging, and alerting, and somebody has to be on call for it. Debugging a request means following it across process boundaries instead of reading one stack trace.
None of that makes you faster on its own. What you buy with all that cost is independence: a team can change its service and ship it without anyone else’s permission. If you don’t actually get the independence, you’ve paid for it and got nothing back.
Can a team deploy on its own?
One question tells you whether you have microservices or a monolith with extra network hops in it. Can a team ship a change to its own service this afternoon, without asking another team for anything?
If the answer is no, look for the coupling. It tends to hide in a few places:
- A shared database. Two services that read and write the same tables can’t change their schemas independently. The database is the real interface between them, and nobody designed it as one.
- A shared client library that every service has to upgrade in the same week. Those services deploy together whether or not anyone calls it that.
- A release checklist listing which versions of which services have to go out at the same time.
- A shared staging environment that has to be green for every team before anyone can ship.
Each of these puts coordination back into the process, and coordination is what services were supposed to remove. The system is still one deployable unit. It just has a network in the middle of it now.
Keeping services independent takes discipline on both sides of an API. Make changes backward compatible, keep an old endpoint around until its callers have moved off it, and let each service own its data so nobody else reaches into its tables.
Use Conway’s law on purpose
In 1968, Melvin Conway observed that organizations design systems that mirror their own communication structures. Give a project to a front-end team, a back-end team, and a database team, and you’ll get a three-layer system where every feature needs all three teams to finish it.
That’s why splitting the code without changing the teams rarely works. Draw service boundaries on a whiteboard, hand them to the same org chart, and the org chart wins. The services drift back toward the shape of the teams, and features keep crossing the same lines they crossed before.
So turn it around. Decide which part of the business each team owns, say search or checkout, and give that team everything it needs to ship its part: the code, the deploy pipeline, the data, and the pager. Werner Vogels described Amazon’s version of this back in 2006 as “you build it, you run it.” A team that runs its own service in production hears about problems from customers directly, which is the learning loop again. Then let the service boundaries follow the team boundaries.
Fix how you ship first
If you’re thinking about moving to microservices, start by asking how long it takes today to get a small change from an idea to a customer, and what that time is spent on.
If most of it goes to waiting on other teams or coordinating a release, splitting the system along team lines can help.
If most of it goes to an hour-long test suite or a monthly deploy that everyone is afraid of, services won’t fix that. You’ll have the same slow pipeline, once per service. Fix the deploy process in the monolith first. Get one codebase to continuous delivery, and you may find you don’t need to split it at all.
Pick the architecture that lets your teams learn fastest. Sometimes that’s a set of services owned by independent teams. Sometimes it’s a monolith with a deploy button anyone can press.