Skip to main content

Event Listeners

Key Insight

Event Listeners are all about trade-offs. They're not inherently good or bad—it depends on the context and requirements of your system.

1. Introduction and Key Question

When should we use Event Listeners, and when should we avoid them? Is there a clear right or wrong, or is it always a trade-off?

2. Event Management in System Architecture

In modern architectures, especially Microservices and Event-Driven Architecture, several patterns exist for managing events:

Store all changes to application state as a sequence of events.

Impact on Code Quality Metrics

Why Event Management Matters

As event volume grows, it impacts various aspects of your codebase differently:

🔻 Declining Metrics

  • Code Readability
  • Module Cohesion

🔺 Improving Metrics

  • Decoupling Dependencies
  • System Flexibility
note

In modular or microservice systems where decoupling is crucial, Event Listeners can be particularly valuable.

3. Team Contract for Event Listeners

Core Principle

Using Event Listeners within a single module is prohibited. They should only be used for communication between separate modules.

Event Listeners as Orchestrators

Event listeners should focus solely on orchestration responsibilities, not core business logic execution. They should remain as lightweight as possible by:

  • Delegating business logic to dedicated service layers
  • Avoiding complex conditionals or business rules
  • Minimizing synchronous operations and blocking calls
  • Keeping the listener focused on routing and coordination

This approach maintains clear separation of concerns and improves maintainability.

Example Scenario

Allowed

✅ Allowed: Module A fires an event that Module B listens to

Not Allowed

❌ Not Allowed: Module A directly calls Module B's methods

Why This Matters

Direct module coupling reduces independence and makes the system more rigid. Events create a looser, more maintainable architecture.

4. Implementation Guidelines

Common Scenarios

Decision Matrix

ScenarioStatusImpact
Direct connection between entities of two modules❌ ProhibitedViolates modularity
Directly calling a service from another module⚠️ DiscouragedCauses tight coupling
Firing an event from Module A and listening in Module B✅ AllowedPromotes loose coupling
Best Practice

When in doubt, prefer the event-based approach for inter-module communication.

5. Business Events Standard

Definition

A Business Event represents a meaningful business occurrence that other parts of the system might be interested in.

Key Characteristics

  • Future-proofs your architecture
  • Enables loose coupling between modules
  • Makes the system more observable
// Example: Firing a business event
class OrderService {
async completeOrder(orderId) {
// Business logic...
eventBus.publish('order.completed', { orderId, timestamp: Date.now() });
}
}

6. Decision Framework

When to Use Event Listeners

✅ Use When:
  • Communicating between independent modules
  • Decoupling is more important than direct coupling
  • Multiple components need to react to an event

When to Avoid Event Listeners

❌ Avoid When:
  • Communication stays within a single module
  • Direct coupling is simpler and more maintainable
  • You need synchronous communication

7. Final Guidelines

Key Points
  • Refactor any intra-module event listeners when found
  • Keep inter-module event-based communication
  • Document all business events and their purposes
Remember

Even if there are no current listeners, firing business events for important occurrences helps maintain flexibility for future requirements.