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,383