Ben yoksul adamın adapte edilmiş CQRS 1 Bir veri deposunda granül verilere sahip olan esneklik seviyorum çünkü analiz için büyük olanaklar sağlayan şimdi oldukça zaman ve böylece iş değeri artırmak ve okur arttırılmış performans için denormalized verileri içeren başka gerektiğinde .
Fakat ne yazık ki, başından beri, bu tür bir mimaride tam olarak iş mantığını yerleştirmem gereken sorunla mücadele ediyordum.
Anladığım kadarıyla, bir komut niyeti iletmek için bir araçtır ve kendi başına bir etki alanı ile bağları yoktur. Bunlar temelde veridir (dilsiz - dilerseniz) transfer nesneleridir. Bu, komutları farklı teknolojiler arasında kolayca aktarılabilir kılmaktır. Aynısı, başarıyla tamamlanan olaylara verilen yanıtlar olarak da olaylar için geçerlidir.
Tipik bir DDD uygulamasında iş mantığı varlıklar, değer nesneleri, toplu kökler içinde bulunur, bunlar hem veriler hem de davranış bakımından zengindir. Ancak bir komut, bir etki alanı nesnesi değildir; bu nedenle, verilerin etki alanı gösterimleriyle sınırlı kalmamalıdır, çünkü bu bunlar üzerinde çok fazla baskı oluşturur.
Yani asıl soru şudur: Mantık tam olarak nerede?
Bu mücadeleyle en sık karşılaştığımı, değerlerinin birleşimi hakkında bazı kurallar koyan oldukça karmaşık bir küme inşa etmeye çalıştığımı öğrendim. Ayrıca, etki alanı nesnelerini modellerken, bir nesnenin bir yönteme ne zaman ulaştığını bilmek geçerli bir durumda olduğunu bilerek , başarısız hızlı paradigmasını izlemeyi severim .
Bir kümenin Car
iki bileşen kullandığını varsayalım :
Transmission
,Engine
.
Hem Transmission
ve Engine
değer nesneler süper türleri olarak temsil edilir ve uygun alt türleri vardır, vardır Automatic
ve Manual
yayınlar ya Petrol
ve Electric
motorlar sırasıyla.
Bu alanda, başarıyla oluşturuldu kendi a yaşayan Transmission
olsun, Automatic
ya Manual
, ya bir iki tip Engine
tamamen gayet iyi. Ama Car
agrega sadece uygulanabilir bir kaç yeni kurallar, tanıtır Transmission
ve Engine
nesneler aynı bağlamda kullanılır. Yani:
- Bir araba
Electric
motor kullandığında , izin verilen tek şanzıman tipidirAutomatic
. - Bir araba
Petrol
motoru kullandığında , her iki türüne de sahip olabilirTransmission
.
Bu bileşen kombinasyonu ihlalini bir komut oluşturma düzeyinde yakalayabilirdim, ancak daha önce de belirttiğim gibi, yapılmaması gerektiğini anladığımdan, komut daha sonra etki alanı katmanıyla sınırlı olması gereken iş mantığını içerecektir.
Seçeneklerden biri, bu iş mantığı doğrulamasını doğrulayıcının kendisine komut vermek üzere taşımaktır, ancak bu da doğru görünmemektedir. Komutu yapıştıracağım, alıcılar tarafından elde edilen özelliklerini kontrol edip doğrulayıcıda karşılaştıracağımı ve sonuçları denetleyeceğimi hissediyorum. Bu bana Demeter yasasını ihlal ediyor gibi bağırıyor .
Söz konusu doğrulama seçeneğini atmak, uygun görünmediğinden, birinin komutu kullanması ve toplamı ondan oluşturması gerektiği anlaşılmaktadır. Peki bu mantık nerede olmalı? Somut bir komutun işlenmesinden sorumlu komut işleyicisinin içinde mi olmalı? Ya da belki de komut doğrulayıcıda mı olmalı (Ben de bu yaklaşımı sevmiyorum)?
Şu anda bir komut kullanıyorum ve sorumlu komut işleyicisi içinde ondan bir toplama oluşturuyorum. Ancak bunu yaptığımda, bir komut doğrulayıcısına sahip olsam bile hiçbir şey içermez, çünkü CreateCar
komut mevcutsa ayrı durumlar için geçerli olduğunu bildiğim bileşenler içerir, ancak toplam farklı olabilir.
Farklı doğrulama işlemlerini karıştıran farklı bir senaryo düşünelim - bir CreateUser
komut kullanarak yeni bir kullanıcı yaratın.
Komut, Id
oluşturulacak kullanıcıları ve bunlardan birini içerir Email
.
Sistem, kullanıcının e-posta adresi için aşağıdaki kuralları belirtir:
- eşsiz olmalı,
- boş olmamalı,
- en fazla 100 karakter içermelidir (en fazla db sütunu uzunluğu).
Bu durumda, benzersiz bir e-postaya sahip olmak bir iş kuralı olsa da, bir toplu halde kontrol etmek çok az mantıklıdır, çünkü sistemdeki tüm mevcut e-posta kümesini bir belleğe yüklemem ve komuttaki e-postayı kontrol etmem gerekir. agregaya karşı ( Eeeek! Bir şey, bir şey, performans.). Bu nedenle, bu kontrolü UserRepository
bir bağımlılık olarak alacak ve depoda e-postaya sahip olan bir kullanıcının zaten mevcut olup olmadığını kontrol etmek için kullanacak olan komut doğrulayıcısına taşırdım .
Buna gelince aniden diğer iki e-posta kuralını komut doğrulayıcısına da koymak mantıklı geliyor. Ama bir his kuralları dahilinde gerçekten mevcut olmalıdır sahip User
agrega ve komut doğrulayıcı sadece eşsizliği kontrol etmelidir ve doğrulama başarılı olursa ben oluşturmaya devam gerektiğini User
de agrega CreateUserCommandHandler
ve kaydedilmesine bir depo geçmek.
Böyle hissediyorum çünkü deponun kaydetme yöntemi, toplama geçtikten sonra tüm değişmezlerin yerine getirilmesini sağlayan bir toplama kabul etme olasılığı yüksektir. Mantık (örneğin boşluksuzluk) sadece komut onaylama kendiliğinden mevcutsa, başka bir programcı bu onaylamayı tamamen atlayabilir ve kaydetme yöntemini doğrudan ölümcül bir veritabanı hatasına yol açabilecek UserRepository
bir User
nesneyle çağırabilir; Çok uzun oldu.
Bu karmaşık doğrulama ve dönüşümleri bizzat nasıl ele alıyorsunuz? Çözümümden çoğunlukla memnunum, ancak fikirlerim ve yaklaşımlarımın seçimlerden oldukça mutlu olmak için tamamen aptal olmadığına dair bir onay istiyorum. Tamamen farklı yaklaşımlara tamamen açığım. Şahsen denediğiniz ve sizin için çok iyi çalıştığınız bir şeye sahipseniz, çözümünüzü görmeyi çok isterim.
1 RESTful sistemler oluşturmaktan sorumlu bir PHP geliştiricisi olarak çalışmak, benim CQRS hakkındaki yorumumun , bazen komutların eşzamanlı olarak işlenmesi gereği nedeniyle komutlardan sonuçların döndürülmesi gibi standart eşzamansız-komut işleme yaklaşımından biraz farklıdır .
CommandDispatcher
.