Designing and Implementing Event-Driven Architecture dengan Claude Code
Pelajari tentang designing and implementing event-driven architecture menggunakan Claude Code. Dilengkapi tips praktis dan contoh kode.
event駆動arsitektur
event駆動arsitektur(EDA) 、event 発行 dan 購読 oleh sistem 疎結合 設計 pola.Claude Code 使えば、EDA 設計 dari implementasiま efisien 進められ.
type safetyなeventバス
type EventMap = {
"user.created": { userId: string; email: string };
"user.updated": { userId: string; changes: Record<string, unknown> };
"order.created": { orderId: string; userId: string; total: number };
"order.completed": { orderId: string; completedAt: Date };
"order.cancelled": { orderId: string; reason: string };
"payment.processed": { paymentId: string; amount: number };
};
type EventName = keyof EventMap;
type EventHandler<T extends EventName> = (payload: EventMap[T]) => Promise<void>;
class EventBus {
private handlers = new Map<string, Set<Function>>();
on<T extends EventName>(event: T, handler: EventHandler<T>) {
if (!this.handlers.has(event)) {
this.handlers.set(event, new Set());
}
this.handlers.get(event)!.add(handler);
// unsubscribefungsi 返す
return () => {
this.handlers.get(event)?.delete(handler);
};
}
async emit<T extends EventName>(event: T, payload: EventMap[T]) {
const handlers = this.handlers.get(event);
if (!handlers) return;
const results = await Promise.allSettled(
Array.from(handlers).map((handler) => handler(payload))
);
const failures = results.filter((r) => r.status === "rejected");
if (failures.length > 0) {
console.error(
`${failures.length} handlers failed for ${event}:`,
failures
);
}
}
}
const eventBus = new EventBus();
registrasi eventhandler
// penggunapembuatan時 pemrosesan
eventBus.on("user.created", async ({ userId, email }) => {
// ウェルカムメールpengiriman
await emailQueue.add("send", {
to: email,
subject: "ようこそ!",
template: "welcome",
data: { userId },
});
});
eventBus.on("user.created", async ({ userId }) => {
// デフォルトpengaturan pembuatan
await prisma.userSettings.create({
data: {
userId,
theme: "light",
language: "ja",
notifications: true,
},
});
});
// 注文selesai時 pemrosesan
eventBus.on("order.completed", async ({ orderId }) => {
const order = await prisma.order.findUnique({
where: { id: orderId },
include: { user: true, items: true },
});
if (!order) return;
// 在庫 pembaruan
for (const item of order.items) {
await prisma.product.update({
where: { id: item.productId },
data: { stock: { decrement: item.quantity } },
});
}
});
domaineventpola
abstract class DomainEvent {
readonly occurredAt: Date;
readonly eventId: string;
constructor() {
this.occurredAt = new Date();
this.eventId = crypto.randomUUID();
}
}
class OrderCreatedEvent extends DomainEvent {
constructor(
public readonly orderId: string,
public readonly userId: string,
public readonly items: Array<{ productId: string; quantity: number }>,
public readonly total: number
) {
super();
}
}
// Aggregate Root
class Order {
private domainEvents: DomainEvent[] = [];
static create(params: {
userId: string;
items: Array<{ productId: string; quantity: number; price: number }>;
}): Order {
const order = new Order();
const orderId = crypto.randomUUID();
const total = params.items.reduce(
(sum, item) => sum + item.price * item.quantity,
0
);
order.domainEvents.push(
new OrderCreatedEvent(orderId, params.userId, params.items, total)
);
return order;
}
pullDomainEvents(): DomainEvent[] {
const events = [...this.domainEvents];
this.domainEvents = [];
return events;
}
}
CQRS pola
// Command側(writing)
interface Command<T = void> {
execute(): Promise<T>;
}
class CreateOrderCommand implements Command<string> {
constructor(
private userId: string,
private items: Array<{ productId: string; quantity: number }>
) {}
async execute(): Promise<string> {
// validasi
for (const item of this.items) {
const product = await prisma.product.findUnique({
where: { id: item.productId },
});
if (!product || product.stock < item.quantity) {
throw new Error(`Insufficient stock: ${item.productId}`);
}
}
// 注文pembuatan
const order = await prisma.order.create({
data: {
userId: this.userId,
status: "pending",
items: {
create: this.items.map((item) => ({
productId: item.productId,
quantity: item.quantity,
})),
},
},
});
// event発行
await eventBus.emit("order.created", {
orderId: order.id,
userId: this.userId,
total: 0,
});
return order.id;
}
}
// Query側(読み取り)
interface Query<T> {
execute(): Promise<T>;
}
class GetOrdersQuery implements Query<OrderSummary[]> {
constructor(
private userId: string,
private page: number = 1
) {}
async execute(): Promise<OrderSummary[]> {
// 読み取り専用 ビューからpengambilan
return prisma.orderView.findMany({
where: { userId: this.userId },
orderBy: { createdAt: "desc" },
take: 20,
skip: (this.page - 1) * 20,
});
}
}
eventstore
interface StoredEvent {
id: string;
aggregateId: string;
aggregateType: string;
eventType: string;
payload: Record<string, unknown>;
version: number;
occurredAt: Date;
}
class EventStore {
async append(
aggregateId: string,
aggregateType: string,
events: DomainEvent[],
expectedVersion: number
) {
// 楽観的ロック
const currentVersion = await this.getVersion(aggregateId);
if (currentVersion !== expectedVersion) {
throw new Error("Concurrency conflict");
}
const storedEvents = events.map((event, i) => ({
id: event.eventId,
aggregateId,
aggregateType,
eventType: event.constructor.name,
payload: event as any,
version: expectedVersion + i + 1,
occurredAt: event.occurredAt,
}));
await prisma.event.createMany({ data: storedEvents });
// event 発行
for (const event of events) {
await eventBus.emit(
event.constructor.name as any,
event as any
);
}
}
async getEvents(aggregateId: string): Promise<StoredEvent[]> {
return prisma.event.findMany({
where: { aggregateId },
orderBy: { version: "asc" },
});
}
private async getVersion(aggregateId: string): Promise<number> {
const last = await prisma.event.findFirst({
where: { aggregateId },
orderBy: { version: "desc" },
});
return last?.version ?? 0;
}
}
Pemanfaatan dengan Claude Code
event駆動arsitektur implementasi Claude Code 依頼 例.非同期pemrosesan mengenai ジョブキュー・非同期pemrosesan、外部integrasi Webhookimplementasipola juga bisa dijadikan referensi.
event駆動arsitektur penerapanして。
- type safetyなeventバス implementasi
- domaineventpola
- CQRS: command dan query 分離
- eventstore implementasi
- 既存 service層 refactoringしてintegrasi
event駆動設計 詳細 Martin Fowler - Event-Driven Architecture silakan lihat.Claude Code 使い方 公式dokumen konfirmasi bisa dilakukan.
Summary
event駆動arsitektur sistem 疎結合性 dan スケーラビリティ 高め.Claude Code 使えば、type safetyなeventバス dari CQRS、eventソーシングま 、段階的 EDA penerapan bisa dilakukan.
Tingkatkan alur kerja Claude Code kamu
50 template prompt yang sudah teruji, siap copy-paste ke Claude Code sekarang juga.
PDF Gratis: Cheatsheet Claude Code dalam 5 Menit
Perintah penting, pintasan, dan contoh prompt dalam satu halaman siap cetak.
Tentang Penulis
Masa
Engineer yang aktif menggunakan Claude Code. Mengelola claudecode-lab.com, media teknologi 10 bahasa dengan lebih dari 2.000 halaman.
Artikel Terkait
Pengantar Claude Code Agent SDK — Bangun Agen Otonom dengan Cepat
Pelajari cara membangun agen AI otonom dengan Claude Code Agent SDK. Mencakup setup, definisi tool, dan eksekusi multi-langkah dengan contoh kode praktis.
Panduan Lengkap Teknik Manajemen Konteks di Claude Code
Pelajari teknik praktis untuk memaksimalkan context window Claude Code. Mencakup optimasi token, pembagian percakapan, dan penggunaan CLAUDE.md.
Setup MCP Server Claude Code dan Use Case Praktis
Panduan lengkap tentang kemampuan MCP server Claude Code. Pelajari cara menghubungkan tool eksternal, mengonfigurasi server, dan contoh integrasi dunia nyata.