When an online order is placed, the customer sees a simple message:
"Your order has been confirmed."
Behind that message, however, an entire chain of events begins.
The inventory must be updated.
The payment must be recorded.
The customer should receive an email.
Analytics dashboards need updating.
Fraud detection systems may need to run.
Loyalty points might need to be awarded.
Shipping labels may need to be generated.
In small systems, developers often connect these actions directly.
Order Service
├── Update Inventory
├── Send Email
├── Update Analytics
├── Create Invoice
└── Start Shipping
At first, this seems perfectly reasonable.
Then the business grows.
And everything starts breaking.
The Architecture That Works Until It Doesn't
Imagine an e-commerce platform processing 50 orders per day.
A customer places an order.
The Order Service directly calls:
Inventory Service
Email Service
Analytics Service
Billing Service
Shipping Service
Everything succeeds.
Everyone is happy.
The architecture appears simple.
The problem is that simplicity is deceptive.
The Order Service now depends on every downstream service.
If any one of them is slow, the entire workflow becomes slow.
If any one of them fails, the customer experience can fail.
The more business capabilities added, the larger this dependency chain becomes.
Over time the Order Service quietly transforms into the center of the entire company.
Every new feature adds another dependency.
Every new dependency increases risk.
A Real Failure Scenario
Consider this order workflow:
Customer
↓
Order Service
↓
Inventory Service
↓
Email Service
↓
Analytics Service
One day the Email Service experiences an outage.
Now what happens?
Many systems accidentally end up with behavior like this:
create_order()
reserve_inventory()
send_confirmation_email()
update_analytics()
Email fails.
The transaction stops.
Analytics never updates.
The customer may not even receive order confirmation.
A problem in one subsystem cascades across the platform.
This is known as tight coupling.
The services are technically separate.
Operationally, they are not.
The Postmortem Nobody Wants to Write
A common production incident looks something like this:
What happened?
A third-party email provider experienced elevated latency.
Impact
Order creation response times increased from:
200ms
to
8-15 seconds
Business Impact
Customers abandoned checkout.
Conversion rates dropped.
Support tickets increased.
Revenue was affected.
Root Cause
The Order Service was waiting for Email Service completion before responding.
Architectural Problem
The platform treated a non-critical operation as a critical dependency.
Notice something important.
The email system wasn't actually required to create the order.
The order should have succeeded regardless.
The architecture created the outage.
Not the email provider.
Enter Publish-Subscribe
Instead of directly calling every service, the Order Service publishes an event.
Order Service
↓
Order Created Event
↓
Message Broker
↓
Inventory
Email
Analytics
Billing
Shipping
Now the Order Service only has one responsibility:
Create Order
Publish Event
Done
It no longer cares who needs the information.
It simply announces:
Order Created
Anyone interested can react.
This changes everything.
Thinking in Events Instead of Calls
Traditional systems think:
Do this.
Then do that.
Then do another thing.
Event-driven systems think:
Something happened.
Whoever cares can respond.
That shift sounds small.
Architecturally, it is enormous.
The producer no longer knows:
Who consumes the event
How many consumers exist
When consumers process it
What consumers do with it
The producer simply publishes facts.
The Message Broker Becomes the Traffic Controller
A message broker sits between producers and consumers.
Examples include:
Apache Kafka
RabbitMQ
Amazon SNS
Amazon SQS
The broker receives events and distributes them to interested systems.
Publisher
↓
Broker
├── Inventory
├── Email
├── Billing
├── Analytics
└── Fraud Detection
Services no longer communicate directly.
The broker acts as the central nervous system.
Why Business Leaders Should Care
Most architectural decisions eventually become business decisions.
Publish-Subscribe creates advantages that executives feel directly.
Faster Feature Delivery
Imagine marketing wants a loyalty points system.
In a tightly coupled architecture:
Modify Order Service
Retest Order Service
Redeploy Order Service
Risk Order Service
In Pub/Sub:
Create Loyalty Consumer
Subscribe to Order Created
Deploy Independently
The order system remains untouched.
New business capabilities can be added safely.
Reduced Revenue Risk
If Analytics fails:
Orders continue.
Payments continue.
Customers continue.
Only analytics is affected.
The failure is isolated.
This dramatically reduces blast radius.
Better Organizational Scaling
As companies grow:
Payments Team
Inventory Team
Data Team
Growth Team
Customer Team
Each team can consume events independently.
Teams become less dependent on one another.
This increases development velocity.
Why Developers Love Event-Driven Systems
Developers eventually discover a painful truth:
The hardest part of scaling is not traffic.
It's dependencies.
Pub/Sub removes many of them.
Loose Coupling
Without Pub/Sub:
Order Service
↓
Inventory
↓
Email
↓
Analytics
With Pub/Sub:
Order Service
↓
Broker
↓
Consumers
The producer has one dependency.
Instead of ten.
Independent Deployments
A team can deploy:
Recommendation Engine
Fraud Detection
Customer Segmentation
without touching the ordering system.
This dramatically reduces deployment risk.
Better Resilience
Suppose Billing Service crashes.
The broker stores events.
When Billing returns:
Order Created Event #1001
Order Created Event #1002
Order Created Event #1003
can still be processed.
The platform recovers automatically.
But Publish-Subscribe Creates New Problems
Many architecture articles stop at benefits.
Production systems do not.
Every architectural gain introduces tradeoffs.
Problem #1: Eventual Consistency
In synchronous systems:
Order Created
Inventory Updated
Response Returned
Everything happens immediately.
In Pub/Sub:
Order Created
Response Returned
Inventory Updated Later
There is now a time gap.
Systems may temporarily disagree.
This is called:
Eventual Consistency
One of the most misunderstood realities of distributed systems.
Problem #2: Duplicate Events
Networks fail.
Retries happen.
Consumers crash.
The same event may arrive twice.
Order Created #123
Order Created #123
Consumers must be idempotent.
Otherwise:
Inventory reduced twice
Customer charged twice
Production incidents happen.
Problem #3: Observability Becomes Hard
In monolithic workflows:
Request → Response
Easy to trace.
In event-driven systems:
Order Created
↓
Inventory Updated
↓
Billing Created
↓
Email Sent
↓
Analytics Updated
A single customer action can generate dozens of events.
Tracking failures becomes significantly harder.
This is why mature organizations invest heavily in:
Distributed tracing
Correlation IDs
Event monitoring
Audit logs
How Large Platforms Actually Think
The most successful architectures do not ask:
"Which service should call which?"
Instead they ask:
"What business events exist?"
Examples:
Order Created
Payment Authorized
Shipment Created
Invoice Generated
User Registered
Subscription Renewed
These events become the language of the business.
Systems are then built around reacting to those events.
The result is an architecture that grows with the company instead of fighting it.
The Real Lesson
Publish-Subscribe is not primarily about messaging.
It is about organizational scalability.
It allows systems to evolve without every team depending on every other team.
It reduces blast radius.
It improves resilience.
It accelerates feature delivery.
But it also introduces complexity, eventual consistency, and operational challenges that teams must be prepared to handle.
The companies that scale successfully are rarely the ones with the most services.
They are the ones with the clearest events.
Because once systems start speaking in events instead of direct dependencies, growth becomes far easier to sustain.
Key Takeaway
A mature architecture doesn't ask:
"Who should I call next?"
It asks:
"What happened?"
That single shift from commands to events is one of the biggest architectural transitions in modern software systems.
Top comments (0)