हमेशा की तरह, यह ™ निर्भर करता है। उत्तर उस समस्या पर निर्भर करता है जिसे हल करने का प्रयास किया जा रहा है। इस उत्तर में, मैं कुछ सामान्य प्रेरक बलों को संबोधित करने की कोशिश करूँगा:
अनुकूल छोटे कोड आधार
यदि आपके पास स्प्रिंग कॉन्फ़िगरेशन कोड की 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 # जैसी सांख्यिकीय रूप से टाइप की गई भाषाएं, आपको टाइप सिस्टम में कई निर्णय बिंदुओं को एनकोड करने में सक्षम बनाती हैं। इसका मतलब यह है कि हजारों परीक्षण लिखने के बजाय, कंपाइलर आपको यह बताएगा कि क्या आपने सभी संभावित कोड पथ (एक हद तक; यह सिल्वर बुलेट नहीं है) से निपटा है।
इसके अलावा, निर्भरता इंजेक्शन कार्यात्मक नहीं है । सही कार्यात्मक प्रोग्रामिंग को निर्भरता की संपूर्ण धारणा को अस्वीकार करना चाहिए । परिणाम सरल कोड है।
सारांश
यदि सी # के साथ काम करने के लिए मजबूर किया जाता है, तो मैं ठीक-ठाक निर्भरता इंजेक्शन पसंद करता हूं क्योंकि यह मुझे परीक्षण के मामलों की प्रबंधनीय संख्या के साथ पूरे कोड आधार को कवर करने में सक्षम बनाता है।
अंत में, मेरी प्रेरणा तेजी से प्रतिक्रिया है। फिर भी, यूनिट परीक्षण प्रतिक्रिया प्राप्त करने का एकमात्र तरीका नहीं है ।