From Event Storming To Working Code

 

# Big Picture

Event Storming

First Event

 

What is the goal?

Tell A Story

What needs to happen, to achieve the goal?

Order By Time

What happens when?

Group By Context

What belongs together?

Explore The Domain

What are the details?

Identify Hot Spots

Highlight important questions, that can't be answered now!

# Design Level Event Storming / Modeling

Team Collaboration

Discuss and experiment. Define requirements. Describe User Stories.

Project Management

Derive features from design sessions. Keep an eye on the Hot Spots.

Document activities.

# Event Engine

<?php


namespace Inspectio\Board\Domain\Api;



// Event Engine Aggregate Description



$eventEngine->process(Command::INSTALL_USER_BOARD)


  
  ->withNew(self::BOARD)
  ->identifiedBy(Payload::BOARD_ID)
  ->provideContext(BoardInstallerProvider::class)
  ->handle([BoardBehavior::class, 'installUserBoard'])



  ->recordThat(Event::BOARD_INSTALLED)
  ->apply([BoardBehavior::class, 'whenBoardInstalled']);


public static function installUserBoard(
    Board\Command\InstallUserBoard $command, 
    BoardInstaller $installer
): \Generator
{
    if(!$installer->hasEnoughQuotaFor($command->userInfo()->userId())) {
        throw NoBoardQuotaAvailable::forUser($command->userInfo()->userId());
    }

    yield Board\Event\BoardInstalled::fromRecordData([
        Board\Event\BoardInstalled::BOARD_ID => $command->boardId(),
        Board\Event\BoardInstalled::OWNER_ID => $command->userInfo()->userId(),
        Board\Event\BoardInstalled::NAME => $command->name(),
        Board\Event\BoardInstalled::BOARD_VERSION => BoardVersion::forNewBoardOfOwner($command->userInfo()->userId()),
        Board\Event\BoardInstalled::CURRENT_QUOTA => $installer->boardQuota(),
        Board\Event\BoardInstalled::LAST_MODIFIED => LastModified::fromDateTime(UtcDateTime::now()),
    ]);
}

public static function whenBoardInstalled(Board\Event\BoardInstalled $event): Board\Board
{
    return Board\Board::fromRecordData([
        Board\Board::BOARD_ID => $event->boardId(),
        Board\Board::OWNER_ID => $event->ownerId(),
        Board\Board::NAME => $event->name(),
        Board\Board::BOARD_VERSION => $event->boardVersion(),
        Board\Board::LAST_MODIFIED => $event->lastModified(),
    ]);
}
$eventEngine->on(self::BOARD_INSTALLED, [BoardQuotaPolicy::class, 'onBoardInstalled']);
<?php

declare(strict_types=1);

namespace Inspectio\Board\Domain\Model\User;

use Inspectio\Board\Domain\Model\Board\Event\BoardDeleted;
use Inspectio\Board\Domain\Model\Board\Event\BoardInstalled;
use Inspectio\Board\Domain\Model\User\Command\IncreaseBoardQuota;
use Inspectio\Board\Domain\Model\User\Command\ReduceBoardQuota;




final class BoardQuotaPolicy
{
    public static function onBoardInstalled(
       BoardInstalled $boardInstalled
    ): ReduceBoardQuota
    {
        return ReduceBoardQuota::fromRecordData([
            ReduceBoardQuota::USER_ID => $boardInstalled->ownerId(),
            ReduceBoardQuota::CURRENT_QUOTA => $boardInstalled->currentQuota(),
        ]);
    }

    public static function onBoardDeleted(
       BoardDeleted $boardDeleted
    ): IncreaseBoardQuota
    {
        return IncreaseBoardQuota::fromRecordData([
            IncreaseBoardQuota::USER_ID => $boardDeleted->ownerId(),
            IncreaseBoardQuota::QUOTA => $boardDeleted->newOwnerQuota(),
        ]);
    }
}
<?php


namespace Inspectio\Board\Domain\Api;



// Event Engine Aggregate Description






$eventEngine->process(Command::REDUCE_BOARD_QUOTA)







  ->withExisting(self::USER)
  ->handle([UserBehavior::class, 'reduceQuota'])
  
  
  
  
  
  
  
  ->recordThat(Event::BOARD_QUOTA_REDUCED)
  ->apply([UserBehavior::class, 'whenBoardQuotaReduced']);
<?php


namespace Inspectio\Board\Domain\Model\User;


//...


public static function reduceQuota(
  User\User $state, 
  User\Command\ReduceBoardQuota $reduceBoardQuota
  ): \Generator
{
  $newQuota = $reduceBoardQuota->currentQuota()->reduce();

  if($state->quota()->toInt() <= $newQuota->toInt()) {
	//Duplicate or outdated command received
	yield null;
	return;
  }

  yield User\Event\BoardQuotaReduced::fromRecordData([
  	User\Event\BoardQuotaReduced::USER_ID => $state->userId(),
    User\Event\BoardQuotaReduced::QUOTA => $newQuota,
  ]);
}

public static function whenBoardQuotaReduced(
  User\User $state, 
  User\Event\BoardQuotaReduced $boardQuotaReduced
): User\User
{
  return $state->with([User\User::QUOTA => $boardQuotaReduced->quota()]);
}

Questions?

event-driven-development

By prooph

event-driven-development

  • 2,269