--- title: Use Event-Driven Architecture for Decoupling impact: MEDIUM-HIGH impactDescription: Enables async processing and modularity tags: architecture, events, decoupling --- ## Use Event-Driven Architecture for Decoupling Use `@nestjs/event-emitter` for intra-service events and message brokers for inter-service communication. Events allow modules to react to changes without direct dependencies, improving modularity and enabling async processing. **Incorrect (direct service coupling):** ```typescript // Direct service coupling @Injectable() export class OrdersService { constructor( private inventoryService: InventoryService, private emailService: EmailService, private analyticsService: AnalyticsService, private notificationService: NotificationService, private loyaltyService: LoyaltyService, ) {} async createOrder(dto: CreateOrderDto): Promise { const order = await this.repo.save(dto); // Tight coupling - OrdersService knows about all consumers await this.inventoryService.reserve(order.items); await this.emailService.sendConfirmation(order); await this.analyticsService.track('order_created', order); await this.notificationService.push(order.userId, 'Order placed'); await this.loyaltyService.addPoints(order.userId, order.total); // Adding new behavior requires modifying this service return order; } } ``` **Correct (event-driven decoupling):** ```typescript // Use EventEmitter for decoupling import { EventEmitter2 } from '@nestjs/event-emitter'; // Define event export class OrderCreatedEvent { constructor( public readonly orderId: string, public readonly userId: string, public readonly items: OrderItem[], public readonly total: number, ) {} } // Service emits events @Injectable() export class OrdersService { constructor( private eventEmitter: EventEmitter2, private repo: Repository, ) {} async createOrder(dto: CreateOrderDto): Promise { const order = await this.repo.save(dto); // Emit event - no knowledge of consumers this.eventEmitter.emit( 'order.created', new OrderCreatedEvent(order.id, order.userId, order.items, order.total), ); return order; } } // Listeners in separate modules @Injectable() export class InventoryListener { @OnEvent('order.created') async handleOrderCreated(event: OrderCreatedEvent): Promise { await this.inventoryService.reserve(event.items); } } @Injectable() export class EmailListener { @OnEvent('order.created') async handleOrderCreated(event: OrderCreatedEvent): Promise { await this.emailService.sendConfirmation(event.orderId); } } @Injectable() export class AnalyticsListener { @OnEvent('order.created') async handleOrderCreated(event: OrderCreatedEvent): Promise { await this.analyticsService.track('order_created', { orderId: event.orderId, total: event.total, }); } } ``` Reference: [NestJS Events](https://docs.nestjs.com/techniques/events)