Monolith vs. Microservices

Written by:

It feels like every growing team encounters the time they need to make the decision: Monolith or Microservice. It turns out that most end up doing a somewhat hybrid experience, where you have a main codebase and start ‘attaching’ services as it seems fit. The debate between microservices and monolithic structures remains a hot topic. Let’s dive in.

Microservices: Strict roles leads to simplicity

Pros of Microservices:

  1. Scalability: Each service can scale independently, which is particularly useful for parts of your application that require more resources.
  2. Flexibility: Teams can work on different microservices concurrently using the tech stack best suited for each service.
  3. Resilience: A failure in one service doesn’t necessarily mean the whole system goes down.

Cons of Microservices:

  1. Increase overhead: There’s an undeniable increased overhead in managing multiple services. Multiple repos, multiple databases, etc.
  2. Deployment: Continuous integration and continuous deployment become more challenging with so many moving parts. It now increase the level of care you must take in deploying features.
  3. Data Management: Ensuring data consistency across services can be a hurdle. Most microservices have dedicated databases to keep it ‘blind’.

Monoliths: The One and Only

Pros of Monolithic Architecture:

  1. Simplicity: With all functionalities housed under one roof, development, testing, and deployment can be more straightforward.
  2. Data Consistency: With a single database, ensuring data consistency is inherently easier.
  3. Lower Initial Complexity: Starting a project with a monolithic approach can be less overwhelming. It is almost always overkill start “Hello World” with microservices.

Cons of Monolithic Architecture:

  1. Complexity: As the codebase grows, making changes can become more challenging and trigger a cascade of unit test failures, slowing down development cycles.
  2. Scalability: The entire application has to scale, even if only a particular functionality requires more resources.
  3. Single Point of Failure: If one part fails, the entire system is at risk. I don’t always buy this, if my Billing microservice really went down vs my monolith code base, my signup flow still doesn’t work to charge a credit card. I guess they got nearly to the end vs failing instantly.

Split up, just to come together again

We split into microservices to enhance simplicity and that’s great, up until you have a business question about something that includes multiple of our interdependent databases.

Example: How do the orders compare between shoppers in our premium subscription tier to non-premium shoppers?

Sounds simple enough until you realize that because microservices are meant to be interdependent you need query across multiple databases to get your customer information (are they premium subscription or not) and your database with billing transactions (how many orders and how much). Obvious solutions are built to help handle this scenario, data warehousing, ETLs, etc, but now you need either a new developer or likely a new team to handle your data.

Bridging the Gap with Namespaced Databases?

One approach to reducing the overhead of microservices management is by using a shared database and leveraging namespaces for each microservice. This approach combines the data management simplicity of monoliths with the flexibility of microservices. That way instead of needing a data warehouse I can easily query with:

SELECT 
    u.subscription_tier,
    COUNT(o.order_id) AS number_of_orders,
    AVG(o.order_amount) AS average_order_amount
FROM 
    user_service.users u
JOIN 
    orders_service.orders o ON u.user_id = o.user_id
GROUP BY 
    u.subscription_tier;

That way, instead of needing a data warehouse, I can easily query across different microservices seamlessly

Benefits:

  1. Data Consistency: Using a shared database ensures a single source of truth, reducing inconsistencies.
  2. Simplified Data Management: Without the need to synchronize multiple databases, overhead related to data replication or transaction management is reduced.
  3. Resource Efficiency: Maintaining a single database connection pool can be more resource-efficient than managing multiple pools.

Drawbacks:

  1. Tight Coupling: Sharing a database can make services more interdependent, potentially reducing the independence that microservices typically offer.
  2. Migration Challenges: Any changes to the shared database schema can affect all services, making migrations more delicate.
  3. Network issues: If your infra is not up to it, latency can be a source of data frustration.

Conclusion

While microservices inherently increase development overhead compared to monolithic architectures, strategic decisions like using namespaced databases can strike a balance. There are strengths to both approaches and teams can create robust, scalable, and efficient systems, tailored to the unique needs of their applications. As with all architectural decisions, understanding trade-offs and aligning them with project goals is paramount.

Leave a comment

Latest Articles