- Published on
[draft] Monoliths & Microservices
Quotes
Kelsey Hightower
Principal/Distinguished Engineer @ Google
Keith Adams
Principal Engineer @ Facebook/Slack
Jason Warner
Former CTO @ Github
Martin Fowler
Thoughtworks
DHH
Creator of Ruby on Rails
Nick Shrock
Co-creator of GraphQL
Chris Richardson
Author, Microservices Patterns
Sam Newman
Author, Monolith to Microservices
Overview
Neither architecture is superior or perfect, companies are using both very effectively (and not-so-effectively) today. Facebook, Shopify and many others have served their massive and demanding audiences from monolithic applications, so the argument you must start using microservices to "scale" is likely a fallacy. In this article we explore some of the difficulties of adopting microservices.
You should have a clear goal in mind when adopting microservices, not just adopting the sake of following trends or as a way to mend "bad practices in your current application."
Complexity
When adopting microservices, you've now made you application a complex distributed systems, adding a very substantial layer of complexity to your system that shouldn't be overlooked and should be well thought out. It's very easy to overlook and minimize the problems introduced with distributing your application, e.g.
- distributed transactions
- rollbacks for distributed transactions
- handling eventual consistency
- network failures and partitions
- event sourcing, cqrs
- order of message delivery (fifo, lifo, no order guarantees, etc)
- data consistency worker jobs
- competing consumers
- service discovery
- dead-letter queues
- idempotent consumers (at-most once delivery, at-least once delivery, etc)
- reliable event delivery, e.g. outbox pattern
- queue backpressure
- infra complexity, e.g. review apps
- supporting technologies, e.g. client libraries & maintenance
- and many, many other difficulties
One argument you will likely hear during your career is that the application you've been building has become to large to develop and understand in a single codebase. This is likely an issue with your engineering practices/standards that is not just going to magically go away by distributing your system (and will likely become worse). Focusing your efforts towards improving those root issues and building a well modularized monolith will often pay dividends over adding another layer of complexity in your application and infrastructure. Remember, Facebook and Shopify operate primarily with monoliths — your system likely isn't as complex as you've proclaimed.
Scale
Microservices are often touted as being "the way to scale," but this seems to be a bit overdrawn. Shopify handled black-friday traffic running on a monolith, it's very likely that you're organization can operate fine with a monolith. Shopify isn't the only company either — teams such as Facebook, StackOverflow and others have ran massive businesses on a monolith architecture. Putting more of your focus on effective caching mechanisms, improving data access operations and simple horizontal scaling can often have a larger payoff than just breaking up your application. You're organization is likely not dealing with the same scale issues as Netlix or Google, so you probably don't need the same solutions.
Organization structure
Organizational topology can arguably be the strongest rationale for adopting microserivces. If your organizations that have teams that operate truly indepedently and have almost zero cross-functional work, this can be the perfect fit for microservices. Google is a great example of this as their product offerings between Gmail, Search and Photos have very little overlap and are essentially autonomous organizations.
Teams often turn to microservices as a way to simplify the code a team interacts with, but this often tends to add more complexity. Facebook runs in a monolith, allowing all developers to contribute to a single codebase that powers their entire application. The simplicity of this removes a large level of cognitive overhead.
Co-Creator GraphQL, https://twitter.com/schrockn/status/1130567665548873728
Fault Isolation
Fault isolation is the idea that a failure in one part of the application won't bring down the entire system. In some languages, this can be a valid starting point for discussion. In languages like PHP, you get a sort of inherent fault isolation because of the architecture of PHP (all web requests get their own heap/stack). There are other potential solutions to this issue such as the "circuit breaker" technique or simply running those small pieces in isolated environments (e.g. lambda functions, etc.)
Hiring Talent
Our industry struggles to attract enough talent to fill typical "software development engineer" roles. When you are looking to hiring microservices experts, the talent pool is drastically smaller than the pool of typical frontend & backend engineers. Once again, your team is not Netflix/Google/etc. so you probably don't have the seemingly endless capital (to offer $500k+ salaries) or the brand recognition to attract and retain these individuals.
Bottom Line
Don't fall in the trap of adopting microservices to match the latest trends. Technology exists as a solution to a problem and microservices likely aren't the one solution to the issues you are, or think you are facing. Monoliths can be very "majestic" (David Heinemeier Hansson, creator of Ruby on Rails).