What is the goal?
What needs to happen, to achieve the goal?
What happens when?
What belongs together?
What are the details?
Highlight important questions, that can't be answered now!
Discuss and experiment. Define requirements. Describe User Stories.
Derive features from design sessions. Keep an eye on the Hot Spots.
Document activities.
<?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()]);
}