DEV Community

Cover image for Where Do You Draw the Lines Between Services? (Explained with Swiggy)
Vignesh Athiappan
Vignesh Athiappan

Posted on

Where Do You Draw the Lines Between Services? (Explained with Swiggy)

Splitting an app into microservices sounds easy — until you try it. Draw the boundaries wrong and you get a distributed mess that's harder to run than the monolith you started with. This post covers the 5 ideas that help you draw those lines well, using Swiggy.


The 5 ideas

# Concept One-line
1 DDD (bounded contexts) Split by business domain, not tech
2 Strangler Fig Safely kill a monolith piece by piece
3 Anti-Corruption Layer A translator guarding your clean model from a messy one
4 BFF (Backend-for-Frontend) A tailored backend per client (mobile vs web)
5 API Gateway One front door for all services

1. DDD — Bounded Contexts

The core skill: split services by business domain, not by technical layer.

The word "order" means different things in different parts of Swiggy. DDD says: let each area own its own meaning.

❌ Wrong split (by tech):   [All Controllers] [All Databases] [All Logic]
✅ Right split (by domain): [Ordering] [Delivery] [Payments] [Restaurant]
Enter fullscreen mode Exit fullscreen mode

A bounded context = a boundary where a word has ONE clear meaning.

Word In Ordering In Delivery
"Order" items + price + cart pickup + drop location + route

Same word, different meaning per context. Each context is a candidate microservice.

✅ Good ❌ Bad
Boundaries match the business Needs deep domain knowledge
Teams own a whole domain Over-splitting early = pain

Swiggy: Ordering, Delivery, Payments, Restaurant Onboarding, Search — each a bounded context, each a team.
The rule: find where the language changes → that's a boundary.


2. Strangler Fig

Kill a monolith gradually — never a risky big-bang rewrite.

Named after a vine that grows around a tree and slowly replaces it. You wrap the old system, peel off one feature at a time, until the monolith is gone.

Step 1: [Monolith] ← all traffic
Step 2: [Facade] → routes SEARCH to a new service, rest to monolith
Step 3: more features moved out...
Step 4: [Monolith gone] — all services new
Enter fullscreen mode Exit fullscreen mode
✅ Good ❌ Bad
Low risk, one piece at a time Slow, takes patience
Ship continuously Two systems run in parallel for a while
Roll back easily The facade adds complexity

Swiggy: moving from a 2014 monolith to microservices. You don't rewrite overnight; you strangle it feature by feature.
Azure: API Management as the facade — routes some paths to the old app, some to new services.


3. Anti-Corruption Layer (ACL)

A translator that stops a messy external system from polluting your clean model.

When you integrate with a third party (or a legacy system) whose data model is ugly, you don't let their mess leak into your code. You put a translation layer in between.

[Your clean Payment model] ← ACL translates → [Messy external bank API]
Enter fullscreen mode Exit fullscreen mode
✅ Good ❌ Bad
Your domain stays clean Extra layer to build/maintain
Swap the external system without touching your core Translation adds a little latency

Swiggy: integrating a payment gateway or a legacy restaurant POS that returns weird formats. The ACL converts their mess into your clean shape — the Order service never sees the ugliness.


4. BFF — Backend-for-Frontend

A separate, tailored backend for each type of client.

A mobile app and a web dashboard need different data shapes. Instead of one bloated API serving both badly, give each its own backend.

[Mobile App] → [Mobile BFF]  ─┐
[Web App]    → [Web BFF]      ─┼→ shared microservices
[Partner App]→ [Partner BFF] ─┘
Enter fullscreen mode Exit fullscreen mode
✅ Good ❌ Bad
Each client gets exactly what it needs More backends to maintain
Mobile gets light payloads Some logic duplicated
Change one client without breaking others

Swiggy: the customer app, the delivery-partner app, and the restaurant dashboard each hit their own BFF — mobile gets tiny payloads, the dashboard gets rich data. Same core services underneath.


5. API Gateway

One front door for all your services.

Clients don't call 20 services directly. They hit ONE gateway, which routes, secures, and manages everything.

Clients → [ API Gateway ] → [order] [payment] [search] [delivery]
Enter fullscreen mode Exit fullscreen mode

What it handles in one place:

Job Meaning
Routing Send each request to the right service
Auth Check tokens once, centrally
Rate limiting Stop abuse
SSL termination Handle HTTPS here
Aggregation Combine several service calls into one
✅ Good ❌ Bad
One place for cross-cutting concerns A single point of failure (must be highly available)
Clients don't know the internal layout Can become a bottleneck

Azure: this is API Management (APIM).


Gateway vs BFF (the confusion everyone has)

API Gateway BFF
How many? One for everyone One per client type
Job Route + secure + manage Shape data for a specific client
Analogy The building's main reception A personal assistant per VIP

They stack: clients → their BFF → the gateway → services. BFF shapes; gateway routes.


How it all fits together

[Mobile] → [Mobile BFF] ─┐
[Web]    → [Web BFF]     ─┼→ [API Gateway] → microservices split by [Bounded Contexts]
                                                    ↑
                          (Strangler Fig built these by peeling off the monolith)
                          (ACL guards each service from messy external systems)
Enter fullscreen mode Exit fullscreen mode

The whole thing in one line

Draw service boundaries where the business language changes (DDD), migrate to them safely (Strangler Fig), shield them from messy outsiders (ACL), give each client a tailored backend (BFF), and put one front door in front of it all (API Gateway). Get the lines right, and microservices actually pay off.

Top comments (0)