Techies Journal
AboutContact

Techies Journal

A collection of technical essays on systems, backend architecture, and the craft of engineering.

Sections

  • Technology
  • System Design
  • Backend Engineering
  • Cloud & DevOps
  • AI & ML

Connect

  • About Me
  • Contact

Presence

© 2026 Techies Journal. Handcrafted for readability.

PrivacyTerms
System Architecture
2026-01-29

Microservices Didn't Make Us Faster — They Made Us Slower

RU
Rishabh UpadhyaySoftware Engineer & Designer

When Microservices Make You Slower

Microservices were supposed to make teams faster. For many teams, they did the opposite.

What started as a modern architectural upgrade quietly turned into an over-engineering trap.

This post explains what actually went wrong, why modular monoliths are winning again, and how to choose architecture based on reality—not trends.


TL;DR

  • Microservices increase operational complexity
  • Network calls add latency and new failure modes
  • Debugging becomes distributed and slower
  • Infrastructure and observability costs rise faster than business value
  • Modular monoliths deliver speed, clarity, and lower cost for most teams

The Promise of Microservices

Microservices promised:

  • Independent deployments
  • Team autonomy
  • Elastic scalability
  • Faster development

In theory, this works — at massive scale with strong platform capabilities and mature DevOps. Most teams don't operate there.


What Actually Happened

Teams adopting microservices encountered:

  • Kubernetes and container orchestration overhead
  • CI/CD pipelines per service
  • Service meshes, retries, timeouts, and circuit breaking
  • Distributed tracing to debug simple bugs
  • Network calls replacing in-process function calls

The system became harder to understand than the business logic.


The Hidden Cost: Operational Drag

Operational Complexity

Every microservice adds its own:

  • Build & test pipelines
  • Deployment units
  • Monitoring/alerting
  • Security policies & IAM
  • Versioning & backward compatibility

Complexity grows multiplicatively, not linearly.


Network Latency Everywhere

What used to be function calls becomes remote calls with:

  • Serialization/deserialization (JSON)
  • Network latency & TLS handshakes
  • Timeouts, retries, backoff
  • Partial failures & circuit breaking

Failures are now normal, not exceptional.

Code
// Modular monolith
const price = Pricing.calculate(items);

// Microservices
const price = await withTimeout(
 () => pricingService.calculate({ items }), 
 1000
);

Debugging Slows Down

A single user request may span:

  • Multiple services
  • Multiple databases
  • Queues, topics, and workers

Understanding behavior requires dashboards and traces, not just code & stack traces.


Infrastructure Cost Explosion

Each service consumes:

  • Compute & memory (including idle headroom)
  • Network egress
  • Observability (logs, traces, metrics)
  • Platform overhead (service mesh, gateways)

Cost often scales per service, not per feature.

Industry case studies (e.g., Prime Video) reported order-of-magnitude cost reductions when consolidating serverless microservices into a simpler, monolithic design.


Why Modular Monoliths Are Winning Again

A modular monolith is one deployable unit with strong internal boundaries (modules/packages) and clear ownership.

Benefits:

  • In-process calls (microseconds, not milliseconds)
  • Single deployment pipeline
  • Easier debugging with stack traces
  • Simpler data consistency guarantees
  • Faster iteration for most product teams

You keep modularity without paying network overhead.


Microservices vs Modular Monolith

| Dimension | Microservices | Modular Monolith | |---|---|---| | Communication | Remote network calls | In-process function calls | | Latency | Higher (ms + serialization) | Minimal (µs) | | Failure Modes | Cascading across services | Mostly local | | Debugging | Distributed tracing, dashboards | Stack traces, local logs | | Consistency | Sagas, outbox, eventual | ACID transactions | | Deployment | Many pipelines, versions | Single pipeline | | Infra Cost | Higher (per service tax) | Lower | | Best For | Org/scaling constraints | Dev speed & clarity |


Architecture Flow (High-Level)

Microservices Request Flow

Code
Client
 ↓ (HTTP, TLS, latency)
API Gateway / WAF
 ↓
Service A Service B Service C
 ↓    ↓    ↓
 DB A   DB B   DB C
 ↓
Response (after multiple hops)

Each arrow = network call + serialization + timeout + failure risk.


Modular Monolith Flow

Code
Client
 ↓ (HTTP)
Controller → Service Layer → Domain Module(s) → Database
 ↓
Response

Each arrow = an in-process function call (except HTTP and DB).


The Same Feature — Two Implementations

Microservices (Production-grade sketch)

Code
// order-service/createOrder.ts
import { withTimeout, retry, CircuitBreaker } from "./resilience";
import { authService, pricingService, paymentService } from "./clients";

const breaker = new CircuitBreaker({ failureThreshold: 5 });

export async function createOrder(reqBody: unknown) {
 const { token, items, idempotencyKey, currency } = validate(reqBody);

 // 1) AuthN/AuthZ
 const user = await withTimeout(
 () => retry(() => authService.verify(token), { retries: 2 }), 
 1200
 );

 // 2) Pricing
 const price = await withTimeout(
 () => retry(() => pricingService.calculate({ items, currency }), { retries: 2 }), 
 1000
 );

 // 3) Payment with circuit breaker
 const payment = await breaker.exec(() =>
 withTimeout(
  () => paymentService.charge({ 
  customerId: user.sub, 
  amount: price.total, 
  currency 
  }, { idempotencyKey }),
  1800
 )
 );

 // 4) Persist + publish event
 const order = await saveOrder({ userId: user.sub, amount: price.total, items });
 await publishEvent("order.created", { orderId: order.id, items });

 return { orderId: order.id };
}

Key points: timeouts/retries/circuit breaking, idempotency, event publication, structured logs.


Modular Monolith (Transaction-safe sketch)

Code
// app/order/createOrder.ts
import { db } from "../infra/db";
import { Outbox } from "../infra/outbox";
import { PaymentGateway } from "../payments/PaymentGateway";
import { Auth } from "../auth/Auth";

export async function createOrder(input: unknown) {
 const { userId, items, currency, idempotencyKey } = validate(input);

 Auth.ensureUserCanOrder(userId);
 const price = Pricing.calculate(items, currency);

 // First transaction: Check idempotency and create provisional order
 const provisional = await db.transaction(async (tx) => {
 const existing = await tx.order.findUnique({ where: { idempotencyKey } });
 if (existing) return existing;

 return await tx.order.create({
  data: { userId, amount: price.total, currency, status: "PAYMENT_PENDING", idempotencyKey },
 });
 });

 // If order already existed, return early
 if (provisional.status === "PAID") {
 return { orderId: provisional.id, reused: true };
 }

 // External side-effect (outside transaction)
 const payment = await PaymentGateway.charge({ 
 customerId: userId, 
 amount: price.total, 
 currency, 
 idempotencyKey 
 });

 // Second transaction: Update order and publish event
 await db.transaction(async (tx) => {
 await tx.order.update({ 
  where: { id: provisional.id }, 
  data: { status: "PAID", paymentId: payment.id } 
 });
 await Outbox.add(tx, "order.created", { orderId: provisional.id, items });
 });

 return { orderId: provisional.id };
}

Key points: single deployable unit, ACID transaction, DB-enforced idempotency, transactional outbox.


Production Checklist

  • [ ] Strict input validation (types + business invariants)
  • [ ] Authentication and authorization
  • [ ] Timeouts, retries, backoff, and circuit breakers
  • [ ] Idempotency keys stored & enforced server-side
  • [ ] Structured logging with correlation/trace IDs
  • [ ] Metrics & SLOs (latency, error rate, saturation)
  • [ ] Consistency strategy: Saga/Outbox (microservices) or ACID (monolith)
  • [ ] Transaction boundaries that exclude external side-effects
  • [ ] Cost awareness: per-service tax (compute, egress, observability)

Choosing Reality Over Hype

  • If you're < 10 teams or < a few dozen engineers, a modular monolith will usually get you faster feature velocity and lower cost.
  • Adopt microservices for organizational scaling (team autonomy, independent lifecycles) or hard technical constraints (heterogeneous runtimes, regional isolation, per-domain scaling).

** Start simple, modularize hard, and split services only when the seams are obvious.**


Final Takeaway

Microservices aren't inherently bad — but they're often premature optimization.

For most teams, a well-architected modular monolith delivers:

  • Faster iteration
  • Lower costs
  • Easier debugging
  • Simpler consistency

Simple beats clever until scale proves otherwise.


Related Topics

Want to dive deeper?

  • How to structure a modular monolith
  • When to actually split into microservices
  • Cost analysis: Monolith vs Microservices
  • Implementing transactional outbox patterns
Continue Reading
2026-01-27

How Google & Microsoft Authenticator Generate 6-Digit Codes Every 30 Seconds — Even Offline

A deep but simple explanation of how Google and Microsoft Authenticator generate time-based one-time passwords (TOTP) every 30 seconds without internet access.

2026-01-28

When You Send 'Hi' in a WhatsApp Group of 256 People — Does the Database Get Hit 256 Times?

Ever wondered what really happens under the hood when you send a message in a large WhatsApp group? This post breaks down how modern chat systems avoid database overload and scale to billions of messages.

2026-01-26

How Instagram Tells You a Username Is Taken in Under 100ms

A system design deep dive into how Instagram checks username availability instantly at massive scale using caching, normalization, and database constraints.

On This Page

  • When Microservices Make You Slower
  • TL;DR
  • The Promise of Microservices
  • What Actually Happened
  • The Hidden Cost: Operational Drag
  • Operational Complexity
  • Network Latency Everywhere
  • Debugging Slows Down
  • Infrastructure Cost Explosion
  • Why Modular Monoliths Are Winning Again
  • Benefits:
  • Microservices vs Modular Monolith
  • Architecture Flow (High-Level)
  • Microservices Request Flow
  • Modular Monolith Flow
  • The Same Feature — Two Implementations
  • Microservices (Production-grade sketch)
  • Modular Monolith (Transaction-safe sketch)
  • Production Checklist
  • Choosing Reality Over Hype
  • Final Takeaway
  • Related Topics

Share Perspective

TwitterLinkedInInstagram