ddd-event-driven について
ドメインイベント、イベントソーシング、CQRS、信頼性の高い配信パターンを用いてイベント駆動システムを設計するスキルです。集約やサービス間のイベントフローを実装する開発者向けに、ブローカー転送やOutboxによる発行も扱います。
主な機能
- 01ドメインイベントの特定とモデル化
- 02イベントの発行・消費フローの設計
- 03イベントソーシングとCQRSパターンの適用
- 04KafkaやRabbitMQなどのブローカー利用
- 05Outboxと冪等性による配信の信頼性向上
活用シーン
- 01イベントによる集約とサービスの疎結合化
- 02イベントストリームからのアプリケーション状態導出
- 03データベース変更と合わせたイベントの確実な発行
- 04コマンド側と読み取りモデルの分離設計
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ partme-ai/ full-stack-skills --skill ddd-event-drivenインストール後、Claude Code で/ddd-event-drivenを入力して読み込まれたか確認します。
同梱ファイルLICENSE.txt
詳細
このスキルを使用する場面
次のことをユーザーが希望する場合は、いつでもこのスキルを使用してください。
- ドメインイベントを使って集約とサービスを疎結合にする
- イベントストリームから状態を導出するイベントソーシングシステムを設計する
- CQRS(コマンドクエリ責務分離)を実装する
- メッセージブローカー(Kafka、RabbitMQ など)を選定して統合する
- アウトボックスパターンを使ってイベント配信の信頼性を確保する
このスキルの使用方法
ワークフロー
- 集約内で「発生した事実」を表すドメインイベントを特定します
- イベントフローを設計します。公開、転送(メッセージバス)、消費を含みます
- パターンを選択します。シンプルなドメインイベント、イベントソーシング、または完全な CQRS から選びます
- 配信保証を実装します。冪等なコンシューマーを使って、少なくとも 1 回の配信を実現します
1. ドメインイベントの定義
public record OrderPlacedEvent(
String orderId,
String customerId,
BigDecimal totalAmount,
Instant occurredAt
) implements DomainEvent {}
2. ドメインイベントの公開
public class Order extends AggregateRoot {
public void place(List<OrderItem> items) {
// Business logic...
this.status = OrderStatus.PLACED;
registerEvent(new OrderPlacedEvent(this.id, this.customerId, this.total, Instant.now()));
}
}
3. イベントソーシングパターン
public class Account {
private BigDecimal balance = BigDecimal.ZERO;
private final List<DomainEvent> changes = new ArrayList<>();
public void apply(MoneyDepositedEvent event) {
this.balance = this.balance.add(event.amount());
}
public static Account reconstitute(List<DomainEvent> events) {
Account account = new Account();
events.forEach(account::apply);
return account;
}
}
4. CQRS の概要
Write Side: Read Side:
Command → Aggregate → Events → Event Handler → Read Model (View)
(message bus)
5. 信頼性の高い配信のためのアウトボックスパターン
// Save event to outbox table in the same transaction as the aggregate
@Transactional
public void placeOrder(PlaceOrderCommand cmd) {
Order order = Order.place(cmd);
orderRepository.save(order);
outboxRepository.save(new OutboxEntry("OrderPlaced", serialize(order.events())));
}
// A separate poller publishes outbox entries to the message broker
ベストプラクティス
- イベント名は過去形にし、集約 ID と必須データだけを含めます。大きなペイロードや機密情報は避けてください
- 冪等なコンシューマーを使って、少なくとも 1 回の配信を保証します。信頼性の高い公開には、ポーリングを行うアウトボックステーブルを使用します
- 明確なイベントのバージョニングと互換性の戦略を定義します(フィールドの追加、新しいトピックなど)
- 完全なイベントソーシングを採用する前に、シンプルなドメインイベントから始めます。複雑さとのトレードオフが正当化される必要があります
リソース
- Eric Evans 著『Domain-Driven Design』
- Martin Fowler のイベントソーシングに関する解説:https://martinfowler.com/eaaDev/EventSourcing.html
- CQRS:https://martinfowler.com/bliki/CQRS.html
キーワード
イベント駆動型アーキテクチャ、ドメインイベント、イベントソーシング、CQRS、アウトボックスパターン、メッセージブローカー、Kafka、RabbitMQ、結果整合性、冪等なコンシューマー
コメント
Markdown 対応