आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम

इस पेज पर, आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम और उन्हें बनाने के पीछे के सिद्धांत के बारे में बताया गया है. Bazel, आर्टफ़ैक्ट पर आधारित एक बिल्ड सिस्टम है. टास्क पर आधारित बिल्ड सिस्टम, बिल्ड स्क्रिप्ट से बेहतर होते हैं. हालांकि, ये सिस्टम हर इंजीनियर को अपने टास्क तय करने की अनुमति देते हैं, जिससे उन्हें बहुत ज़्यादा अधिकार मिल जाते हैं.

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

फ़ंक्शन के हिसाब से

आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम और फ़ंक्शनल प्रोग्रामिंग के बीच समानताएं ढूंढना आसान है. इंपरेटिव प्रोग्रामिंग की पारंपरिक भाषाओं (जैसे, Java, C, और Python) में, एक के बाद एक स्टेटमेंट को एक्ज़ीक्यूट करने के लिए सूचियां तय की जाती हैं. इसी तरह, टास्क पर आधारित बिल्ड सिस्टम, प्रोग्रामर को एक्ज़ीक्यूट करने के लिए चरणों की एक सीरीज़ तय करने की अनुमति देते हैं. इसके उलट, फ़ंक्शनल प्रोग्रामिंग लैंग्वेज (जैसे, Haskell और ML) को गणित के समीकरणों की सीरीज़ की तरह स्ट्रक्चर किया जाता है. फ़ंक्शनल लैंग्वेज में प्रोग्रामर, कंप्यूटेशन के बारे में बताता है. हालांकि, वह यह जानकारी कंपाइलर पर छोड़ देता है कि कंप्यूटेशन कब और कैसे किया जाएगा.

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

आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम के बारे में जानकारी

Google का बिल्ड सिस्टम, Blaze, आर्टफ़ैक्ट पर आधारित पहला बिल्ड सिस्टम था. Bazel, Blaze का ओपन-सोर्स वर्शन है.

Bazel में, बिल्डफ़ाइल (आम तौर पर इसका नाम BUILD होता है) ऐसी दिखती है:

java_binary(
    name = "MyBinary",
    srcs = ["MyBinary.java"],
    deps = [
        ":mylib",
    ],
)
java_library(
    name = "mylib",
    srcs = ["MyLibrary.java", "MyHelper.java"],
    visibility = ["//java/com/example/myproduct:__subpackages__"],
    deps = [
        "//java/com/example/common",
        "//java/com/example/myproduct/otherlib",
    ],
)

Bazel में, BUILD फ़ाइलें टारगेट तय करती हैं. यहां दो तरह के टारगेट होते हैं: java_binary और java_library. हर टारगेट, एक ऐसे आर्टफ़ैक्ट से जुड़ा होता है जिसे सिस्टम बना सकता है: बाइनरी टारगेट, ऐसी बाइनरी बनाते हैं जिन्हें सीधे तौर पर एक्ज़ीक्यूट किया जा सकता है. वहीं, लाइब्रेरी टारगेट, ऐसी लाइब्रेरी बनाते हैं जिनका इस्तेमाल बाइनरी या अन्य लाइब्रेरी कर सकती हैं. हर टारगेट में ये जानकारी होती है:

  • name: कमांड लाइन और अन्य टारगेट पर टारगेट को कैसे रेफ़र किया जाता है
  • srcs: टारगेट के लिए आर्टफ़ैक्ट बनाने के लिए, कंपाइल की जाने वाली सोर्स फ़ाइलें
  • deps: अन्य टारगेट जिन्हें इस टारगेट से पहले बनाया जाना चाहिए और इससे लिंक किया जाना चाहिए

डिपेंडेंसी, एक ही पैकेज में हो सकती हैं. जैसे, MyBinary की डिपेंडेंसी :mylib पर है. इसके अलावा, ये एक ही सोर्स के क्रम में मौजूद किसी दूसरे पैकेज पर भी हो सकती हैं. जैसे, mylib की डिपेंडेंसी //java/com/example/common पर है.

टास्क पर आधारित बिल्ड सिस्टम की तरह ही, Bazel के कमांड-लाइन टूल का इस्तेमाल करके बिल्ड किए जाते हैं. MyBinary टारगेट बनाने के लिए, bazel build :MyBinary चलाया जाता है. किसी नई रिपॉज़िटरी में पहली बार यह कमांड डालने के बाद, Bazel:

  1. यह वर्कस्पेस में मौजूद हर BUILD फ़ाइल को पार्स करता है, ताकि आर्टफ़ैक्ट के बीच डिपेंडेंसी का ग्राफ़ बनाया जा सके.
  2. यह ग्राफ़ का इस्तेमाल करके, MyBinary की ट्रांज़िटिव डिपेंडेंसी का पता लगाता है. इसका मतलब है कि MyBinary पर निर्भर हर टारगेट और उन टारगेट पर निर्भर हर टारगेट का पता लगाया जाता है.
  3. इनमें से हर डिपेंडेंसी को क्रम से बनाता है. Bazel, उन सभी टारगेट को बनाने से शुरू करता है जिनकी कोई अन्य डिपेंडेंसी नहीं होती. साथ ही, यह ट्रैक करता है कि हर टारगेट के लिए किन डिपेंडेंसी को अब भी बनाया जाना है. किसी टारगेट की सभी डिपेंडेंसी बन जाने के बाद, Bazel उस टारगेट को बनाना शुरू कर देता है. यह प्रोसेस तब तक चलती रहती है, जब तक MyBinary की सभी ट्रांज़िटिव डिपेंडेंसी नहीं बन जातीं.
  4. MyBinary बनाता है, ताकि एक फ़ाइनल एक्ज़ीक्यूटेबल बाइनरी तैयार की जा सके. यह बाइनरी, तीसरे चरण में बनाई गई सभी डिपेंडेंसी से लिंक होती है.

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

हालांकि, इसके फ़ायदे पैरललिज़्म से आगे भी हैं. इस तरीके से हमें जो अगली चीज़ मिलती है वह तब साफ़ तौर पर दिखती है, जब डेवलपर बिना किसी बदलाव के bazel build :MyBinary को दूसरी बार टाइप करता है: Bazel एक सेकंड से भी कम समय में बंद हो जाता है और एक मैसेज दिखाता है कि टारगेट अप-टू-डेट है. ऐसा फ़ंक्शनल प्रोग्रामिंग पैराडाइम की वजह से होता है, जिसके बारे में हमने पहले बात की थी. Bazel को पता है कि हर टारगेट, सिर्फ़ Java कंपाइलर को चलाने का नतीजा है. साथ ही, उसे यह भी पता है कि Java कंपाइलर का आउटपुट, सिर्फ़ उसके इनपुट पर निर्भर करता है. इसलिए, जब तक इनपुट में कोई बदलाव नहीं होता, तब तक आउटपुट को फिर से इस्तेमाल किया जा सकता है. यह विश्लेषण हर लेवल पर काम करता है. अगर MyBinary.java बदलता है, तो Bazel को MyBinary.java को फिर से बनाने के बारे में पता होता है, लेकिन वह mylib का फिर से इस्तेमाल करता है.MyBinary अगर //java/com/example/common के लिए कोई सोर्स फ़ाइल बदलती है, तो Bazel को पता होता है कि उस लाइब्रेरी, mylib, और MyBinary को फिर से बनाना है. हालांकि, //java/com/example/myproduct/otherlib का फिर से इस्तेमाल किया जा सकता है. Bazel को हर चरण में, उन टूल की प्रॉपर्टी के बारे में पता होता है जिन्हें वह चलाता है. इसलिए, वह हर बार सिर्फ़ आर्टफ़ैक्ट का सबसे छोटा सेट फिर से बना पाता है. साथ ही, यह गारंटी देता है कि वह पुरानी बिल्ड नहीं बनाएगा.

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

Bazel के अन्य बेहतरीन सुझाव

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

डिपेंडेंसी के तौर पर टूल

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

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

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

  • होस्ट कॉन्फ़िगरेशन: बिल्ड के दौरान चलने वाले टूल
  • टारगेट कॉन्फ़िगरेशन: वह बाइनरी बनाना जिसके लिए आपने अनुरोध किया था

बिल्ड सिस्टम को एक्सटेंड करना

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

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

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

एनवायरमेंट को अलग करना

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

बाहरी डिपेंडेंसी को डिटरमिनिस्टिक बनाना

हालांकि, अब भी एक समस्या बाकी है: बिल्ड सिस्टम को अक्सर बाहरी स्रोतों से डिपेंडेंसी (चाहे टूल हों या लाइब्रेरी) डाउनलोड करने की ज़रूरत होती है. इसके बजाय, उन्हें सीधे तौर पर नहीं बनाया जा सकता. इसे उदाहरण में @com_google_common_guava_guava//jar डिपेंडेंसी के ज़रिए देखा जा सकता है. यह Maven से JAR फ़ाइल डाउनलोड करती है.

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

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

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

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

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