Episode 6 — Scaling Reliability Microservices Web3 / 6.1 — Microservice Foundations
6.1.b -- When Microservices Make Sense
Microservices are not a universal upgrade -- they are a trade-off. This section gives you a decision framework so you choose the right architecture for your context, not the trendy one.
Navigation << 6.1.a Monolithic vs Microservices | 6.1.b When Microservices Make Sense | 6.1.c Service Boundaries >>
1. The Microservices Premium
Every microservices architecture pays a tax -- an operational overhead that does not exist in monoliths. Before adopting microservices, you must be certain the benefits outweigh this premium.
1.1 What the Premium Includes
| Overhead Item | What It Costs You |
|---|---|
| Service discovery | Each service must find others dynamically (Consul, DNS, K8s services) |
| Distributed tracing | Debugging requires correlation IDs and tools like Jaeger or Datadog |
| Network reliability | Every call can fail; you need retries, timeouts, circuit breakers |
| Data consistency | No more ACID across services; you must implement sagas and eventual consistency |
| Deployment pipelines | N services means N CI/CD pipelines to maintain |
| Monitoring and alerting | N services means N dashboards, N sets of alerts, N log streams |
| Infrastructure | Container orchestration (Kubernetes), load balancers, service meshes |
| Testing complexity | Integration tests require all dependent services to be running or mocked |
| Security surface | Each service endpoint is an attack vector; mTLS, auth between services |
| Cognitive load | Developers must understand distributed systems concepts |
Monolith Complexity Microservices Complexity
+-------------------+ +-------------------+
| | | Network failures |
| Application logic | | Data consistency |
| | | Service discovery |
+-------------------+ | Deployment x N |
| Monitoring x N |
| Application logic |
+-------------------+
Total complexity is HIGHER with microservices.
The question is: do the benefits justify it?
2. Decision Framework
2.1 Team Size Thresholds
| Team Size | Recommended Architecture | Reasoning |
|---|---|---|
| 1-5 engineers | Monolith | A small team cannot absorb the operational overhead |
| 5-15 engineers | Modular monolith | Enforce boundaries inside a single deployable; extract if needed |
| 15-50 engineers | Selective microservices | Extract services where scaling or deployment independence is critical |
| 50+ engineers | Microservices | Independent teams need independent deployables to avoid coordination overhead |
Conway's Law: "Organizations design systems that mirror their communication structures." If you have 3 teams, you will naturally end up with ~3 services. Fight it and you lose.
2.2 Codebase Complexity Signals
Ask yourself these questions:
// Decision function (pseudo-code for your brain)
function shouldUseMicroservices(context) {
const signals = {
deploymentFrequency: context.deploysPerWeek,
teamSize: context.engineers,
codebaseAge: context.yearsInProduction,
scalingNeeds: context.trafficPatternIsUneven,
domainComplexity: context.distinctBusinessDomains,
teamAutonomy: context.teamsNeedIndependentReleases,
};
// Strong signals FOR microservices
const forMicroservices = [
signals.teamSize > 15,
signals.deploymentFrequency > 10, // per week
signals.scalingNeeds === true,
signals.domainComplexity > 4,
signals.teamAutonomy === true,
];
// Strong signals AGAINST microservices
const againstMicroservices = [
signals.teamSize < 5,
signals.codebaseAge < 1,
signals.deploymentFrequency < 3,
signals.domainComplexity < 3,
];
const forCount = forMicroservices.filter(Boolean).length;
const againstCount = againstMicroservices.filter(Boolean).length;
if (forCount >= 3) return 'MICROSERVICES';
if (againstCount >= 3) return 'MONOLITH';
return 'MODULAR_MONOLITH'; // the safe middle ground
}
2.3 The Decision Matrix
Rate each factor from 1 (low) to 5 (high):
| Factor | Score 1-2 (Monolith) | Score 3 (Modular Monolith) | Score 4-5 (Microservices) |
|---|---|---|---|
| Team size | < 8 | 8-20 | > 20 |
| Deploy frequency needed | Weekly | Daily | Multiple per day |
| Domain complexity | Single domain | 2-3 subdomains | 4+ distinct domains |
| Scaling variance | Uniform traffic | Some hot spots | Highly variable per feature |
| Uptime requirements | 99% | 99.9% | 99.99% (per service) |
| Technology diversity needs | Single stack | Minor variance | Different stacks per service |
| Regulatory / compliance boundaries | None | Some | Strong isolation required |
Scoring:
- Total 7-14: Start with a monolith.
- Total 15-21: Build a modular monolith; prepare to extract.
- Total 22-35: Microservices are justified.
3. When Microservices ADD Unnecessary Complexity
3.1 Small Teams (< 5 Engineers)
Developer 1: writes User Service, Order Service, deploys both,
monitors both, debugs distributed transactions,
maintains two CI/CD pipelines, handles service
discovery...
Developer 1: (also) builds features, fixes bugs, talks to
customers, and sleeps occasionally.
Result: Burnout. Slower development. More bugs.
A small team wearing microservices is like a solo hiker carrying a tent designed for 20 people.
3.2 Simple Domains
If your application has a single, well-understood domain (a blog, a portfolio, a simple CRUD app), microservices offer no benefit. There is nothing to decompose.
3.3 Early-Stage Startups
The first priority of a startup is finding product-market fit. That means:
- Rapid iteration
- Frequent pivots
- Throwing away code regularly
Microservices slow all of this down. You cannot pivot quickly when you need to update 5 services, 5 databases, and 5 deployment pipelines for a single feature change.
3.4 When You Do Not Have DevOps Maturity
Microservices require:
- Automated CI/CD
- Container orchestration (or equivalent)
- Centralised logging and monitoring
- Service discovery
- Automated testing infrastructure
If you do not have these, microservices will be a nightmare.
4. Warning Signs You NEED Microservices
| Signal | What It Looks Like |
|---|---|
| Deployment queue | Teams wait days to deploy because they share a release train |
| Merge conflict hell | Multiple teams constantly conflict in the same files |
| Scaling waste | You scale 10x for one hot endpoint, wasting resources on cold modules |
| Blast radius fear | A bug in payments crashes the entire system |
| Onboarding takes weeks | New engineers cannot understand the full codebase |
| Different scaling profiles | Chat needs WebSockets; billing needs batch processing; search needs Elasticsearch |
| Compliance boundaries | PCI-DSS requires payment data isolation; HIPAA requires health data isolation |
| Release bottleneck | One team's delay blocks all other teams |
4.1 Real Scenario: The Deploy Queue
Timeline of a monolith deploy at a 30-person company:
Monday: Team A merges feature. Wants to deploy.
Team B says "wait, we're not done testing."
Tuesday: Team B finishes. Team C says "we have a hotfix, let us go first."
Wednesday: All three teams merge. Deploy breaks -- Team A's code conflicts
with Team C's hotfix.
Thursday: Rollback. Debug. Fix.
Friday: Finally deploy. 4 days for a feature that was ready Monday.
With microservices:
Monday: Team A deploys their service. Done. 15 minutes.
Team B and C are unaffected.
5. Warning Signs You DO NOT Need Microservices
| Signal | What It Looks Like |
|---|---|
| "Everyone is doing it" | Following trends without evaluating fit |
| Resume-driven development | Choosing tech to pad resumes, not to solve problems |
| "We might need to scale" | Premature optimisation -- you are solving a problem you do not have |
| Team of 3 | Operational overhead will crush velocity |
| No CI/CD | You are adding distributed complexity to a system that cannot even auto-deploy a monolith |
| Single domain | Nothing to decompose |
| Tight deadlines | Microservices slow down initial development |
5.1 The YAGNI Principle
You Ain't Gonna Need It.
// What people imagine when starting with microservices:
//
// "In 2 years we'll have millions of users and 50 engineers!"
//
// What actually happens:
//
// Month 1: Spent setting up Kubernetes instead of building features.
// Month 3: Lost a customer because the competitor shipped faster.
// Month 6: Pivoted. Now 3 of your 5 services are irrelevant.
// Month 9: Back to a monolith. Lesson learned.
6. The Evolutionary Approach
The safest strategy is start simple, evolve when needed:
Stage 1: Monolith
- Ship fast
- Learn the domain
- Find product-market fit
Stage 2: Modular Monolith
- Enforce module boundaries
- Separate concerns with clear interfaces
- Prepare data models for eventual splitting
Stage 3: Selective Extraction
- Extract the module that has divergent scaling needs
- Extract the module that has the highest deployment frequency
- Keep everything else in the monolith
Stage 4: Full Microservices (if warranted)
- Only reached by large teams with complex domains
- Many successful companies never reach this stage
6.1 Code Example: Preparing for Extraction
Build your monolith so modules are extractable:
// BAD: Tight coupling -- Order module directly accesses User table
app.post('/orders', async (req, res) => {
const user = await pool.query('SELECT * FROM users WHERE id = $1', [req.body.userId]);
// ... creates order
});
// GOOD: Loose coupling -- Order module calls User module through an interface
// This interface can later become an HTTP call without changing the Order module.
class UserClient {
constructor(pool) {
this.pool = pool;
}
async getUser(id) {
const result = await this.pool.query('SELECT * FROM users WHERE id = $1', [id]);
return result.rows[0] || null;
}
}
// When you extract User Service, you swap the implementation:
class UserClient {
constructor(baseUrl) {
this.baseUrl = baseUrl;
}
async getUser(id) {
const res = await axios.get(`${this.baseUrl}/users/${id}`);
return res.data;
}
}
// The Order module's code does NOT change -- it still calls userClient.getUser(id).
7. Case Studies
7.1 Segment (Went Back to Monolith)
- Built microservices early with a small team.
- Overhead of maintaining 100+ services with 10 engineers was unsustainable.
- Consolidated back to a monolith. Development velocity tripled.
- Lesson: Microservices at the wrong scale actively harm you.
7.2 Shopify (Modular Monolith)
- One of the largest Rails applications in the world.
- Chose a modular monolith over microservices.
- Enforced strict module boundaries (no cross-module database access).
- Achieved independent team velocity without the distributed systems tax.
- Lesson: The modular monolith is a viable long-term architecture.
7.3 Uber (Scaled to Microservices)
- Started as a monolith.
- As the company scaled to thousands of engineers and dozens of products, the monolith became a bottleneck.
- Migrated to ~2,000 microservices.
- Built extensive internal tooling (service mesh, deployment platform, tracing).
- Lesson: At extreme scale with extreme resources, microservices are necessary.
8. The Cost-Benefit Checklist
Before committing to microservices, ensure you can answer "yes" to at least 4 of these:
[ ] We have 15+ engineers (or will within 6 months).
[ ] We deploy more than once per day (or need to).
[ ] Different parts of the system have different scaling needs.
[ ] Different teams need to deploy independently.
[ ] We have (or can build) CI/CD, monitoring, and orchestration infrastructure.
[ ] Our domain has 4+ clearly distinct business capabilities.
[ ] We have experienced distributed systems engineers on the team.
[ ] We have already hit concrete pain points with the monolith.
If you checked fewer than 4: stay with a monolith or modular monolith.
9. Key Takeaways
- Microservices are a trade-off, not an upgrade. They solve organisational and scaling problems at the cost of distributed systems complexity.
- The microservices premium is real. Service discovery, distributed tracing, data consistency, N pipelines -- this overhead does not vanish.
- Team size is the strongest signal. Small teams should not use microservices. Period.
- Start with a monolith. Even if you plan to use microservices eventually, starting with a monolith lets you learn the domain first.
- The modular monolith is underrated. It gives you boundary enforcement and team independence without the distributed systems tax.
- "We might need to scale" is not a reason. Solve problems you have, not problems you imagine.
- Going back is okay. Segment, SoundCloud, and others consolidated services. It is not a failure -- it is pragmatism.
- Prepare for extraction, do not extract prematurely. Build clean interfaces between modules so you can split when the time comes.
10. Explain-It Challenge
-
Your engineering manager reads a blog post about microservices and says "let's do it." Your team has 4 engineers, the product launched 3 months ago, and you have 500 users. Write the Slack message you would send explaining why this is premature.
-
Explain the "microservices premium" to a non-technical product manager. Use an analogy (e.g., restaurant kitchen, construction crew, etc.) to make it tangible.
-
A company has 25 engineers, deploys twice per week (wants daily), has 3 distinct business domains, and recently had an outage because a bug in the reporting module took down the checkout flow. Using the decision matrix from Section 2.3, score each factor and recommend an architecture.
Navigation << 6.1.a Monolithic vs Microservices | 6.1.b When Microservices Make Sense | 6.1.c Service Boundaries >>