Home > Knowledge Base > Case Study Samples > Migrating Monolith To Microservices Case Study

Migrating Monolith To Microservices Case Study

Published by at October 28th, 2026 , Revised On October 28, 2026

Type: Case Study  |  Subject: Computer Science (Software Engineering)  |  Level: Undergraduate  |  Word Count: ~2,900 words

This model case study was produced by an Essays UK specialist as reference material for learning purposes only. For support in this field, see our computer science writing support.

Overview: This model case study examines how a mid-sized UK online retailer approached the migration of a legacy monolithic application to a microservices architecture. It applies established software engineering theory to analyse the architectural trade-offs, the redesign of the continuous integration and delivery pipeline, and the scalability gains achieved, before setting out a set of evidence-informed recommendations. All organisational detail is illustrative and intended purely as a worked example.

Background and Context

The subject of this case study is an online homeware retailer referred to here by the pseudonym Larkspur Retail Ltd. Larkspur is a mid-sized business trading principally in the United Kingdom, and the figures used throughout are illustrative rather than drawn from a real company. Founded in the early 2010s, it grew from a modest online catalogue into a platform that, in this scenario, serves several hundred thousand active customers and sustains a peak load of roughly 1,200 orders per hour during seasonal sales events. The commercial success of the business placed its engineering estate under pressure it was never designed to absorb.

Larkspur’s web platform was built as a single Java-based monolithic application. One deployable artefact contained every significant capability: the product catalogue, the shopping basket, checkout and payment orchestration, customer accounts, promotions and the administrative back office. These modules shared a single relational database and were compiled, tested and released together as one unit. In the early years this arrangement was an asset rather than a liability. A small team could reason about the whole system, a single transaction could span several modules without distributed-systems complexity, and deployment was a matter of shipping one package. As Fowler and Lewis (2014) observe, a monolith is frequently the correct starting point because it minimises the operational overhead that distributed systems impose.

By 2025, however, the engineering organisation had grown to around forty developers working in six loosely defined teams, and the characteristics that once helped had begun to obstruct delivery. The purpose of this case study is to analyse, using established software engineering theory, why the monolith had become a constraint, what architectural trade-offs the migration to microservices involved, how the continuous integration and delivery pipeline had to be re-conceived, and what scalability and resilience benefits were realistically achievable. The intention is to present a balanced analysis that recognises the genuine costs of microservices as well as their advantages.

Statement of the Problem

The central problem facing Larkspur was that its rate of safe, independent change had fallen well below the rate the business required. Feature lead times had lengthened, releases had become high-risk events scheduled fortnightly rather than continuous, and the platform could not scale selectively under seasonal load without over-provisioning the entire application. These symptoms are not unusual in a maturing monolith, but left unaddressed they threatened both revenue during peak trading and the ability of the organisation to retain engineering talent. The sections that follow identify the specific issues, analyse them against recognised theory, and recommend a migration strategy proportionate to the risk.

Key Issues Identified

Scalability Bottlenecks

Because the monolith was a single process, it could only be scaled as a whole. When the checkout and payment paths came under strain during a flash sale, the only available response was to run more identical copies of the entire application behind a load balancer. This horizontal scaling was wasteful: the catalogue and administrative code were replicated needlessly alongside the components that actually needed more capacity, inflating infrastructure cost. More seriously, every replica contended for the same relational database, which quickly became the true bottleneck. Bass, Clements and Kazman (2021) describe scalability as a quality attribute that must be designed into the architecture rather than retro-fitted, and Larkspur’s experience illustrates the point: no amount of additional application instances could relieve a shared database that had become the limiting resource.

Deployment Risk and Release Velocity

A single deployable artefact meant that any change, however small, required the whole application to be rebuilt, retested and redeployed. A one-line correction to a promotions rule carried the same deployment risk as a substantial change to the payment flow, because both shipped together. This coupling of unrelated changes discouraged frequent release and encouraged large, infrequent batches, which is precisely the pattern that Humble and Farley (2010) identify as the root of release pain. Larger batches contain more changes, are harder to test in combination, and make the eventual failure harder to diagnose, producing a self-reinforcing cycle in which teams release less often because releasing is painful, and releasing becomes more painful because they do it less often.

Tight Coupling and Constrained Team Autonomy

Over time the module boundaries inside the monolith had eroded. Shared utility classes, a common data model and direct in-process calls between modules meant that a change in one area frequently required coordinated changes in another. Teams could rarely complete and release a feature without negotiating with other teams, so the organisation’s communication overhead grew faster than its headcount. This is a direct manifestation of Conway’s Law, the observation that systems tend to mirror the communication structures of the organisations that build them (Conway, 1968). Larkspur’s single, highly connected codebase both reflected and reinforced a pattern of tightly coupled teams, and Brooks’s (1995) classic warning that adding people to a late project can slow it further was visible in miniature: each additional developer increased the coordination cost on a shared artefact.

Fault Isolation and Reliability

Finally, the monolith offered poor fault isolation. Because all modules ran in one process and shared resources such as the database connection pool and the thread pool, a fault in a non-critical area could degrade the whole system. In one illustrative incident, a slow query in the promotions module exhausted the shared connection pool and prevented customers from completing checkout, even though the checkout code itself was healthy. Nygard (2018) describes exactly this class of failure, in which a local problem cascades through shared resources, and argues for stability patterns such as bulkheads and circuit breakers that contain faults rather than allowing them to propagate.

Before and After: The Architectural Shift

The diagram below contrasts the original monolithic design with the target microservices architecture. In the “before” state, a single deployable application contains all business capabilities and depends on one shared relational database. In the “after” state, each capability is realised as an independently deployable service that owns its own data store, with clients reaching services through an API gateway and services communicating asynchronously through a message broker where appropriate.

Before — Monolithic Architecture

Single Deployable Application (one process)

Catalogue
Basket
Checkout
Payments
Accounts
Promotions
Admin

↓

Shared Relational Database

After — Microservices Architecture

Web and Mobile Clients

↓

API Gateway

↓

Catalogue
own datastore
Basket
own datastore
Checkout
own datastore
Payments
own datastore
Accounts
own datastore
Promotions
own datastore

↕

Message Broker (asynchronous events)

Analysis: Applying Software Engineering Theory

Weighing the Architectural Trade-offs

Microservices are not an unqualified improvement over a monolith; they exchange one set of problems for another. Newman (2021) frames the choice in terms of independent deployability and loose coupling: a microservices architecture earns its keep when services can be changed, deployed and scaled independently, and it imposes a heavy tax when they cannot. The principal benefit for Larkspur was that independent deployability would decouple the release of unrelated features, allowing the payments team to ship without waiting for the catalogue team. The principal cost was the introduction of distributed-systems complexity: network calls that can fail or time out, the absence of straightforward cross-module transactions, and a substantial increase in operational tooling. Larkspur therefore had to accept that it was trading the local simplicity of in-process calls for organisational scalability. Bass, Clements and Kazman (2021) are explicit that architecture is the discipline of making such trade-offs deliberately against prioritised quality attributes, rather than adopting a style because it is fashionable.

Service Decomposition and Domain-Driven Design

The most consequential design question was how to divide the monolith. Decomposing by technical layer, for example separating a user-interface service from a data-access service, would have produced services that still had to change together for every feature, defeating the purpose. Instead, Larkspur decomposed by business capability, guided by the bounded contexts of Domain-Driven Design (Evans, 2003; Vernon, 2013). Each service was aligned to a cohesive area of the business such as ordering, catalogue or payments, and owned the data and logic for that area. This approach aims for high cohesion within a service and loose coupling between services, the long-standing design goals that Fowler (2019) argues underpin maintainable software. Aligning services to business capabilities also allowed Larkspur to reorganise its teams around those capabilities, using Conway’s Law deliberately: by designing the desired architecture and then shaping teams to match it, the organisation turned a previously obstructive force to its advantage (Conway, 1968; Newman, 2021).

Data Management and Consistency

The decision that each service should own its data, rather than sharing a single database, was essential to achieving genuine independence, but it was also the source of the deepest difficulty. Richardson (2018) describes the database-per-service pattern as the point at which many microservices migrations succeed or fail, because it removes the shared database that otherwise re-couples services through their schema. Once data was partitioned, operations that previously relied on a single database transaction, such as reserving stock and taking payment, could no longer be guaranteed atomic across services. Larkspur adopted the saga pattern, in which a business process is modelled as a sequence of local transactions coordinated by events, with compensating actions to undo earlier steps if a later one fails (Richardson, 2018). This meant accepting eventual rather than immediate consistency for some processes, and designing the user experience, for example an order held in a “pending” state, to accommodate it. Asynchronous messaging through a broker, following the integration patterns catalogued by Hohpe and Woolf (2003), allowed services to publish events such as “order placed” without depending on the immediate availability of every consumer, improving both decoupling and resilience.

Continuous Integration and Continuous Delivery

A microservices architecture is only workable if each service can be built, tested and deployed independently and automatically; without mature continuous delivery, many small services become harder to manage than one large application. Larkspur therefore invested in its pipeline before extracting services in earnest. Each service received its own pipeline that compiled the code, ran unit and contract tests, built an immutable container image and deployed it through staging to production. Contract testing was particularly important: because services now communicated over the network, a change to one service’s interface could silently break its consumers, so consumer-driven contract tests were used to verify compatibility before deployment. This directly addresses the integration risk that Humble and Farley (2010) place at the centre of continuous delivery. To manage the risk of releasing frequently to production, Larkspur combined small batch sizes with progressive delivery techniques such as blue-green and canary deployments, allowing a new version to be exposed to a fraction of traffic and rolled back automatically if error rates rose. Forsgren, Humble and Kim (2018) report, from their research programme, that deployment frequency, lead time for changes, change failure rate and time to restore service are the metrics that distinguish higher-performing engineering organisations, and these became Larkspur’s targets. Kim et al. (2016) similarly argue that reliable, frequent, low-risk releases are an organisational capability built from automation and small batches rather than from heroics.

Scalability, Resilience and Observability

Decomposition made selective scaling possible for the first time. Under seasonal load, Larkspur could run many instances of the checkout and payment services while leaving the catalogue and administrative services at a modest baseline, matching capacity to demand and reducing the waste inherent in scaling the whole monolith. Because each service owned its own datastore, the single-database bottleneck was also relieved, with each store sized and tuned for its particular access pattern. Resilience improved through fault isolation: the stability patterns described by Nygard (2018), including circuit breakers that stop a failing dependency from being called repeatedly and bulkheads that ring-fence resources, meant that a fault in promotions could no longer exhaust the resources needed for checkout. These benefits, however, depend entirely on good observability. A distributed system has many more points of failure and no single log to inspect, so Larkspur invested in centralised logging, metrics and distributed tracing so that a single customer request could be followed across services. Without this investment, the improved theoretical resilience would have been undermined by the practical difficulty of diagnosing distributed failures.

Illustrative Outcomes of the Migration

The table below summarises the kind of change an organisation such as Larkspur might expect across the delivery and reliability indicators popularised by Forsgren, Humble and Kim (2018). The figures are illustrative targets used to make the argument concrete, not measurements from a real deployment, and they should be read as indicative of direction and order of magnitude rather than as empirical results.

Indicator Before (Monolith) After (Microservices, illustrative)
Deployment frequency Fortnightly, scheduled Several times per day, on demand
Lead time for a change Around two weeks Under one day for most changes
Peak-load scaling Entire application replicated Selective (checkout and payments only)
Time to restore service Hours; whole-system rollback Minutes; per-service rollback
Fault blast radius Whole platform at risk Contained to one service

The pattern these indicators describe is consistent with the central claim of the continuous delivery literature: smaller, more frequent and more isolated changes are both safer and faster, and the architecture exists to make them possible (Humble and Farley, 2010; Forsgren, Humble and Kim, 2018). It is worth stressing that such outcomes are not guaranteed by adopting microservices; they follow only from the disciplined practices described above, and a poorly executed migration can easily perform worse than the monolith it replaced.

Recommendations

Drawing the analysis together, the following recommendations represent a proportionate, risk-aware migration strategy for an organisation in Larkspur’s position.

  1. Migrate incrementally using the strangler-fig pattern. Rather than attempting a risky “big bang” rewrite, new functionality and carefully chosen existing capabilities should be extracted one at a time, with the monolith left in place until each service has proven itself in production (Newman, 2021). This keeps the business running throughout and allows the team to learn.
  2. Extract services along bounded contexts, beginning with a high-value, loosely coupled capability. A capability such as the catalogue, which is read-heavy and has relatively clean boundaries, is a lower-risk first extraction than payments and allows the organisation to build operational confidence before tackling transactional cores (Evans, 2003; Richardson, 2018).
  3. Treat the delivery pipeline and observability as prerequisites, not afterthoughts. Automated per-service pipelines, consumer-driven contract testing, and centralised logging, metrics and tracing should be in place before large-scale extraction, because they are what make many services manageable (Humble and Farley, 2010; Forsgren, Humble and Kim, 2018).
  4. Adopt the database-per-service pattern deliberately and design for eventual consistency. Shared databases should be decomposed in step with the services, and cross-service processes should be modelled as sagas with explicit compensating actions rather than assumed to be atomic (Richardson, 2018).
  5. Build in stability patterns and align teams to services. Circuit breakers, bulkheads and sensible timeouts should be standard, and teams should be organised around the business capabilities they own so that the organisation and the architecture reinforce one another (Conway, 1968; Nygard, 2018).
  6. Retain the monolith where it is adequate. Not every module needs to become a service; capabilities that are stable, rarely changed and not independently scaled can remain in the monolith indefinitely, avoiding unnecessary distributed-systems cost (Fowler and Lewis, 2014).

Conclusion

This case study has analysed the migration of Larkspur Retail’s monolithic platform to a microservices architecture as a deliberate response to specific, well-understood problems rather than as an end in itself. The monolith’s scalability bottlenecks, deployment risk, tight coupling and poor fault isolation were real constraints on the business, and microservices offered a credible means of addressing them by enabling independent deployment, selective scaling and fault containment. The analysis has emphasised, however, that these benefits are conditional. They depend on decomposing the system along business capabilities, on accepting and designing for eventual consistency, on investing in a mature continuous delivery pipeline and in observability, and on aligning the organisation’s teams with its services. Microservices trade local simplicity for organisational scalability, and that trade is only worthwhile when the organisation has outgrown the monolith and is prepared to meet the operational demands of a distributed system. For Larkspur, and for comparable mid-sized platforms, an incremental, evidence-led migration that respects these conditions represents sound software engineering practice. As a worked example, this document is intended to illustrate how architectural reasoning should be structured and justified, and it should be used solely as reference material to support independent study.

References

Bass, L., Clements, P. and Kazman, R. (2021) Software Architecture in Practice. 4th edn. Boston: Addison-Wesley.

Brooks, F.P. (1995) The Mythical Man-Month: Essays on Software Engineering. Anniversary edn. Reading, MA: Addison-Wesley.

Conway, M.E. (1968) ‘How do committees invent?’, Datamation, 14(4), pp. 28–31.

Evans, E. (2003) Domain-Driven Design: Tackling Complexity in the Heart of Software. Boston: Addison-Wesley.

Forsgren, N., Humble, J. and Kim, G. (2018) Accelerate: The Science of Lean Software and DevOps. Portland, OR: IT Revolution Press.

Fowler, M. (2019) Refactoring: Improving the Design of Existing Code. 2nd edn. Boston: Addison-Wesley.

Fowler, M. and Lewis, J. (2014) Microservices. Available at: https://martinfowler.com/articles/microservices.html (Accessed: 20 October 2026).

Hohpe, G. and Woolf, B. (2003) Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions. Boston: Addison-Wesley.

Humble, J. and Farley, D. (2010) Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation. Boston: Addison-Wesley.

Kim, G., Humble, J., Debois, P. and Willis, J. (2016) The DevOps Handbook: How to Create World-Class Agility, Reliability, and Security in Technology Organizations. Portland, OR: IT Revolution Press.

Newman, S. (2021) Building Microservices: Designing Fine-Grained Systems. 2nd edn. Sebastopol, CA: O’Reilly Media.

Nygard, M.T. (2018) Release It! Design and Deploy Production-Ready Software. 2nd edn. Raleigh, NC: Pragmatic Bookshelf.

Richardson, C. (2018) Microservices Patterns: With Examples in Java. Shelter Island, NY: Manning Publications.

Vernon, V. (2013) Implementing Domain-Driven Design. Upper Saddle River, NJ: Addison-Wesley.

About Jesse Pinkman

Avatar for Jesse PinkmanJessie Pinkman has been writing since childhood when her mother gave her a book where she could write her stories. Since then Jessie has always loved to write about the topics she loves. She graduated from Birmingham University in 2012, worked as a teaching assistant, and then turned to full-time writing in 2016.

You May Also Like

WhatsApp Live Chat