डिपेंडेंसी मैनेज करना

किसी समस्या की शिकायत करें स्रोत देखें

पिछले पेजों पर नज़र डालने पर, एक थीम बार-बार दोहराई जाती है: अपने कोड को मैनेज करना बहुत आसान है, लेकिन उसकी डिपेंडेंसी मैनेज करना बहुत ज़्यादा मुश्किल है. सभी तरह की चीज़ें डिपेंडेंसी होती हैं. कभी-कभी, कोई टास्क एक डिपेंडेंसी पर निर्भर होता है, जैसे कि "किसी रिलीज़ को 'पूरा हो गया' के तौर पर मार्क करने से पहले दस्तावेज़ को पुश करें' और कभी-कभी आर्टफ़ैक्ट की डिपेंडेंसी भी ज़रूरी है. उदाहरण के लिए, "मुझे अपना कोड बनाने के लिए, कंप्यूटर विज़न लाइब्रेरी का नया वर्शन होना ज़रूरी है." कभी-कभी, आपको अपने कोड बेस या दूसरे संगठन पर निर्भर होना पड़ता है. हालांकि, किसी भी मामले में, “मुझे यह काम करने से पहले इसकी ज़रूरत होती है” कि सिस्टम, डिज़ाइन सिस्टम में बार-बार दोहराया जाता है. डिपेंडेंसी मैनेज करना आपके लिए बिल्ड सिस्टम का सबसे बुनियादी काम है.

मॉड्यूल और डिपेंडेंसी से जुड़ी सेवाएं

Bazel जैसे आर्टफ़ैक्ट आधारित बिल्ड सिस्टम का इस्तेमाल करने वाले प्रोजेक्ट, मॉड्यूल के सेट में बंटे होते हैं. मॉड्यूल में BUILD फ़ाइलों के ज़रिए एक-दूसरे पर डिपेंडेंसी दिखाई जाती है. इन मॉड्यूल और डिपेंडेंसी के सही तरीके से सेट अप करने से, बिल्ड सिस्टम की परफ़ॉर्मेंस पर असर पड़ सकता है. साथ ही, उसे बनाए रखने में कितना समय लग सकता है, इस बात पर भी काफ़ी असर पड़ता है.

फ़ाइन-ग्रेनेड मॉड्यूल और 1:1:1 नियम का इस्तेमाल करना

आर्टफ़ैक्ट पर आधारित बिल्ड को तैयार करते समय, सबसे पहले जो सवाल आता है वह यह तय करता है कि किसी मॉड्यूल में कितनी फ़ंक्शन शामिल होनी चाहिए. Bazel में, मॉड्यूल को दिखाने के लिए एक टारगेट का इस्तेमाल किया जाता है, जिसमें java_library या go_binary जैसी बिल्डेबल यूनिट के बारे में बताया जाता है. एक बार में, तो पूरे प्रोजेक्ट को एक मॉड्यूल में शामिल किया जा सकता है. इसके लिए, एक BUILD फ़ाइल को रूट करके रखा जाना चाहिए और उस प्रोजेक्ट की सभी सोर्स फ़ाइलों को बार-बार रखना चाहिए. इसके अलावा, करीब-करीब हर सोर्स फ़ाइल को उसके मॉड्यूल में बनाया जा सकता है. इसलिए, ज़रूरी है कि हर फ़ाइल को BUILD फ़ाइल की सूची में शामिल किया जाए, ताकि वह हर उस फ़ाइल पर निर्भर हो.

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

हालांकि, जानकारी का सटीक लेवल, भाषा के हिसाब से और अक्सर भाषा के अंदर भी अलग-अलग होता है, फिर भी Google, आम तौर पर टास्क-आधारित बिल्ड सिस्टम में मौजूद मॉड्यूल की तुलना में बहुत छोटे मॉड्यूल को प्राथमिकता देता है. Google में आम तौर पर बनाई गई बाइनरी, अक्सर हज़ारों टारगेट पर निर्भर करती है. साथ ही, सामान्य आकार वाली टीम भी अपने कोडबेस में सैकड़ों टारगेट चुन सकती है. आम तौर पर, Java जैसी भाषाओं में पैकेजिंग के बारे में खास जानकारी मौजूद होती है. आम तौर पर, हर डायरेक्ट्री में एक पैकेज, टारगेट, और BUILD फ़ाइल होती है (Bazel पर आधारित दूसरे बिल्ड सिस्टम को यह 1:1:1 नियम कहते हैं). कमज़ोर पैकेजिंग वाली भाषाओं में, अक्सर हर BUILD फ़ाइल के लिए कई टारगेट तय किए जाते हैं.

छोटे बिल्ड टारगेट के फ़ायदे बड़े पैमाने पर दिखते हैं, क्योंकि इनमें टारगेट किए गए बिल्ड तेज़ी से लोड होते हैं और टारगेट को फिर से बनाने की ज़रूरत कम पड़ती है. टेस्टिंग के नतीजे दिखने के बाद, फ़ायदे और भी ज़्यादा असरदार हो जाते हैं. ऐसा इसलिए, क्योंकि बारीक टारगेट का मतलब यह होता है कि बिल्ड सिस्टम में जांच के सीमित सबसेट को चलाया जा सकता है, जिसमें किसी खास बदलाव का असर हो सकता है. Google छोटे-छोटे टारगेट को इस्तेमाल करने के व्यवस्थित फ़ायदों पर भरोसा करता है, इसलिए हमने डेवलपर को परेशान करने से बचने के लिए BUILD फ़ाइलों को अपने-आप मैनेज करने वाले टूल का इस्तेमाल करके कुछ खर्च कम कर लिए हैं.

इनमें से कुछ टूल, जैसे कि buildifier और buildozer, buildtools डायरेक्ट्री में बैजल के साथ उपलब्ध हैं.

मॉड्यूल विज़िबिलिटी कम करना

{0} निजी टारगेट को सिर्फ़ उसकी BUILD फ़ाइल में ही रेफ़र किया जा सकता है. टारगेट से, BUILD फ़ाइलों की साफ़ तौर पर बताई गई सूची के टारगेट को ज़्यादा लोग देख सकते हैं. इसके अलावा, सार्वजनिक तौर पर दिखने के लिए, फ़ाइल फ़ोल्डर में मौजूद सभी टारगेट को टारगेट कर सकते हैं.

आम तौर पर, ज़्यादातर प्रोग्रामिंग भाषाओं के लिए, अपने प्रॉडक्ट को ज़्यादा से ज़्यादा लोगों को दिखाने की कोशिश की जाती है. आम तौर पर, Google की टीमें, टारगेट को सिर्फ़ तब सार्वजनिक करेंगी, जब वे टारगेट Google की किसी भी टीम के लिए मौजूद लाइब्रेरी का बड़े पैमाने पर इस्तेमाल करते हों. जिन टीमों को अन्य उपयोगकर्ताओं के साथ कोड का उपयोग करने से पहले उनके साथ मिलकर काम करना पड़ता है, तो उन टीमों को टारगेट की अनुमति वाली सूची मिलनी चाहिए. हर टीम के अंदरूनी लागू टारगेट सिर्फ़ उन डायरेक्ट्री तक सीमित होंगे, जिनका मालिकाना हक टीम के पास है. ज़्यादातर BUILD फ़ाइलों में सिर्फ़ एक ऐसा टारगेट होगा जो निजी नहीं है.

डिपेंडेंसी मैनेज करना

मॉड्यूल एक-दूसरे से जुड़े होने चाहिए. कोडबेस को ठीक-ठाक मॉड्यूल में बदलने का नकारात्मक पहलू यह है कि आपको उन मॉड्यूल के बीच डिपेंडेंसी मैनेज करनी होगी (हालांकि, टूल की मदद से इसे अपने-आप चलाने में मदद मिल सकती है). इन डिपेंडेंसी को ज़ाहिर करने से, आम तौर पर BUILD फ़ाइल में एक साथ कई कॉन्टेंट मौजूद होते हैं.

इंटरनल डिपेंडेंसी

बेहतर मॉड्यूल में बांटे गए ज़्यादातर प्रोजेक्ट, ज़्यादातर डिपेंडेंसी इंटरनल होते हैं. इसका मतलब है कि एक ही सोर्स रिपॉज़िटरी में बनाए गए और टारगेट किए गए किसी दूसरे टारगेट पर. इंटरनल डिपेंडेंसी, अलग-अलग डिपेंडेंसी पर निर्भर करती हैं. डिवाइस बनाने के दौरान, इन्हें पहले से बने आर्टफ़ैक्ट के तौर पर डाउनलोड करने के बजाय, सोर्स से बनाया जाता है. इसका मतलब यह भी है कि अंदरूनी डिपेंडेंसी के लिए कोई “वर्शन” नहीं दिया जाता है. यह एक टारगेट है और इसकी सभी इंटरनल डिपेंडेंसी हमेशा रिपॉज़िटरी में, एक ही तय/बदलाव पर बनाई जाती हैं. एक समस्या जिसे इंटरनल डिपेंडेंसी के लिए, सावधानी से इस्तेमाल करना चाहिए वह है, ट्रांज़िशनल डिपेंडेंसी को मैनेज करना. (पहला डायग्राम). मान लें कि टारगेट A, टारगेट B पर निर्भर है, जो एक सामान्य लाइब्रेरी टारगेट C पर निर्भर करता है. क्या टारगेट A को, टारगेट C में दी गई क्लास का इस्तेमाल करने की सुविधा देनी चाहिए?

स्थायी निर्भरता

पहला डायग्राम. स्थायी निर्भरता

अगर बुनियादी टूल की बात करें, तो इसमें कोई समस्या नहीं है. B C के बनने के बाद B और C दोनों को टारगेट A से लिंक कर दिया जाएगा. इसलिए, C में तय किए गए सभी सिंबल A के बारे में पता होंगे. बेज़ल ने कई सालों तक इसकी अनुमति दी, लेकिन जैसे-जैसे Google आगे बढ़ा, हमें समस्याएं दिखने लगीं. मान लीजिए कि B को रिस्पॉन्स में इस तरह बदला गया है कि अब अब उसे C के भरोसे नहीं रहना पड़ता. इसके बाद, अगर C पर B का डिपेंडेंसी हटाया जाता है, तो A और उससे जुड़ी ऐसी अन्य टारगेट फ़ाइलें भी हटा दी जाएंगी जो B की डिपेंडेंसी के ज़रिए C का इस्तेमाल करती हैं. दरअसल, टारगेट की डिपेंडेंसी सार्वजनिक अनुबंध का हिस्सा बन गई है और उसे कभी भी सुरक्षित तरीके से बदला नहीं जा सकता. इसका मतलब है कि समय के साथ इकट्ठा होने वाली Google की डिपेंडेंसी, धीरे-धीरे कम होने लगी.

Google ने Bazel में “सख्त, निर्भरता मोड” को लागू करके, इस समस्या को हल कर लिया. इस मोड में, Bazel यह पता लगाता है कि कोई टारगेट सीधे तौर पर निर्भर किए बिना, चिह्न को रेफ़र करने की कोशिश करता है या नहीं. अगर ऐसा होता है, तो यह किसी गड़बड़ी और शेल कमांड के साथ काम नहीं करता. इसका इस्तेमाल, डिपेंडेंसी को अपने-आप डालने के लिए किया जा सकता है. इस बदलाव को Google के पूरे कोडबेस में रोल आउट करना और हमारे हर एक बिल्ड टारगेट को साफ़ तौर पर बताई गई, ताकि उनकी डिपेंडेंसी को साफ़ तौर पर सूची में शामिल किया जा सके इसमें कई साल की मेहनत लगी, लेकिन यह फ़ायदेमंद था. हमारे बिल्ड अब बहुत तेज़ हो गए हैं, क्योंकि टारगेट पर कम गैर-ज़रूरी डिपेंडेंसी लागू होती हैं. इंजीनियर्स के पास ऐसी डिपेंडेंसी हटाने की सुविधा होती है जिनकी उन्हें ज़रूरत नहीं होती जो टारगेट किए गए टारगेट पर निर्भर होने की चिंता किए बिना काम करती हैं.

सामान्य तौर पर, हमेशा इस्तेमाल होने वाली डिपेंडेंसी को लागू करने के लिए, समझौते के तहत काम शुरू करना पड़ा. हालांकि, अब फ़ाइलों के ऐक्शन वर्बोस हो जाते हैं, क्योंकि आम तौर पर इस्तेमाल होने वाली लाइब्रेरी में कॉन्टेंट डालने के बजाय, उसे कई जगहों पर आसानी से डालने की ज़रूरत होती है. साथ ही, इंजीनियर को BUILDफ़ाइल डिपेंडेंसी जोड़ने के लिए ज़्यादा कोशिश करनी पड़ती है. इसके बाद, हमने ऐसे टूल बनाए हैं जो टूल पर निर्भर न रहकर, उसकी बहुत सारी डिपेंडेंसी का पता अपने-आप लगा लेते हैं. इसके अलावा, उन टूल को BUILD फ़ाइलों में भी जोड़ देते हैं जो डेवलपर के काम में किसी तरह की रुकावट नहीं डालते. हालांकि, इस तरह के टूल के बिना, हम यह देखते हैं कि कोड-बेस स्केल में बताई गई डील-देन सही मानी जाती है: BUILD फ़ाइल में डिपेंडेंसी जोड़ना साफ़ तौर पर एक बार लगने वाला खर्च है. हालांकि, इंडिपेंडेंट डिपेंडेंसी से जुड़े काम की वजह से, बिल्ड टारगेट बने रहने में समस्या हो सकती है. Bazel की सुविधा, डिफ़ॉल्ट रूप से Java कोड पर, पूरी तरह से ट्रांसपेरंसी डिपेंडेंसी लागू करती है.

एक्स्टर्नल डिपेंडेंसी

अगर कोई डिपेंडेंसी अंदरूनी नहीं है, तो उसका बाहरी वर्शन होना ज़रूरी है. एक्सटर्नल डिपेंडेंसी, उन आर्टफ़ैक्ट पर निर्भर करती हैं जिन्हें बिल्ड सिस्टम से बाहर बनाया और स्टोर किया जाता है. डिपेंडेंसी, सीधे डेटा स्टोर करने की जगह से इंपोर्ट की जाती है (आम तौर पर, इसे इंटरनेट से ऐक्सेस किया जाता है) और इसे सोर्स से बनाए जाने के बजाय, ज्यों का त्यों इस्तेमाल किया जाता है. बाहरी और अंदरूनी डिपेंडेंसी में सबसे बड़ा अंतर यह है कि बाहरी डिपेंडेंसी के वर्शन भी होते हैं और वे वर्शन भी प्रोजेक्ट के सोर्स कोड से अलग होते हैं.

ऑटोमैटिक बनाम मैन्युअल डिपेंडेंसी मैनेजमेंट

बिल्ड सिस्टम, बाहरी डिपेंडेंसी के वर्शन को मैन्युअल या अपने-आप मैनेज करने की अनुमति देते हैं. बिल्डफ़ाइल को मैन्युअल रूप से मैनेज करने पर, वह साफ़ तौर पर उन वर्शन की सूची बनाता है जिन्हें वह आर्टफ़ैक्ट रिपॉज़िटरी से डाउनलोड करना चाहता है. इसके लिए, आम तौर पर 1.1.4 जैसे सिमेंटिक वर्शन स्ट्रिंग का इस्तेमाल किया जाता है. अपने-आप मैनेज होने की वजह से, सोर्स फ़ाइल स्वीकार किए जाने वाले वर्शन की रेंज तय करती है और बिल्ड सिस्टम हमेशा सबसे नए वर्शन को डाउनलोड करता है. उदाहरण के लिए, Gradle को किसी डिपेंडेंसी वर्शन को “1.+” के तौर पर बताने की अनुमति मिलती है. इससे यह पता चलता है कि डिपेंडेंसी का कोई भी माइनर या पैच वर्शन तब तक स्वीकार किया जाता है, जब तक मेजर वर्शन 1 होता है.

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

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

एक-वर्शन वाला नियम

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

कई वर्शन को अनुमति देने में सबसे बड़ी समस्या डायमंड डिपेंडेंसी की है. मान लीजिए कि टारगेट A, टारगेट B और किसी बाहरी लाइब्रेरी के v1 पर निर्भर करता है. अगर टारगेट B को बाद में उसी बाहरी लाइब्रेरी के v2 पर निर्भरता जोड़ने के लिए फिर से कोशिश की जाती है, तो टारगेट A टूट जाएगा, क्योंकि अब यह साफ़ तौर पर उसी लाइब्रेरी के दो अलग-अलग वर्शन पर निर्भर करता है. असल में, टारगेट से तीसरे पक्ष की लाइब्रेरी में कई वर्शन वाली नई डिपेंडेंसी जोड़ना, कभी भी सुरक्षित नहीं होता है. ऐसा इसलिए, क्योंकि टारगेट के किसी भी उपयोगकर्ता के लिए, पहले से ही किसी दूसरे वर्शन का इस्तेमाल किया जा सकता है. एक-वर्शन के नियम का पालन करने से यह विवाद नामुमकिन हो जाता है—अगर कोई टारगेट किसी तीसरे-पक्ष की लाइब्रेरी पर कोई डिपेंडेंसी जोड़ता है, तो सभी मौजूदा डिपेंडेंसी पहले से उसी वर्शन पर रहेंगी, ताकि वे आपस में मेल खा सकें.

ट्रांज़ैक्शनल बाहरी डिपेंडेंसी

बाहरी डिपेंडेंसी के लिए, कुछ समय के लिए जो डिपेंडेंसी दी जाती हैं उससे जुड़ी समस्या हल करना मुश्किल हो सकता है. Maven Central जैसे कई आर्टफ़ैक्ट रिपॉज़िटरी, आर्टफ़ैक्ट को रिपॉज़िटरी में दूसरे आर्टफ़ैक्ट के खास वर्शन पर निर्भरता बताने की अनुमति देते हैं. Maven या Gradle जैसे टूल बनाने के लिए, अक्सर डिफ़ॉल्ट रूप से हर बार अस्थायी तौर पर एक डिपेंडेंसी डाउनलोड की जाती है. इसका मतलब है कि अपने प्रोजेक्ट में एक डिपेंडेंसी जोड़ने से, दर्जनों कलाकृतियां डाउनलोड हो सकती हैं.

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

इस वजह से, Bazel, ट्रांज़िशनल डिपेंडेंसी अपने-आप डाउनलोड नहीं करता. और, माफ़ करें, इसके लिए कोई ज़रूरी बात नहीं है. बैज़ेल के लिए एक ऐसी ग्लोबल फ़ाइल की ज़रूरत है जो रिपॉज़िटरी की सभी बाहरी डिपेंडेंसी और एक खास वर्शन की जानकारी देती हो, जिसका इस्तेमाल पूरे डेटा स्टोर करने की जगह के लिए किया जाता है. अच्छी बात यह है कि Bazel ऐसे टूल उपलब्ध कराता है जिनसे ऐसी फ़ाइल अपने-आप जनरेट हो सकती है. इस फ़ाइल में Maven आर्टफ़ैक्ट की कुछ समय के लिए इस्तेमाल होने वाली डिपेंडेंसी शामिल हैं. यह टूल किसी प्रोजेक्ट के लिए शुरुआती WORKSPACE फ़ाइल जनरेट करने के लिए एक बार चलाया जा सकता है. इसके बाद, उस फ़ाइल को हर डिपेंडेंसी के वर्शन में बदलाव करने के लिए, मैन्युअल तरीके से अपडेट किया जा सकता है.

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

कैश मेमोरी का इस्तेमाल करने के लिए, बाहरी डिपेंडेंसी का इस्तेमाल करना

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

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

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

बाहरी डिपेंडेंसी की सुरक्षा और भरोसा

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