For the past few years, microservice-style architecture has been very popular, to the point where software projects fail to consider other options. Instead of asking themselves, “Should we use microservices?” developers just assume the answer is yes.
Microservices break up applications into separate components, with each component specializing in specific tasks and communicating with other components without needing to know the details of how they work. This kind of design can be useful if the application is large and requires many developers to maintain. Development teams gain the flexibility to work on different components in tandem without worrying whether changes will break other parts of the application.
What are microservices?
Many discuss microservices as if they are a homogeneous concept, but even after deciding to build an application using microservices, there are still a lot of other decisions to make. In fact, the vast majority of architectural decisions, such as what logic should be grouped together, and how components should communicate, still remain.
Ideally, the specific needs of the customer and the desired functionality determine application architecture, so whether microservices should be used in the first place should be carefully considered.
Adopt Microservices Only When You Need Them
Will Gant, a software developer based in Nashville who co-hosts a software development podcast called Complete Developer Podcast, spoke to Built In about how to decide when to avoid microservices in an application.
Instead of splitting an application up into microservices at the beginning of a project, Gant recommends starting with a monolith and moving to microservices when the application naturally develops a need for it.
“That typically is what I do early on, at least until I start to get some feedback,” Gant said. “Proofs of concept are easier to stand up in a single codebase.”
If redundancies begin to pop up and it becomes more complicated to keep coding as a monolith, that’s when the application has reached the point where you should break it up. These opportunities come up frequently over the course of an application lifecycle.
Gant gave an example of letting the natural progression of an application inform architectural design at a company that creates legal software.
“You got some part of the app that maybe needs to more quickly deal with changes in the business landscape, or changes in tax law, or integration points,” he said. “You might need to break that off into a microservice, just to be able to iterate on that differently than you do on the rest of the app.”
“If programmers don’t have a feedback cycle from users or from stakeholders, we become our own feedback cycle — and we go off into the weeds.”
Gant said he can usually predict whether development issues in monolith projects will snowball into more problems down the road. If so, that’s a good indication that the application needs to be redesigned, possibly by splitting off a portion into a microservice. But he stressed the importance of not trying to jump too many steps ahead.
“Human beings are terrible about predicting the future,” Gant said. “I’ve done the big engineering up-front thing so many times, and I’ve over engineered stuff that just didn’t need to be.”
If a company practices agile development, it should be able to pivot quickly when a monolith application needs to adopt a microservice architecture. Meanwhile, architecting out the entire solution as microservices before beginning development could be a waste of time if assumptions made at the beginning of the project were incorrect.
“Microservices as a default for a situation where you’re building the whole product up front — it’s not that that’s necessarily good or bad,” Gant said. “It’s that building the whole product up front is very, very hard to do well. If programmers don’t have a feedback cycle from users or from stakeholders, we become our own feedback cycle — and we go off into the weeds. You don’t want to create microservices for this hypothetical when the hypothetical is something you probably don’t want to be doing.”
Don’t Mistake Distributed Monoliths for Microservices
Gant said it’s important for everyone on a development team to understand what microservices are before attempting to write them. Sometimes, applications that look like microservices are actually “distributed monoliths.”
Distributed monolith applications are “entangled, often by way of the data store,” he said. “I’ve seen it with things like e-commerce refunds, where [a company decides], ‘This one report in the website, we don’t want the report to show here, so we’re changing this repository method to not return those.’ But what they didn’t realize is there’s this app, sitting off to the side, that’s using that same library and is calling through that, and now the reports that come out of that app are wrong.”
Distributed monoliths have disadvantages when it comes to making code changes quickly and dealing with maintenance, but Gant said that it ultimately still comes down to the individual application — building a small application that will only be used one time as a distributed monolith probably won’t do much harm, because the most difficult part is maintenance.
Is Your Team Ready to Handle Microservices?
When deciding whether to build an application using microservices, there are less technical concerns to consider as well.
“If we’ve created a scenario that doesn’t work with a microservice, it’s not necessarily the code — a lot of it is just a lack of understanding within the organization,” Gant said.
If a company only has a few developers, or the application is small, it doesn’t make sense to spend the extra effort breaking the application into separate components. That’s because developers likely don’t need to worry about other parts of the application breaking during changes.
“The thing I’ve learned over the years is that 99 percent of programming problems are actually people problems, because the machine does whatever we tell it to.”
It’s also important to determine whether development and DevOps teams are robust enough to handle the demands of writing and managing microservices. A well-developed DevOps foundation is important for managing the many components of a microservice application, which works best when separate components can move through the DevOps pipeline independently. For developers, clean separation between microservices requires correspondingly clean code.
“I’ve been in companies where the copy-paste coding is going on, everything’s just kind of hacked together, and you know they’ve basically made a giant game of mousetrap with all their code,” Gant said. “If you introduce a microservice there, it’s going to break, probably almost immediately.... The thing I’ve learned over the years is that 99 percent of programming problems are actually people problems, because the machine does whatever we tell it to.”
Microservices Will Not Help You Outsource More Effectively
Gant said some companies decide to break an application into microservices when they see it as an opportunity to outsource work on those separate components, but he cautioned against the practice.
“The problem is that you have to agree upon the interfaces beforehand, and how you’re going to talk to each other, how you’re going to do the typical microservice things,” Gant said. “It’s even worse with an outsourced team because typically you’re not outsourcing to somebody in the same time zone — you’re doing it halfway across the planet.... It’s going to be difficult to have the appropriate conversations with that other party.”
With developers in different time zones not communicating as much as they need to, it becomes difficult to agree on the contracts that are necessary for a successful microservice design. Ultimately, it’s those conversations with team members that determines whether an application will find success with microservices.
“You can’t fix communication with an architectural choice,” Gant said.