Etkinlik kaynağı, bir etkinlik, iki toplamın durumu değişti


10

DDD ve ilgili konuların yollarını öğrenmeye çalışıyorum. Ben "banka" uygulamak için basit sınırlı bağlam fikri geldi: hesapları var, para yatırılabilir, geri çekilebilir ve aralarında aktarılabilir. Değişikliklerin geçmişini tutmak da önemlidir.

Hesap varlığını belirledim ve bu olay satın alması, değişikliklerin izlenmesinde iyi olur. Diğer varlıklar veya değer nesneleri sorunla ilgili değildir, bu yüzden onlardan bahsetmeyeceğim.

Mevduat ve para çekme işlemleri düşünüldüğünde - nispeten basittir, çünkü sadece bir agrega değiştirilmiştir.

Farklı aktarırken - iki toplama bir MoneyTransferred olayı tarafından değiştirilmelidir . DDD, bir işlemde birden çok toplama değiştirmeyi kullanımdan kaldırır. Öte yandan olay tedarikinin kuralı, olayları varlıklara uygulamak ve bunlara dayalı olarak durumu değiştirmektir. Olay sadece veritabanında saklanabilirse, sorun olmaz. Ancak olay kaynaklı varlıkların aynı anda değiştirilmesini önlemek için, her bir toplamın olay akışını düzenleyen bir şey uygulamalıyız (işlem sınırlarını korumak için). Sürüm oluşturma ile başka bir sorun geliyor - Olayları saklamak ve bunları bir araya getirmek için bunları geri okumak için basit yapıları kullanamıyorum.

Sorum şu - bu üç prensibi nasıl bir araya getirebilirim: "bir toplu bir işlem", "olay-> toplamda değişiklik" ve "eşzamanlı değişiklik önleme"?

Yanıtlar:


7

Farklı aktarırken - iki toplama bir MoneyTransferred olayı tarafından değiştirilmelidir.

Para transferi, defterleri güncellemekten ayrı bir eylemdir.

MoneyTransferred
AccountCredited
AccountDebited

Sonunda benim için gevşek olan egzersiz AccountOverdrawn, bunun bir olay olduğunu fark ediyordu , bu borsadaki diğer katılımcılara bakmadan hesabın durumunu açıklıyor, bu yüzden onu üreten bir hesaba karşı bir komut çalıştırılmalıdır.

AccountOverdrawnOkuma modelinden olduğu gibi durumu makul bir şekilde türetemezsiniz , çünkü henüz tüm olayları görüp görmediğinizi bilemezsiniz - herhangi bir anda sadece toplamın tarihi tam olarak görebilir.

Cevap, elbette, her yerde her yerde mevcut - hesaplar bankanın müşterilerine olan yükümlülüklerini yansıtması için kredilendirilir veya borçlandırılır.

Tamam, ancak bu, mevduat ve para çekme işlemleri için de AccountCredited ve AccountDebited olaylarını kullanmam gerektiği anlamına geliyor, bu yüzden sadece değişikliğin nedenini değil, başka bir eylemin neden olduğu değişikliği kaydediyorum. Eylemi geri çevirmek istersem yapamadım çünkü tüm olaylar kaydedilmedi.

Aşağıdaki tamamen emin değilim, çünkü (böyle bir durumda) işlem kimliğinin kendisi olan doğal bir korelasyon tanımlayıcısı var.

İkinci şey - bu destan gibi bir şey kullanmam gerektiği anlamına geliyor.

Biraz farklı yazım denetimi: Doğru komutları gönderen bir insan gibi bir şeye ihtiyacınız var .

Bunu yapmanın en az iki yolu vardır. Bunlardan biri, bir aboneyi dinlemek MoneyTransferredve iki komutu defterlere göndermek olacaktır.

Başka bir alternatif, işlemin ayrı bir toplu olarak işlenmesini izlemek olacaktır - bir işlem gerçekleştikten sonra yapılması gereken tüm şeylerin bir kontrol listesi olarak düşünün. Böylece bir MoneyTransferredolay işleyicisi yapılacak işi zamanlayan ve hangi işin tamamlandığını kontrol eden ProcessTransaction gönderir.


Tamam, ancak bu, mevduat ve para çekme işlemleri için de AccountCredited ve AccountDebited olaylarını kullanmam gerektiği anlamına geliyor, bu yüzden sadece değişikliğin nedenini değil, başka bir eylemin neden olduğu değişikliği kaydediyorum. Eylemi geri çevirmek istersem yapamadım çünkü tüm olaylar kaydedilmedi. Bunu nasıl yapabilirim (olayların nedensellik)? İkinci şey - bu destan gibi bir şey kullanmam gerektiği anlamına geliyor. O zaman transfer nasıl modellenmelidir? Bir an hesapta transfer yöntemi var. Denildiğinde MoneyTransferred etkinliğini yayınlar . Saga gibi bir şeye neyin başlaması gerektiğini bilmiyorum.
cocsackie

Öyle değil mi -> AccountCredited ve AccoundDebited sonra MoneyTransferred ? İlk çözüm tek işlem (hiçbir tutarlılık garantisi hem agrega günceller herhangi türden)? Ayrıca MoneyTransferred -> korelasyon yayınlayabilecek bir toplama da yoktur . İkinci çözüm daha iyi gibi görünüyor - ProcessTransaction yayınlayabilir MoneyTransferred ve ben olayları yayınlayabilirsiniz tek işlemde birden agrega değişiklik önlemek için Hesabı işlem yapılıyor sonra. Titiz olduğum için üzgünüm. Yeni başlayanlar için anlaşılması zordur - diğerinden başka bir desen kullanamazsınız.
cocsackie

1

İşleme dayalı hesapları anlamada önemli bir ayrıntı: balanceözniteliği accountaslında denormalizasyon örneğidir. Kolaylık sağlamak için orada. Gerçekte, bir hesabın bakiyesi, işlemlerinin toplamıdır ve bakiyenin olması için hesabın kendisine gerçekten ihtiyacınız yoktur .

Bunu göz önünde bulundurarak, bir para transfer etme eyleminin güncellenmesi accountdeğil, içine sokulması gerekir transaction.

Bununla birlikte, bir başka önemli kural daha vardır: a ekleme eylemi transaction, (denormalize denge alanına) bir güncelleme ile atomik olmalıdır account.

Şimdi DDD agrega kavramını anlarsam, aşağıdakiler alakalı görünür:

Toplam, belirli bir bağlamdaki bir ticari işlemde değişebilecek şeyler için mantıklı bir sınırdır. Toplam, tek bir sınıfla veya çok sayıda sınıfla temsil edilebilir. Bir toplamı birden fazla sınıf oluşturuyorsa, bunlardan biri kök sınıf veya varlık olarak adlandırılır. Agregaya dışarıdan tüm erişim kök sınıfı aracılığıyla gerçekleşmelidir.

DDD tasarımı açısından şunu öneririm:

  1. Devri temsil edecek bir toplam var

  2. Toplama şu nesnelerden oluşur: transfer (kök nesne); kök nesne iki işlem listesine bağlıdır (her hesap için bir tane); ve her işlem listesi bir hesaba bağlanır.

  3. Aktarıma tüm erişim kök nesne (the transfer) tarafından meditasyon yapılmalıdır .

Eşzamansız aktarım desteği uygulamaya çalışıyorsanız, ana kodunuz aktarımı oluşturma konusunda "beklemede" durumunda olmalıdır. Parayı gerçekten hareket ettiren (işlem geçmişine ekleme ve dolayısıyla bakiyeleri güncelleme) ve aktarımı "kaydedildi" olarak ayarlayan başka bir iş parçanız veya işiniz olabilir.

Gerçek zamanlı, transfer işlemini engelleyen bir iş mantığı oluşturmak transferistiyorsanız , iş mantığı bir oluşturmalı ve bu nesne diğer aktiviteleri gerçek zamanlı olarak koordine edecektir.

Eşzamanlılık sorunlarını önleme açısından, ilk iş emri, borçlanma işlemini kaynak hesabın işlem listesine eklemek (elbette bakiyeyi güncellemek) olmalıdır. Bu, veritabanı düzeyinde atomik olarak gerçekleştirilmelidir (saklı yordam aracılığıyla). Borç oluştuktan sonra, havale işleminin geri kalanı, eşzamanlılık sorunlarından bağımsız olarak başarılı olmalıdır, çünkü hedef hesaba krediyi önleyen herhangi bir iş kuralı olmamalıdır.

(Gerçek dünyada, banka hesaplarında tembel iki aşamalı bir taahhüt kavramını destekleyen bir dekontu kavramı vardır. Not postasının oluşturulması hafif ve kolaydır ve ayrıca sorunsuz bir şekilde geri alınabilir. sabit bir gönderiye yapılacak not, paranın gerçekten hareket ettiği - bu geri alınamaz - ve iki aşamalı taahhüdün ikinci aşamasını temsil eder, ancak tüm doğrulama kuralları kontrol edildikten sonra gerçekleşir).


0

Ayrıca şu anda öğrenme aşamasındayım. Uygulama açısından bakıldığında, bu eylemi gerçekleştireceğinizi hissediyorum.

Aşağıdaki olayları yükselten TransferMoneyCommand gönder [MoneyTransferEvent, AccountDebitedEvent]

Bu olayları başlatmadan önce, yüzeysel komut doğrulaması ve etki alanı mantık doğrulamasının gerçekleştirilmesi gerekeceğini unutmayın, yani hesabın yeterli bakiyesi var mı?

Tutarlılık sorunları olmadığından emin olmak için etkinliklere (sürüm oluşturma ile) devam edin. Bundan önce olayları başarabilmeyi ve kaydetmeyi başaran başka bir eşzamanlı komutun (tüm parayı geri çek gibi) olabileceğini unutmayın, bu nedenle toplamın mevcut durumu güncel olmayabilir ve bu nedenle olaylar eski durumda yükseltilir ve yanlıştır. Olayların kaydedilmesi başarısız olursa, komutu en baştan yeniden denemeniz gerekir.

Olaylar başarıyla veritabanına kaydedildikten sonra, oluşturulan iki olayı yayımlayabilirsiniz.

AccountDebitedEvent, parayı ödeme yapan kişinin hesabından kaldıracaktır (toplu durumu ve ilgili görünüm / projeksiyon modellerini günceller)

MoneyTransferEvent Saga / Process Manager uygulamasını başlatır.

Destan / süreç yöneticisinin görevi, alacaklının hesabını kredilendirmeye çalışmak olacaktır, eğer başarısız olursa, bakiyeyi geri ödeyene geri vermesi gerekecektir.

Saga / İşlem yöneticisi alacaklı hesabına uygulanan ve AccountCreditedEvent'ten başarılı olursa bir CreditAccountCommand yayınlayacaktır.

Bir olay kaynağı bakış açısından, bu işlemi geri almak isterseniz, bu işlemdeki tüm olayların geri alma / geri alma işlemleri için olayları yükseltmek için kullanabileceğiniz orijinal TransferMoneyCommand olarak korelasyon / nedensel kimliği olacaktır.

Yukarıdaki sorunları veya olası iyileştirmeleri önermekten çekinmeyin.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.