So your server works. It authenticates. It writes to your database. It serves static assets like a beast. But nothing you make is ever good enough, so now you’ll need to break it up into smaller services.
Wait… why would I ever deliberately make my life harder?
Hey, you chose to get into software engineering. Deal with it.
A microservice is loosely defined as a small, specific, and lightweight service. Rather than having a single server that does auth, database interaction, and asset serving, you have separate services doing each of these things which then communicate with each other.
Jokes aside, there are advantages to microservices architectures, namely the decoupling of functionality. Rather than a massive monolithic piece of software deployed, you have several smaller pieces that function independently, yet together to deliver some sort of end goal.
From the point of view of the user/customer, there’s still only “one app.” For example, Amazon, to most users, is just online shopping app. But we as software engineers are aware of the various microservices which compose the entire experience.
Let’s use a metaphor to understand the advantages and disadvantages — imagine you own a restaurant: Scrumpty Dumpty’s Italian.
Let’s say there’s high demand for your pizza, but let’s say the ovens come coupled to the building, and the building has no space for more. So if you want more ovens, you need a new building. Or you need to remodel the building.
That would suck, right?
That’s basically what it’s like to deal with a massive monolithic service. Your only option is to replicate the whole thing to increase performance, even if only a specific functionality is overloaded.
On the other hand, using a microservices architecture, you’d just replicate the specific service. For example, if your application has an unusually large number of reads/writes to the database, only your database services would be replicated. No need for more auth servers or asset servers.
You could just buy more ovens for your restaurant. No need for additional pasta strainers.
Let’s say you find out one of the stovetops isn’t working properly, so you’ll need to replace it. Problem is, it’s hardwired straight into the building, so in order to replace it, the maintenance crew will have to shut off electricity — your whole restaurant is down until further notice.
That’s like what happens to Monolith app — even if you’re only deploying changes to the database portion of code, you still have to stop the whole thing to deploy the new code*.
*in practice, people employ “High Availability”, but that comes with its own set of problems I won’t cover here.
Let’s also mention that changing tightly intertwined code has the possibility of breaking everything else. Just like your maintenance crew might accidentally damage the circuit for half your building.
With microservices architecture, you can just take down the relevant service while the rest continue. Your static assets and streaming don’t require the database, so you can still keep your site up, and since those services are separate code bases, your changes to database code will not affect them***.
***WITH CAVEAT: Your changes to X microservice will break Y microservice if the input and/or output between the two changes. If Y expects A,B,C from X but then X is modified to send A;B;C then you’ll have problems. See Caveat section below.
Scrumpty Dumpty’s has a partnership with Whirlpond and gets special pricing on appliances. But let’s say KitchenHelper makes better stovetops. With a Massive Monolith, you can’t buy KitchenHelper equipment because your building only works with Whirlpond appliances.
If you have one large application, it’d be difficult to write parts of it in Java and parts of it in Python. I guess you could technically use Jython, but yuck.
With microservices architecture, the building is appliance-agnostic, and you buy whatever brand of appliances you want as long as the voltage input is consistent. If you have engineers who are better at Java than Python, they can write a microservice using Spring Boot. The only requirement is the expected inputs/outputs for each microservice are clearly communicated.
While it may be simpler to write microservices with single responsibilities, the complication is in the communication.
Your restaurant’s staff can be considered “microservices.” Certain people are responsible for specific things: waitstaff to take orders and deliver food, kitchen staff to cook, etc.
In order for this system to function and for customers to get their food, there has to be communication between each component. Waitstaff punch in food orders to the kitchen to cook, front-desk attendant seats guests and notifies waitstaff, etc.
Likewise, it also follows that communication becomes a possible point of failure in your architecture: what if your managers spoke French while your waitstaff spoke Chinese and your customers were vegan?
Subsequently, when designing a microservice, it’s highly imperative that the expected input and output of each service is clearly communicated to developers working on other components. If one service sends incorrect JSON to another service, that service might crash or encounter an error.
Especially at scale, one of the disadvantages of microservices is how complex the architecture can start to be. You will need to bake in logging and monitoring systems and then aggregate that data somewhere.
You’ll also have to take into account complex high availability strategies (HA), message brokering and queuing, and various other complex architectural situations you wouldn’t need to consider if everyone was baked into one app.
If so many services all have multiple replicas and are all trying to communicate with each other, this obviously poses challenges in terms of keeping information and data in-sync.
Generally speaking, if your application will not grow in complexity and is not expected to scale, then you can just implement everything in one service. But that might be, what, 10% of all software projects (I don’t know or have figures on this)? What company doesn’t want to scale and acquire more traffic/customers/money?
Especially if you’re planning on trying to take over the world one day like Google or Amazon, then you might want to consider implementing microservices architecture. Your app is easier to expand and modify, and it’s more efficient to manage individual portions in smaller pieces.
But remember that due to the caveats of microservices mentioned, these technical complications and situations can naturally make things extremely difficult and unstable, so it needs to be made clear that while microservices have their advantages, they’re not necessarily magic bullets - the user must learn to wield the gun.
Good luck, and happy engineering.