Microservices Done Right: Understanding Service Boundaries
Microservices are easy to draw on a whiteboard.
Boxes.
Arrows.
APIs everywhere.
But scoping microservices correctly is one of the hardest engineering problems — and most teams get it wrong the first time.
Microservices fail not because of technology, but because of poor boundaries.
Let’s understand how to draw those boundaries correctly, using loose coupling and high cohesion — not as buzzwords, but as engineering principles.
Start With a Simple System (Again)
Imagine you’re building an online learning platform.
Basic features:
- User registration
- Courses
- Enrollments
- Payments
- Certificates
At first, everything lives in a monolith.
Life is good.
Then scale happens.
Now multiple teams are involved:
- One team works on payments
- One on courses
- One on analytics
- One on certificates
You decide: “Let’s move to microservices.”
But the real question is:
How do we decide what becomes a service?
The Biggest Mistake: Splitting by Technical Layers
Many beginners do this:
- UserControllerService
- UserRepositoryService
- PaymentControllerService
- PaymentRepositoryService
This looks “clean” on paper.
But it violates high cohesion.
Why?
Because a service should represent a business capability, not a technical layer.
If one user flow requires:
- 3 services
- 5 network calls
- 2 databases
You’ve just converted method calls into network calls.
And network calls are:
- Slower
- Unreliable
- Harder to debug
This is accidental complexity.
High Cohesion: Keep Related Things Together
High cohesion means:
Things that change together should live together.
Let’s apply this.
In our learning platform:
- Course creation
- Course updates
- Course visibility
- Course pricing
These almost always change together.
So instead of breaking them apart, you group them into:
👉 Course Service
This service:
- Owns course data
- Owns course rules
- Owns course APIs
Anyone who wants course information must talk to this service.
This reduces confusion and duplication.
Loose Coupling: Reduce Dependency Between Services
Now imagine enrollment.
Enrollment needs:
- User info
- Course info
- Payment confirmation
A tightly coupled system would:
- Directly query user DB
- Directly query course DB
- Directly depend on payment internals
This is dangerous.
Instead, loose coupling means:
- Each service exposes clear contracts
- Services interact via APIs or events
- Internal changes don’t break others
Enrollment service doesn’t care how payment works — only whether payment succeeded.
Get Arpit Srivastav’s stories in your inbox
Join Medium for free to get updates from this writer.
That’s loose coupling.
A Realistic Example: Order & Payment
Let’s simplify with a classic example.
Bad Scoping:
- Order Service calls Payment DB directly
- Payment logic leaks into Order Service
- Any payment change breaks orders
This means:
- Tight coupling
- Low cohesion
- Fear-driven development
Correct Scoping:
- Order Service creates an order
- Payment Service handles money
- Order Service listens for PaymentSuccess event
Now:
- Payment team can change internals freely
- Order team only reacts to events
- Failure is isolated
This is loose coupling in action.
Ownership Is a Hidden Signal
If you can’t clearly assign ownership, your service boundary is wrong.
A good microservice:
- Has one owning team
- Has clear responsibility
- Has clear APIs
If two teams constantly argue:
- “Who owns this logic?”
- “Who should fix this bug?”
Your service boundary is leaking.
Databases: The Silent Boundary Breaker
Another common mistake:
“Let’s have multiple services share the same database.”
This completely breaks microservices.
Why?
Because database sharing:
- Couples services tightly
- Exposes internal schemas
- Makes independent deployment impossible
Correct approach:
- One service → one database
- Communication only via APIs/events
Yes, it’s harder.
But correctness often is.
Think in Terms of Change, Not Features
A powerful way to scope services is to ask:
- What changes frequently?
- What changes independently?
- What changes for different reasons?
If certificates logic changes due to compliance,
and course logic changes due to product decisions —
they shouldn’t be in the same service.
This mindset comes directly from high cohesion.
A Rule of Thumb That Actually Works
Before creating a microservice, ask:
- Can this be owned by one team?
- Can it evolve independently?
- Does it represent a business capability?
- Does it reduce coordination overhead?
If the answer is “no” to most of these —
don’t create a service yet.
Why This Matters for Students & Interviews
In system design interviews, interviewers aren’t impressed by:
- Number of services
- Fancy tools
- Complex diagrams
They look for:
- Reasoning
- Trade-offs
- Boundary decisions
If you say:
“I grouped these together because they change together”
You sound like a senior engineer, not a tutorial follower.
Final Takeaway
Microservices are not about:
- Splitting code
- Writing APIs
- Using containers
They are about:
- Drawing boundaries responsibly
- Reducing cognitive load
- Allowing teams to move independently
Loose coupling and high cohesion are not academic terms.
They are survival principles for large systems.
And once you understand them deeply,
you stop asking:
“How many microservices should I create?”
You start asking:
“Where should responsibility live?”
If You Enjoyed This Story
If you found this article useful, a like or share would mean a lot! ❤️
I’d love to hear your thoughts, questions, or experiences with building resilient, large-scale systems — drop them in the comments below!
Got a topic in mind — whether it’s replication, failover, database architecture, event driven architecture, scaling or another engineering challenge?
Let me know, and I’ll dive into it in my next story. 🚀










