डिपेंडेंसी इंजेक्शन कितना है?


38

मैं एक ऐसी परियोजना में काम करता हूं जो (स्प्रिंग) निर्भरता इंजेक्शन का उपयोग करता है वस्तुतः हर चीज के लिए जो एक वर्ग की निर्भरता है। हम उस बिंदु पर हैं जहां स्प्रिंग कॉन्फ़िगरेशन फ़ाइल लगभग 4000 लाइनों तक बढ़ गई है। बहुत समय पहले मैंने यूट्यूब पर अंकल बॉब की एक वार्ता देखी थी (दुर्भाग्य से, मुझे लिंक नहीं मिल पाया) जिसमें उन्होंने मुख्य घटक में केवल केंद्रीय निर्भरता (जैसे कारखानों, डेटाबेस, ...) के एक जोड़े को इंजेक्ट करने की सिफारिश की, जिसमें से वे तब करेंगे वितरित किया जाए।

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

तो मेरा प्रश्न वास्तव में एक या दूसरे दृष्टिकोण में आपके द्वारा देखे गए अन्य फायदे या नुकसान क्या हैं। क्या कोई सर्वोत्तम प्रथाएं हैं? आपके उत्तरों के लिए बहुत धन्यवाद!


3
4000 लाइन कॉन्फ़िगरेशन फ़ाइल होने पर निर्भरता इंजेक्शन की गलती नहीं है ... इसे ठीक करने के बहुत सारे तरीके हैं: फ़ाइल को कई छोटी फ़ाइलों में संशोधित करें, एनोटेशन आधारित इंजेक्शन पर स्विच करें, xml के बजाय JavaConfig फ़ाइलों का उपयोग करें। मूल रूप से, आप जो समस्या अनुभव कर रहे हैं, वह आपके एप्लिकेशन की निर्भरता इंजेक्शन आवश्यकताओं की जटिलता और आकार का प्रबंधन करने में विफलता है।
है_Factor

1
@Maybe_Factor TL; DR परियोजना को छोटे घटकों में विभाजित करता है।
वॉलफ्रैट

जवाबों:


44

हमेशा की तरह, यह ™ निर्भर करता है। उत्तर उस समस्या पर निर्भर करता है जिसे हल करने का प्रयास किया जा रहा है। इस उत्तर में, मैं कुछ सामान्य प्रेरक बलों को संबोधित करने की कोशिश करूँगा:

अनुकूल छोटे कोड आधार

यदि आपके पास स्प्रिंग कॉन्फ़िगरेशन कोड की 4,000 लाइनें हैं, तो मुझे लगता है कि कोड आधार में हजारों कक्षाएं हैं।

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

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

जबकि मुझे एहसास है कि यह पहली सलाह आसानी से कम से कम व्यावहारिक है, मेरा यह भी मानना ​​है कि यह सबसे महत्वपूर्ण है, और इसलिए मैं इसे शामिल करता हूं। कोड की जटिलता गैर-रैखिक रूप से (संभवतः घातीय रूप से) कोड आधार के आकार के साथ भिन्न होती है।

अनुकूल शुद्ध डि

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

मुझे स्प्रिंग के साथ कोई व्यावहारिक अनुभव नहीं है, लेकिन मैं मान रहा हूं कि कॉन्फ़िगरेशन फ़ाइल द्वारा , XML फ़ाइल निहित है।

XML का उपयोग करके निर्भरता को कॉन्फ़िगर करना दोनों दुनिया में सबसे खराब है। सबसे पहले, आप संकलन-समय प्रकार सुरक्षा खो देते हैं, लेकिन आप कुछ भी हासिल नहीं करते हैं। एक XML कॉन्फ़िगरेशन फ़ाइल आसानी से बड़ी हो सकती है क्योंकि कोड इसे बदलने की कोशिश करता है।

समस्या की तुलना में यह पता लगाने के लिए निर्भर करता है, निर्भरता इंजेक्शन कॉन्फ़िगरेशन फ़ाइलें कॉन्फ़िगरेशन जटिलता घड़ी पर गलत स्थान पर कब्जा कर लेती हैं

मोटे अनाज पर निर्भरता इंजेक्शन के लिए मामला

मैं मोटे अनाज पर निर्भरता इंजेक्शन के लिए मामला बना सकता हूं। मैं ठीक-ठीक निर्भरता इंजेक्शन के लिए एक मामला भी बना सकता हूं (अगला भाग देखें)।

यदि आप केवल कुछ 'केंद्रीय' निर्भरता को इंजेक्ट करते हैं, तो अधिकांश वर्ग इस तरह दिख सकते हैं:

public class Foo
{
    private readonly Bar bar;

    public Foo()
    {
        this.bar = new Bar();
    }

    // Members go here...
}

यह अभी भी वर्ग के वंशानुक्रम पर डिजाइन पैटर्न के पक्ष वस्तु संरचना फिट बैठता है , क्योंकि Fooरचना करता है Bar। एक स्थिरता के दृष्टिकोण से, इसे अभी भी बनाए रखा जा सकता है, क्योंकि यदि आपको संरचना को बदलने की आवश्यकता है, तो आप बस इसके लिए स्रोत कोड को संपादित करते हैं Foo

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

डिपेंडेंसी इंजेक्शन पर अपनी पुस्तक के पहले संस्करण में , मैं अस्थिर और स्थिर निर्भरता के बीच अंतर करता हूं।

अस्थिर निर्भरता वे निर्भरताएं हैं जिन्हें आपको इंजेक्शन लगाने पर विचार करना चाहिए। उनमे शामिल है

  • संकलन के बाद पुनः निर्भर होने वाली निर्भरताएँ
  • एक और टीम द्वारा समानांतर में विकसित की गई निर्भरता
  • गैर-नियतात्मक व्यवहार के साथ निर्भरता, या दुष्प्रभाव के साथ व्यवहार

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

हालांकि, परीक्षण के नजरिए से, यह इकाई परीक्षण को कठिन बनाता है। आप अब Fooस्वतंत्र इकाई परीक्षण नहीं कर सकते Bar। जैसा कि जेबी रेन्सबर्गर बताते हैं , एकीकरण परीक्षण जटिलता के एक दहनशील विस्फोट से पीड़ित हैं। यदि आप 4-5 कक्षाओं के एकीकरण के माध्यम से सभी रास्तों को कवर करना चाहते हैं, तो आपको वस्तुतः दसियों हज़ार परीक्षण मामलों को लिखना होगा।

इसका प्रतिवाद यह है कि अक्सर, आपका कार्य किसी कक्षा को प्रोग्राम करना नहीं है। आपका कार्य एक ऐसी प्रणाली विकसित करना है जो कुछ विशिष्ट समस्याओं को हल करती है। यह व्यवहार-प्रेरित विकास (BDD) के पीछे की प्रेरणा है ।

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

यदि आप सॉफ्टवेयर के विकास पर इस दृष्टिकोण को लेते हैं, तो मोटे अनाज पर निर्भरता इंजेक्शन समझ में आता है।

ठीक अनाज निर्भरता इंजेक्शन के लिए मामला

दूसरी ओर, ठीक-ठाक निर्भरता इंजेक्शन, सभी चीजों को इंजेक्शन के रूप में वर्णित किया जा सकता है !

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

BDD के प्रस्तावक इस तर्क से मुकाबला करेंगे कि आपको परीक्षणों के साथ सभी कोड पथ को कवर करने की आवश्यकता नहीं है। आपको केवल उन लोगों को कवर करना होगा जो व्यावसायिक मूल्य का उत्पादन करते हैं।

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

इसने मुझे ठीक-ठाक निर्भरता इंजेक्शन के पक्ष में कर दिया है, क्योंकि यह मुझे अलगाव में सभी वस्तुओं के आक्रमणकारियों का परीक्षण करने में सक्षम बनाता है।

अनुकूल कार्यात्मक प्रोग्रामिंग

हालांकि मैं ठीक-ठाक निर्भरता इंजेक्शन की ओर झुकता हूं, मैंने अपना जोर कार्यात्मक प्रोग्रामिंग की ओर स्थानांतरित कर दिया है, अन्य कारणों से क्योंकि यह आंतरिक रूप से परीक्षण योग्य है

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

अनुकूल सांख्यिकीय रूप से टाइप किए गए कार्यात्मक प्रोग्रामिंग

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

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

इसके अलावा, निर्भरता इंजेक्शन कार्यात्मक नहीं है । सही कार्यात्मक प्रोग्रामिंग को निर्भरता की संपूर्ण धारणा को अस्वीकार करना चाहिए । परिणाम सरल कोड है।

सारांश

यदि सी # के साथ काम करने के लिए मजबूर किया जाता है, तो मैं ठीक-ठाक निर्भरता इंजेक्शन पसंद करता हूं क्योंकि यह मुझे परीक्षण के मामलों की प्रबंधनीय संख्या के साथ पूरे कोड आधार को कवर करने में सक्षम बनाता है।

अंत में, मेरी प्रेरणा तेजी से प्रतिक्रिया है। फिर भी, यूनिट परीक्षण प्रतिक्रिया प्राप्त करने का एकमात्र तरीका नहीं है


1
मुझे वास्तव में यह उत्तर पसंद है, और विशेष रूप से वसंत के संदर्भ में इस्तेमाल किया गया यह कथन: "एक्सएमएल का उपयोग करके निर्भरता को कॉन्फ़िगर करना दोनों दुनिया में सबसे खराब है। सबसे पहले, आप संकलन-समय प्रकार की सुरक्षा खो देते हैं, लेकिन आप कुछ भी हासिल नहीं करते हैं। एक्सएमएल कॉन्फ़िगरेशन। फ़ाइल आसानी से उतनी बड़ी हो सकती है जितना कि कोड इसे बदलने की कोशिश करता है। "
थॉमस कार्लिसले

@ThomasCarlisle XML कॉन्फ़िगरेशन का बिंदु नहीं था जिसे बदलने के लिए आपको कोड (यहां तक ​​कि संकलन) को छूने की आवश्यकता नहीं है? मार्क ने जिन दो चीजों का उल्लेख किया है, उनके कारण मैंने कभी (या बमुश्किल) इसका उपयोग नहीं किया है, लेकिन आप बदले में कुछ हासिल करते हैं।
एल मैक

1

विशाल DI सेटअप कक्षाएं एक समस्या हैं। लेकिन उस कोड के बारे में सोचिए जो इसे बदलता है।

आपको उन सभी सेवाओं और व्हाट्सएप को इंस्टेंट करना होगा। ऐसा करने के लिए कोड या तो app.main()प्रारंभिक बिंदु में होगा और मैन्युअल रूप से इंजेक्ट किया जाएगा, या this.myService = new MyService();वर्गों के भीतर कसकर युग्मित किया जाएगा ।

अपने सेटअप वर्ग के आकार को कम करके इसे कई सेटअप कक्षाओं में विभाजित करें और उन्हें प्रोग्राम प्रारंभ बिंदु से कॉल करें। अर्थात।

main()
{
   var c = new diContainer();
   var service1 = diSetupClass.SetupService1(c);
   var service2 = diSetupClass.SetupService2(c, service1); //if service1 is required by service2
   //etc

   //main logic
}

आपको उन्हें अन्य ci सेटअप विधियों में पास करने के अलावा service1 या 2 को संदर्भित करने की आवश्यकता नहीं है।

यह कंटेनर से उन्हें प्राप्त करने के प्रयास से बेहतर है क्योंकि यह सेटअप को कॉल करने के क्रम को लागू करता है।


1
जो लोग इस अवधारणा को आगे देखना चाहते हैं (कार्यक्रम की शुरुआत बिंदु पर अपने वर्ग के पेड़ का निर्माण) के लिए, खोज करने के लिए सबसे अच्छा शब्द "रचना जड़" है
e_i_pi

@ क्या वह ciचर है?
सुपरजोस

स्थिर विधियों के साथ आपका ci सेटअप वर्ग
Ewan

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