Recommended resources
The freely available resources this lesson will direct you to.
- When To Use Microservices (And When Not To!) • Sam Newman & Martin Fowler • GOTO 2020www.youtube.com
- LARACON EU 2024 // MATEUS GUIMARÃES :: UNVEILING THE MODULAR MONOLITHwww.youtube.com
- Microservices Assessment and Readiness - Azure Architecture Centerlearn.microsoft.com
- Microservice Trade-Offsmartinfowler.com
Welcome back. Last lesson identified two plausible business boundaries for the workshop feature: Workshop Planning describes and publishes workshops, while Reservations decides whether a place can be confirmed. Those boundaries tell us who owns each decision, but not how many applications to deploy.
This lesson makes that second choice. You’ll compare a modular monolith with separately deployed services using the constraints that matter for this feature: preventing overbooking, releasing changes safely, scaling under load, and operating the system when something fails. Allow about 40–45 minutes, including the video and readings.
Separate modularity from deployment
A modular monolith is one deployable application with deliberate internal boundaries. Modules expose limited ways for other modules to use them, while keeping their implementation details private. Services put some of those boundaries between separately deployed processes that communicate over a network.
The distinction is easier to see as two independent questions: Are responsibilities well separated? and How many units must be deployed?

Watch the selected portions of a Laravel-focused talk before applying that distinction to the workshop.
LARACON EU 2024 // MATEUS GUIMARÃES :: UNVEILING THE MODULAR MONOLITH
In “Unveiling the Modular Monolith,” presented by Mateus Guimarães at Laracon EU, notice which properties come from module boundaries and which require separate deployment.
Watch the comparison of monoliths and microservices. Then watch deployment and organization for the single-release-artifact distinction, and module contracts for why a module’s public interface matters more than its folder name.
For the workshop application, both candidate contexts could live in one Laravel deployment. Workshop Planning might call a small, public Reservations operation to request a booking-limit change. It should not update reservation tables directly. Keeping modules in one process makes that call local; it does not make permission to bypass the boundary acceptable.
A separate Reservations service would make direct calls into its code harder, but it would introduce network communication and another deployment to operate. A bounded context is a reason to define a model boundary, not by itself a reason to create a service.
Test the choice against the hardest business rule
The workshop’s decisive invariant is that confirmed places must never exceed the approved booking limit. Suppose two members request the final place at nearly the same time. Reservations must make the admission decision using authoritative, current facts; the availability number previously shown in React cannot make that decision.
In a modular monolith, Reservations can own the limit and commitments and enforce admission in a database transaction. Workshop Planning can request a limit change through Reservations’ public operation, which must reject any reduction that would invalidate existing confirmations. One deployment does not guarantee correctness—you still have to implement concurrency control—but the relevant authoritative writes can remain within one transactional system.
Splitting Planning and Reservations into services does not require the admission rule itself to become distributed. Reservations can still own both facts needed to decide whether to confirm. Trouble begins if Planning independently writes the “real” limit while Reservations independently writes confirmations: a request may see an old limit, or both sides may accept changes that are individually reasonable but jointly invalid. A network call to Planning on every confirmation would also make confirmation depend on Planning being reachable.
The useful split is therefore not “one service per noun.” It is a split that preserves one admission authority. A workshop page may show slightly stale availability, provided a confirmation request still receives an authoritative accept-or-decline response. Likewise, a newly published workshop should not be offered for booking until Reservations has accepted its booking configuration. That handoff needs an explicit contract whether the components are modules or services.
Martin Fowler’s trade-off analysis provides a way to weigh the benefits of stronger deployment boundaries against these costs.
Read “Microservice Trade-Offs” by Martin Fowler to evaluate what separate services buy you—and what they make harder. Focus on the trade-offs, rather than treating either architecture as a rule.
In “Strong Module Boundaries (Pro),” read module boundaries, from the opening explanation through the warning about misplaced boundaries. In “Distribution (Con),” read remote calls, beginning with performance and ending with failure handling. In “Eventual Consistency (Con),” start where the text says “Microservices introduce eventual consistency issues” and read data consistency through the comparison with smaller monoliths. In “Independent Deployment (Pro),” read release independence, from the account of difficult releases through the warning about coordinated ones. Finally, in “Summing Up,” read the concluding paragraph containing the premium and Fowler’s recommendation immediately after it.
Two cautions follow. First, a single deployment can still be continuously delivered; independent deployment is an advantage only when independent releases solve a real problem. Second, separate services do not ensure independence if every change requires simultaneous updates to both services. That arrangement pays much of the operational cost without gaining the intended release benefit.
Weight the constraints, including the ability to operate the result
For a senior engineer, the question is not “Which architecture scales?” Both can scale, but in different ways. You can run more instances of a monolithic application under load, even though each instance contains the whole application. With services, you can scale a busy component separately—but only if that distinction matters enough to justify the additional deployment, communication, and monitoring work.
The same applies to team autonomy. A small team sharing a release schedule may gain little from running two services. Two teams that need to release independently may gain a great deal, if their contracts and data ownership actually allow it. Before recommending services, assess whether the teams can build, deploy, observe, and respond to failures across the boundary.
Microservices Assessment and Readiness - Azure Architecture Center
Use Microsoft’s “Microservices Assessment and Readiness” as an operational check on the decision. Read the selected sections as questions to investigate, not as a requirement to adopt every practice before changing any architecture.
Under “Assess team composition,” read team readiness, starting with the explanation of focused, cross-functional teams and continuing through the listed assessment factors. Under “Assess DevOps readiness,” read delivery readiness, from the opening paragraph through the build-and-deployment-automation question. While reading, ask who would own each workshop service when it fails outside working hours.
Here is how those considerations could change the recommendation for the same workshop domain. These are illustrative constraints, not facts established by the product brief.
| Constraint | Situation A | Situation B |
|---|---|---|
| Teams and releases | One small team; changes usually ship together | Separate teams; coordinated releases regularly delay work |
| Admission and data | Reservations can own the limit and confirmations in one database | Reservations still owns admission, but Planning can evolve through a stable contract |
| Load | Current load is handled by scaling the application | Measured, uneven load makes independent scaling worthwhile |
| Operations | One reliable deployment pipeline; limited capacity for additional on-call work | Automated service deployments, monitoring, and clear failure ownership |
For Situation A, choose a modular monolith. Keep Planning and Reservations separate in the code, make Reservations the only admission authority, and deploy the Laravel application as one unit. This addresses the known rule without adding a remote dependency between the two parts. A React frontend does not change that backend decision merely because it has its own component structure.
For Situation B, separately deployed services may be justified. The strongest argument is not that two bounded contexts were discovered; it is that independent releases or scaling have become valuable and achievable. Planning can own descriptive workshop information while Reservations owns approved booking limits and commitments. Their contract must make publication and limit changes safe. If the proposed design requires every confirmation to synchronously consult Planning, or every release to update both services together, reconsider the split.
Make the recommendation revisitable
Architecture choices are made with incomplete information. For the current workshop feature, absent evidence of sustained independent-release or scaling pressure, a modular monolith is the lower-cost starting choice. That is a conditional recommendation, not a claim that services would always be wrong.
Keep the option to revisit it by making the internal boundary real: give Reservations a narrow public interface, keep its admission data under its control, and prevent Planning from reaching into its internals. Then watch for evidence that would change the decision: repeated release coordination, a measured scaling imbalance, or teams that can own and operate the components independently. Conversely, if a proposed service split creates frequent cross-service calls or shared writes, that is evidence against the split even if the code is neatly separated.
The key takeaway is that modularity and deployment solve related but different problems. Preserve the workshop invariant and clear decision ownership in either design. Choose additional services only when their independent deployment benefits outweigh their distribution and operational costs.
Next, you’ll move inside a boundary and model a business invariant with entities and value objects, introducing a domain service only when the behavior belongs to neither.