Etki alanı modeli için doğrulamayı nereye koymalıyız


38

Etki alanı modeli doğrulaması için hala en iyi uygulamayı arıyorum. Doğrulamayı etki alanı modelinin kurucusuna koymak iyi mi? etki alanı modeli doğrulama örneğim şöyle:

public class Order
 {
    private readonly List<OrderLine> _lineItems;

    public virtual Customer Customer { get; private set; }
    public virtual DateTime OrderDate { get; private set; }
    public virtual decimal OrderTotal { get; private set; }

    public Order (Customer customer)
    {
        if (customer == null)
            throw new  ArgumentException("Customer name must be defined");

        Customer = customer;
        OrderDate = DateTime.Now;
        _lineItems = new List<LineItem>();
    }

    public void AddOderLine //....
    public IEnumerable<OrderLine> AddOderLine { get {return _lineItems;} }
}


public class OrderLine
{
    public virtual Order Order { get; set; }
    public virtual Product Product { get; set; }
    public virtual int Quantity { get; set; }
    public virtual decimal UnitPrice { get; set; }

    public OrderLine(Order order, int quantity, Product product)
    {
        if (order == null)
            throw new  ArgumentException("Order name must be defined");
        if (quantity <= 0)
            throw new  ArgumentException("Quantity must be greater than zero");
        if (product == null)
            throw new  ArgumentException("Product name must be defined");

        Order = order;
        Quantity = quantity;
        Product = product;
    }
}

Tüm öneriniz için teşekkürler.

Yanıtlar:


47

Martin Fowler'ın bu konuyla ilgili, çoğu insanın (ben dahil) göz ardı etme eğilimini vurgulayan ilginç bir makalesi var :

Ancak insanları sürekli gezdirdiğini düşündüğüm bir şey, nesnenin geçerliliğini isValid yöntemi gibi bir bağlamdan bağımsız bir şekilde nesnenin geçerliliği olduğunu düşünmeleridir.

Doğrulamayı bir içeriğe bağlı bir şey - genellikle yapmak istediğiniz bir eylem olarak düşünmek daha yararlı olur. Bu siparişin doldurulması geçerli mi, bu müşteri otele giriş yapmak için geçerli mi? Yani isValid gibi yöntemlerden çok isValidForCheckIn gibi yöntemlerden yararlanın.

Bu yapıcı gerektiğini şu itibaren değil , doğrulama yapmak bütün bağlamlarda tarafından belki bazı çok temel aklı paylaşılan Kontrolden hariç.

Yine makaleden:

Hakkında Face Alan Alan Cooper, geçerli durum fikirlerimizin bir kullanıcının eksik bilgi girmesini (ve kaydetmesini) önlemesine izin vermememiz gerektiğini savundu. Birkaç gün önce Jimmy Nilsson'un üzerinde çalıştığı bir kitap taslağını okurken bunu hatırlatmıştım. Bir nesneyi, içinde hataları olsa bile, her zaman kurtarabilmeniz gerektiğini ilke edinmiştir. Bunun mutlak bir kural olması gerektiğine ikna olmama rağmen, insanların gereğinden fazla tasarruf etmeyi önleme eğiliminde olduğunu düşünüyorum. Doğrulama bağlamı hakkında düşünmek bunu önlemeye yardımcı olabilir.


Şükürler olsun ki biri bunu söyledi. Verilerin% 90'ına sahip olan ancak hiçbir şey kaydetmeyen formlar, diğerlerini% 10'unu sadece veri kaybetmemek için yapan kullanıcılar için haksızdır, bu nedenle yapılan tüm doğrulama sistemi% 10'unu kaybetmeye zorlar. yapıldı. Arka uçta da benzer sorunlar olabilir - veri aktarımı. Genellikle geçersiz verilerle düzgün çalışmayı denemekten daha iyi olduğunu buldum.
psr

2
@psr Verileriniz ısrar edilmezse arka uç mantığa ihtiyacınız var mı? Verilerinizin işletme modelinizde bir anlamı yoksa, tüm manipülasyonları müşteri tarafında bırakabilirsiniz. Veriler anlamsız ise, ileri ve geri (istemci - sunucu) mesajları göndermek için kaynak israfı da olurdu. Bu nedenle, "etki alanı nesnelerinin geçersiz duruma girmesine asla izin vermeyin!" .
Geo C.

2
Neden böyle belirsiz bir cevap için bu kadar çok oy kullandığını merak ediyorum. DDD kullanırken, bazen bazı verilerin INT olup olmadığını veya aralıkta olup olmadığını kontrol eden bazı kurallar vardır. Örneğin, uygulama kullanıcınızın ürünlerindeki bazı kısıtlamaları seçmesine izin verdiğinizde (biri ürünümü kaç kez önizleyebilir ve bir ayın hangi günlerinde). Burada her iki kısıtlama int olmalıdır ve bunlardan biri 0-31 aralığında olmalıdır. Bu, DDD olmayan bir ortamda bir hizmete veya denetleyiciye sığabileceği veri biçimi doğrulaması gibi görünüyor. Ancak DDD’de etki alanında doğrulamayı sürdürme tarafındayım (% 90’ı).
Geo C.

2
Üst katmanları etki alanı hakkında geçerli bir durumda tutmak için etki alanı hakkında çok fazla şey bilmemesi kötü tasarım gibi kokuyor. Alan geçerli olduğunu garanti eden alan olmalıdır. Üst katmanların omuzlarında çok fazla hareket etmek, alanınızı anemik hale getirebilir ve işinize zarar verebilecek bazı önemsiz kısıtlamaları kaldırabilirsiniz. Şimdi anladığım kadarıyla, doğru bir genelleme, onayınızı kalıcılığınıza mümkün olduğunca yakın tutmak veya veri işleme kodunuza (son duruma ulaşmak için manipüle edildiğinde) yakın tutmak olacaktır.
Geo C.

PS Yetkilendirmeyi (bir şey yapmama izin verilir), kimlik doğrulamasını (mesaj doğru konumdan geldi mi ya da doğru müşteri tarafından gönderildi, her ikisi de api tuşu / token / kullanıcı adı ya da başka bir şeyle karıştırıldı) format doğrulaması ile karıştırmayın veya iş kuralları. % 90 deyince, çoğu da biçimsel doğrulama içeren bu işletme kurallarını kastediyorum. Tabii ki format doğrulaması üst katmanlarda olabilir, fakat çoğu etki alanında olacaktır (hatta EmailAddress değer nesnesinde doğrulanacak olan e-posta adres formatı).
Geo C.

5

Bu sorunun biraz eskimiş olmasına rağmen, kayda değer bir şey eklemek istiyorum:

@MichaelBorgwardt ile aynı fikirdeyim ve test edilebilirliği artırarak genişletmek istiyorum. "Eski Kod ile Etkili Bir Şekilde Çalışmak" bölümünde, Michael Feathers test etmenin önündeki engeller hakkında çok konuşuyor ve bu engellerden biri de "inşa edilmesi zor" nesneler. Geçersiz bir nesne oluşturmak mümkün olmalı ve Fowler'ın önerdiği gibi, içeriğe bağlı geçerlilik kontrolleri bu koşulları tanımlayabilmelidir. Bir test donanımında nasıl bir obje yapılacağını bulamıyorsanız, sınıfınızı test etmekte zorlanacaksınız.

Geçerliliğe gelince, kontrol sistemlerini düşünmeyi seviyorum. Kontrol sistemleri sürekli olarak bir çıkışın durumunu analiz ederek ve çıkış ayar noktasından saptıkça düzeltici eylem uygulayarak çalışırlar, buna kapalı döngü kontrolü denir. Kapalı döngü kontrolü kendinden sapmaları bekler ve onları düzeltmek için hareket eder ve gerçek dünya bu şekilde çalışır, bu yüzden tüm gerçek kontrol sistemleri tipik olarak kapalı döngü denetleyicileri kullanır.

Bağlam bağımlı doğrulama ve nesnelerin yapımı kolay kullanılmasının sisteminizin yolda çalışmasını kolaylaştıracağını düşünüyorum.


1
Çoğu zaman nesneler sadece inşa etmek zor görünüyor. Örneğin, bu durumda kamu kurucusunu, test edilen sınıftan miras alan bir Wrapper sınıfı oluşturarak atlayabilir ve temel nesnenin bir örneğini geçersiz bir durumda oluşturmanıza izin verebilir. Sınıflar ve yapıcılar üzerinde doğru erişim değiştiricilerin kullanılması devreye giriyor ve doğru kullanılmazsa teste gerçekten zarar verebilir. Ek olarak, "mühürlü" sınıflardan ve uygun yöntemlerden kaçınmak, bir kodu test etmeyi kolaylaştıracak uzun bir yol izler.
P. Roe

4

Eminim ki zaten biliyorsun ...

Nesneye yönelik programlamada, bir sınıftaki bir kurucu (bazen ctor kısaltılır), bir nesnenin oluşturulmasında adı verilen özel bir alt yordam türüdür. Yeni nesneyi kullanıma hazırlar ve genellikle yapıcının, nesne ilk oluşturulduğunda gereken tüm üye değişkenleri ayarlamak için kullandığı parametreleri kabul ederek hazırlar. Yapıcı olarak adlandırılır çünkü sınıfın veri üyelerinin değerlerini oluşturur.

C'tor parametreleri olarak iletilen verilerin geçerliliğini kontrol etmek kesinlikle yapıcıda geçerlidir - aksi takdirde geçersiz bir nesnenin oluşturulmasına izin veriyorsunuzdur.

Ancak (ve bu sadece benim görüşüme göre, bu noktada herhangi bir iyi dokümanı bulamıyor) - veri doğrulaması karmaşık işlemler gerektiriyorsa (örneğin, zaman uyumsuz işlemler gibi - belki de bir masaüstü uygulaması geliştirirken sunucu tabanlı doğrulama) Bir tür başlatma veya açık doğrulama işlevi koymak ve üyeler nullc'tor'da varsayılan değerlere (örneğin ) ayarlanır.


Ayrıca, kod numaranıza yazdığınız gibi bir not gibi ...

'Da daha fazla doğrulama (veya başka bir işlevsellik) AddOrderLineyapmazsanız, büyük olasılıkla bir cephe gibi davranmak List<LineItem>yerine mülkü bir özellik Orderolarak açıklardım .


Kabı neden açığa çıkarın? Kabın ne olduğu üst katmanlara ne fark eder? Bir AddLineItemyönteme sahip olmak tamamen mantıklı . Aslında, DDD için bu tercih edilir. Eğer List<LineItem>bir bağlıydı özel bir koleksiyon nesnesi, daha sonra maruz özellik ve her şey olarak değiştirilir List<LineItem>mülkiyet değişimi, hata ve istisna tabidir.
IA

4

Doğrulama en kısa sürede yapılmalıdır.

Herhangi bir bağlamda doğrulama, biz Etki Alanı modeli ya da herhangi bir yazılım yazma yöntemi, doğrulamak istediğiniz Neyi ve şu anda hangi seviyede olduğunuzu amacına hizmet etmelidir.

Sorunuza dayanarak, cevabı doğrulamayı bölmek olacağını tahmin ediyorum.

  1. Malın validasyonu, o malın değerinin doğru olup olmadığını, örneğin 1-10 arasında bir aralık beklendiğinde kontrol eder.

  2. Nesne doğrulama, nesne üzerindeki tüm özelliklerin birbiriyle bağlantılı olarak geçerli olduğunu garanti eder. örneğin, BeginDate, EndDate'den önce. Veri deposundan bir değer okuduğunuzu ve hem BeginDate hem de EndDate'in DateTime.Min'e varsayılan olarak başlatıldığını varsayalım. BeginDate'i ayarlarken, "EndDate'den önce olmalı" kuralını uygulamak için hiçbir sebep yoktur, çünkü bu YET'i uygulamaz. Tüm özellikler ayarlandıktan SONRA bu kural kontrol edilmelidir. Bu toplam kök düzeyinde çağrılabilir

  3. Doğrulama ayrıca toplu (veya toplam kök) varlık üzerinde önceden yapılmalıdır. Bir Order nesnesi geçerli veriler içerebilir ve bu yüzden de OrderLines. Ancak bir iş kuralı, hiçbir emrin 1.000 $ 'dan fazla olamayacağını belirtir. IS'nin izin verdiği bazı durumlarda bu kuralı nasıl uygularsınız. Bu yalnızca "kötüye kullanım" özelliğini ekleyemezsiniz, çünkü bu kötüye kullanıma yol açacaktır (er ya da geç, belki de sadece, bu "iğrenç isteği" ortadan kaldırmak için).

  4. daha sonra sunum katmanında doğrulama var. Gerçekten başarısız olacağını bilerek, nesneyi ağ üzerinden gönderecek misiniz? Yoksa kullanıcıyı bu cenaze töreninden kurtarır ve geçersiz bir değer girer girmez onu bilgilendirirsiniz. Örneğin, DEV ortamınız çoğu zaman üretime göre daha yavaş olacaktır. “Patronunuz boynunuzu soluyorken sabitlenecek bir üretim hatası olduğunda,“ bu alanı henüz başka bir test sırasında TEKRARLA unuttunuz ”hakkında bilgilendirilmeden önce 30 saniye beklemek ister misiniz?

  5. Kalıcılık seviyesindeki doğrulama, özellik değer doğrulamasına mümkün olduğu kadar yakın olmalıdır. Bu, herhangi bir tür veya düz eski veri okuyucunun eşleyicilerini kullanırken "boş" veya "geçersiz değer" hataları okuma istisnalarının önlenmesine yardımcı olacaktır. Saklı yordamlar kullanmak bu sorunu çözer, ancak aynı değerleme mantığını AGAIN yazıp AGAIN yürütmek gerekir. Ve saklı yordamlar DB yönetici alanıdır, bu nedenle HIS işini de yapmayı denemeyin (ya da daha da kötüsü para kazanmadığı bu “nitty picking” ile uğraşmayın.

Bu yüzden bazı "meşhur" sözleriyle söylemek gerekirse, ama artık en azından artık neye bağlı olduğunu biliyorsunuz.

Keşke bütün bunları tek bir yere koyabilseydim ama maalesef bu yapılamaz. Bunu yapmak, TÜM katmanlar için TÜM doğrulama içeren bir "Tanrı nesnesine" bağımlılık getirir. O karanlık yolda ilerlemek istemezsin.

Bu nedenle, doğrulama istisnalarına sadece özellik seviyesi atıyorum. Diğer tüm seviyeler ValidaResult'u IsValid yöntemiyle kullanıp tüm "bozuk kuralları" toplarım ve bunları kullanıcıya tek bir AggregateException'da iletirim.

Çağrı yığınını çoğaltırken, sunum katmanına ulaşana kadar bunları tekrar AggregateExceptions içinde toplarım. Hizmet katmanı, WCF durumunda bir FaultException olması durumunda bu istisnayı doğrudan müşteriye atabilir.

Bu, istisnayı benim almamı ve her giriş kontrolünde bireysel hatalar göstermesini ya da düzleştirip tek bir listede göstermesini ya bölmemi sağlıyor. Seçim senin.

bu yüzden sunumun doğrulanmasından bahsettim, mümkün olduğunca kısa devre yapmak için.

Ayrıca neden onaylama seviyesini toplama seviyesine getirdiğimi merak ediyorsanız (ya da isterseniz hizmet seviyesi), bunun nedeni, gelecekte hizmetlerimi kimlerin kullanacağını söyleyen bir kristal topum olmamasıdır. Geçersiz verileri girerek başkalarının sizinkileri yanlış yapmalarını önlemek için kendi hatalarınızı bulma konusunda yeterince sorun yaşayacaksınız. A uygulamasını yönetirken, ancak B uygulaması hizmetinizi kullanarak bazı verileri besler. Tahmin et, bir böcek olduğunda önce kime sorarlar? B uygulamasının yöneticisi kullanıcıyı "benim açımdan bir hata yok, sadece veriyi besliyorum" şeklinde bilgilendirecektir.

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.