Production Engineering/
Lesson

The monolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices.-vs-microservicesWhat is microservices?An architecture where an application is split into small, independently deployed services that communicate over the network, each owning its own data. debate is one of the most heated in software. You'll find engineers who swear by one and dismiss the other. The truth is neither is universally better, it depends entirely on where you are in your product's life. This lesson gives you the map to make that call yourself.

What a monolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices. looks like

A monolith puts everything, auth, users, products, orders, payments, into a single codebase that deploys as one unit. When you push code, the entire application updates at once.

MyApp/
  src/
    auth/
    users/
    products/
    orders/
    payments/

One build → One deployment → One running process

Services talk to each other through direct function calls. No network involved. Simple.

02

What microservicesWhat is microservices?An architecture where an application is split into small, independently deployed services that communicate over the network, each owning its own data. look like

Microservices split the application into small, independently deployed services. Each service owns its own database and communicates with others over HTTPWhat is http?The protocol browsers and servers use to exchange web pages, API data, and other resources, defining how requests and responses are formatted. or a message queue.

auth-service/        → runs on port 3001
user-service/        → runs on port 3002
product-service/     → runs on port 3003
order-service/       → runs on port 3004
payment-service/     → runs on port 3005

What was a function call in the monolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices. becomes a network request in microservices, with all the complexity that implies.

03

Side-by-side comparison

AspectMonolithMicroservices
Setup complexityLowHigh
Development speedFaster early onSlower initially
DeploymentAll at onceIndependent per service
ScalingScale everythingScale only what needs it
DebuggingOne place to lookTrace across services
Team fitSmall to mediumLarge, multi-team
TestingRun one appNeed multiple services running
Tech stackUnifiedMix and match per service
DataShared databaseDatabase per service
04

Communication: the key difference

This is where the trade-off becomes concrete. In a monolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices., calling another moduleWhat is module?A self-contained file of code with its own scope that explicitly exports values for other files to import, preventing name collisions. is just a function call. In microservicesWhat is microservices?An architecture where an application is split into small, independently deployed services that communicate over the network, each owning its own data., it's a network request that can fail, time out, or return unexpected data.

// Monolith: simple, fast, reliable
async function createOrder(userId, items) {
  const user = getUserById(userId);       // function call
  const total = calculateTotal(items);    // function call
  processPayment(user, total);            // function call
  sendConfirmation(user.email);           // function call
}

// Microservices: flexible, but more failure surfaces
async function createOrder(userId, items) {
  const user = await fetch(`http://user-service/users/${userId}`);
  const total = await fetch('http://product-service/calculate', { items });
  await fetch('http://payment-service/charge', { user, total });
  await fetch('http://email-service/send', { email: user.email });
  // Any of these can fail or be slow
}
With microservices you need to handle partial failures, retries, timeouts, and circuit breakers. This is real engineering work that adds weeks to any feature.
05

When to choose a monolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices.

Start with a monolith when you have a small team (under 10 developers), an unproven product, a tight timeline, or when your domain is not yet well understood. Almost all successful products started here.

06

When microservicesWhat is microservices?An architecture where an application is split into small, independently deployed services that communicate over the network, each owning its own data. make sense

Consider splitting services when you have large teams that step on each other's deployments, parts of the system with very different scaling needs (a video encoding job shouldn't compete with your login APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses.), or when different features genuinely need different technology.

07

The typical migrationWhat is migration?A versioned script that changes your database structure (add a column, create a table) so every developer and server stays in sync. path

1. Build a modular monolith (clear internal boundaries)
2. Grow until you feel real pain - slow deploys, team conflicts, scaling bottlenecks
3. Extract one service (auth and payments are common first candidates)
4. Learn from that extraction
5. Repeat only where justified

Netflix has over 500 services. They started as a DVD-by-mail monolithWhat is monolith?A software architecture where the entire application lives in a single codebase and deploys as one unit. Simpler to build and debug than microservices.. They did not redesign everything on day one.

Shared databases in a microservices setup defeat the entire purpose. If two services share a database, they are still tightly coupled, you get the complexity of microservices with none of the independence benefits.
08

Quick reference

SignalRecommendation
Team < 10, early productStart with monolith
Team > 20, multiple squadsEvaluate microservices
Uniform trafficMonolith fine
Spiky, uneven load by featureMicroservices help
Low DevOps maturityStay with monolith
Weekly releasesMonolith is fine
Multiple daily deploysMicroservices unlock independence
javascript
// Example: Monolith vs Microservices

// MONOLITH APPROACH
// app.js, Everything in one application
const express = require('express');
const app = express();

// All services in one app
const authService = require('./services/auth');
const userService = require('./services/users');
const orderService = require('./services/orders');

app.post('/orders', async (req, res) => {
  // Direct function calls (fast, simple)
  const user = await userService.getUser(req.userId);
  const order = await orderService.createOrder(req.body);
  await authService.logActivity(user, 'order_created');

  res.json(order);
});

app.listen(3000);

// ---

// MICROSERVICES APPROACH
// order-service/app.js
const express = require('express');
const axios = require('axios');
const app = express();

app.post('/orders', async (req, res) => {
  try {
    // HTTP calls to other services (slower, more complex)
    const user = await axios.get(`http://user-service:3001/users/${req.userId}`);
    const order = await createOrder(req.body);
    await axios.post('http://auth-service:3002/activity', {
      userId: user.id,
      action: 'order_created'
    });

    res.json(order);
  } catch (error) {
    // Network failures, timeouts, etc.
    console.error('Service call failed:', error);
    res.status(500).json({ error: 'Service unavailable' });
  }
});

app.listen(3003);

// user-service/app.js (separate application)
const express = require('express');
const app = express();

app.get('/users/:id', async (req, res) => {
  const user = await database.users.findById(req.params.id);
  res.json(user);
});

app.listen(3001);

// auth-service/app.js (separate application)
const express = require('express');
const app = express();

app.post('/activity', async (req, res) => {
  await database.activity.insert(req.body);
  res.json({ success: true });
});

app.listen(3002);

// docker-compose.yml (needed for microservices)
version: '3'
services:
  user-service:
    build: ./user-service
    ports:
      - "3001:3001"

  auth-service:
    build: ./auth-service
    ports:
      - "3002:3002"

  order-service:
    build: ./order-service
    ports:
      - "3003:3003"