Events sind nicht gleich Events. Je nach Zweck, Ursprung und Verwendung lassen sich verschiedene Typen unterscheiden, die jeweils eigene Charakteristika und Anwendungsgebiete haben. Das Verständnis dieser Unterscheidungen ist fundamental für die korrekte Modellierung event-getriebener Systeme.
Events lassen sich nach ihrem semantischen Gehalt in drei Hauptkategorien einteilen:
Zustandsänderungs-Events dokumentieren, dass sich
der Zustand einer Geschäftsentität verändert hat. Sie beschreiben ein
bereits eingetretenes Faktum und sind unveränderlich. Ein
OrderPlaced Event signalisiert beispielsweise, dass eine
Bestellung erfolgreich aufgegeben wurde – dieser Zustand ist historisch
und kann nicht rückgängig gemacht werden.
Aktions-Events fordern eine bestimmte Handlung oder
Verarbeitung an. Sie haben eher Command-Charakter, auch wenn sie als
Events modelliert sind. Ein ProcessPayment Event könnte die
Zahlungsabwicklung für eine Bestellung anstoßen.
Ableitungs-Events entstehen durch Verarbeitung oder
Aggregation anderer Events. Sie repräsentieren berechnete oder
abgeleitete Informationen. Ein DailyOrderSummary Event
könnte aus allen OrderPlaced Events eines Tages generiert
werden.
| Event-Typ | Charakteristikum | E-Commerce Beispiel | Zeitbezug |
|---|---|---|---|
| Zustandsänderung | Dokumentiert Fakten | OrderPlaced, PaymentCompleted |
Vergangenheit |
| Aktion | Fordert Verarbeitung | ProcessPayment, ReserveInventory |
Zukunft |
| Ableitung | Aggregiert/Berechnet | DailyOrderSummary,
CustomerLifetimeValue |
Zeitlos |
Domain Events entstehen direkt aus der
Geschäftslogik eines Bounded Context heraus. Sie repräsentieren
geschäftsrelevante Ereignisse in der Fachdomäne und verwenden die
Ubiquitous Language des jeweiligen Kontexts. Im E-Commerce wären das
Events wie OrderPlaced, PaymentProcessed oder
ProductAddedToCart.
// Spring Boot - Domain Event
@Component
public class OrderDomainEvents {
public static class OrderPlaced {
private final String orderId;
private final String customerId;
private final List<OrderItem> items;
private final BigDecimal totalAmount;
private final Instant placedAt;
// Constructor, getters...
}
public static class OrderCancelled {
private final String orderId;
private final String reason;
private final Instant cancelledAt;
// Constructor, getters...
}
}# Python - Domain Event
from dataclasses import dataclass
from typing import List
from datetime import datetime
from decimal import Decimal
@dataclass(frozen=True)
class OrderPlaced:
order_id: str
customer_id: str
items: List[dict]
total_amount: Decimal
placed_at: datetime
@dataclass(frozen=True)
class OrderCancelled:
order_id: str
reason: str
cancelled_at: datetimeIntegration Events dienen der Kommunikation zwischen verschiedenen Bounded Contexts oder externen Systemen. Sie enthalten oft zusätzliche technische Informationen und können abstrahierte oder transformierte Versionen von Domain Events sein.
// Spring Boot - Integration Event
public class OrderIntegrationEvent {
private String eventId;
private String eventType;
private String source;
private Instant timestamp;
private Map<String, Object> data;
// Zusätzliche Metadaten für Integration
private String correlationId;
private String causationId;
private Integer version;
}# Python - Integration Event
@dataclass(frozen=True)
class OrderIntegrationEvent:
event_id: str
event_type: str
source: str
timestamp: datetime
data: dict
# Integration-spezifische Metadaten
correlation_id: str
causation_id: str
version: intDomain Events bleiben innerhalb ihres Ursprungskontexts rein und ausdrucksstark, während Integration Events die notwendige Flexibilität für systemübergreifende Kommunikation bieten.
Business Events beschreiben Ereignisse, die für
Geschäftsanwender verständlich und relevant sind. Sie korrespondieren
direkt mit Geschäftsprozessen und können in der Regel mit Fachbegriffen
erklärt werden. CustomerRegistered,
OrderShipped oder PaymentDeclined sind
typische Business Events.
Technical Events entstehen aus technischen
Notwendigkeiten der Systemarchitektur. Sie dienen der Koordination
zwischen Systemkomponenten, haben aber keinen direkten Geschäftsbezug.
DatabaseConnectionPoolExhausted, CacheEvicted
oder ServiceHealthCheck sind Technical Events.
// Spring Boot - Business vs. Technical Events
public class BusinessEvent {
// Geschäftssprache, domänenspezifisch
public static class CustomerUpgradedToPremium {
private String customerId;
private String previousTier;
private String newTier;
private BigDecimal upgradeBonus;
}
}
public class TechnicalEvent {
// Technische Systemereignisse
public static class OrderServiceInstanceStarted {
private String instanceId;
private String version;
private Instant startTime;
private Map<String, String> configuration;
}
}Die Trennung hilft bei der Klarstellung der Zielgruppe: Business Events interessieren Produktmanager und Geschäftsanwender, Technical Events sind für Entwickler und Betriebsteams relevant.
Die Granularität von Events beeinflusst maßgeblich die Systemarchitektur. Zu fein granulare Events können zu Event-Storms führen, zu grob granulare Events erschweren flexible Verarbeitung.
Fein granulare Events beschreiben atomare Geschäftsereignisse:
// Sehr fein granular
public class ItemAddedToCart {
private String cartId;
private String productId;
private Integer quantity;
}
public class CartQuantityUpdated {
private String cartId;
private String productId;
private Integer oldQuantity;
private Integer newQuantity;
}Grob granulare Events fassen zusammengehörige Informationen zusammen:
// Gröbere Granularität
public class CartModified {
private String cartId;
private List<CartChange> changes;
private CartSnapshot currentState;
public static class CartChange {
private String productId;
private String changeType; // ADD, UPDATE, REMOVE
private Integer oldQuantity;
private Integer newQuantity;
}
}Event-Komposition ermöglicht es, aus mehreren atomaren Events zusammengesetzte Events zu bilden:
# Python - Event-Komposition
@dataclass(frozen=True)
class OrderCompleted:
"""Komponiertes Event aus mehreren atomaren Events"""
order_id: str
payment_confirmed: bool
inventory_reserved: bool
shipping_prepared: bool
@classmethod
def from_atomic_events(cls, order_placed, payment_event,
inventory_event, shipping_event):
return cls(
order_id=order_placed.order_id,
payment_confirmed=payment_event.status == 'confirmed',
inventory_reserved=inventory_event.status == 'reserved',
shipping_prepared=shipping_event.status == 'prepared'
)Die richtige Granularität hängt von den Verarbeitungsanforderungen ab. Für Real-time Analytics könnten fein granulare Events optimal sein, für Reporting-Zwecke eher grob granulare Events.
In der E-Commerce-Domäne manifestieren sich die verschiedenen Event-Typen folgendermaßen:
// Spring Boot - Vollständiges Beispiel verschiedener Event-Typen
@Component
public class ECommerceEvents {
// Domain Event - Zustandsänderung
public static class OrderPlaced {
private String orderId;
private String customerId;
private List<OrderItem> items;
private Instant placedAt;
}
// Integration Event - Systemübergreifend
public static class OrderPlacedIntegration {
private String eventId;
private String orderId;
private Map<String, Object> customerData;
private String targetSystem;
}
// Technical Event - Systemverhalten
public static class OrderProcessingStarted {
private String orderId;
private String processingNode;
private Duration estimatedDuration;
}
// Ableitungs-Event - Berechnet
public static class DailyOrderMetrics {
private LocalDate date;
private Integer totalOrders;
private BigDecimal totalRevenue;
private BigDecimal averageOrderValue;
}
}# Python - Entsprechende Implementierung
from abc import ABC
from enum import Enum
class EventType(Enum):
DOMAIN = "domain"
INTEGRATION = "integration"
TECHNICAL = "technical"
DERIVED = "derived"
class BaseEvent(ABC):
"""Basis für alle Event-Typen"""
pass
@dataclass(frozen=True)
class OrderPlaced(BaseEvent):
"""Domain Event - Zustandsänderung"""
order_id: str
customer_id: str
items: List[dict]
placed_at: datetime
@property
def event_type(self) -> EventType:
return EventType.DOMAIN
@dataclass(frozen=True)
class OrderProcessingMetrics(BaseEvent):
"""Derived Event - Berechnung"""
timeframe: str
orders_processed: int
average_processing_time: float
error_rate: float
@property
def event_type(self) -> EventType:
return EventType.DERIVEDDie bewusste Kategorisierung von Events nach Typ, Herkunft und Granularität schafft Klarheit in der Systemarchitektur und erleichtert die Entscheidung, welche Events wann und wo verwendet werden sollen. Diese Fundament bildet die Basis für alle weiteren Modellierungsentscheidungen in event-getriebenen Systemen.