"A well-designed system isn't just about having the right classes. It's about how those classes collaborate to accomplish real work."
In the previous article, we learned how Class Diagrams help us model the structure of a system.
They answer questions like:
- What objects exist?
- What responsibilities do they own?
- How are they related?
But they leave one important question unanswered.
What actually happens when a user clicks a button?
Knowing that a Customer, Order, and Payment class exist doesn't explain how an order gets placed.
Who creates the order?
Who validates the payment?
Who updates the inventory?
Who sends the confirmation?
This is where Sequence Diagrams become incredibly valuable.
Instead of showing what exists, they show how objects collaborate over time.
Why Class Diagrams Aren't Enough
Imagine someone hands you this Class Diagram.
Customer
Cart
Order
Payment
Inventory
Notification
You understand the building blocks.
But if someone asks:
"Walk me through what happens when a customer places an order."
You still don't know the answer.
The missing piece is behavior.
Class Diagrams describe structure.
Sequence Diagrams describe interaction.
What Is a Sequence Diagram?
A Sequence Diagram visualizes how different objects communicate while performing a specific task.
Instead of asking:
"What objects exist?"
It asks:
"Who talks to whom, and in what order?"
Every interaction is represented as a message passed from one object to another.
Together, these messages tell the complete story of how a feature works.
Think of it as watching a movie instead of looking at a photograph.
Time Flows Downward
One of the most important concepts in Sequence Diagrams is that time always moves from top to bottom.
Every message appears below the previous one.
Start
│
▼
Validate Request
│
▼
Create Order
│
▼
Process Payment
│
▼
Update Inventory
│
▼
Send Confirmation
Reading a Sequence Diagram is almost like reading a story.
Each action naturally follows the previous one.
The Main Participants
Every Sequence Diagram is made up of participants.
These participants are usually:
- users
- controllers
- services
- repositories
- databases
- external systems
For example:
Customer
OrderController
OrderService
InventoryService
PaymentService
Database
Each participant represents something that takes part in completing the request.
Lifelines
Every participant has a vertical line beneath it.
This is called a lifeline.
Customer OrderService Database
│ │ │
│ │ │
│ │ │
A lifeline simply shows that the participant exists during the interaction.
Messages travel between these lifelines.
Messages Represent Method Calls
Whenever one object asks another object to perform work, we draw a message.
Customer
│
│ placeOrder()
▼
OrderController
That message might represent:
- a method call
- an API request
- an event
- a service invocation
The exact implementation isn't important.
The collaboration is.
A Simple Login Flow
Let's model a login request.
User
│
▼
AuthController
│
▼
AuthService
│
▼
UserRepository
│
▼
Database
Now let's walk through it.
The user submits login credentials.
The controller receives the request.
The controller delegates authentication to the service.
The service retrieves the user from the repository.
The repository queries the database.
The result travels back through the same chain.
Even without reading code, the runtime behavior is immediately clear.
Why Controllers Delegate
One pattern appears in almost every backend system.
User
│
▼
Controller
│
▼
Service
│
▼
Repository
│
▼
Database
Beginners sometimes wonder why there are so many layers.
Because each layer has a different responsibility.
The controller receives requests.
The service contains business logic.
The repository handles persistence.
Each component focuses on one job.
Sequence Diagrams make this separation obvious.
A Real-World Example: Ordering Food
Imagine a customer places an order using a food delivery app.
The interaction might look like this.
Customer
│
▼
Order Controller
│
▼
Order Service
│
├────────► Inventory Service
│
├────────► Payment Service
│
└────────► Notification Service
Notice something interesting.
The OrderService doesn't do everything itself.
Instead, it coordinates multiple specialized services.
This is exactly how large backend systems are designed.
Synchronous vs Asynchronous Communication
Not every interaction behaves the same way.
Some operations require an immediate response.
Others don't.
Synchronous Communication
The caller waits until the work finishes.
Checkout
│
▼
Payment Service
│
(wait)
│
Success
The user cannot continue until payment completes.
Asynchronous Communication
The caller continues immediately.
Order Created
│
├────────► Email Service
└────────► Analytics Service
The order is successfully created even if the email is sent a few seconds later.
This improves responsiveness and scalability.
Understanding when to use each approach is an important engineering skill.
A Sequence Diagram Tells a Story
Consider booking a movie ticket.
User
│
▼
Booking Controller
│
▼
Booking Service
│
▼
Seat Service
│
▼
Payment Service
│
▼
Booking Repository
Read it like a story.
The user requests a booking.
The booking service checks seat availability.
If seats are available, payment is processed.
Only after payment succeeds is the booking stored.
The order matters.
Changing the order changes the business behavior.
Weak Thinking vs Strong Thinking
Weak Thinking
I'll call whichever service
I need whenever I want.
Strong Thinking
Every interaction should have
a clear responsibility and sequence.
Weak Thinking
The controller should handle
all the business logic.
Strong Thinking
Controllers coordinate requests.
Services implement business logic.
Weak Thinking
The database is the system.
Strong Thinking
The database is just one participant
in a larger collaboration.
Common Beginner Mistakes
Skipping intermediate layers
Many beginners draw something like this.
User
│
▼
Database
Real applications rarely work this way.
Business logic almost always sits between the user and the database.
Mixing responsibilities
Controllers should not calculate discounts.
Repositories should not validate payments.
Each participant should perform exactly one type of work.
Ignoring alternative flows
Happy paths are easy.
Real systems also handle:
- payment failures
- inventory shortages
- invalid requests
- retry mechanisms
Good Sequence Diagrams acknowledge these possibilities.
Trying to show everything
A Sequence Diagram should explain one specific scenario.
Trying to model every possible path quickly makes the diagram unreadable.
Keep each diagram focused.
Interview Perspective
In Low-Level Design interviews, interviewers often ask:
"Walk me through what happens when the user places an order."
They're not asking for code.
They're evaluating your ability to think about runtime behavior.
Strong candidates naturally explain:
- who receives the request
- where business logic lives
- which services collaborate
- how data flows
- when the request completes
Even if you never draw a formal Sequence Diagram, thinking this way makes your explanations significantly stronger.
The Most Important Insight
Class Diagrams tell you what exists.
Sequence Diagrams tell you how those objects collaborate.
A system isn't successful because it has good classes.
It's successful because those classes communicate in a clear, predictable, and maintainable way.
Understanding interactions is just as important as understanding structure.
One-Line Takeaway
Great software isn't just a collection of well-designed objects—it's a collection of well-designed conversations between those objects.
Top comments (0)