Microservices Introduction
Understand microservices architecture - when to use it, trade-offs, and how it compares to monoliths.
What are Microservices?#
Microservices is an architectural style where an application is built as a collection of small, independent services that:
- Run in their own process
- Communicate over the network (HTTP, gRPC, messages)
- Can be deployed independently
- Can use different technologies
┌─────────────────────────────────────────────────────────────────┐
│ MONOLITH │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Users │ Products │ Orders │ Payments │ Notifications │ │
│ │ │ │ │ │ │ │
│ │ Single Codebase │ │
│ │ Single Database │ │
│ │ Single Deployment │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
vs
┌─────────────────────────────────────────────────────────────────┐
│ MICROSERVICES │
│ │
│ ┌─────────┐ ┌──────────┐ ┌────────┐ ┌──────────┐ │
│ │ Users │ │ Products │ │ Orders │ │ Payments │ ... │
│ │ API │ │ API │ │ API │ │ API │ │
│ │ DB │ │ DB │ │ DB │ │ DB │ │
│ └─────────┘ └──────────┘ └────────┘ └──────────┘ │
│ │ │ │ │ │
│ └────────────┴────────────┴────────────┘ │
│ Network Communication │
└─────────────────────────────────────────────────────────────────┘
Monolith vs Microservices#
Monolith Architecture#
Everything in one application:
// One codebase handles everything
const app = express();
// User routes
app.use('/api/users', userRoutes);
// Product routes
app.use('/api/products', productRoutes);
// Order routes
app.use('/api/orders', orderRoutes);
// Payment routes
app.use('/api/payments', paymentRoutes);
// Single database
mongoose.connect('mongodb://localhost/myapp');
app.listen(3000);
Pros:
- Simple to develop and deploy
- Easy to debug (one codebase)
- No network latency between components
- Easier data consistency (single database)
- Good for small teams and MVPs
Cons:
- Harder to scale specific parts
- One failure can crash everything
- Harder to adopt new technologies
- Deployment requires full redeployment
- Code can become tangled over time
Microservices Architecture#
Separate services for each domain:
// User Service (port 3001)
const userApp = express();
userApp.use('/api/users', userRoutes);
mongoose.connect('mongodb://localhost/users');
userApp.listen(3001);
// Product Service (port 3002)
const productApp = express();
productApp.use('/api/products', productRoutes);
mongoose.connect('mongodb://localhost/products');
productApp.listen(3002);
// Order Service (port 3003)
const orderApp = express();
orderApp.use('/api/orders', orderRoutes);
// Calls User Service and Product Service
orderApp.listen(3003);
Pros:
- Scale individual services
- Independent deployments
- Technology flexibility per service
- Fault isolation (one service fails, others work)
- Teams can work independently
Cons:
- Network complexity and latency
- Distributed system challenges
- Data consistency is harder
- More infrastructure to manage
- Debugging across services is harder
When to Use Each#
The Rule of Thumb
Start with a monolith unless you have a specific reason for microservices.
Most applications don't need microservices. They add complexity that may not be worth it for your use case.
Use a Monolith When:#
- Starting a new project - Get to market faster
- Small team (< 10 developers) - Less coordination overhead
- Unclear domain boundaries - Refactor is easier in one codebase
- Limited DevOps resources - Simpler infrastructure
- Tight deadlines - Less complexity to manage
Use Microservices When:#
- Large teams (50+ developers) - Teams can work independently
- High scale requirements - Need to scale parts differently
- Different scaling patterns - Payment processing vs user browsing
- Technology requirements - Part needs Python ML, part needs Node.js
- Independent deployment needs - Ship features without affecting others
- Clear domain boundaries - Well-understood business domains
Real-World Examples#
Monolith Success Stories#
- Shopify - Started as a monolith, handles billions in transactions
- Basecamp - Runs entirely as a monolith
- Stack Overflow - Monolith serving millions of developers
Microservices Success Stories#
- Netflix - Hundreds of services for streaming
- Amazon - Thousands of services for e-commerce
- Uber - Microservices for global ride-sharing
Warning
Netflix and Amazon built microservices because they HAD to at their scale. They didn't start with microservices. Don't adopt microservices just because big companies use them.
The Middle Ground: Modular Monolith#
A well-structured monolith with clear boundaries:
my-app/
├── src/
│ ├── modules/
│ │ ├── users/ # User module (own controllers, services, models)
│ │ │ ├── controllers/
│ │ │ ├── services/
│ │ │ ├── models/
│ │ │ └── index.js # Module public API
│ │ ├── products/ # Product module
│ │ ├── orders/ # Order module
│ │ └── payments/ # Payment module
│ ├── shared/ # Shared utilities
│ └── index.js # Main entry
// modules/users/index.js - Module public API
export { UserService } from './services/userService.js';
export { User } from './models/User.js';
// modules/orders/services/orderService.js
// Import from other modules through their public API
import { UserService } from '../users/index.js';
import { ProductService } from '../products/index.js';
export class OrderService {
async createOrder(userId, productIds) {
const user = await UserService.findById(userId);
const products = await ProductService.findByIds(productIds);
// ...
}
}
Benefits:
- Monolith simplicity
- Clear boundaries (easy to extract to microservices later)
- Teams can own modules
- Single deployment, single database
- Can evolve to microservices when needed
Extracting to Microservices#
When you're ready, extract one module at a time:
Phase 1: Modular Monolith
┌──────────────────────────────┐
│ Users │ Products │ Orders │ ← Single app
└──────────────────────────────┘
Phase 2: Extract High-Traffic Service
┌──────────────────────┐ ┌───────────┐
│ Users │ Orders │ ←→ │ Products │ ← Separate service
└──────────────────────┘ └───────────┘
Phase 3: Continue Extracting
┌─────────┐ ┌──────────┐ ┌────────┐
│ Users │ │ Products │ │ Orders │ ← All separate
└─────────┘ └──────────┘ └────────┘
Key Challenges of Microservices#
1. Service Communication#
- How do services talk to each other?
- Synchronous (HTTP/gRPC) vs Asynchronous (message queues)
2. Data Consistency#
- Each service has its own database
- Transactions across services are hard
- Eventual consistency vs strong consistency
3. Service Discovery#
- How does Order service find User service?
- What if User service moves to a different server?
4. Distributed Tracing#
- Request spans multiple services
- How do you debug when something fails?
5. Deployment Complexity#
- Many services to deploy and monitor
- Need container orchestration (Kubernetes)
- CI/CD for each service
Key Takeaways#
- Start with a monolith - Extract to microservices when needed
- Build a modular monolith - Clear boundaries make future extraction easier
- Microservices add complexity - Only adopt when benefits outweigh costs
- Scale isn't the only reason - Team independence, technology flexibility matter too
- Don't follow the hype - What works for Netflix may not work for you
Ready to level up your skills?
Explore more guides and tutorials to deepen your understanding and become a better developer.