2014-05-04 13 views
10

Ich lese Accounting Pattern und ziemlich neugierig über die Implementierung in CQRS.Wie modellieren Banküberweisung in CQRS

Ich denke AccountingTransaction ein Aggregat Wurzel ist, da es die unveränderliche schützt:

Kein Geld Lecks, sollte es Übertragung von einem Konto auf ein anderes sein.

public class AccountingTransaction { 
    private String sequence; 
    private AccountId from; 
    private AccountId to; 
    private MonetaryAmount quantity; 
    private DateTime whenCharged; 

    public AccountingTransaction(...) { 
     raise(new AccountingEntryBookedEvent(sequence, from, quantity.negate(),...); 
     raise(new AccountingEntryBookedEvent(sequence, to, quantity,...); 
    } 
} 

Wenn die AccountingTransaction zu seinem Repository hinzugefügt wird. Es veröffentlicht mehrere AccountingEntryBookedEvent, die verwendet werden, um den Kontostand der entsprechenden Konten auf der Abfrageseite zu aktualisieren.

Ein Aggregat Stamm aktualisiert pro DB-Transaktion, eventuelle Konsistenz, so weit so gut.

Aber was ist, wenn einige Konten Übertragungsbeschränkungen anwenden, wie z. B. kann die Menge nicht mehr übertragen, die aktuelle Balance? Ich kann die Abfrageseite verwenden, um den Kontostand abzurufen, aber ich mache mir Sorgen, dass Daten von der Abfrageseite veraltet sind.

public class TransferApplication { 
    public void transfer(...) { 
     AccountReadModel from = accountQuery.findBy(fromId); 
     AccountReadModel to = accountQuery.findBy(toId); 
     if (from.balance() > quantity) { 
      //create txn 
     } 
    } 
} 

Sollte ich das Konto in der Befehlsseite modellieren? Ich muss mindestens drei Aggregatwurzeln pro DB-Transaktion (von/zu Konto und Konto txn) aktualisieren.

public class TransferApplication { 
    public void transfer(...) { 
     Account from = accountRepository.findBy(fromId); 
     Account to = accountRepository.findBy(toId); 
     Transaction txn = new Transaction(from, to, quantity); 
     //unit or work locks and updates all three aggregates 
    } 
} 

public class AccountingTransaction { 
    public AccountingTransaction(...) { 
     if (from.permit(quantity) { 
      from.debit(quantity); 
      to.credit(quantity); 
      raise(new TransactionCreatedEvent(sequence, from, to, quantity,...); 
     } 
    } 
} 
+0

Möchten Sie Bankanwendung mit DDD? – Developer

+0

@Singh danke für Ihren Kommentar. Ja, DDD mit CQRS. – Hippoom

+0

Ich habe ein Projekt über Bankapplication. Willst du es? – Developer

Antwort

3

Es gibt einige Anwendungsfälle, die keine Konsistenz zulassen. CQRS ist in Ordnung, aber die Daten können müssen 100% konsistent sein. CQRS impliziert keine endgültige Konsistenz.

Der Transaktions-/Domänenmodellspeicher ist jedoch konsistent und der Saldo wird in konsistent sein, den speichern, da es den aktuellen Status darstellt. In diesem Fall sollte die Transaktion trotzdem fehlschlagen, unabhängig von einer inkonsistenten Abfrageseite. Dies wird eine etwas seltsame Benutzererfahrung sein, so dass ein 100% konsistenter Ansatz besser sein könnte.

3

Ich erinnere mich an Bits davon, aber M Fowler verwendet eine andere Bedeutung von Ereignis im Vergleich zu einem Domain-Ereignis. Er verwendet den "falschen" Begriff, da wir in seiner "Ereignis" -Definition einen Befehl erkennen können. Also im Grunde spricht er über Befehle, während ein Domain-Event etwas ist, das passiert ist und sich niemals ändern kann.

Es ist möglich, dass ich nicht ganz verstanden habe, dass Fowler sich darauf bezieht, aber ich würde die Dinge anders modellieren, genauer so nah wie möglich an der Domäne. Wir können nicht einfach ein Muster extrahieren, das immer auf eine finanzielle App angewendet werden kann, die kleinen Details können die Bedeutung eines Konzepts verändern.

Im Beispiel von OP würde ich sagen, dass wir eine nicht explizite 'Transaktion' haben können: Wir brauchen ein Konto mit einem Betrag und ein anderes Guthaben mit dem gleichen Betrag. Der einfachste Weg, denke ich, ist, es über eine Sage umzusetzen.

Debit_Account_A -> Konto_A_Debited -> Credit_Account_B-> Konto_B_Credited = Transaktion abgeschlossen.

Dies sollte in wenigen ms in den meisten Sekunden passieren und dies würde ausreichen, um ein gelesenes Modell zu aktualisieren. Menschen und Browser sind langsamer als ein paar Sekunden. Und ein Benutzer weiß, F5 zu schlagen oder einige Minuten/Stunden zu warten. Ich werde mich nicht sehr um die Genauigkeit des Lesemodells kümmern.

Wenn die Transaktion explizit ist, d. H., Die Domäne hat einen Transaktionsbegriff und das Geschäft speichert Transaktionen wirklich, was eine ganz andere Geschichte ist.Aber selbst in diesem Fall würde die Transaktion wahrscheinlich durch eine Anzahl von Konto-IDs und einigen Beträgen und vielleicht einer abgeschlossenen Flagge definiert werden. An diesem Punkt ist es jedoch sinnlos, fortzufahren, weil es wirklich von der Definition und den Anwendungsfällen der Domäne abhängt.

0

Nur zwei Wörter: "Event Sourcing" mit dem Reservierungsmuster. Und vielleicht, aber nicht immer, benötigen Sie möglicherweise auch das Muster "Sagas".