डोमेन-चालित-डिजाइन - इकाई समस्या में बाहरी निर्भरता


23

मैं डोमेन-चालित-डिजाइन शुरू करना चाहता हूं, लेकिन कई समस्याएं हैं जिन्हें मैं शुरू करने से पहले हल करना चाहूंगा :)

आइए कल्पना करें कि मेरे पास एक समूह और उपयोगकर्ता हैं और जब उपयोगकर्ता एक समूह में शामिल होना चाहता है, तो मैं groupsService.AddUserToGroup(group, user)विधि बुला रहा हूं । DDD में मुझे करना चाहिए group.JoinUser(user), जो बहुत अच्छा लग रहा है।

समस्या तब दिखाई देती है जब मैं उपयोगकर्ता को जोड़ने के लिए कुछ सत्यापन नियम हैं, या उपयोगकर्ता को समूह में जोड़े जाने पर कुछ बाहरी कार्यों को शुरू करने की आवश्यकता होती है। इन कार्यों के होने से इकाई को बाहरी निर्भरता प्राप्त होगी।

एक उदाहरण हो सकता है - एक प्रतिबंध जो उपयोगकर्ता केवल 3 समूहों में भाग ले सकता है अधिकतम। इसे सत्यापित करने के लिए समूह के अंदर DB.JoinUser विधि से DB-कॉल की आवश्यकता होगी।

लेकिन यह तथ्य कि एक इकाई कुछ बाहरी सेवाओं / वर्गों पर निर्भर करती है, मुझे इतनी अच्छी और "स्वाभाविक" नहीं लगती।

DDD में इससे निपटने का उचित तरीका क्या है?

जवाबों:


15

आइए कल्पना करें कि मेरे पास एक समूह और उपयोगकर्ता हैं और जब उपयोगकर्ता किसी समूह में शामिल होना चाहता है, तो मैं groupService.AddUserToGroup (समूह, उपयोगकर्ता) विधि को कॉल कर रहा हूं। DDD में मुझे group.JoinUser (उपयोगकर्ता) करना चाहिए, जो बहुत अच्छा दिखता है।

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

समस्या यह है कि अगर मुझे कोई उपयोगकर्ता जोड़ने के लिए कुछ मान्यता नियम हैं ...

सत्यापन नियम डोमेन मॉडल से संबंधित हैं! उन्हें डोमेन ऑब्जेक्ट्स (संस्थाओं आदि) के अंदर इनकैप्सुलेट किया जाना चाहिए।

... या उपयोगकर्ता को समूह में जोड़ने पर कुछ बाहरी कार्यों को शुरू करने की आवश्यकता होती है। इन कार्यों के होने से इकाई को बाहरी निर्भरता प्राप्त होगी।

जबकि मुझे नहीं पता कि आप किस प्रकार के बाहरी कार्य के बारे में बात कर रहे हैं, मुझे लगता है कि यह कुछ ऐसा है जैसे ईमेल भेजना आदि लेकिन यह वास्तव में आपके डोमेन मॉडल का हिस्सा नहीं है। यह एप्लिकेशन लेयर में रहना चाहिए और वहां imho को लटका दिया जाना चाहिए। आपकी एप्लिकेशन परत में एक सेवा हो सकती है जो उन कार्यों को करने के लिए डोमेन सेवाओं और संस्थाओं पर काम करती है।

लेकिन यह तथ्य कि एक इकाई कुछ बाहरी सेवाओं / वर्गों पर निर्भर करती है, मुझे इतनी अच्छी और "स्वाभाविक" नहीं लगती।

यह अप्राकृतिक है और ऐसा नहीं होना चाहिए। इकाई को सामान के बारे में नहीं पता होना चाहिए जो इसकी जिम्मेदारी नहीं है। सेवाओं को ऑर्केस्ट्रेट इकाई इंटरैक्शन के लिए उपयोग किया जाना चाहिए।

DDD में इससे निपटने का उचित तरीका क्या है?

आपके मामले में, रिश्ते को संभवतः अप्रत्यक्ष होना चाहिए। क्या उपयोगकर्ता समूह में शामिल होता है या समूह उपयोगकर्ता को अपने डोमेन पर निर्भर करता है। क्या उपयोगकर्ता समूह में शामिल होता है? या उपयोगकर्ता को एक समूह में जोड़ा जाता है? यह आपके डोमेन में कैसे काम करता है?

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

सत्यापन तब संस्था द्वारा किया जाना चाहिए। पूरी चीज़ को एप्लिकेशन लेयर की एक सेवा से बुलाया जाता है जो तकनीकी सामान भी कर सकती है, जैसे ईमेल भेजना आदि।

हालाँकि, यदि सत्यापन तर्क वास्तव में जटिल है, तो एक डोमेन सेवा एक बेहतर समाधान हो सकती है। उस स्थिति में, वहाँ व्यापार नियमों को एनकैप्सुलेट करें और फिर इसे अपने एप्लिकेशन लेयर से कॉल करें।


लेकिन अगर हम इकाई के बाहर इतने तर्क रखते हैं, तो अंदर क्या रखा जाना चाहिए?
साइबेरियाईगूई

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

इसके अलावा, आपको पता है कि आपको एक सेवा की आवश्यकता है जब दो या अधिक अन्यथा असंबंधित वस्तुओं को किसी कार्य को पूरा करने के लिए भाग लेने की आवश्यकता होती है।
फाल्कन

1
आपके उत्तर के लिए धन्यवाद, फाल्कन! Btw, मैंने हमेशा स्टेटलेस सेवाओं का उपयोग करने की कोशिश की, इसलिए मैं DDD के करीब एक कदम हूं :) मान लीजिए कि एक डोमेन में यह UserJoinsToGroup ऑपरेशन समूह से संबंधित है। समस्या यह है कि उस ऑपरेशन को मान्य करने के लिए मुझे यह जानने की जरूरत है कि उपयोगकर्ता कितने समूहों में पहले से ही भाग ले रहा है (यदि यह पहले से ही है तो ऑपरेशन को अस्वीकार करने के लिए> 3)। यह जानने के लिए कि मुझे डेटाबेस को क्वेरी करने की आवश्यकता है। मैं समूह इकाई से कैसे कर सकता हूं? मेरे पास कुछ और उदाहरण हैं, जब मुझे ऑपरेशन में डीबी को छूने की आवश्यकता है जो स्वाभाविक रूप से इकाई से संबंधित होना चाहिए (मैं उन्हें पोस्ट करूंगा यदि आवश्यक हो :))
Shaddix

2
ठीक है, अगर मैं इसके बारे में सोचता हूं: GroupMembership संस्था के बारे में क्या? इसका निर्माण किसी कारखाने द्वारा किया जा सकता है और यह कारखाना रेस्पिरेटरी तक पहुंच सकता है। यह अच्छा DDD होगा और सदस्यता के निर्माण को समझाया जाएगा। कारखाना रिपॉजिटरी तक पहुंच सकता है, एक सदस्यता बनाता है और उपयोगकर्ता और समूह में क्रमशः इसे जोड़ता है। यह नई इकाई विशेषाधिकारों का भी अतिक्रमण कर सकती है। शायद यह एक अच्छा विचार है।
फाल्कन

3

जिस तरह से मैं सत्यापन की समस्या से संपर्क करूंगा वह इस प्रकार है: एक डोमेन सेवा बनाएं जिसे कहा जाता है MembershipService:

class MembershipService : IMembershipService
{
   public MembershipService(IGroupRepository groupRepository)
   { 
     _groupRepository = groupRepository;
   }
   public int NumberOfGroupsAssignedTo(UserId userId)
   {
        return _groupsRepository.NumberOfGroupsAssignedTo(userId);
   }
}

समूह इकाई के साथ इंजेक्शन लगाने की आवश्यकता है IMemberShipService। यह वर्ग स्तर या विधि स्तर पर किया जा सकता है। मान लेते हैं कि हम इसे विधि के स्तर पर करते हैं।

class Group{

   public void JoinUser(User user, IMembershipService membershipService)
   {
       if(membershipService.NumberOfGroupsAssignedTo(user.UserId) >= 3)
         throw new BusinessException("User assigned to more than 3 groups. Cannot proceed");

       // do some more stuff
   }
}

एप्लिकेशन सेवा: कंस्ट्रक्टर इंजेक्शन का उपयोग करके GroupServiceइंजेक्ट किया जा सकता है IMemberShipService, जिसे वह कक्षा JoinUserकी विधि में पास कर सकता है Group


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