Laden...

Redundante Daten zwischen mehreren Klassen

Erstellt von Lighttec vor 5 Jahren Letzter Beitrag vor 5 Jahren 2.547 Views
L
Lighttec Themenstarter:in
6 Beiträge seit 2018
vor 5 Jahren
Redundante Daten zwischen mehreren Klassen

Hallo,

ich habe in meinem Program zwei separate Listen von Kontoaktivitäten sowie von Konten. Momentan hat sowohl die Klasse Kontoaktivität, als auch die Klasse Konto ein Id-Feld, da ich die zwei Listen getrennt voneinander speichere. Meine Klassenbeziehung sind als prinzipiell genau wie in einer relationalen Datenbank, eine Kontoaktivität hat zwei Fremdschlüssel Zahlungsempfänger und Zahlungsauftraggeber.

Die eigentlich Operationen werden aber auf dem Konto ausgeführt (Kontostand abfragen, neue Buchungen erstellen, etc.). Wäre es da nicht sinnvoller in dem jeweiligen Konto eine Liste mit allen relevanten Transaktionen zu speichern? Gerade die Berechnung des Kontostandes würde dadurch natürlich vereinfacht werden. Allerdings könnte es dann auch zu Dateninkonsistenzen kommen, wenn eine Buchung, die zwei Konten betrifft, nur auf einem gelöscht wird.

Was sind eure Meinungen dazu? Sollte jedes Konto eine Liste mit Buchungen haben, oder soll ich das mit der Id beibehalten?

Viele Grüße,
Lighttec

P
1.090 Beiträge seit 2011
vor 5 Jahren

Ich hab ehrlich gesagt nicht genau verstanden was, du machen möchtes.

Also in ein (SQL) DB ist der Eintrag für beide Weg wenn du ihn in der zwischen Tabelle löschst.

Objekt Orientiert können sich beide Klassen die gleiche Liste Teilen. Dann wird der Eintrag aus beiden gelöscht. Du kannst aber auch eine übergeordnete Klasse (Bank) machen welche die Verwaltung übernimmt.

(Es ist besser wenn man nicht Versucht DB Konzepte auf die OOP zu übertragen)

Von der Buchhaltung her (wenn ich es richtig im Kopf habe) darfst du den Eintrag gar nicht Löschen sondern musst eine Stornierung buchen. Also gleicher Betrag in anderer Richtung.

Erklär vielleicht mal was du machen möchtest. Und nicht wie du es Programmieren würdest.

Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern

16.842 Beiträge seit 2008
vor 5 Jahren

Finanz-Transaktionen sind ein Paradebeispiel Event-Sourcing.

Das bedeutet:
> Jede Transaktion wird protokolliert (im Event Store). Eine Transaktion ist dabei ein Event.
> Die Summe bzw. der Kontostand wird (der State) in der Tabelle (=> Application State Storage) gehalten
> Eine neue Transaktion startet ein Event, ein Eventhandler berechnet den neuen Kontostand
> Es wird nie(!) etwas gelöscht, das für das Bilden des States relevant ist
> Es kann nie* zu Inkonsistenzen kommen

Das Gesamtsystem ist damit voll auditierbar.
Sollte - warum auch immer - der aktuelle Kontostand, der in einem temporären Summen-Feld gehalten wird, verloren gehen, dann können alle Transaktionen erneut durchlaufen werden, um jederzeit und immer den Kontostand ermitteln zu können.

Solche Systeme sind gerade im Finanzwesen absolut gesetzt, ebenso beim Umgang von Bestellungen, Logistik...

PS: Im Finanzwesen werden viele Anforderungen an Systeme und die Datenhaltung durchaus von der BaFin vorgegeben.

* jedenfalls technisch durch eine korrekte Software.
Physikalisch Zugriff auf ungesicherte Datenbanken kann solch ein Konzept nie abdecken.
Sollte ein "physikalischer" Schutz vor Manipulation von Events gewünscht sein, dann sind Konzepte wie Blockchain existent.

3.511 Beiträge seit 2005
vor 5 Jahren

Ich komme aus der Finanzwelt und kann Abt da nur voll und ganz zustimmen. Gerade der Punkt "Allerdings könnte es dann auch zu Dateninkonsistenzen kommen, wenn eine Buchung, die zwei Konten betrifft, nur auf einem gelöscht wird", hat mich erzittern lassen 😃. Nie nie nie, werden Buchungen gelöscht! Sie werden storniert. Nur so bleibt alles konsistent.

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

L
Lighttec Themenstarter:in
6 Beiträge seit 2018
vor 5 Jahren

Danke für die Antworten, ich habe beim erneuten Lesen den Kopf über mich selbst geschüttelt: Natürlich dürfen die Buchungen nicht gelöscht werden, wie bin ich nur auf so einen Unsinn gekommen?

Mein Konzept an sich ist nicht neu, viele Anwendungen bieten das bereits, aber eben nicht in der Art und Weise, die ich gerne haben möchte: Prinzipiell geht es darum gebuchte Umsätze von einem oder mehreren Bankkonten auf mehrere lokale Budgettöpfe aufzuteilen und so einen besseren Überblick über das verfügbare Geld zu erhalten. Das Program ist schon fertig und funktioniert auch, allerdings habe ich mir nun den Refactor-Hut aufgesetzt, da der Code hauptsächlich durch Probieren und Debuggen entstanden ist und (noch) wenig klare Struktur aufweist. Daher beschäftige ich mich jetzt erstmal mit der Datenstruktur und den Beziehungen der Daten, bevor ich dann neuen Code schreibe.

Das mit den Events klingt interessant, da werde ich mich nochmal ransetzen.

L
Lighttec Themenstarter:in
6 Beiträge seit 2018
vor 5 Jahren

Ich habe noch eine Frage zu dem Event Sourcing-Ansatz:
Verstehe ich das richtig, dass meine Klasse 'Topf' eine Projektion des Eventstreams darstellt? Und wenn ich einen Umsatz einem Topf zuordnen will, sollte ich die Events dann in EinzahlungEvent und AbhebungEvent trennen? Oder sollte ich nur ein UmsatzErstelltEvent erstellen?

Mein Gedanke dahinter ist folgender: Jeder Topf bekommt seinen eigenen Eventstream. Dort können dann Einzahlungs- und Abhebungsevents gespeichert werden. Bei Umbuchungen zwischen zwei Töpfen würde der eine Topf ein Einzahlungsevent und der andere Topf ein Abhebungsevent bekommen. Könnte das nicht zu Inkonsistenzen führen? Wenn beispielsweise beim Abspeichern der Events in der Datenbank ein Fehler auftritt und nur das Einzahlevent, nicht aber das Abhebeevent gespeichert wird?

Wenn ich aber stattdessen ein atomares UmsatzErstelltEvent benutze, dann muss ich in dem Event Zahlungsempfänger und auch Zahlungssender abspeichern. Ich bräuchte dann zusätzlich noch einen UmsatzAggregator, dem diese Events zugeordnet werden können. In diesem Falle könnte ich aus der Datenbank nicht direkt die Umsatzevents für einen Topf laden, sondern müsste alle Umsatzevents in dem Umsatzaggregator speichern und sie dann in meinem Program manuell meinen Töpfen wieder zuordnen. Ich kann mir vorstellen, dass das wiederum mehr Aufwand bedeutet.

Gibt es da einen bestimmten Ansatz, den man verfolgen sollte?

Und noch eine Frage: Wie sieht das aus mit dem Datenverbrauch? Theoretisch muss ich ja den gesamten Eventstream runterladen und neu abspielen, um den aktuellen Zustand zu bekommen. Geht das nicht, gerade bei mobilen Anwendung, ordentlich ins verbrauchte Datenvolumen?

16.842 Beiträge seit 2008
vor 5 Jahren

Verstehe ich das richtig, dass meine Klasse 'Topf' eine Projektion des Eventstreams darstellt?

Ich weiß nicht, woher der Name "Topf" kommt, und was er darstellt.
Aber an für sich gibt es eben eine Trennung von Schreib- und Lesevoränge; also Commands und Queries.

Alles, was Du abfragst, ist demnach ein Query.

Und wenn ich einen Umsatz einem Topf zuordnen will, sollte ich die Events dann in EinzahlungEvent und AbhebungEvent trennen? Oder sollte ich nur ein UmsatzErstelltEvent erstellen?

Generell ist die Trennung zu bevorzugen.
Denn Du designst Events ja so, dass die so genaue wie möglich das Event darstellen - sodass eben potentiell viele Konsumenten dieses Event so genau wie möglich subscriben können.

Ein Konsument, den nur das Einzahlen interessiert. zB eine Middleware, die Geldwäsche nach Merkmalen prüft, interessiert sich zB nur für die Geld-Empfänge. Eine Middleware, die zB. Zoll-Embargos prüft, eben nur für Geld-Ausgänge.

Könnte das nicht zu Inkonsistenzen führen?
Wenn beispielsweise beim Abspeichern der Events in der Datenbank ein Fehler auftritt und nur das Einzahlevent, nicht aber das Abhebeevent gespeichert wird?

Jap. Jetzt wird es komplexer.
Prinzipiell gibt es stets den Wunsch, Event Chaining zu vermeiden - denn das wird komplex und führt nicht selten zu einem Kontrollverlust.

Daher gibt es in Event Sourcing durchaus SAGA.
Saga kann man als Prozesse sehen, die länger leben bzw. Transaktionen mehrerer Commands.
Länger leben nicht im Sinne von Zeit, sondern über "mehrere Messages hinweg".

Und noch eine Frage: Wie sieht das aus mit dem Datenverbrauch? Theoretisch muss ich ja den gesamten Eventstream runterladen und neu abspielen, um den aktuellen Zustand zu bekommen. Geht das nicht, gerade bei mobilen Anwendung, ordentlich ins verbrauchte Datenvolumen?

Event Sourcing ist nichts für eine App, sondern im Bereich des Backends anzusiedeln.
Eine App würde prinzipiell nie Teil eines Event Sourcing sein. Eine App würde nur mit einem Backend sprechen, das dies verinnerlicht hat.

Wenn Du kein Backend hast, das Deine gesamte Businesslogik übernimmt, dann ist Event Sourcing nichts für Deine Anwendung.
In Apps (oder eine einzelne Anwendung) passt dieses Konzept selten, weil Event Sourcing schon ein aufwändiges, strukturelles Thema ist.

L
Lighttec Themenstarter:in
6 Beiträge seit 2018
vor 5 Jahren

Ich weiß nicht, woher der Name "Topf" kommt, und was er darstellt.
Aber an für sich gibt es eben eine Trennung von Schreib- und Lesevoränge; also Commands und Queries.

Das hatte ich in dem vorherigen Post geschrieben, ein Topf ist sozusagen nur eine andere Bezeichnung für ein lokales Konto. Das läuft dann auf CQRS hinaus?

Generell ist die Trennung zu bevorzugen.
Denn Du designst Events ja so, dass die so genaue wie möglich das Event darstellen - sodass eben potentiell viele Konsumenten dieses Event so genau wie möglich subscriben können.

Ein Konsument, den nur das Einzahlen interessiert. zB eine Middleware, die Geldwäsche nach Merkmalen prüft, interessiert sich zB nur für die Geld-Empfänge. Eine Middleware, die zB. Zoll-Embargos prüft, eben nur für Geld-Ausgänge.

Okay, ja das ergibt Sinn. Gleichzeitig könnte man auch einen Reaktor auf die Einzahlevents ansetzen, der eine automatische Zuordnung vornimmt.

Event Sourcing ist nichts für eine App, sondern im Bereich des Backends anzusiedeln.
Eine App würde prinzipiell nie Teil eines Event Sourcing sein. Eine App würde nur mit einem Backend sprechen, das dies verinnerlicht hat.

Wenn Du kein Backend hast, das Deine gesamte Businesslogik übernimmt, dann ist Event Sourcing nichts für Deine Anwendung.
In Apps (oder eine einzelne Anwendung) passt dieses Konzept selten, weil Event Sourcing schon ein aufwändiges, strukturelles Thema ist.

Okay, also beispielsweise läuft das Backend zusammen mit dem Persistenzmechanismus auf einem Server und die App (sei es nun Desktop oder Mobil) holt sich nur die Projektionen vom Backend?

Ich lass mir das ganze nochmal durch den Kopf gehen, ich glaube Event Sourcing ist dann doch nicht das, nach dem ich suche. Aber dennoch ein sehr sehr interessanter Ansatz!

16.842 Beiträge seit 2008
vor 5 Jahren

Das läuft dann auf CQRS hinaus?

CQRS ist mit der weit verbreitetste Ansatz dafür.

Okay, also beispielsweise läuft das Backend zusammen mit dem Persistenzmechanismus auf einem Server und die App (sei es nun Desktop oder Mobil) holt sich nur die Projektionen vom Backend?

Genau.

L
Lighttec Themenstarter:in
6 Beiträge seit 2018
vor 5 Jahren

Angenommen ich habe jetzt mein Backend, welches auf Event Sourcing basiert. Das Backend läuft auf einem externen Server. Wenn ich jetzt einen neuen Umsatz erstelle, dann muss ich doch theoretisch auch meine App mittels Event Sourcing realisieren, oder? Ich meine, die App muss ja auch die Events an das Backend senden, damit dieses das ganze persistieren kann.

Verstehe ich da irgendwa was falsch?

16.842 Beiträge seit 2008
vor 5 Jahren

Prinzipiell ja, denn man gibt den Event Sourcing Bereich nicht "raus".

Microservices in einer entsprechenden Umsetzung gibt man ja auch nicht nach außen raus.
Applikationen sprechen immer mit Hilfe von Connectors - nichts anderes als APIs. Diese Connectors wandeln dann zB eine REST Anfrage in ein Event um.
Die Antwort kann aufgrund der Architektur ja nicht direkt erfolgen, daher würde eine API in diesem Fall immer mit 201 Created antworten.
Der Rückkanal erfolgt dann zB. über WebSockets.

Im Endeffekt ändert sich eigentlich für die App nichts - nur für das Backend.

Wie gesagt, Event Sourcing oder CQRS sind wirklich sehr mächtige und sehr leistungsstarke Systeme.
Der Aufwand das Umzusetzen - auch an die Infrastruktur - ist alles andere als gering; und daher auch nicht für jeden Zweck wirtschaftlich.

Neben dem Aufwand ist aber auch das Mindset ein Problem: es gibt nicht wirklich viele Entwickler, die mit Event Sourcing sofort zurecht kommen - und die Einstiegshürde ist ja auch nicht gering.
Mein Hinweis mit Event Sourcing sollte jetzt eigentlich auch nicht Dein ganzen Plan umwerfen 😃

Im Anhang eine sehr vereinfachte Darstellung, wie die Tier-View aussehen könnte.
Das Event Sourcing steht quasi in Konkurrenz zu Micro Services (was evtl. etwas verwirrt, weil Du durchaus Micro Services zur Umsetzung von Event Sourcing verwenden kannst) - aber auf die Schnelle ist mir keine bessere Darstellung eingefallen.
Aber es ist hoffentlich zu erkennen, dass eine App nicht direkt auf den Kern der Plattform zugreift; egal wie umgesetzt.
Da spielen natürlich Berechtigungen genauso eine Rolle wie zB die Versionierung von Apps (Multi Version Support etc).

16.842 Beiträge seit 2008
vor 5 Jahren

Jeff Fritz stellt heute um 16 Uhr in seinem C# Stream den CQRS Pattern vor.
https://www.twitch.tv/csharpfritz

Das Video ist dann auf Twitch auch nach der Live Session verfügbar.
(https://www.twitch.tv/videos/295926850)

L
Lighttec Themenstarter:in
6 Beiträge seit 2018
vor 5 Jahren

Danke für all die Tipps! Ich denke ich werde das Backend auf dem Server laufen lassen. Die Clientanwendung kann sich dann die Projektionen runterladen und bei Bedarf auch Daten (bzw. Events) noch nachladen, um den Datenverbrauch zu reduzieren. Das Backend wird dann eine Schnittstelle bereitstellen, um neue Daten einzufügen. Es dann nimmt sozusagen Kommandos entgegen, die ich theoretisch auch auf dem Client cachen könnte, bis eine bessere Verbindung (oder WLAN) besteht.