In vielen Projekten kommt früher oder später der Wunsch nach Historisierung oder Protokollierung von Änderungen auf. Im aktuellen Projekt kommt dazu noch der Wunsch nach geplanten Änderungen, d.h. es soll möglich sein Daten so zu ändern, dass die Änderungen erst zu einem Zeitpunkt in der Zukunft in Kraft treten.
Das Problem mit diesen Wünschen und Anforderungen ist, dass sie meist nicht wohl definiert sind. Dem entsprechend ist es schwer zu beurteilen, wie die Funktion zu modellieren ist. In diesem Artikel werde ich die verschiedenen mir bekannten Strategien vorstellen und vergleichen. Da ich diese Ansätze nicht als bekannte, benannte Patterns kenne, habe ich ihnen nach eigenem Gusto Namen gegeben.
Audittrail
Bei jeder Änderung eines Objektes wird ein zusätzliches Objekt als Kopie erzeugt, um einen Timestamp ergänzt und gespeichert.
Der Vorteil dieser Strategie ist ihre Einfachheit. Sie ist sogar so einfach, dass sie mit Datenbankmitteln leicht zu implementieren ist, z.B. über Trigger. Mit einem solchen Audit-Log ist zu jedem Objekt der Zustand zu einem bestimmten Zeitpunkt ermittelbar. Ganze Objektstrukturen sind aber nur mühselig zu rekonstruieren, da für jedes Element des Objektgraphen an Hand des Zeitstempels die passende Version gefunden werden muss.
Change Log
Ähnlich wie beim Audittrail wird hier bei jeder Änderung ein Datensatz weggeschrieben, der beschreibt aber nicht den Zustand vor oder nach der Änderung, sondern die Änderung selbst, etwa in dem alter und neuer Wert der betrachteten Attribute weggeschrieben werden. Auch dies kann recht einfach automatisiert werden.Ein solches Change Log kann für Analysen sehr interessant sein. Es können Fragen wie 'Wie oft ändern Kunden ihre E-Mail Adresse' sehr einfach beantwortet werden. Wenn es wirklich vollständig sein soll, wird es aber sehr schnell sehr umfangreich, da für jedes Attribut jeweils der alte und der neue Wert gespeichert werden muss.
Snapshots
Als Snapshots bezeichne ich Kopien eine Objektgraphen zu einem bestimmten Zeitpunkt. Im Gegensatz zu den ersten beiden Strategien wird hier wirklich ein Objektgraph historisiert, nicht ein einzelnes Objekt beziehungsweise ein einfacher Datensatz. Dabei kann die historisierte Version des Objektgraphen durchaus auch eine ganz andere Struktur haben als der ursprüngleiche Objektgraph, da man mit historisierten Informationen oft ganz andere Dinge tun möchte, als mit aktuellen Daten. Der Vorteil dieses Ansatzes liegt in der direkten Navigierbarkeit des Objektgraphen, wie man es bei einem Domänen basierten Design erwartet. Nachteilig ist, dass die Teile des Objektgraphes, die sich langsamer ändern immer wieder mit historisiert werden, obwohl sie sich geändert haben. Außerdem muss jeder auf diese Weise historisierbarer Teilgraph einzelnd identifiziert werden.
Versionierte Objekte
Beim Versionierten Objekt gibt es zu einem Objekt mehrere Versionen, die als Teil des Domänen Modells modelliert werden. Etwa so:
public class Thing {
private Set
versions;
public ThingVersion getVersion(Date timestamp){...}
...
}
public class ThingVersion {
private Date validFrom;
...
}
Während die vorigen Ansätze nur vergangene Zustände protokolliert werden, können mit diesem Ansatz auch geplante Änderungen abgebildet werden. Wenn keine zusätzlichen Einschränkungen vornimmt, können auch in der Vergangenheit liegende Informationen auf die gleiche Weise bearbeitet werden, wie zukünftige. Für Audit Funktionalität, d.h. um bestimmte Sachverhalte im Nachhinein zu belegen ist es daher weniger geeignet.
Andere Objekte können je nach Bedarf auf ein Thing, d.h. das fragliche Objekt unabhängig von Versionen, oder eine ThingVersion verweisen, d.h. auf eine bestimmte Version des Objektes. Am spannendsten ist aber vielleicht die Möglichkeit mit einer Referenz auf das Thing + einem Timestamp auf den Zustand des Objektes zu einem bestimmten Zeitpunkt zu verweisen, unabhängig davon welchen Zustand das Objekt zu diesem Zeitpunkt hat. D.h. die zu dem Zeitpunkt gültige Version kann sich noch ändern, ohne dass das referenzierende Objekt aktualisiert werden müsste.
Dieser Ansatz ist extrem mächtig, allerdings kann die Lage schnell verwirrend werden, wenn versionierte Objekte auf andere versionierte Objekte verweisen, oder wenn ein Objekt auf unterschiedliche Versionen des gleichen Objektes verweist. Wie bei jeder starken Medizin gilt es also auch hier die richtige Dosierung zu ermitteln.
Und vor jeder Medikamentation sollte natürlich ein klare Diagnose stehen.
Talks
Wan't to meet me in person to tell me how stupid I am? You can find me at the following events: