Skip to content

Can we refactor events? #214

Open
Open
@mmmoli

Description

@mmmoli

You know how much I love this lib… ❤

From the Docs:

order.addEvent('OTHER_EVENT', (...args) => {
    console.log(args);
});

// Or add an EventHandler instance
order.addEvent(new OrderCreatedEvent());

order.dispatchEvent('ORDER_HAS_BEGUN');

// dispatch with args
order.dispatchEvent('OTHER_EVENT', { info: 'custom_args' });

// OR call all added events
await order.dispatchAll();

My understanding

  • Order is the Aggregate Root
  • I want to add the event "OrderCreatedEvent" in a method within the domain
  • Later, in a use-case, I might decide to dispatch the event

Complexity

Dispatching the event requires some infrastructure: My Event Bus.
I don't want to add this in the domain layer – bad practice.

What I think I want, is:

  1. Add the event in the domain layer (with custom args!)
  2. Dispatch the event in the use case

Problem

The docs describe this round the opposite way, no?

Things I've tried

1. Custom Constructor to EventHandler

order.addEvent(new OrderItemAdded({ newItem }));

– Great, but I still can't dispatch without importing my Event Bus.

2. Custom Parameter

class Order extends AggregateRoot {
    function addItem(eventHandler? EventHandler<Order>) {
        ...do work
        if (eventHandler) this.addEvent(eventHandler)
    }
}

  • Great, but I cannot pass additional args of "newItem"

API I think we need

In domain layer

order.addEvent('ORDER_ITEM_ADDED', { newItem });

– I don't care how it's dispatched here. So I don't care about a "handler".

In UseCase

export class AddItemUseCase extends UseCase {

    constructor(deps: {
        orderItemAddedHandler: EventHandler<Order>
    })

    execute() {
        ...
        order.addItem(...)
        order.dispatch('ORDER_ITEM_ADDED', this.deps.orderItemAddedHandler)
    }
}

– I'm not creating the handler here, I'm just passing it and saying "use this to dispatch the event, thanks!"

And finally, in infra:


export class OrderItemAddedHander extends EventHandler<Order> {

    constructor(deps: {
        eventBus: EventBus
    })

    dispatch(order: Order, args) {
        this.deps.eventBus.dispatch({
           custom: {
               shape: {
                  order,
                  item: args.newItem
               }
           }
        })
    }
}

and


export const addOrderItemUseCase = new AddItemUseCase({
    orderItemAddedHandler: new OrderItemAddedHander()
})

– All the definitions of things without any understanding or logic as to when this all gets called.

Bonus!

Strict typing of the event args would be 👌🏻

Something like:

interface CustomArgs {
   newItem: …
}
EventHandler<Order, CustomArgs>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions