top of page
Logo [color] - single line w_ cart_edite

Monolith vs Microservice: Building a Dietary Preferences Application as a Case Study


The Pain of the Monolith and the Promise of Microservices


Imagine your engineering team is celebrating a minor bug fix, not because the fix itself was complex, but because testing it in lower environments took hours and getting it deployed took a week. If this resonates with you, you’re likely working with a monolithic application. Now imagine a request for a new feature in said application (Yuck!). Monolithic architectures with their massive, tightly coupled designs, have become a roadblock for teams looking to develop new features quickly because they necessitate long build times, complex, high-risk deployments, and frustratingly slow development cycles. 


The industry standard alternative to monolithic architecture is to use microservices, but does this approach really pay off? Microservice architecture offers a modern, scalable, and agile alternative approach that speeds up development and deployment times, improves code quality, and facilitates easier long term maintenance of your organization’s applications. 


This is the story of one agile team’s transition to developing a simple microservice, iteratively and quickly. It will outline the benefits of this architectural shift, focusing on how it specifically empowered the development, deployment, and maintenance of a new microservice.


Dietary Preferences For All


Recently, a major regional grocery chain contracted with Commerce Architects to migrate its e-commerce platform from a monolithic architecture to a modern microservices architecture. While the full migration was still in progress, the client asked us to also develop an application for managing a user’s dietary preferences. We saw this as a great opportunity to demonstrate the benefits they could look forward to by using a modern microservices approach. 


At its core, the Dietary Preferences application allows users to perform RESTful CRUD operations on user-selected dietary preferences. Simple enough on the surface. But the details made it interesting:


  • A separate business team needed to manage the available preferences

  • Those preferences had to be shared across multiple brands and organizations

  • Multiple teams needed access in different ways — not all of them inside this client's tech ecosystem


In the old monolith, this request would have been painful. In a microservices world, it was exactly the kind of problem we love.


Design Speed Increases and Complexity Savings


Had we been designing this dietary preferences functionality in the client’s monolithic e-commerce application, we would have needed a general understanding of the entire massive application and all the interwoven production-critical systems within. While three of our developers have varying levels of understanding of this monolithic application, none of us have a complete understanding of all of the interdependent systems and subsystems that would have to be involved in developing dietary preferences in that application. 


If we were asked to develop in the monolith, design time would have meant:

  • Reading through the code base to avoid collisions with other existing features

  • Planning out relational db schemas in an existing massive database used for almost all of the application’s existing functionality (think carts, profiles, checkout, orders, etc)

  • Trying to understand how to best migrate that data in an event-driven manner to other teams

  • Figuring out how to best serve multiple organizations' dietary preferences from a single organization’s on-prem e-commerce solution without polluting that organization’s persistence layer with the data of other organizations. 


I hesitate to even estimate the time, complexity, challenges, and cost of such a design process. 


Thankfully building a service like Dietary Preferences — which needs to be fast, reliable, and decoupled from other systems — is exactly where microservices shine. The design process, complete with architectural diagrams, requirements documents, and collaboration with other dependent teams, took about one day


During this time, we ironed out our data model, our persistence layer queries and infrastructure, full contracts for our API endpoints, an approach for serving multiple organizational brands’ dietary preferences (with completely different tech organizations), and a method of providing an event-driven method of sharing these preferences with other teams. We also uncovered gotchas like what happens when the business changes or removes the underlying dietary preferences available for a user to select, and what happens when the service providing us the available dietary preferences goes down. 


The next day we wrote stories that covered nearly all the development work — clear, detailed, and understood by every developer on the team. That's the payoff of building with industry-standard technologies everyone knows: Springboot, DynamoDB, event streams, RESTful APIs.


Moving Faster, With Less Risk


In the microservices world, a small team can own their microservice from end-to-end. After our design meeting, with a clear shared vision of what we were building, we were ready to develop our Dietary Preferences application. Like many teams out there, you’re never just focused on supporting one application. Sprint goals almost always include multiple fronts of work, and this was the case during our development of Dietary Preferences. Throughout the development cycle, at any given time, an average of two developers would end up working on Dietary Preferences during a given sprint. Our shared vision and detailed stories allowed any of our developers to pick up any part of the development work and implement it with complete autonomy and little ambiguity.


Implementing new functionality from scratch involves a lot of different types of tasks. At any given time a developer might be:

  • Writing the CI/CD pipeline

  • Creating and deploying the infrastructure

  • Developing the API endpoints

  • Implementing the persistence layer

  • Updating documentation and runbooks

  • Testing other developers’ features

  • Making sure observability and logging are in place


Completing these tasks in a monolith requires developers to move more slowly. Build cycle times in a monolith can take minutes instead of seconds. Because the dietary preferences functionality would not be self-contained in its own codebase, persistence layer, infrastructure, or deployment cycle, other teams can introduce code changes that can affect your code as well. On top of all that, IDE support is nearly non-existent for older monolithic applications, leading to a more frustrating quality of life for developers. 


Additionally, completing this dietary preferences functionality in a monolith involves more risk for the business. Deployments are never scoped to just a few code changes, as there are multiple teams working in the same codebase. Environments to test changes in are always polluted with changes outside the scope of what you’re testing. While you do get some things for free by implementing new features inside a monolith, like an existing CI/CD pipeline, infrastructure, and the persistence layer, you are never truly certain if the thing you wrote is going to unintentionally break some other mission-critical feature and cost the business money and reputation with its customers.


What Happens After We Leave?


For the next several years, the business is going to have to maintain the Dietary Preferences application. There are new feature requests and bug fixes for any application. What happens if the team you used to develop this application is split up and all working on different things because of a re-org? Or worse, what if they have left the company and taken some of that domain-relevant information with them? Let’s look at what that means for the business in our two different development architectures.


In a monolith architecture, a domain expert leaving the company is a major event. They usually take with them years of knowledge about features long forgotten but still critical to the business. Hiring a new employee with the right expertise is time-consuming and costly. Experts with the right knowledge know their worth and charge for it. Even if you can find and hire a relevant expert, they still need to get up to speed on the entire application. This takes longer with a larger, more complex codebase, which costs more expert developer hours and salary. On top of that, you’re essentially paying for someone to learn old knowledge that likely won’t be technologically applicable to the future of your organization.


With a modern microservices approach, the calculus changes. The candidate pool is larger because the technologies are current and widely understood. The codebase is smaller and self-contained. New team members can get productive faster. And the knowledge CA transfers during the build — how the system works, why decisions were made, how to extend it — lives with the client's team, not locked in someone's head.


That knowledge transfer isn't an afterthought for us. It's part of the job.


The Bigger Picture


The client was thrilled when we delivered Dietary Preferences ahead of schedule. But the real win isn't one feature. It's the direction of travel.


Every microservice we build during this migration is another piece of the monolith that no longer holds the business back. Each one ships faster, runs independently, and is easier to maintain. The monolith that slowed this team down for years is headed for the dustbin — one well-built service at a time.


That's what modernization actually looks like in practice.


bottom of page