Saturday 16 March 2013

CQRS in Scala: Commands

I have been working with the CQRS pattern in C# for a while, and about a year ago have been implementing it in Scala.  Over the last year I have been simplifying down my approach. Please, any comments, suggestions or criticism are most welcome. It assumes knowledge of the principles of CQRS.  You might also find this post helpful 

The following implementation does not yet take into account events, however this will be covered.

First we have a trait to mark a command
trait Command


Individual command will implement this trait, such as

case class NewUserCommand(string:Login, string:Password) extends Command


For each command there should be a handler which will extend the following:

trait Handler[T <: Command] {
  def handle(command:T):Unit
}

The command handlers I use follow the cake pattern, and have state wired in.  For example

trait NewUserCommandHandler extends Handler[NewUserCommand] {
  this:SecurityService with PersistencyService =>

  def handle(command:NewUserCommand) { ... }
}

In this example state is a document cache required by the PersistencyService:

trait DocumentPersistencyService extends PersistencyService {
  def state:DocumentCache

  ...

I have created a registry for holding the constructor of the command handlers.  Here state is a type parameter, though I don't think that's entirely necessary. The registry is mutable only until first use, I have followed the same approach that I used here.

trait CommandRegistry[State] {
  def getHandler[T <: Command:TypeTag](implicit state:State):Handler[T]
}

trait CommandConstructorRegistry[State] extends CommandRegistry[State] {

  private val registryBuffer = new ListBuffer[(TypeSymbol, (State) => Handler[_])]
  private lazy val registry = registryBuffer.toMap

  def getHandler[T <: Command:TypeTag](implicit state:State):Handler[T] = registry(typeOf[T].typeSymbol.asType)(state).asInstanceOf[Handler[T]]

  def register[T <: Command:TypeTag](constructor:((State) => Handler[T])) {
    registryBuffer += ((typeOf[T].typeSymbol.asType, constructor))
  }
}

A command dispatcher wraps this all up, so that all commands can be issued via the dispatcher.

trait CommandDispatcher[State] {

  def dispatch[T <: Command:TypeTag](command:T)(implicit state:State):Unit
}


trait DefaultCommandDispatcher[State] extends CommandDispatcher[State] {
  this:CommandRegistry[State] =>
  def dispatch[T <: Command:TypeTag](command:T)(implicit state:State) {
    val handler = getHandler[T]
    handler.handle(command)
  }
}

So tying it all together looks something like this:

val commandDispatcher = new DefaultCommandDispatcher[DocumentCache] with CommandConstructorRegistry[DocumentCache] {
  register(s => new NewUserCommandHandler with DefaultSecurityService with DocumentPersistencyService { val state = s })
}

implicit val state = new DocumentCache()
val command = NewUserCommand("login","password")
commandDispatcher.dispatch(command)

You could also enrich the dispatcher through the use of mixins, say if you wanted to log the commands content:

trait CommandLogger[State] extends CommandDispatcher[State] {
  
  abstract override def dispatch[T <: Command:TypeTag](command:T)(implicit state:State) {
    println(command)
    super.dispatch(command)
  }
}

No comments:

Post a Comment