15 Event-Typen: Zustandsänderung, Aktion, Ableitung

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.

15.1 Grundlegende Event-Kategorien

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

15.2 Domain Events vs. Integration Events

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: datetime

Integration 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: int

Domain Events bleiben innerhalb ihres Ursprungskontexts rein und ausdrucksstark, während Integration Events die notwendige Flexibilität für systemübergreifende Kommunikation bieten.

15.3 Business Events vs. Technical Events

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.

15.4 Event-Granularität und Komposition

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.

15.5 Praktische Anwendung der Event-Typen

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.DERIVED

Die 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.