Loading learning content...
You've learned about monoliths, microservices, and modular monoliths. You understand their characteristics, benefits, challenges, and evolution paths. Now comes the critical question: Which architecture is right for your situation?
This isn't a question with a universal answer. The right architecture depends on your organization, your product, your team, your scale, and your constraints. What works for Netflix doesn't work for a 10-person startup. What works for a startup finding product-market fit doesn't work for an enterprise with 500 developers.
This page provides a decision framework—a structured approach to evaluating your context and making an informed architectural choice. This isn't a flowchart that produces 'the answer'; it's a thinking tool that helps you weigh factors and make defensible decisions.
By the end of this page, you will have a systematic framework for evaluating architectural options, understand the key decision factors, be able to match architectures to organizational contexts, know how to present and defend architectural decisions, and recognize when to revisit decisions.
Architectural decisions should be made systematically, considering multiple factors. Here's a framework that organizes the key dimensions:
| Dimension | Key Questions | Why It Matters |
|---|---|---|
| Team Size & Structure | How many developers? How are they organized? What's their operational maturity? | Microservices require critical mass; small teams can't staff autonomous services |
| Domain Understanding | How well do you understand the business domain? Are boundaries clear? | Wrong service boundaries are expensive; discover boundaries before committing |
| Scale Requirements | What's current traffic? What's projected? Are there differential scaling needs? | Microservices shine when components have vastly different scaling needs |
| Deployment Velocity | How often do you need to deploy? Is monolith deployment a bottleneck? | If deployment speed is critical and blocked by monolith testing, extraction helps |
| Fault Isolation Needs | Can features fail independently? Is partial availability acceptable? | Microservices enable subset failures; monoliths are all-or-nothing |
| Technology Requirements | Do different components need different tech stacks? | Polyglot needs favor microservices; uniform stacks favor monoliths |
| Operational Capability | Do you have DevOps maturity, observability, and on-call culture? | Microservices require operational sophistication that many teams lack |
| Time to Market | How quickly must you ship? Is speed or architecture the priority? | Monoliths ship faster initially; over-engineering slows time to market |
The Core Principle:
Choose the simplest architecture that solves your current problems while remaining evolvable.
This principle has two implications:
Don't solve imaginary problems — If you don't have scaling problems, don't architect for scale you might never reach. If teams aren't blocked, don't add independence overhead.
Don't paint yourself into a corner — Build in a way that evolution is possible. A well-structured monolith can evolve; a poorly structured one traps you.
The default should be the simplest option (monolith or modular monolith). The burden of proof is on complexity. You should be able to articulate specific, current problems that justify microservices—not future hypotheticals or industry trends.
Team size is one of the strongest predictors of appropriate architecture. Microservices require enough people to staff autonomous teams. Without this, you're adding complexity without gaining independence.
| Team Size | Recommended Architecture | Rationale |
|---|---|---|
| 1-5 developers | Simple monolith | Too small for even modular overhead; focus on shipping |
| 5-15 developers | Structured or modular monolith | Large enough for structure; too small for service teams |
| 15-50 developers | Modular monolith, possibly selective extraction | Team coordination becomes an issue; modules help |
| 50-200 developers | Microservices or hybrid | Multiple autonomous teams viable; independence needed |
| 200+ developers | Microservices with platform team | Full organizational independence; sophisticated ops |
Team Structure Matters:
Beyond size, how teams are organized affects architectural fit:
Functional Teams (frontend, backend, DBA, QA) — Favor monoliths. Cross-functional services require cross-team coordination for every change.
Feature Teams (team owns a feature end-to-end) — Can work with modular monoliths. Each team owns modules; coordination happens through APIs.
Product Teams (team owns a product area completely) — Fit for microservices. Teams can own services, make technology choices, and deploy independently.
Conway's Law Applies:
"Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations."
If your teams communicate constantly, your services will be tightly coupled. If you want loosely coupled services, you need loosely coupled teams. Architecture follows organization.
A service needs at least 2-3 people for sustainable ownership (vacations, sick days, attrition). If you have 10 developers and want 10 services, you can't sustainably own them. This is a common failure mode—services become orphaned and unmaintained.
Wrong service boundaries are extremely expensive to fix. In a monolith, refactoring boundaries is a code change. In microservices, wrong boundaries require re-architecting infrastructure, migrating data, and renegotiating team responsibilities.
Your understanding of the domain directly impacts your ability to draw correct boundaries.
| Domain Understanding | Boundary Confidence | Recommended Approach |
|---|---|---|
| Low (early startup, new product) | Low | Monolith—boundaries will change with learning |
| Moderate (established product, some stability) | Moderate | Modular monolith—define boundaries but keep them flexible |
| High (mature domain, stable requirements) | High | Microservices viable—boundaries are proven |
Signs of Low Domain Understanding:
Signs of High Domain Understanding:
Martin Fowler's 'Monolith First' principle: Start with a well-structured monolith. Discover boundaries through operation. Extract to services only when you have both the scaling need AND the boundary understanding. This is the safest path for most organizations.
Scale requirements affect architecture choice, but not as simply as 'big = microservices.' What matters is differential scaling needs—whether different parts of your system have vastly different capacity requirements.
| Scale Pattern | Example | Architecture Implication |
|---|---|---|
| Uniform scale | All features get proportionally more traffic | Monolith can scale horizontally |
| Differential scale (moderate) | Search is 3x other features | Caching, optimization; likely still monolith |
| Differential scale (extreme) | Events ingestion is 100x API traffic | Extract high-scale component |
| Burst traffic | Black Friday 10x normal | Auto-scaling; architecture less relevant |
| Mixed workloads | Real-time + batch in same system | Consider extraction for workload isolation |
When Scale Justifies Extraction:
Extreme Differential — If one component genuinely needs 10-100x the capacity of others—not a hypothetical, but an actual measured need—extraction saves significant infrastructure cost.
Different Resource Profiles — One component is CPU-bound, another is memory-bound, another is I/O-bound. Optimal hardware differs.
Database Bottleneck — A single database can't handle the load. You need to partition, and the partition aligns with a service boundary.
Different Availability Requirements — Some features can tolerate occasional downtime; others are revenue-critical and need maximum availability.
When Scale Doesn't Justify Extraction:
Many massive-scale systems run on monoliths. Stack Overflow handles 1.3B page views/month with a monolith. Shopify handles enormous e-commerce traffic. Scale alone doesn't mandate microservices. Differential scaling and organizational needs together drive the decision.
Microservices require operational sophistication that many organizations lack. Without it, microservices become operational chaos. This factor is often underweighted in architecture decisions.
| Level | Characteristics | Architecture Fit |
|---|---|---|
| Basic | Manual deployments, basic monitoring, no on-call | Simple monolith only |
| Developing | CI/CD exists, APM tools, informal on-call | Structured monolith |
| Established | Automated deployment, logging, metrics, formal on-call | Modular monolith, selective extraction |
| Advanced | Full observability, self-healing, incident management | Microservices viable |
| Elite | Platform team, everything automated, chaos engineering | Full microservices at scale |
The Operational Cost Reality:
Microservices create operational load that compounds:
Without sophisticated tooling and processes, this operational load overwhelms teams.
Adopting microservices without operational capability is the most common cause of microservices failures. Teams deploy services, can't effectively monitor or debug them, incidents take days to resolve, and the architecture is blamed. The architecture wasn't wrong—the operational foundation was missing.
Combining all factors, here's a comprehensive decision matrix. For each factor, assess your situation and see which architecture pattern fits best.
| Factor | Favors Monolith | Favors Modular Monolith | Favors Microservices |
|---|---|---|---|
| Team size | < 15 developers | 15-50 developers | 50 developers |
| Team structure | Functional teams | Feature teams | Product teams |
| Domain understanding | Still learning | Mostly stable | Mature and stable |
| Scaling needs | Uniform traffic | Moderate differential | Extreme differential (10x+) |
| Deployment frequency | Weekly or less | Daily | Multiple times daily per component |
| Fault isolation | All-or-nothing OK | Some isolation desired | Independent failures required |
| Technology needs | Single stack | Mostly single stack | Genuine polyglot requirements |
| Operational maturity | Basic/Developing | Established | Advanced/Elite |
| Time to market | Maximum speed needed | Speed with structure | Speed through independence |
How to Use This Matrix:
Assess Each Factor — For each row, determine which column best describes your situation.
Count the Columns — Which architecture gets the most tallies?
Weight Critical Factors — Some factors may be decisive in your context. Operational maturity, for example, is often a hard constraint.
Consider Trajectory — Where will you be in 18 months? If you're 10 developers growing to 50, plan for future state.
Beware Single-Factor Decisions — If only one factor points to microservices (e.g., 'we need polyglot'), question whether that's enough to justify the overhead.
Be brutally honest when assessing your situation. 'We'll grow to 100 developers' isn't the same as having 100 developers. 'We'll need 100x scale' isn't the same as actually having 100x traffic. Decide based on current reality, not optimistic projections.
Architecture decisions must be communicated and defended to stakeholders—leadership, peers, and future team members. Here's how to structure that communication.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
# ADR-001: Modular Monolith for Order Management System ## StatusAccepted (2024-01-15) ## ContextWe're building a new Order Management System to replace our legacy system.- Team: 20 developers, growing to 35 over 18 months- Scale: ~100K orders/day, projecting 500K in 2 years- Timeline: MVP in 6 months, full feature parity in 12 months ## Decision Drivers- Time to market is critical (competitor launching)- Team has limited microservices operational experience - Domain boundaries are understood from legacy system- Scaling is uniform across features currently ## Options Considered1. **Traditional Monolith** - Fastest initially, but tangling risk2. **Modular Monolith** - Structured, evolvable, deployment simplicity3. **Microservices** - Independent deployment, but operational overhead ## DecisionWe will build a **modular monolith** with clear bounded contexts:- Order Management module- Inventory module - Customer module- Notification module ## Rationale- Team size (20) doesn't support 4+ autonomous service teams- Operational maturity is "Developing"—not ready for microservices ops- Domain boundaries are known from legacy; can encode in modules- Time to market is critical; monolith deployment is simpler ## Trade-offs Accepted- Cannot scale modules independently (accepted: uniform traffic pattern)- Single failure domain (accepted: designing for resilience within)- Technology uniformity (accepted: no polyglot requirements) ## Consequences- Modules must have enforced boundaries (ArchUnit tests)- Database schemas partitioned by module ownership- CI/CD for single deployment artifact- Module extraction path documented for future scale needs ## Review Triggers- Team exceeds 50 developers- Differential scaling need exceeds 10x between modules- Deployment coordination becomes significant bottleneck- Database becomes scaling bottleneckHandling Pushback:
You will face pushback. Here are common objections and responses:
"Netflix/Uber/Google uses microservices"
They have thousands of engineers and dedicated platform teams. We have 20 people. Their solution doesn't fit our context.
"Monoliths don't scale"
Stack Overflow serves 1.3B monthly views on a monolith. Shopify processes billions in transactions. Scale is about optimization, not architecture.
"We'll be stuck with old technology"
A modular monolith can evolve. When we need extraction, boundaries are already defined. We're not preventing future evolution.
"Microservices are the modern approach"
Architecture should solve problems, not follow trends. What specific problem would microservices solve that we can't address with our chosen approach?
The best defense of an architecture decision is specificity. Vague statements like 'we need flexibility' are easily contested. Specific statements like 'with 20 developers and developing operational maturity, we cannot sustainably staff autonomous service teams' are harder to argue with.
Architecture decisions aren't permanent. Conditions change, and decisions should be revisited when the context that informed them shifts.
Building in Review Cadence:
Don't wait for crisis. Schedule periodic architecture reviews:
Quarterly Architecture Check-In — Is the current architecture serving us? Any emerging pain points?
Annual Architecture Review — Deep dive. Revisit the original decision. Has context changed?
Trigger-Based Reviews — When specific thresholds are crossed (team size, traffic, deployment frequency), automatically review.
The Reversibility Principle:
Remember that moving toward complexity is hard to reverse. Extracting services is straightforward (if boundaries are defined). Re-consolidating services into a monolith is very difficult. This asymmetry should bias you toward waiting until evolution is clearly needed.
A good architecture decision made 3 years ago may no longer be good. This doesn't mean it was wrong—it means conditions changed. The mark of a mature organization is regularly revisiting decisions in light of new information, without blame for past choices made with past information.
We've established a comprehensive framework for making architectural decisions—not based on trends or idealism, but on the specifics of your situation.
The Final Word:
There is no universally 'best' architecture. There is only the architecture that best fits your context—your team, your product, your constraints, your goals. The framework and principles in this module enable you to make that choice deliberately, defend it rationally, and evolve it as conditions change.
The best architects aren't those who know the most patterns or follow the latest trends. They're those who understand context deeply, make informed trade-offs, and adapt as they learn. With the knowledge from this module, you're equipped to do exactly that.
You've completed the comprehensive module on Monolith vs Microservices vs Modular Monolith. You understand each architecture's characteristics, benefits, and challenges. You can evaluate evolution paths and apply a decision framework to choose the right architecture for any context. This knowledge is foundational to system design at scale.