Learn
Changelog
Architectural Decisions Record
2024-01-05 Domain Logic Ownership

Domain Logic Ownership

Date: 2024-01-05

Who should implement the business logic (aka send and apply) between Event and State?

trait Event {
    fn apply(&self, state: &mut State);
}
 
// OR
 
trait State {
    fn apply(&mut self, event: &Event);
}

When doing Dependency Injection, following Effect principles, it is preferable to use the context at the last moment so that basic elements can be built and exchanged.

// ✅ Good
struct Command {} // Can be built without knowing the context
 
impl Command {
  fn execute(&self, context: &Context) -> (); // Also, this pattern allows us to implement variations depending on the context
}
 
// ❌ Bad
struct Command {
  context: Context // Cannot be built without knowing the context, need to be owned and/or to have a lifetime
}

In our case, the Event is the basic element and the State is the context. Thus, it is preferable to use the State at the last moment, which means that the Event should implement apply.

However, we also have Projection that need to apply events and we cannot implement Vec<Event> from the application layer.

💡

We need to implement apply on State and Projection.