Course → Module 1: Architectural Foundations & Core Concepts

Two Ways to Build Software

Every application starts as a single thing. One codebase, one deployment, one process. At some point, teams face a decision: keep it together or break it apart. This is the monolith-versus-microservices question, and it is one of the most consequential architectural decisions you will make.

The answer is rarely obvious, and the industry has swung between extremes. Understanding the real tradeoffs, not the marketing, is what matters.

The Monolith

A monolithic architecture deploys the entire application as a single unit. All modules, whether they handle user authentication, payment processing, notifications, or reporting, live in one codebase and run in one process (or a set of identical processes behind a load balancer).

Monolith: A software architecture where all components are packaged and deployed as a single unit. Function calls between modules happen in-process, not over the network.

Monoliths are not inherently bad. They have real structural advantages:

The problems emerge as the team and codebase grow. A change to the payment module requires redeploying the entire application. A memory leak in the reporting module crashes the authentication module. A team of 80 engineers stepping on each other in the same repository slows everyone down.

Microservices

A microservice architecture decomposes the application into small, independently deployable services. Each service owns a specific business capability, runs in its own process, and communicates with other services over the network (typically HTTP/REST or gRPC).

Microservices: An architectural style where the application is composed of loosely coupled, independently deployable services, each responsible for a specific business capability and maintaining its own data store.

graph TB subgraph Monolith M[Single Deployment Unit] M --- MA[Auth Module] M --- MB[Payment Module] M --- MC[Notification Module] M --- MD[Reporting Module] M --- DB1[(Single Database)] end
graph TB subgraph Microservices GW[API Gateway] GW --> SA[Auth Service] GW --> SB[Payment Service] GW --> SC[Notification Service] GW --> SD[Reporting Service] SA --- DB2[(Auth DB)] SB --- DB3[(Payment DB)] SC --- DB4[(Notif DB)] SD --- DB5[(Report DB)] end

The advantages are real but come with costs:

The costs:

Comparison Across Dimensions

Dimension Monolith Microservices
Deployment Single artifact, all-or-nothing Independent per service
Codebase One repository (usually) Many repositories or monorepo
Communication In-process function calls Network calls (HTTP, gRPC, messaging)
Data management Single shared database Database per service
Scaling Scale entire application Scale individual services
Debugging Single stack trace, single log Distributed tracing across services
Team structure Teams share one codebase Teams own individual services
Fault isolation One failure can crash everything Failures contained to one service
Time to first deploy Fast (minimal infrastructure) Slow (needs orchestration, CI/CD)

Conway's Law

In 1967, Melvin Conway observed that "any organization that designs a system will produce a design whose structure is a copy of the organization's communication structure." This observation, later named Conway's Law, explains why architecture decisions and team decisions are inseparable.

Conway's Law: The architecture of a system mirrors the communication structure of the organization that builds it. A company with four teams will produce a system with four major components, regardless of what the optimal architecture might be.

Conway's Law works in both directions. If you have a single team, a monolith is natural and effective. As Martin Fowler notes, "a dozen or two people can have deep and informal communications, so Conway's Law indicates they will create a monolith, and that is fine." If you have 15 teams and force them into one monolith, they will create implicit service boundaries anyway through code ownership conventions, module walls, and meeting schedules.

The Inverse Conway Maneuver deliberately structures teams to encourage the desired architecture. Want microservices? Create small, autonomous teams organized around business capabilities. Want a well-structured monolith? Keep the team small and communicating tightly.

When to Start With What

Martin Fowler's "Monolith First" argument is straightforward: almost all successful microservice stories started with a monolith that grew too big and was broken up. Almost all cases where systems were built as microservices from scratch ended up in serious trouble.

The reasoning is practical. Early in a product's life, you do not know where the real boundaries are. You do not know which features will matter, which will be thrown away, and where the load will concentrate. A monolith lets you discover these boundaries cheaply. Refactoring a function boundary inside a monolith is an afternoon of work. Redrawing a service boundary in a microservice system means migrating data, rewriting APIs, and coordinating multiple teams.

The signal that you might need to break apart is usually organizational, not technical. When the team is large enough that people are blocked by each other. When deployment frequency drops because too many changes are coupled. When a single module's scaling needs are dramatically different from the rest. These are structural pressures that microservices address.

The Modular Monolith: A Middle Path

A modular monolith maintains strict module boundaries inside a single deployment. Modules communicate through defined internal APIs, not by reaching into each other's database tables or internal classes. The code is structured as if it could be split into services, but it runs as one process.

This approach captures the deployment simplicity of a monolith while maintaining the clear boundaries that make a future migration to microservices feasible. Shopify famously operates a modular monolith that serves millions of merchants, demonstrating that you do not need microservices to reach enormous scale.

Further Reading

Assignment

This assignment has two parts.

Part 1: Write a 3-sentence argument FOR starting with a monolith for a new startup building a food delivery app. Address why a monolith is the right choice at this stage.

Part 2: Write a 3-sentence argument for WHEN to break the monolith apart. Identify the specific signals (team size, deployment pain, scaling bottlenecks) that would trigger the transition to microservices.

In both parts, reference Conway's Law. How does the team's current structure support your recommendation?