it-swarm.asia

DDD Agregaları bir Web Uygulamasında gerçekten iyi bir fikir midir?

Etki Alanına Dayalı Tasarım'a daldım ve karşılaştığım bazı kavramlar yüzeyde çok anlamlı geliyor, ancak daha fazla düşündüğümde bunun gerçekten iyi bir fikir olup olmadığını merak etmeliyim.

Örneğin, Agregalar kavramı mantıklıdır. Tüm etki alanı modeliyle uğraşmak zorunda kalmamak için küçük sahiplik alanları oluşturursunuz.

Ancak, bunu bir web uygulaması bağlamında düşündüğümde, küçük veri alt kümelerini geri çekmek için veritabanına sık sık vuruyoruz. Örneğin, bir sayfa yalnızca sipariş sayısını listeleyebilir, siparişi açmak ve sipariş kimliklerini görmek için tıklanacak bağlantılar bulunur.

Toplamları doğru anlıyorsam, genellikle GetAll, GetByID, Delete ve Save. Tamam, kulağa hoş geliyor. Fakat...

Tüm siparişlerimi listelemek için GetAll'ı çağırırsam, bu kalıbın toplam bilgi listesinin, siparişlerin tamamlanması, sipariş satırları vb. (yalnızca başlık bilgileri).

Bir şey mi kaçırıyorum? Yoksa burada kullanacağınız bir optimizasyon seviyesi var mı? İhtiyacınız olmadığında kimsenin tüm bilgi topluluğunu iade etmeyi savunacağını düşünemiyorum.

Kuşkusuz, deponuzda GetOrderHeaders gibi yöntemler yaratılabilir, ancak bu ilk etapta depo gibi bir desen kullanma amacını bozuyor gibi görünüyor.

Bunu benim için kimse aydınlatabilir mi?

Düzeltme:

Çok daha fazla araştırmadan sonra, buradaki kopukluğun, saf bir Depo modelinin çoğu insanın bir Depo olarak düşündüğünden farklı olduğunu düşünüyorum.

Fowler, bir havuzu, toplama semantiği kullanan ve genellikle bellekte tutulan bir veri deposu olarak tanımlar. Bu, tüm bir nesne grafiğinin oluşturulması anlamına gelir.

Evans, Depoyu Toplam Kökleri içerecek şekilde değiştirir ve bu nedenle depo yalnızca bir Toplamadaki nesneleri desteklemek üzere kesilir.

Çoğu kişi depoları yüceltilmiş Veri Erişim Nesneleri olarak düşünüyor gibi görünüyor, burada istediğiniz verileri elde etmek için yöntemler oluşturuyorsunuz. Bu, Fowler'in Kurumsal Uygulama Mimarisi Kalıplarında açıklanan amaç gibi görünmüyor.

Yine de diğerleri, bir depoyu öncelikle test ve alay etmeyi kolaylaştırmak veya kalıcılığı sistemin geri kalanından ayırmak için kullanılan basit bir soyutlama olarak düşünmektedir.

Sanırım cevap, ilk düşündüğümden çok daha karmaşık bir kavram.

43
Erik Funkenbusch

Etki Alanı Modelinizi ve toplamalarınızı sorgulama için kullanmayın.

Aslında sorduğunuz şey, bundan kaçınmak için bir dizi ilke ve kalıp oluşturulduğuna dair yeterince yaygın bir sorudur. Buna CQRS denir.

31
quentin-starin

Etki Alanına Dayalı Tasarımda depo deseninin en iyi şekilde nasıl kullanılacağı ile mücadele ettim ve hala mücadele ediyorum. Şimdi ilk kez kullandıktan sonra, aşağıdaki uygulamaları buldum:

  1. Bir havuz basit olmalıdır; yalnızca etki alanı nesnelerini depolamaktan ve bunları almaktan sorumludur. Diğer tüm mantık fabrikalar ve alan hizmetleri gibi diğer nesnelerde olmalıdır.

  2. Bir depo, toplama kökleri gibi bir bellek koleksiyonundaymış gibi bir koleksiyon gibi davranır.

  3. Havuz genel bir DAO değildir, her havuzun kendine özgü ve dar bir arayüzü vardır. Bir havuzda genellikle koleksiyonu alan adı açısından aramanıza izin veren özel Finder yöntemleri bulunur (örneğin: X kullanıcısı için tüm açık siparişleri ver). Havuzun kendisi jenerik bir DAO yardımıyla uygulanabilir.

  4. İdeal olarak Finder yöntemleri yalnızca toplu kökleri döndürür. Bu verimsiz ise, tam olarak ihtiyacınız olanı içermektense salt okunur değer nesneleri de döndürebilir (bu değer nesneleri alan adı olarak da ifade edilebilirse artıdır). Son çare olarak, veri havuzu, bir alt kökün alt kümelerini veya alt kümelerinin koleksiyonlarını döndürmek için de kullanılabilir.

  5. Bu gibi seçenekler, kullanılan teknolojilerle etki alanı modelinizi en verimli şekilde ifade etmenin bir yolunu bulmanız gerektiğinden, kullanılan teknolojilere bağlıdır.

8
Kdeveloper

GetOrderHeaders yönteminizin deponun amacını hiç yenmediğini düşünmüyorum.

DDD (diğer şeylerin yanı sıra), ihtiyacınız olanı toplu kök yoluyla almanızı sağlamakla ilgilidir (örneğin, bir OrderDetailsRepository'ye sahip olmazsınız), ancak bahsettiğiniz şekilde sizi sınırlamaz.

OrderHeader bir Etki Alanı kavramıysa, bunu böyle tanımlamanız ve bunları almak için uygun havuz yöntemlerine sahip olmanız gerekir. Bunu yaparken doğru agrega kökünden geçtiğinizden emin olun.

6
Eric King

DDD kullanımım "saf" DDD olarak kabul edilemez, ancak aşağıdaki gerçek dünya stratejilerini DDD kullanarak bir DB veri deposuna uyarladım.

  • Toplam kökün ilişkili bir havuzu vardır
  • İlişkili havuz yalnızca bu toplu kök tarafından kullanılır (herkese açık değildir)
  • Bir havuz sorgu çağrıları içerebilir (örneğin GetAllActiveOrders, GetOrderItemsForOrder)
  • Hizmet, havuzun ve diğer crud olmayan işlemlerin genel bir alt kümesini ortaya çıkarır (örneğin, bir banka hesabından diğerine Para Aktarma, LoadById, Search/Find, CreateEntity, vb.).
  • Kök -> Hizmet -> Depo yığınını kullanıyorum. Bir DDD hizmetinin yalnızca bir Varlığın kendisine cevap veremediği her şey için (örneğin LoadById, TransferMoneyFromAccountToAccount) kullanılabileceği varsayılır, ancak gerçek dünyada, CRUD ile ilgili diğer hizmetlere de (Kaydet, Sil, Sorgu) rağmen root bunları "cevaplayabilmeli/gerçekleştirebilmelidir". Bir varlığa başka bir toplam kök hizmetine erişim izni vermede yanlış bir şey olmadığını unutmayın! Ancak, bir hizmete (GetOrderItemsForOrder) dahil etmeyeceğinizi, ancak Toplama Kökü'nden yararlanabilmesi için bunu depoya ekleyeceğinizi unutmayın. Bir hizmetin, depo kutusu gibi açık sorguları göstermemesi gerektiğini unutmayın.
  • Genellikle etki alanı modelinde (arabirim aracılığıyla) bir Havuzu tanımlarım ve ayrı bir somut uygulama sağlarım. Etki alanı modelinde, kullanımı için somut bir depoya enjekte edilen bir hizmeti tam olarak tanımlarım.

** Bir agreganın tamamını geri getirmek zorunda değilsiniz. Ancak, daha fazlasını istiyorsanız, başka bir hizmet veya depoya değil, köke sormanız gerekir. Bu tembel yükleme ve kötü adam tembel yükleme ile (uygun havuzu/hizmeti kök içine enjekte ederek) manuel olarak veya bunu destekleyen ve ORM kullanılarak yapılabilir.

Örneğinizde, ayrıntıları ayrı bir çağrıya yüklemek istersem büyük olasılıkla yalnızca sipariş başlıklarını getiren bir depo çağrısı sağlarım. Bir "OrderHeader" a sahip olarak, aslında alan adına ek bir kavram eklediğimizi unutmayın.

4
Mike Rowley

Alan adı modeliniz, iş mantığınızı en saf haliyle içerir. Ticari operasyonları destekleyen tüm ilişkiler ve işlemler. Kavramsal haritanızda eksik olan şey ygulama Hizmet Katmanı hizmet katmanının etki alanı modelinin etrafına sarılması ve iş etki alanının (izin verirseniz bir projeksiyon) basitleştirilmiş bir görünümünü sağlar. hizmet katmanını kullanan uygulamaları doğrudan etkilemeden gerektiğinde değiştirmek için Etki Alanı modeli.

Daha ileri gidiyor. Agrega fikri, agreganın tutarlılığını korumaktan sorumlu bir nesne, agrega kökü olmasıdır. Örneğinizde, sipariş, sipariş satırlarını değiştirmekle sorumlu olacaktır.

Örneğin, hizmet katmanı GetOrdersForCustomer gibi yalnızca siparişlerin özet listesini görüntülemek için gerekenleri döndüren (OrderHeaders olarak adlandırdığınız) bir işlemi ortaya koyar.

Son olarak, Havuz kalıbı SADECE bir koleksiyon değildir, aynı zamanda bildirim sorgularına da izin verir. C # 'da Sorgu Nesnesi olarak LINQ kullanabilirsiniz veya diğer birçok O/RM de bir Sorgu Nesnesi belirtimi sağlar.

Bir Depo, bir bellek içi etki alanı nesne koleksiyonu gibi davranarak etki alanı ve veri eşleme katmanları arasında aracılık eder. İstemci nesneleri, bildirim belirtimlerini bildirici olarak oluşturur ve memnuniyet için bunları Havuz'a gönderir. ( Fowler'in Depo sayfasından )

Depoya karşı sorgular oluşturabildiğinizi görünce, ortak sorguları ele alan kolaylık yöntemleri sağlamak da mantıklıdır. Yani yalnızca siparişinizin üstbilgilerini istiyorsanız, yalnızca üstbilgiyi döndüren bir sorgu oluşturabilir ve bunu depolarınızdaki bir kolaylık yönteminden gösterebilirsiniz.

Umarım bu bir şeyleri netleştirmeye yardımcı olur.

3
Michael Brown

Bunun eski bir soru olduğunu biliyorum ama farklı bir cevaba geldim.

Bir Depo yaptığımda genellikle bazı önbellek sorguları kaydırır.

Fowler, bir havuzu, toplama semantiği kullanan ve genellikle bellekte tutulan bir veri deposu olarak tanımlar. Bu, tüm bir nesne grafiğinin oluşturulması anlamına gelir.

Bu depoları sunucularınızda saklayın. Sadece nesnelerden veritabanına geçmezler!

Siparişleri listeleyen bir sayfa içeren bir web uygulamasındaysanız, ayrıntıları görmek için tıklayabilirsiniz, sipariş listesi sayfamın siparişlerle ilgili ayrıntılara sahip olmasını isteyeceğim (Kimlik, İsim, Tutar, Tarih) kullanıcının hangisine bakmak istediğine karar vermesine yardımcı olmak için.

Bu noktada iki seçeneğiniz var.

  1. Veritabanını sorgulayabilir ve giriş yapmak için tam olarak ne yapmanız gerektiğini geri çekebilir, ardından ayrıntı sayfasında görmeniz gereken ayrıntıları tek tek almak için tekrar sorgulayabilirsiniz.

  2. Tüm bilgileri geri çeken ve önbelleğe alan 1 sorgu yapabilirsiniz. Bir sonraki sayfa isteğinde veritabanı yerine sunucu koçundan okudunuz. Kullanıcı geri vurursa veya bir sonraki sayfayı seçerse, veritabanına yine de sıfır yolculuk yaparsınız.

Gerçekte bunu nasıl uyguladığınız ve uygulama ayrıntısıdır. En büyük kullanıcımın 10 siparişi varsa, muhtemelen seçenek 2 ile gitmek istiyorum. Eğer 10.000 sipariş konuşuyorsanız, seçenek 1'e ihtiyaç vardır. Yukarıdaki her iki durumda ve diğer birçok durumda da havuzun bu uygulama detayını gizlemesini istiyorum.

Kullanıcıya sipariş listesi sayfasında geçen ay siparişlerde ( toplu veri ne kadar harcadıklarını bildirmek için bir bilet alırsam, SQL'de hesaplamak ve DB'ye bir tur daha yapmak için mantığı yazmayı mı tercih edersiniz yoksa zaten sunucu ram'ında bulunan verileri kullanarak hesaplamayı mı tercih edersiniz?

Benim deneyimime göre, alan kümeleri büyük faydalar sunuyor.

  • Onlar gerçekten çalışan büyük bir parça kodu yeniden.
  • Sql sunucusunun bunu yapmasını sağlamak için bir altyapı katmanını delmek yerine iş mantığınızı çekirdek katmanında doğru tutarak kodu basitleştirir.
  • Ayrıca, kolayca önbelleğe alabileceğiniz için yapmanız gereken sorgu sayısını azaltarak yanıt sürelerinizi önemli ölçüde hızlandırabilirler.
  • Yazdığım SQL genellikle daha sürdürülebilir, çünkü genellikle her şeyi soruyorum ve sunucu tarafını hesaplıyorum.
0
WhiteleyJ