जहां हमें डोमेन मॉडल के लिए सत्यापन करना चाहिए


38

मैं अभी भी डोमेन मॉडल सत्यापन के लिए सबसे अच्छा अभ्यास देख रहा हूं। क्या डोमेन मॉडल के निर्माण में सत्यापन करना अच्छा है? मेरा डोमेन मॉडल सत्यापन उदाहरण निम्नानुसार है:

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;
    }
}

आपके सभी सुझाव के लिए धन्यवाद।

जवाबों:


47

उस विषय पर मार्टिन फाउलर का एक दिलचस्प लेख है जो एक पहलू को उजागर करता है जिसमें अधिकांश लोग (मेरे सहित) अनदेखी करते हैं:

लेकिन एक चीज जो मुझे लगता है कि लोगों को लगातार यात्राएं होती है, जब वे वस्तु के वैधता के संदर्भ में स्वतंत्र तरीके से सोचते हैं जैसे कि एक अमान्य विधि का अर्थ है।

मुझे लगता है कि मान्यता के बारे में सोचना अधिक उपयोगी है क्योंकि कुछ ऐसा है जो एक संदर्भ से जुड़ा है - आमतौर पर एक ऐसी कार्रवाई जो आप करना चाहते हैं। क्या यह आदेश भरा जाना वैध है, क्या यह ग्राहक होटल में जांच करने के लिए वैध है। इसलिए इसके बजाय तरीकों की तरह है। अमान्य के पास तरीके हैं जैसे कि isValidForCheckIn।

इसी से यह इस प्रकार है कि निर्माता चाहिए नहीं सत्यापन करते हैं, सभी संदर्भों के अलावा शायद कुछ बहुत ही बुनियादी विवेक साझा जाँच।

लेख से फिर:

के बारे में फेस एलन कूपर ने वकालत की कि हम मान्य राज्यों के हमारे विचारों को एक उपयोगकर्ता को अधूरी जानकारी दर्ज करने (और सहेजने) से रोकना नहीं चाहिए। मुझे कुछ दिनों पहले यह याद दिलाया गया था जब जिमी निल्सन एक पुस्तक का मसौदा पढ़ रहे थे। उन्होंने एक सिद्धांत कहा कि आपको हमेशा एक वस्तु को बचाने में सक्षम होना चाहिए, भले ही उसमें त्रुटियां हों। हालांकि मुझे यकीन नहीं है कि यह एक पूर्ण नियम होना चाहिए, मुझे लगता है कि लोग जितना चाहते हैं उससे अधिक बचत करने से रोकते हैं। मान्यता के संदर्भ के बारे में सोचने से रोकने में मदद मिल सकती है।


शुक्रिया किसी ने यह कहा। जिन प्रपत्रों में 90% डेटा है, लेकिन कुछ भी नहीं बचाएंगे, वे उपयोगकर्ताओं के लिए अनुचित हैं, जो अक्सर डेटा खो नहीं करने के लिए अन्य 10% बनाते हैं, इसलिए सभी सत्यापन किए गए सिस्टम को 10% का ट्रैक खोने के लिए मजबूर करते हैं बनाया गया था। इसी तरह के मुद्दे बैक एंड पर हो सकते हैं - एक डेटा आयात कहते हैं। मैंने पाया है कि आमतौर पर अमान्य डेटा के साथ ठीक से काम करने की कोशिश करना बेहतर होता है ताकि इसे कभी भी होने से रोका जा सके।
Psr

2
@psr क्या आपको बैक-एंड लॉजिक की भी आवश्यकता है यदि आपका डेटा कायम नहीं है? यदि आपके डेटा का आपके व्यवसाय मॉडल पर कोई अर्थ नहीं है, तो आप क्लाइंट की ओर से सभी हेरफेर छोड़ सकते हैं। यदि डेटा अर्थहीन है तो संदेशों को आगे और पीछे (क्लाइंट - सर्वर) भेजने के लिए संसाधनों की बर्बादी भी होगी। इसलिए हम "डोमेन ऑब्जेक्ट्स को कभी भी अमान्य स्थिति में प्रवेश करने की अनुमति नहीं देते" की विचारधारा पर वापस आते हैं! ।
जियो सी।

2
मुझे आश्चर्य है कि इस तरह के अस्पष्ट जवाब के लिए इतने सारे वोट क्यों। DDD का उपयोग करते समय, कभी-कभी कुछ नियम होते हैं जो बस यह जांचते हैं कि कुछ डेटा INT है या एक सीमा में है। उदाहरण के लिए जब आप अपने ऐप उपयोगकर्ता को इसके उत्पादों पर कुछ अड़चनें चुनने देते हैं (कितनी बार कोई मेरे उत्पाद का पूर्वावलोकन कर सकता है, और एक महीने के अंतराल में)। यहां दोनों बाधाओं को अंतर होना चाहिए और उनमें से एक 0-31 की सीमा में होना चाहिए। ऐसा लगता है कि डेटा प्रारूप सत्यापन एक गैर DDD वातावरण में एक सेवा या नियंत्रक में फिट होगा। लेकिन DDD में मैं डोमेन (इसकी 90%) वैलिडियन रखने की तरफ हूं।
जियो सी।

2
डोमेन के बारे में बहुत अधिक जानने के लिए ऊपरी परतों को लागू करने से इसे वैध स्थिति में रखने से खराब खराब डिजाइन जैसी गंध आती है। डोमेन ऐसा होना चाहिए जो इसकी गारंटी देता है कि यह मान्य है। ऊपरी परतों के कंधों पर बहुत अधिक चलना आपके डोमेन को एनीमिक बना सकता है और आप कुछ आवेगी बाधाओं को खिसका सकते हैं जो आपके व्यवसाय को नुकसान पहुंचा सकते हैं। अब मुझे क्या पता है, एक उचित सामान्यीकरण आपकी मान्यता को अपनी दृढ़ता के जितना संभव हो सके, या अपने डेटा हेरफेर कोड (जब यह एक अंतिम स्थिति तक पहुंचने के लिए हेरफेर किया जाता है) के करीब हो।
जियो सी।

पुनश्च I मैं प्राधिकरण नहीं मिलाता (कुछ करने की अनुमति है), प्रमाणीकरण (संदेश सही स्थान से आया था या सही ग्राहक द्वारा भेजा गया था, दोनों को एपीआई कुंजी / टोकन / उपयोगकर्ता नाम या कुछ और द्वारा पहचाना जा रहा है) प्रारूप सत्यापन के साथ या व्यावसायिक नियम। जब मैं कहता हूं कि 90% का मतलब उन व्यावसायिक नियमों से है जिनमें से अधिकांश में प्रारूप सत्यापन भी शामिल है। फ़ॉरेस्ट प्रारूप सत्यापन ऊपरी परतों में हो सकता है, लेकिन उनमें से अधिकांश डोमेन में होंगे (यहां तक ​​कि ईमेल पता प्रारूप भी जो ईमेल आईडी मान में मान्य होगा)।
जियो सी।

5

इस तथ्य के बावजूद कि यह सवाल थोड़ा बासी है, मैं कुछ सार्थक जोड़ना चाहूंगा:

मैं @MichaelBorgwardt से सहमत होना चाहता हूं और परीक्षण क्षमता लाकर विस्तार करना चाहता हूं। "वर्किंग इफ़ेक्टली विद लिगेसी कोड" में, माइकल फेदर्स परीक्षण के लिए बाधाओं के बारे में बहुत सारी बातें करते हैं और उन बाधाओं में से एक है "वस्तुओं का निर्माण करना कठिन"। एक अमान्य वस्तु का निर्माण संभव होना चाहिए, और जैसा कि फाउलर सुझाव देते हैं, संदर्भ निर्भर वैधता जांच उन स्थितियों की पहचान करने में सक्षम होना चाहिए। यदि आप यह पता नहीं लगा सकते हैं कि किसी टेस्ट हार्नेस में किसी ऑब्जेक्ट का निर्माण कैसे किया जाए तो आपको अपनी क्लास का परीक्षण करने में परेशानी होगी।

वैधता के बारे में मुझे नियंत्रण प्रणालियों के बारे में सोचना पसंद है। नियंत्रण प्रणाली एक आउटपुट की स्थिति का लगातार विश्लेषण करके और सुधारात्मक कार्रवाई को लागू करके काम करती है क्योंकि आउटपुट सेट बिंदु से विचलन करता है, इसे बंद लूप नियंत्रण कहा जाता है। बंद लूप नियंत्रण आंतरिक रूप से विचलन की अपेक्षा करता है और उन्हें सही करने के लिए कार्य करता है और यह है कि वास्तविक दुनिया कैसे काम करती है, यही कारण है कि सभी वास्तविक नियंत्रण प्रणालियां आमतौर पर बंद लूप नियंत्रकों का उपयोग करती हैं।

मुझे लगता है कि संदर्भ पर निर्भर मान्यता का उपयोग करना और वस्तुओं का निर्माण करना आसान है, जिससे आपके सिस्टम को सड़क के नीचे काम करने में आसानी होगी।


1
कई बार वस्तुओं का निर्माण मुश्किल होता है। उदाहरण के लिए, इस मामले में आप सार्वजनिक निर्माणकर्ता को एक रैपर वर्ग बनाकर बायपास कर सकते हैं जो परीक्षण किए जा रहे वर्ग से विरासत में मिलता है और आपको अमान्य राज्य में आधार ऑब्जेक्ट का एक उदाहरण बनाने की अनुमति देता है। यह वह जगह है जहाँ कक्षाओं और कंस्ट्रक्टर्स पर सही एक्सेस मॉडिफायर का उपयोग किया जाता है और यदि अनुचित तरीके से उपयोग किया जाता है तो यह वास्तव में परीक्षण के लिए हानिकारक हो सकता है। इसके अलावा "सीलबंद" कक्षाओं और पद्धति से परहेज करना जहां उपयुक्त हो, कोड को परीक्षण करने में आसान बनाने के लिए एक लंबा रास्ता तय करना होगा।
पी। रो

4

जैसा कि मुझे यकीन है कि आप पहले से ही जानते हैं ...

ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग में, क्लास में एक कंस्ट्रक्टर (कभी-कभी छोटा कर दिया जाता है) एक विशेष प्रकार का सबरूटीन होता है जिसे ऑब्जेक्ट के निर्माण में कहा जाता है। यह उपयोग के लिए नई वस्तु तैयार करता है, अक्सर उन मापदंडों को स्वीकार करता है जो निर्माणकर्ता किसी भी सदस्य चर को सेट करने के लिए उपयोग करता है जब ऑब्जेक्ट पहली बार बनाया जाता है। इसे कंस्ट्रक्टर कहा जाता है क्योंकि यह क्लास के डेटा सदस्यों के मूल्यों का निर्माण करता है।

कंस्ट्रक्टर में दिए गए डेटा की वैधता की जाँच करना निश्चित रूप से कंस्ट्रक्टर में मान्य है - अन्यथा आप संभवतः किसी अमान्य ऑब्जेक्ट के निर्माण की अनुमति दे रहे हैं।

हालाँकि (यह सिर्फ मेरी राय है, इस बिंदु पर इस पर कोई अच्छा डॉक्स नहीं मिल सकता है) - यदि डेटा सत्यापन के लिए जटिल संचालन की आवश्यकता होती है (जैसे कि async संचालन - शायद डेस्कटॉप आधारित ऐप को विकसित करने पर सर्वर-आधारित सत्यापन), तो बेहतर है कुछ प्रकार के प्रारंभिक या स्पष्ट सत्यापन समारोह में डाल दिया और सदस्यों को डिफ़ॉल्ट मान (जैसे कि null) कोटर में सेट करें।


इसके अलावा, बस एक साइड नोट के रूप में आप इसे अपने कोड नमूने में शामिल करते हैं ...

जब तक आप आगे सत्यापन (या अन्य कार्यक्षमता) नहीं कर रहे हैं AddOrderLine, मैं सबसे अधिक संभावना है List<LineItem>कि एक संपत्ति Orderके रूप में एक मुखौटा के रूप में कार्य कर सकता हूं ।


कंटेनर का पर्दाफाश क्यों? यह ऊपरी परतों के लिए क्या मायने रखता है कंटेनर क्या है? यह एक AddLineItemविधि के लिए पूरी तरह से उचित है । वास्तव में, डीडीडी के लिए, यह पसंद किया जाता है। यदि List<LineItem>कस्टम संग्रह ऑब्जेक्ट में बदल दिया जाता है, तो उजागर संपत्ति और संपत्ति पर निर्भर सब कुछ List<LineItem>परिवर्तन, त्रुटि और अपवाद के अधीन है।
आइब्रेट

4

जितनी जल्दी हो सके वैधता का प्रदर्शन किया जाना चाहिए।

किसी भी संदर्भ में मान्यता, या तो डोमेन मॉडल या सॉफ्टवेयर लिखने का कोई अन्य तरीका, आपको उस समय क्या करना है और किस स्तर पर आप इसे करना चाहते हैं, इस उद्देश्य की पूर्ति करनी चाहिए।

आपके प्रश्न के आधार पर, मुझे लगता है कि उत्तर सत्यापन को विभाजित करने के लिए होगा।

  1. संपत्ति सत्यापन जाँच करता है कि उस संपत्ति के लिए मूल्य सही है जैसे कि जब 1-10 के बीच की सीमा समाप्त हो जाती है।

  2. ऑब्जेक्ट सत्यापन की गारंटी है कि ऑब्जेक्ट पर सभी गुण एक दूसरे के साथ संयोजन के रूप में मान्य हैं। जैसे EndDate EndDate से पहले है। मान लीजिए कि आपने डेटा स्टोर से एक मान पढ़ा है और डिफ़ॉल्ट रूप से BeginDate और EndDate दोनों आरंभिक हैं। बिग्रेड सेट करते समय, "एंडडेट से पहले होना चाहिए" नियम को लागू करने का कोई कारण नहीं है, क्योंकि यह वाईईटी लागू नहीं करता है। इस नियम की जांच होनी चाहिए कि सभी संपत्तियों को निर्धारित किया गया है। इसे कुल रूट स्तर पर कहा जा सकता है

  3. मान्यता भी कुल (या कुल मूल) इकाई पर पूर्ववर्ती होनी चाहिए। ऑर्डर ऑब्जेक्ट में वैध डेटा हो सकता है और इसलिए यह ऑर्डरलाइन है। लेकिन तब एक व्यापार नियम कहता है कि कोई भी आदेश $ 1,000 से अधिक नहीं हो सकता है। आप इस नियम को कुछ मामलों में कैसे लागू करेंगे, यह आईएस ने अनुमति दी है। आप सिर्फ एक "राशि को मान्य नहीं कर सकते हैं" संपत्ति को नहीं जोड़ सकते क्योंकि इससे दुरुपयोग (जल्दी या बाद में, शायद आप भी, बस इस "बुरा अनुरोध" को पाने के लिए हो सकता है)।

  4. अगले प्रस्तुति परत पर सत्यापन है। क्या आप नेटवर्क पर वस्तु भेजने के लिए वास्तव में जा रहे हैं, यह जानते हुए कि यह विफल हो जाएगा? या क्या आप उपयोगकर्ता को इस बर्डन को छोड़ देंगे और जैसे ही वह एक अमान्य मूल्य दर्ज करता है, उसे सूचित कर देगा। उदाहरण के लिए, जब आपका DEV वातावरण उत्पादन की तुलना में धीमा हो जाएगा तो अधिकांश समय। क्या आप "अभी तक ANOTHER टेस्ट चलाने के दौरान आप इस क्षेत्र को भूल गए हैं" के बारे में सूचित करने से पहले आप 30sec की प्रतीक्षा करना चाहेंगे, खासकर जब आपके बॉस द्वारा आपकी गर्दन को सांस लेने के साथ उत्पादन बग तय किया जाना है?

  5. दृढ़ता के स्तर पर वैधता को यथासंभव संपत्ति मूल्य सत्यापन के करीब माना जाता है। यह किसी भी प्रकार या सादे पुराने डेटा पाठकों के मैपर्स का उपयोग करते समय "अशक्त" या "अमान्य मान" त्रुटियों को पढ़ने के साथ अपवादों को रोकने में मदद करेगा। संग्रहीत प्रक्रियाओं का उपयोग करने से यह समस्या हल हो जाती है, लेकिन उसी वैल्यूएशन लॉजिक को फिर से लिखना होगा और इसे AGAIN निष्पादित करना होगा। और संग्रहीत कार्यविधियाँ डीबी एडमिन डोमेन हैं, इसलिए एचआईएस जॉब करने की कोशिश न करें (या उसे इस "नट्टी पिकिंग जिसके लिए उसे भुगतान नहीं मिल रहा है" के साथ परेशान करें।

इसलिए इसे कुछ प्रसिद्ध शब्दों के साथ "यह निर्भर करता है" बताने के लिए, लेकिन अब आप जानते हैं कि यह क्यों निर्भर करता है।

काश मैं यह सब एक ही जगह पर कर सकता, लेकिन दुर्भाग्य से, यह नहीं किया जा सकता है। ऐसा करने से "भगवान वस्तु" पर एक निर्भरता होगी जिसमें सभी परतों के लिए सभी सत्यापन शामिल हैं। आप उस अंधेरे रास्ते से नीचे नहीं जाना चाहते हैं।

इस कारण से मैं केवल एक संपत्ति स्तर के अपवाद को फेंक देता हूं। अन्य सभी स्तरों पर मैं सभी "टूटे हुए नियमों" को इकट्ठा करने के लिए एक एकल विधि के साथ ValidationResult का उपयोग करता हूं और उन्हें एक एकल एग्रीगेटएक्स अपवाद में उपयोगकर्ता को पास करता हूं।

जब कॉल स्टैक को प्रचारित किया जाता है, तो मैं तब तक AggregateException में इन्हें फिर से इकट्ठा करता हूं जब तक कि मैं प्रस्तुति परत तक नहीं पहुंच जाता। सेवा परत WCF के मामले में क्लाइंट के लिए इस अपवाद को सीधे FaultException के रूप में फेंक सकती है।

यह मुझे अपवाद लेने की अनुमति देता है और या तो प्रत्येक इनपुट नियंत्रण पर अलग-अलग त्रुटियों को दिखाने के लिए इसे विभाजित करता है या इसे समतल करता है और इसे एक सूची में दिखाता है। चुनना आपको है।

यही कारण है कि मैंने प्रस्तुति सत्यापन का भी उल्लेख किया, जितना संभव हो सके शॉर्ट सर्किट के लिए।

यदि आप सोच रहे हैं कि मेरे पास एकत्रीकरण स्तर (या सेवा स्तर यदि आपको पसंद है) पर मान्यता क्यों है, तो यह इसलिए है क्योंकि मेरे पास यह बताने के लिए क्रिस्टल बॉल नहीं है कि भविष्य में मेरी सेवाओं का उपयोग कौन करेगा। आपको अपनी गलतियों को ढूंढने में बहुत परेशानी होगी, दूसरों को वहाँ गलतियाँ करने से रोकने के लिए :) अवैध डेटा इनपुट करके। आप आवेदन ए का प्रशासन करते हैं, लेकिन आवेदन बी आपकी सेवा का उपयोग करके कुछ डेटा खिलाता है। लगता है कि जब वे बग पूछना चाहते हैं, तो वे पहले कौन हैं? एप्लिकेशन बी के व्यवस्थापक को उपयोगकर्ता को खुशी से सूचित करना होगा "मेरे अंत में कोई त्रुटि नहीं है, मैं सिर्फ डेटा में फ़ीड करता हूं"।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.