oop - डीडीडी-नियम है कि संस्थाएं सीधे रेपॉजिटरीज़ तक नहीं पहुंच सकती हैं




domain-driven-design repository-pattern (8)

क्या यह एरिक इवांस डोमेन संचालित डिजाइन पुस्तक से आया था, या यह कहीं और से आया था?

यह पुरानी चीजें है। एरिक की किताब ने इसे थोड़ा और बढ़ा दिया।

इसके पीछे तर्क के लिए कुछ अच्छी व्याख्या कहां हैं?

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

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

समानता में: यदि आप हस्तलेखन करना सीख रहे हैं, तो आपको समझने के साथ बोझ नहीं होना चाहिए कि कलम कहाँ बनाया गया था, कागज पर स्याही क्यों रखी जाती है, जब पेपर का आविष्कार किया जाता है और अन्य प्रसिद्ध चीनी आविष्कार क्या हैं।

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

कारण अभी भी वही है जैसा मैंने ऊपर बताया है। यहां यह सिर्फ एक कदम आगे है। यदि संस्थाएं पूरी तरह से (कम से कम करीब) हो सकती हैं तो संस्थाएं आंशिक रूप से अज्ञान क्यों होनी चाहिए? हमारे मॉडल के कम डोमेन-असंबद्ध चिंताओं - अधिक सांस लेने का कमरा हमारे दिमाग को तब समझता है जब इसे फिर से समझना पड़ता है।

डोमेन संचालित डिजाइन में, ऐसा लगता है कि संस्थाओं को सीधे रेपॉजिटरीज़ तक नहीं पहुंचना चाहिए।

क्या यह एरिक इवांस डोमेन संचालित डिजाइन पुस्तक से आया था, या यह कहीं और से आया था?

इसके पीछे तर्क के लिए कुछ अच्छी व्याख्या कहां हैं?

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

अपडेट करें: मैंने BacceSR को बक्षीस दिया क्योंकि उसका जवाब निकटतम लग रहा था, लेकिन मैं अभी भी इस बारे में अंधेरे में सुंदर हूं। यदि यह एक महत्वपूर्ण सिद्धांत है, तो इसके बारे में कुछ अच्छे लेख यहां कहीं भी होना चाहिए, निश्चित रूप से?

अद्यतन: मार्च 2013, इस सवाल पर उपरोक्त अर्थ यह है कि इसमें बहुत रुचि है, और भले ही बहुत सारे उत्तर हैं, फिर भी मुझे लगता है कि लोगों के बारे में विचार होने पर और अधिक जगह है।


डेटा एक्सेस अलग क्यों करें?

पुस्तक से, मुझे लगता है कि अध्याय मॉडल ड्राइव डिजाइन के पहले दो पृष्ठ कुछ औचित्य देते हैं कि आप डोमेन मॉडल के कार्यान्वयन से तकनीकी कार्यान्वयन विवरणों को क्यों सारण करना चाहते हैं।

  • आप डोमेन मॉडल और कोड के बीच एक कड़े कनेक्शन रखना चाहते हैं
  • तकनीकी चिंताओं को अलग करने से यह साबित होता है कि मॉडल कार्यान्वयन के लिए व्यावहारिक है
  • आप सर्वव्यापी भाषा को सिस्टम के डिजाइन के माध्यम से पार करना चाहते हैं

ऐसा लगता है कि यह एक अलग "विश्लेषण मॉडल" से बचने के उद्देश्य से है जो सिस्टम के वास्तविक कार्यान्वयन से तलाक हो जाता है।

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

दूसरी दिशा में, डोमेन मॉडल में बहुत से तकनीकी चिंताओं को पेश करने वाले डेवलपर्स इस विभाजन को भी जन्म दे सकते हैं।

तो आप इस बात पर विचार कर सकते हैं कि दृढ़ता जैसे चिंताओं को अलग करने का अभ्यास इन डिजाइनों के खिलाफ एक विश्लेषण मॉडल को अलग करने में मदद कर सकता है। यदि मॉडल में दृढ़ता जैसी चीज़ों को पेश करना आवश्यक लगता है तो यह एक लाल झंडा है। शायद मॉडल कार्यान्वयन के लिए व्यावहारिक नहीं है।

का हवाला देते हुए:

"एकल मॉडल त्रुटि की संभावनाओं को कम करता है, क्योंकि डिजाइन अब ध्यान से विचार किए गए मॉडल का प्रत्यक्ष विस्तार है। डिजाइन, और यहां तक ​​कि कोड स्वयं भी एक मॉडल की संचारशीलता है।"

जिस तरह से मैं इसका व्याख्या कर रहा हूं, यदि आप डेटाबेस पहुंच जैसी चीज़ों से निपटने वाले कोड की अधिक पंक्तियों के साथ समाप्त हो जाते हैं, तो आप उस संचार को खो देते हैं।

यदि डेटाबेस तक पहुंचने की आवश्यकता विशिष्टता की जांच करने जैसी चीजों के लिए है, तो इस पर एक नज़र डालें:

उडी दहन: डीडीडी लागू करते समय सबसे बड़ी गलतियां टीम बनाते हैं

http://gojko.net/2010/06/11/udi-dahan-the-biggest-mistakes-teams-make-when-applying-ddd/

"सभी नियम बराबर नहीं बनाए गए" के अंतर्गत

तथा

डोमेन मॉडल पैटर्न को नियोजित करना

http://msdn.microsoft.com/en-us/magazine/ee236415.aspx#id0400119

"डोमेन मॉडल का उपयोग न करने के लिए परिदृश्य" के अंतर्गत, जो एक ही विषय पर छूता है।

डेटा एक्सेस को अलग कैसे करें

एक इंटरफ़ेस के माध्यम से डेटा लोड हो रहा है

"डेटा एक्सेस लेयर" को एक इंटरफ़ेस के माध्यम से सारणीबद्ध किया गया है, जिसे आप आवश्यक डेटा पुनर्प्राप्त करने के लिए कॉल करते हैं:

var orderLines = OrderRepository.GetOrderLines(orderId);

foreach (var line in orderLines)
{
     total += line.Price;
}

पेशेवर: इंटरफ़ेस "डेटा एक्सेस" प्लंबिंग कोड को अलग करता है, जिससे आप अभी भी परीक्षण लिख सकते हैं। एक सामान्य रणनीति की तुलना में बेहतर प्रदर्शन की अनुमति के आधार पर डेटा एक्सेस को मामले के आधार पर संभाला जा सकता है।

विपक्ष: कॉलिंग कोड को यह मानना ​​चाहिए कि क्या लोड किया गया है और क्या नहीं है।

कहें GetOrderLines प्रदर्शन कारणों के लिए एक null ProductInfo संपत्ति के साथ ऑर्डरलाइन ऑब्जेक्ट देता है। डेवलपर को इंटरफ़ेस के पीछे कोड का अंतरंग ज्ञान होना चाहिए।

मैंने असली सिस्टम पर इस विधि की कोशिश की है। आप निष्पादन समस्याओं को ठीक करने के प्रयास में हर समय लोड होने के दायरे को बदलना समाप्त कर देते हैं। आप डेटा एक्सेस कोड को देखने के लिए इंटरफ़ेस के पीछे देख रहे हैं कि यह देखने के लिए कि क्या लोड किया जा रहा है और लोड नहीं किया जा रहा है।

अब, चिंताओं को अलग करने से डेवलपर को कोड के एक पहलू पर एक बार, जितना संभव हो सके ध्यान केंद्रित करने की अनुमति देनी चाहिए। इंटरफ़ेस तकनीक इस डेटा को लोड करने के तरीके को हटा देती है, लेकिन यह नहीं कि कितना डेटा लोड होता है, जब इसे लोड किया जाता है, और जहां यह लोड होता है।

निष्कर्ष: काफी कम अलगाव!

धीरे लोड हो रहा है

डेटा मांग पर भरा हुआ है। डेटा लोड करने के लिए कॉल ऑब्जेक्ट ग्राफ़ के भीतर ही छिपा हुआ है, जहां किसी संपत्ति को एक्सेस करने से परिणाम लौटने से पहले SQL क्वेरी निष्पादित हो सकती है।

foreach (var line in order.OrderLines)
{
    total += line.Price;
}

पेशेवर: डोमेन लॉजिक पर ध्यान केंद्रित करने वाले डेवलपर से डेटा एक्सेस का 'कब, कहां और कैसे' छुपाया जाता है। कुल मिलाकर कोई कोड नहीं है जो लोडिंग डेटा से संबंधित है। लोड किए गए डेटा की मात्रा कोड द्वारा आवश्यक सटीक राशि हो सकती है।

विपक्ष: जब आप किसी प्रदर्शन समस्या से प्रभावित होते हैं, तो आपके पास सामान्य "एक आकार सभी फिट बैठता है" समाधान ठीक करना मुश्किल होता है। आलसी लोडिंग समग्र रूप से खराब प्रदर्शन कर सकती है, और आलसी लोडिंग को लागू करना मुश्किल हो सकता है।

रोल इंटरफेस / उत्सुक लेटिंग

प्रत्येक उपयोग मामले को कुल वर्ग द्वारा लागू रोल इंटरफेस के माध्यम से स्पष्ट किया जाता है, जिससे डेटा लोडिंग रणनीतियों को प्रति उपयोग मामले में संभाला जा सकता है।

रणनीति प्राप्त करना इस तरह दिखेगा:

public class BillOrderFetchingStrategy : ILoadDataFor<IBillOrder, Order>
{
    Order Load(string aggregateId)
    {
        var order = new Order();

        order.Data = GetOrderLinesWithPrice(aggregateId);

        return order;
    }

}

फिर आपका कुल इस तरह दिख सकता है:

public class Order : IBillOrder
{
    void BillOrder(BillOrderCommand command)
    {
        foreach (var line in this.Data.OrderLines)
        {
            total += line.Price;
        }

        etc...
    }
}

BillOrderFetchingStrategy कुल बनाने के लिए उपयोग किया जाता है, और उसके बाद कुल कार्य करता है।

पेशेवर: इष्टतम प्रदर्शन के लिए अनुमति देने वाले कस्टम कोड प्रति उपयोग केस की अनुमति देता है। इंटरफेस पृथक्करण सिद्धांत के साथ इनलाइन है। कोई जटिल कोड आवश्यकता नहीं है। यूनिट परीक्षणों को जोड़ना लोडिंग रणनीति की नकल करने की आवश्यकता नहीं है। जेनेरिक लोडिंग रणनीति का उपयोग अधिकांश मामलों के लिए किया जा सकता है (उदाहरण के लिए "सभी लोड करें" रणनीति) और आवश्यक होने पर विशेष लोडिंग रणनीतियों को लागू किया जा सकता है।

विपक्ष: डेवलपर को अभी भी डोमेन कोड बदलने के बाद लाने की रणनीति को समायोजित / समीक्षा करना है।

लर्निंग रणनीति दृष्टिकोण के साथ आप अभी भी व्यवसाय नियमों में बदलाव के लिए कस्टम फ़ेचिंग कोड बदल सकते हैं। यह चिंताओं का एकदम सही अलगाव नहीं है लेकिन अधिक रखरखाव खत्म हो जाएगा और पहले विकल्प से बेहतर होगा। लाने की रणनीति कैसे घटती है, कब और कहां डेटा लोड होता है। यह लचीलापन खोने के बिना चिंताओं का एक बेहतर अलगाव है, एक आकार की तरह सभी आलसी लोडिंग दृष्टिकोण फिट बैठता है।


क्या एक उत्कृष्ट सवाल है। मैं खोज के एक ही रास्ते पर हूं, और इंटरनेट पर अधिकांश उत्तर समाधान लाने के रूप में कई समस्याएं उत्पन्न करते हैं।

तो (कुछ ऐसा लिखने के जोखिम पर जो मैं अब से एक वर्ष से असहमत हूं) यहां मेरी खोजें हैं।

सबसे पहले, हम एक समृद्ध डोमेन मॉडल पसंद करते हैं , जो हमें उच्च खोज योग्यता (हम कुल के साथ क्या कर सकते हैं) और पठनीयता (अभिव्यक्तिपूर्ण विधि कॉल) देता है।

// Entity
public class Invoice
{
    ...
    public void SetStatus(StatusCode statusCode, DateTime dateTime) { ... }
    public void CreateCreditNote(decimal amount) { ... }
    ...
}

हम किसी इकाई के कन्स्ट्रक्टर में किसी भी सेवा को इंजेक्शन दिए बिना हासिल करना चाहते हैं, क्योंकि:

  • एक नए व्यवहार का परिचय (जो एक नई सेवा का उपयोग करता है) एक रचनाकार परिवर्तन का कारण बन सकता है, जिसका अर्थ यह है कि परिवर्तन प्रत्येक पंक्ति को प्रभावित करता है जो इकाई को तत्काल बनाता है !
  • ये सेवाएं मॉडल का हिस्सा नहीं हैं , लेकिन कन्स्ट्रक्टर-इंजेक्शन सुझाव देगा कि वे थे।
  • अक्सर एक सेवा (यहां तक ​​कि इसका इंटरफ़ेस) डोमेन के हिस्से के बजाय एक कार्यान्वयन विवरण है। डोमेन मॉडल में बाहरी पक्ष की निर्भरता होगी
  • यह भ्रमित हो सकता है कि क्यों इन निर्भरताओं के बिना इकाई मौजूद नहीं हो सकती है। (एक क्रेडिट नोट सेवा, आप कहते हैं? मैं क्रेडिट नोट्स के साथ कुछ भी करने वाला नहीं हूं ...)
  • यह कठिन तेज़ कर देगा, इस प्रकार परीक्षण करना मुश्किल होगा
  • समस्या आसानी से फैलती है, क्योंकि इसमें शामिल अन्य संस्थाओं को समान निर्भरता मिलती है - जो उन पर बहुत ही अप्राकृतिक निर्भरताओं की तरह लग सकती हैं।

तो, हम यह कैसे कर सकते हैं? मेरा निष्कर्ष अब तक है कि विधि निर्भरता और डबल प्रेषण एक सभ्य समाधान प्रदान करते हैं।

public class Invoice
{
    ...

    // Simple method injection
    public void SetStatus(IInvoiceLogger logger, StatusCode statusCode, DateTime dateTime)
    { ... }

    // Double dispatch
    public void CreateCreditNote(ICreditNoteService creditNoteService, decimal amount)
    {
        creditNoteService.CreateCreditNote(this, amount);
    }

    ...
}

CreateCreditNote() अब ऐसी सेवा की आवश्यकता है जो क्रेडिट नोट बनाने के लिए ज़िम्मेदार है। यह Invoice इकाई से खोज Invoice बनाए रखते हुए, जिम्मेदार सेवा में काम को पूरी तरह से ऑफ़लोड करने के लिए डबल प्रेषण का उपयोग करता है।

SetStatus() अब लॉगर पर एक साधारण निर्भरता है , जो स्पष्ट रूप से काम का हिस्सा करेगा।

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

हम अपने इरादे को प्रकट करने की उम्मीद में अभी भी पैरामीटर 'लॉगर' नाम दे सकते हैं। हालांकि, थोड़ा कमजोर लगता है।

इसके बजाए, मैं एक IInvoiceLogger (जैसा कि हम कोड नमूना में पहले से ही करते हैं) के लिए पूछने का विकल्प चुनते हैं और IInvoiceService उस इंटरफ़ेस को कार्यान्वित करते हैं। क्लाइंट कोड केवल इन Invoice विधियों के लिए अपनी एकल IInvoiceService उपयोग कर सकता है जो किसी भी विशेष, चालान-अंतर्निहित 'मिनी-सेवा' के लिए पूछता है, जबकि विधि हस्ताक्षर अभी भी स्पष्ट रूप से स्पष्ट करते हैं कि वे क्या पूछ रहे हैं।

मैंने देखा है कि मैंने भंडारों को पूरी तरह से संबोधित नहीं किया है । खैर, लॉगर एक भंडार है या उपयोग करता है, लेकिन मुझे एक और स्पष्ट उदाहरण भी प्रदान करने दें। यदि एक विधि या दो में भंडार की आवश्यकता है, तो हम उसी दृष्टिकोण का उपयोग कर सकते हैं।

public class Invoice
{
    public IEnumerable<CreditNote> GetCreditNotes(ICreditNoteRepository repository)
    { ... }
}

वास्तव में, यह कभी-कभी परेशान आलसी भार का विकल्प प्रदान करता है । हम केवल Invoice को लोड किए गए क्रेडिट नोट्स को याद कर सकते हैं, और फिर से लोड होने से बच सकते हैं।

सच के लिए, संपत्ति आधारित आलसी भार, मैं वर्तमान में कन्स्ट्रक्टर इंजेक्शन का उपयोग करता हूं, लेकिन एक दृढ़ता से अनजान तरीके से।

public class Invoice
{
    // Lazy could use an interface (for contravariance if nothing else), but I digress
    public Lazy<IEnumerable<CreditNote>> CreditNotes { get; }

    // Give me something that will provide my credit notes
    public Invoice(Func<Invoice, IEnumerable<CreditNote>> lazyCreditNotes)
    {
        this.CreditNotes = new Lazy<IEnumerable<CreditNotes>>() => lazyCreditNotes(this));
    }
}

एक तरफ, डेटाबेस से Invoice लोड करने वाले एक भंडार में ऐसे फ़ंक्शन तक निःशुल्क पहुंच हो सकती है जो संबंधित क्रेडिट नोट लोड करेगी, और उस फ़ंक्शन को Invoice में इंजेक्ट करेगी।

दूसरी ओर, एक वास्तविक नया Invoice बनाता है जो कोड केवल एक फ़ंक्शन पास करेगा जो खाली सूची लौटाता है:

new Invoice(inv => new List<CreditNote>() as IEnumerable<CreditNote>)

(एक कस्टम ILazy<out T> हमें बदसूरत कलाकारों से ILazy<out T> छुटकारा पा सकता है, लेकिन इससे चर्चा जटिल हो जाएगी।)

मुझे आपकी राय, वरीयताओं और सुधारों को सुनकर खुशी होगी!


बस वर्नन वॉन एक समाधान देता है:

कुल व्यवहार का आह्वान करने से पहले निर्भर वस्तुओं को देखने के लिए एक भंडार या डोमेन सेवा का उपयोग करें। एक ग्राहक आवेदन सेवा इसे नियंत्रित कर सकती है।



मैंने ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग को कोड करने के बारे में सीखा है, इससे पहले कि यह अलग परत बज़ दिखाई दे, और मेरी पहली ऑब्जेक्ट्स / क्लासेस सीधे डेटाबेस पर डीआईडी ​​मैप करें।

आखिरकार, मैंने एक इंटरमीडिएट परत जोड़ा क्योंकि मुझे किसी अन्य डेटाबेस सर्वर पर माइग्रेट करना पड़ा था। मैंने कई बार एक ही परिदृश्य के बारे में देखा / सुना है।

मुझे लगता है कि आपके व्यापार तर्क से डेटा एक्सेस (उर्फ "रिपोजिटरी") को अलग करना, उन चीजों में से एक है, जिन्हें कई बार पुनर्निर्मित किया गया है, डोमेन संचालित डिज़ाइन बुक को देखा गया है, इसे बहुत "शोर" बनाते हैं।

मैं वर्तमान में 3 परतों (जीयूआई, तर्क, डेटा एक्सेस) का उपयोग करता हूं, जैसे कई डेवलपर करता है, क्योंकि यह एक अच्छी तकनीक है।

डेटा को अलग करने के लिए, एक Repository परत (उर्फ Data Access लेयर) में, एक अच्छी प्रोग्रामिंग तकनीक की तरह देखा जा सकता है, न केवल नियम, पालन करने के लिए।

कई तरीकों की तरह, आप इसे लागू करने के बाद, लागू नहीं कर सकते हैं, और अंततः, अपने प्रोग्राम को अपडेट कर सकते हैं।

उद्धरण: इलियड का पूरी तरह से होमर द्वारा आविष्कार नहीं किया गया था, कारमिना बुराना का कार्ल ऑर्फ़ द्वारा पूरी तरह से आविष्कार नहीं किया गया था, और दोनों मामलों में, जो व्यक्ति दूसरों को काम करता है, सभी टॉजिटर को क्रेडिट मिला ;-)


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

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

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

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

टिप्पणी 1 का जवाब : सही, अच्छा सवाल। इसलिए डोमेन परत में सभी सत्यापन नहीं होते हैं। शार्प में एक विशेषता "डोमेन सिग्नेचर" है जो आप चाहते हैं। यह दृढ़ता से अवगत है, लेकिन एक विशेषता होने से डोमेन परत साफ हो जाती है। यह सुनिश्चित करता है कि आपके पास एक उदाहरण नाम के साथ एक डुप्लिकेट इकाई नहीं है।

लेकिन चलिए अधिक जटिल सत्यापन नियमों के बारे में बात करते हैं। मान लें कि आप Amazon.com हैं। क्या आपने कभी एक कालबाह्य क्रेडिट कार्ड के साथ कुछ आदेश दिया है? मेरे पास है, जहां मैंने कार्ड अपडेट नहीं किया है और कुछ खरीदा है। यह आदेश स्वीकार करता है और यूआई मुझे सूचित करता है कि सब कुछ peachy है। लगभग 15 मिनट बाद, मुझे एक ई-मेल मिलेगा जिसमें कहा गया है कि मेरे आदेश में कोई समस्या है, मेरा क्रेडिट कार्ड अमान्य है। यहां क्या हो रहा है कि, आदर्श रूप से, डोमेन परत में कुछ regex सत्यापन है। क्या यह सही क्रेडिट कार्ड नंबर है? यदि हां, तो आदेश जारी रखें। हालांकि, एप्लिकेशन कार्य परत पर अतिरिक्त सत्यापन है, जहां क्रेडिट कार्ड पर भुगतान किया जा सकता है या नहीं, यह देखने के लिए बाहरी सेवा की पूछताछ की जाती है। यदि नहीं, तो वास्तव में कुछ भी शिप न करें, आदेश को निलंबित करें और ग्राहक की प्रतीक्षा करें। यह सब एक सेवा परत में होना चाहिए।

सेवा परत पर सत्यापन ऑब्जेक्ट्स बनाने के लिए डरो मत जो रिपॉजिटरीज़ तक पहुंच सकते हैं। बस इसे डोमेन परत से बाहर रखें।


सबसे पहले, मैं अपनी कुछ संस्थाओं को भंडारों तक पहुंचने की अनुमति देने के लिए प्रेरणा मिली थी (यानी ओआरएम के बिना आलसी लोडिंग)। बाद में मैं इस निष्कर्ष पर पहुंचा कि मुझे नहीं करना चाहिए और मुझे वैकल्पिक तरीके मिल सकते हैं:

  1. हमें अनुरोध में हमारे इरादे और डोमेन से क्या चाहिए, इसलिए हम कुल व्यवहार के निर्माण या आविष्कार से पहले भंडार कॉल कर सकते हैं। यह असंगत इन-मेमोरी स्टेटस और आलसी लोडिंग की आवश्यकता से बचने में मदद करता है (इस article )। गंध यह है कि आप डेटा एक्सेस के बारे में चिंता किए बिना अब अपनी इकाई के स्मृति उदाहरण में नहीं बना सकते हैं।
  2. सीक्यूएस (कमांड क्वेरी सेपरेशन) हमारी संस्थाओं में चीजों के लिए भंडार को कॉल करने की आवश्यकता को कम करने में मदद कर सकता है।
  3. हम डोमेन तर्क आवश्यकताओं को समाहित और संवाद करने के लिए एक specification का उपयोग कर सकते हैं और इसके बजाय भंडार में पास कर सकते हैं (एक सेवा हमारे लिए इन चीजों को व्यवस्थित कर सकती है)। विनिर्देश उस इकाई से आ सकता है जो उस आविष्कार को बनाए रखने के प्रभारी है। भंडार विनिर्देश के कुछ हिस्सों को इसके स्वयं के प्रश्न कार्यान्वयन में व्याख्या करेगा और क्वेरी परिणामों पर विनिर्देशन से नियम लागू करेगा। इसका उद्देश्य डोमेन परत में डोमेन तर्क रखना है। यह सर्वव्यापी भाषा और संचार को भी बेहतर बनाता है। कल्पना करें कि "अतिदेय आदेश विनिर्देश" कह रहा है "tbl_order से फ़िल्टर ऑर्डर जहां sy_date से पहले set_at 30 मिनट से कम है" (यह answer देखें)।
  4. एकल-जिम्मेदारी सिद्धांत का उल्लंघन होने के कारण यह संस्थाओं के व्यवहार के बारे में तर्क अधिक कठिन बनाता है। यदि आपको भंडारण / दृढ़ता के मुद्दों को हल करने की आवश्यकता है तो आप जानते हैं कि कहां जाना है और कहां नहीं जाना है।
  5. यह वैश्विक स्थिति (भंडार और डोमेन सेवाओं के माध्यम से) को एक द्वि-दिशात्मक पहुंच प्रदान करने के खतरे से बचाता है। आप अपनी लेनदेन सीमा तोड़ना नहीं चाहते हैं।

लाल पुस्तक कार्यान्वयन डोमेन-संचालित डिजाइन में वर्नॉन वॉन इस मुद्दे को दो स्थानों पर संदर्भित करता है जो मुझे पता है (नोट: इस पुस्तक को इवांस द्वारा पूरी तरह से समर्थन दिया जाता है जैसा कि आप प्रस्ताव में पढ़ सकते हैं)। सेवाओं पर अध्याय 7 में, वह एक डोमेन सेवा का उपयोग करता है और एक रिपॉजिटरी का उपयोग करने के लिए कुल आवश्यकता के आसपास काम करने के लिए एक विनिर्देश और दूसरा उपयोगकर्ता यह निर्धारित करने के लिए कि कोई उपयोगकर्ता प्रमाणित है या नहीं। उन्होंने कहा है:

अंगूठे के नियम के रूप में, यदि संभव हो तो हमें एग्रीगेट्स के अंदर से रेपॉजिटरीज़ (12) के उपयोग से बचने की कोशिश करनी चाहिए।

वेरनॉन, वॉन (2013-02-06)। डोमेन-संचालित डिजाइन कार्यान्वित करना (किंडल स्थान 6089)। पियरसन शिक्षा। किंडल संस्करण।

और समेकन पर अध्याय 10 में, "मॉडल नेविगेशन" शीर्षक वाले अनुभाग में वह कहता है (जब वह अन्य कुल जड़ें संदर्भित करने के लिए वैश्विक अद्वितीय आईडी के उपयोग की सिफारिश करता है):

पहचान द्वारा संदर्भ मॉडल के माध्यम से नेविगेशन को पूरी तरह से रोक नहीं है। कुछ लुकअप के लिए कुल के अंदर से एक रिपोजिटरी (12) का उपयोग करेंगे। इस तकनीक को डिस्कनेक्टेड डोमेन मॉडल कहा जाता है, और यह वास्तव में आलसी लोडिंग का एक रूप है। एक अलग अनुशंसित दृष्टिकोण है, हालांकि: समग्र व्यवहार का आह्वान करने से पहले निर्भर वस्तुओं को देखने के लिए एक रिपोजिटरी या डोमेन सेवा (7) का उपयोग करें। एक क्लाइंट एप्लिकेशन सेवा इसे नियंत्रित कर सकती है, फिर कुल को प्रेषित कर सकती है:

वह कोड में इसका एक उदाहरण दिखाता है:

public class ProductBacklogItemService ... { 

   ... 
   @Transactional 
   public void assignTeamMemberToTask( 
        String aTenantId, 
        String aBacklogItemId, 
        String aTaskId, 
        String aTeamMemberId) { 

        BacklogItem backlogItem = backlogItemRepository.backlogItemOfId( 
                                        new TenantId( aTenantId), 
                                        new BacklogItemId( aBacklogItemId)); 

        Team ofTeam = teamRepository.teamOfId( 
                                  backlogItem.tenantId(), 
                                  backlogItem.teamId());

        backlogItem.assignTeamMemberToTask( 
                  new TeamMemberId( aTeamMemberId), 
                  ofTeam,
                  new TaskId( aTaskId));
   } 
   ...
}     

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

तब मैंने हमेशा दयालु मार्को पिवेटा @Ocramius ओक्रैमियस के साथ कुछ discussion , जिसने मुझे डोमेन से एक विनिर्देश खींचने और उस का उपयोग करने पर थोड़ा सा कोड दिखाया:

1) यह अनुशंसित नहीं है:

$user->mountFriends(); // <-- has a repository call inside that loads friends? 

2) एक डोमेन सेवा में, यह अच्छा है:

public function mountYourFriends(MountFriendsCommand $mount) { /* see http://store.steampowered.com/app/296470/ */ 
    $user = $this->users->get($mount->userId()); 
    $friends = $this->users->findBySpecification($user->getFriendsSpecification()); 
    array_map([$user, 'mount'], $friends); 
}




s#arp-architecture