A
A
alexg-nn2020-03-12 16:33:08
OOP
alexg-nn, 2020-03-12 16:33:08

What is the best way to organize a domain event using a simple example?

Hello.

Practicing OOP with a DDD approach using a simple example. Let's say we have a faucet in the garden for watering the beds. Let's try to simulate its work. So the faucet can be opened and closed. Let's have a Tap aggregate

class Tap {
 // ... id и другие свойства опущены
 public function open() { // Emit TapOpened event }
 public function close() { // Emit TapClosed event }
}

class TapOpened extends DomainEvent {
  // tapId и другие свойства
}

class TapClosed extends DomainEvent {
  // tapId и другие свойства
}


Now we complicate the task - we do not want to stand at the tap for an hour and wait for the beds to water. We want to set up automatic shutdown (for simplicity) of the tap on a timer. In the implementation of the crane, nothing changes. As a timer, we use an external service TimerService , which can be asked to throw a TimerCreated and TimerTimeout event at the right time. This service can have many clients, so it throws one TimerTimeout event for all:

interface TimerService {
  public function windUp(period): TimerIdentity;
}

class TimerCreated extends DomainEvent {
  // timerId и другие свойства
}

class TimerTimeout extends DomainEvent {
  // timerId и другие свойства
}


To activate such an advanced tap, we use the TapAutoCloser service

class TapAutoCloser {
  private timeService;

  public function openTapFor(tap, period) {
    tap.open();
    timer = timeService->windUp(period);
    //...
  }

  public function timeoutHandler(timerTimeoutEvent) {
   // ..
   tap.close()
   // ..
  }
}


I omitted the moments where the closing tap itself is located on the timeout event.

Next is the question. For example, five minutes before the automatic closing of the tap, the siren should turn on.

At first I thought it was the job of the tap context to fire an event like LessThan5MinutesRemainedToTapAutoclose that would catch the siren context. But I thought about it and decided that if more conditions are added in the future, for example, turn on the light half an hour before the end of watering, then this will again require modifications to the context of the tap, which knows nothing about the time of its work. And in general, he cannot know what else other contexts will want from him. It turns out that time must "understand" the contexts of the siren and lighting.

But in order for them to calculate their fortune themselves, they need to know when the faucet is scheduled to close. And in our case, the tap context only says that it is open (TapOpened), but does not say anything about when it will be closed (because it does not know). Where in this scheme to transfer knowledge about the running time of the crane through events to other contexts?

I see only one option - the timer service knows about the presence of a tap and instead of impersonal TimerCreated and TimerTimeout it will throw something like TapAutocloseTimerCreated and TapAutocloseTimerTimeout . But then the timer service comes out narrowly focused. And if now the light also needs to be turned on by a timer, then is it really possible to create your own timer for this. Will TapCloseTimerand LightSwitchTimer etc? Or can they be combined somehow?

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question