หน้านี้ครอบคลุมระบบบิลด์ที่อิงตามอาร์ติแฟกต์และปรัชญาเบื้องหลังการสร้างระบบดังกล่าว Bazel เป็นระบบบิลด์ที่อิงตามอาร์ติแฟกต์ แม้ว่าระบบการสร้างตามงานจะดีกว่าสคริปต์การสร้าง แต่ก็ให้อำนาจมากเกินไปแก่ วิศวกรแต่ละคนโดยการอนุญาตให้กำหนดงานของตนเอง
ระบบบิลด์ที่อิงตามอาร์ติแฟกต์มีงานจำนวนน้อยที่ระบบกำหนด
ซึ่งวิศวกรสามารถกำหนดค่าได้ในลักษณะที่จำกัด วิศวกรยังคงบอกระบบว่าควรสร้างอะไร แต่ระบบบิลด์จะเป็นตัวกำหนดวิธีสร้าง เช่นเดียวกับ
ระบบบิลด์ที่อิงตามงาน ระบบบิลด์ที่อิงตามอาร์ติแฟกต์ เช่น Bazel ยังคง
มีไฟล์บิลด์ แต่เนื้อหาของไฟล์บิลด์เหล่านั้นจะแตกต่างกันมาก ไฟล์ BUILD ใน Bazel เป็นไฟล์ประกาศที่อธิบายชุดอาร์ติแฟกต์ที่จะสร้าง การขึ้นต่อกัน และชุดตัวเลือกที่จำกัดซึ่งส่งผลต่อวิธีสร้างอาร์ติแฟกต์เหล่านั้น แทนที่จะเป็นชุดคำสั่งที่จำเป็นในภาษาการเขียนสคริปต์ที่สมบูรณ์แบบของทัวริงซึ่งอธิบายวิธีสร้างเอาต์พุต เมื่อวิศวกรเรียกใช้ bazel
ในบรรทัดคำสั่ง วิศวกรจะระบุชุดเป้าหมายที่จะสร้าง (อะไร) และ
Bazel จะมีหน้าที่กำหนดค่า เรียกใช้ และกำหนดเวลาขั้นตอนการคอมไพล์ (อย่างไร) เนื่องจากตอนนี้ระบบบิลด์ควบคุมเครื่องมือที่จะเรียกใช้ได้เต็มที่ ระบบจึงรับประกันได้ดียิ่งขึ้น ซึ่งช่วยให้มีประสิทธิภาพมากขึ้นมากในขณะที่ยังคงรับประกันความถูกต้อง
มุมมองด้านฟังก์ชัน
การเปรียบเทียบระหว่างระบบบิลด์ที่อิงตามอาร์ติแฟกต์กับการเขียนโปรแกรมเชิงฟังก์ชันนั้นทำได้ง่าย ภาษาโปรแกรมแบบคำสั่งดั้งเดิม (เช่น Java, C และ Python) จะระบุรายการคำสั่งที่จะดำเนินการทีละรายการในลักษณะเดียวกับที่ระบบบิลด์แบบงานช่วยให้นักโปรแกรมกำหนดชุดขั้นตอนที่จะดำเนินการได้ ในทางตรงกันข้าม ภาษาโปรแกรมเชิงฟังก์ชัน (เช่น Haskell และ ML) มีโครงสร้างคล้ายกับชุดสมการทางคณิตศาสตร์มากกว่า ในภาษาฟังก์ชัน โปรแกรมเมอร์จะอธิบายการคำนวณที่จะดำเนินการ แต่ ปล่อยให้คอมไพเลอร์เป็นผู้จัดการรายละเอียดของเวลาและวิธีการดำเนินการคำนวณนั้น อย่างแน่นอน
ซึ่งสอดคล้องกับแนวคิดในการประกาศไฟล์ Manifest ในระบบบิลด์ที่อิงตามอาร์ติแฟกต์ และปล่อยให้ระบบพิจารณาวิธีดำเนินการบิลด์ ปัญหาหลายอย่างไม่สามารถ แสดงออกได้อย่างง่ายดายโดยใช้การเขียนโปรแกรมเชิงฟังก์ชัน แต่ปัญหาที่ทำได้จะได้รับประโยชน์ อย่างมากจากภาษาดังกล่าว เนื่องจากภาษามักจะสามารถขนานโปรแกรมดังกล่าวได้อย่างง่ายดาย และรับประกันความถูกต้องของโปรแกรมได้อย่างมั่นใจ ซึ่งเป็นสิ่งที่ เป็นไปไม่ได้ในภาษาแบบคำสั่ง ปัญหาที่ง่ายที่สุดในการแสดงออกโดยใช้ การเขียนโปรแกรมเชิงฟังก์ชันคือปัญหาที่เกี่ยวข้องกับการเปลี่ยนข้อมูลหนึ่ง เป็นอีกข้อมูลหนึ่งโดยใช้ชุดกฎหรือฟังก์ชัน และนั่นคือสิ่งที่ระบบบิลด์เป็น ระบบทั้งหมดเป็นฟังก์ชันทางคณิตศาสตร์ที่รับไฟล์ต้นฉบับ (และเครื่องมือต่างๆ เช่น คอมไพเลอร์) เป็นอินพุตและสร้างไบนารีเป็นเอาต์พุต ดังนั้นจึงไม่น่าแปลกใจที่การสร้างระบบ บิลด์ตามหลักการของการเขียนโปรแกรมเชิงฟังก์ชันจึงได้ผลดี
ทำความเข้าใจระบบบิลด์ที่อิงตามอาร์ติแฟกต์
ระบบบิลด์ของ Google อย่าง Blaze เป็นระบบบิลด์ที่อิงตามอาร์ติแฟกต์ระบบแรก Bazel เป็นเวอร์ชันโอเพนซอร์สของ Blaze
ไฟล์บิลด์ (โดยปกติจะชื่อ BUILD) ใน Bazel มีลักษณะดังนี้
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 จะกําหนดเป้าหมาย ซึ่งเป้าหมาย 2 ประเภทที่นี่คือ
java_binary และ java_library เป้าหมายทุกรายการสอดคล้องกับอาร์ติแฟกต์ที่ระบบสร้างได้ โดยเป้าหมายไบนารีจะสร้างไบนารีที่เรียกใช้ได้โดยตรง และเป้าหมายไลบรารีจะสร้างไลบรารีที่ไบนารีหรือไลบรารีอื่นๆ ใช้ได้ ทุกเป้าหมายมีสิ่งต่อไปนี้
name: วิธีอ้างอิงเป้าหมายในบรรทัดคำสั่งและโดยเป้าหมายอื่นๆsrcs: ไฟล์ต้นฉบับที่จะคอมไพล์เพื่อสร้างอาร์ติแฟกต์สำหรับเป้าหมายdeps: เป้าหมายอื่นๆ ที่ต้องสร้างก่อนเป้าหมายนี้และลิงก์เข้าไป
การอ้างอิงอาจอยู่ในแพ็กเกจเดียวกัน (เช่น MyBinary อ้างอิง :mylib) หรืออยู่ในแพ็กเกจอื่นในลำดับชั้นของแหล่งที่มาเดียวกัน (เช่น mylib อ้างอิง //java/com/example/common)
เช่นเดียวกับระบบบิลด์ที่อิงตามงาน คุณจะทำการบิลด์โดยใช้เครื่องมือบรรทัดคำสั่งของ Bazel
หากต้องการสร้างMyBinaryเป้าหมาย ให้เรียกใช้ bazel build :MyBinary หลังจากป้อนคำสั่งดังกล่าวเป็นครั้งแรกในที่เก็บที่ล้างข้อมูลขยะแล้ว Bazel จะทำสิ่งต่อไปนี้
- แยกวิเคราะห์ไฟล์
BUILDทุกไฟล์ในพื้นที่ทำงานเพื่อสร้างกราฟการอ้างอิง ระหว่างอาร์ติแฟกต์ - ใช้กราฟเพื่อกำหนดทรัพยากร Dependency แบบทรานซิทีฟของ
MyBinaryซึ่งก็คือทุกเป้าหมายที่MyBinaryขึ้นอยู่กับ และทุกเป้าหมายที่เป้าหมายเหล่านั้นขึ้นอยู่กับแบบเรียกซ้ำ - สร้างการขึ้นต่อกันแต่ละรายการตามลำดับ Bazel เริ่มต้นด้วยการบิลด์แต่ละเป้าหมายที่ไม่มีการขึ้นต่อกันอื่นๆ และติดตามว่าการขึ้นต่อกันใดที่ยังต้องบิลด์สำหรับแต่ละเป้าหมาย ทันทีที่สร้างทรัพยากร Dependency ทั้งหมดของเป้าหมาย
Bazel จะเริ่มสร้างเป้าหมายนั้น กระบวนการนี้จะ
ดำเนินต่อไปจนกว่าจะสร้างการอ้างอิงแบบทรานซิทีฟทั้งหมดของ
MyBinary - สร้าง
MyBinaryเพื่อสร้างไบนารีที่ปฏิบัติการได้ขั้นสุดท้ายซึ่งลิงก์ใน การขึ้นทั้งหมดที่สร้างขึ้นในขั้นตอนที่ 3
โดยพื้นฐานแล้ว สิ่งที่เกิดขึ้นที่นี่อาจดูไม่แตกต่างจากสิ่งที่เกิดขึ้นเมื่อใช้ระบบบิลด์ตามงานมากนัก แน่นอนว่า ผลลัพธ์สุดท้ายคือไบนารีเดียวกัน และกระบวนการสร้างไบนารีนี้เกี่ยวข้องกับ การวิเคราะห์ขั้นตอนต่างๆ เพื่อค้นหาการขึ้นต่อกันระหว่างขั้นตอนเหล่านั้น แล้วจึงเรียกใช้ ขั้นตอนเหล่านั้นตามลำดับ แต่ก็มีความแตกต่างที่สำคัญ รายการแรกจะปรากฏในขั้นตอนที่ 3 เนื่องจาก Bazel รู้ว่าแต่ละเป้าหมายจะสร้างได้เฉพาะไลบรารี Java จึงรู้ว่าสิ่งที่ต้องทำคือเรียกใช้คอมไพเลอร์ Java แทนที่จะเป็นสคริปต์ที่ผู้ใช้กำหนดเองโดยพลการ จึงรู้ว่าการเรียกใช้ขั้นตอนเหล่านี้แบบขนานนั้นปลอดภัย ซึ่งจะช่วยปรับปรุงประสิทธิภาพได้มากเมื่อเทียบกับการสร้างเป้าหมายทีละรายการในเครื่องแบบมัลติคอร์ และทำได้ก็เพราะว่าแนวทางที่อิงตามอาร์ติแฟกต์จะทำให้ระบบบิลด์เป็นผู้รับผิดชอบกลยุทธ์การดำเนินการของตัวเอง เพื่อให้มั่นใจได้มากขึ้นเกี่ยวกับการทำงานแบบคู่ขนาน
แต่ประโยชน์ไม่ได้มีแค่การทำงานแบบคู่ขนาน สิ่งต่อไปที่แนวทางนี้มอบให้เราจะเห็นได้ชัดเมื่อนักพัฒนาซอฟต์แวร์พิมพ์คำสั่งเดิมbazel
build :MyBinaryเป็นครั้งที่ 2 โดยไม่มีการเปลี่ยนแปลงใดๆ ซึ่ง Bazel จะออกภายในเวลาไม่ถึง 1 วินาทีพร้อมข้อความที่ระบุว่าเป้าหมายเป็นเวอร์ชันล่าสุด ซึ่งเป็นไปได้เนื่องจากกระบวนทัศน์การเขียนโปรแกรมเชิงฟังก์ชันที่เราพูดถึงก่อนหน้านี้ Bazel รู้ว่าแต่ละเป้าหมายเป็นผลลัพธ์ของการเรียกใช้คอมไพเลอร์ Java เท่านั้น และรู้ว่าเอาต์พุตจากคอมไพเลอร์ Java ขึ้นอยู่กับอินพุตเท่านั้น ดังนั้นตราบใดที่อินพุตไม่เปลี่ยนแปลง ก็สามารถนำเอาต์พุตกลับมาใช้ซ้ำได้
และการวิเคราะห์นี้จะทำงานในทุกระดับ หาก MyBinary.java มีการเปลี่ยนแปลง Bazel จะทราบ
ว่าต้องสร้าง MyBinary ใหม่ แต่จะนำ mylib กลับมาใช้ซ้ำ หากไฟล์ต้นฉบับสำหรับ
//java/com/example/common มีการเปลี่ยนแปลง Bazel จะทราบว่าต้องสร้างไลบรารี mylib และ MyBinary ใหม่ แต่จะใช้ //java/com/example/myproduct/otherlib ซ้ำ
เนื่องจาก Bazel ทราบคุณสมบัติของเครื่องมือที่เรียกใช้ในทุกขั้นตอน
จึงสามารถสร้างอาร์ติแฟกต์ชุดขั้นต่ำใหม่ได้ทุกครั้ง
พร้อมรับประกันว่าจะไม่สร้างบิลด์ที่ล้าสมัย
การเปลี่ยนกรอบกระบวนการบิลด์ในแง่ของอาร์ติแฟกต์แทนที่จะเป็นงานนั้นเป็นเรื่องเล็กน้อย แต่มีประสิทธิภาพ การลดความยืดหยุ่นที่แสดงต่อโปรแกรมเมอร์จะช่วยให้ระบบบิลด์ทราบข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่ดำเนินการในทุกขั้นตอนของการบิลด์ โดยสามารถใช้ความรู้นี้เพื่อทำให้การบิลด์มีประสิทธิภาพมากขึ้นด้วยการบิลด์แบบขนาน และนำเอาต์พุตกลับมาใช้ซ้ำ แต่จริงๆ แล้วนี่เป็นเพียงขั้นตอนแรก และ องค์ประกอบพื้นฐานของการทำงานแบบคู่ขนานและการนำกลับมาใช้ใหม่เหล่านี้เป็นรากฐานของระบบบิลด์แบบกระจาย และปรับขนาดได้สูง
เคล็ดลับอื่นๆ ที่น่าสนใจของ Bazel
ระบบการสร้างที่อิงตามอาร์ติแฟกต์จะแก้ปัญหาเกี่ยวกับการทำงานแบบคู่ขนาน และการนำกลับมาใช้ใหม่ซึ่งมีอยู่ในระบบการสร้างที่อิงตามงานได้โดยพื้นฐาน แต่ก็ยังมี ปัญหาเล็กๆ น้อยๆ ที่เกิดขึ้นก่อนหน้านี้ซึ่งเรายังไม่ได้แก้ไข Bazel มีวิธีที่ชาญฉลาด ในการแก้ปัญหาแต่ละอย่างเหล่านี้ และเราควรพูดถึงเรื่องนี้ก่อนที่จะไปยังส่วนถัดไป
เครื่องมือเป็นทรัพยากร Dependency
ปัญหาหนึ่งที่เราพบก่อนหน้านี้คือบิลด์ขึ้นอยู่กับเครื่องมือที่ติดตั้งในเครื่องของเรา และการสร้างบิลด์ซ้ำในระบบต่างๆ อาจเป็นเรื่องยากเนื่องจากเครื่องมือมีเวอร์ชันหรือตำแหน่งที่แตกต่างกัน ปัญหายิ่งซับซ้อนมากขึ้น เมื่อโปรเจ็กต์ของคุณใช้ภาษาที่ต้องใช้เครื่องมือที่แตกต่างกันตามแพลตฟอร์มที่ใช้สร้างหรือคอมไพล์ (เช่น Windows กับ Linux) และแต่ละแพลตฟอร์มเหล่านั้นต้องใช้ชุดเครื่องมือที่แตกต่างกันเล็กน้อยเพื่อทำงานเดียวกัน
Bazel แก้ปัญหาในส่วนแรกนี้ด้วยการถือว่าเครื่องมือเป็นทรัพยากร Dependency ของแต่ละเป้าหมาย java_library ทุกรายการในพื้นที่ทำงานจะขึ้นอยู่กับคอมไพเลอร์ Java
โดยค่าเริ่มต้น ซึ่งเป็นคอมไพเลอร์ที่รู้จักกันดี เมื่อใดก็ตามที่ Bazel สร้าง
java_library จะตรวจสอบว่าคอมไพเลอร์ที่ระบุพร้อมใช้งาน
ในตำแหน่งที่รู้จัก เช่นเดียวกับ Dependency อื่นๆ หากคอมไพเลอร์ Java
มีการเปลี่ยนแปลง ระบบจะสร้างอาร์ติแฟกต์ทุกรายการที่ขึ้นอยู่กับคอมไพเลอร์นั้นใหม่
Bazel แก้ปัญหาในส่วนที่ 2 ซึ่งก็คือการไม่ขึ้นอยู่กับแพลตฟอร์มโดยการตั้งค่าการกำหนดค่าบิลด์ แทนที่จะ กำหนดเป้าหมายโดยตรงตามเครื่องมือ แต่จะกำหนดตามประเภทการกำหนดค่า
- การกำหนดค่าโฮสต์: สร้างเครื่องมือที่ทำงานระหว่างการสร้าง
- การกำหนดค่าเป้าหมาย: สร้างไบนารีที่คุณขอในท้ายที่สุด
การขยายระบบบิลด์
Bazel มีเป้าหมายสำหรับภาษาโปรแกรมยอดนิยมหลายภาษาตั้งแต่เริ่มต้น แต่วิศวกรจะต้องการทำสิ่งต่างๆ มากขึ้นเสมอ ข้อดีอย่างหนึ่งของระบบที่อิงตามงานคือความยืดหยุ่นในการรองรับกระบวนการบิลด์ทุกประเภท และเราไม่ควรละทิ้งข้อดีนี้ในระบบบิลด์ที่อิงตามอาร์ติแฟกต์ โชคดีที่ Bazel อนุญาตให้ขยายประเภทเป้าหมายที่รองรับได้โดยการเพิ่มกฎที่กำหนดเอง
หากต้องการกำหนดกฎใน Bazel ผู้เขียนกฎจะต้องประกาศอินพุตที่กฎต้องการ (ในรูปแบบของแอตทริบิวต์ที่ส่งในไฟล์ BUILD) และชุดเอาต์พุตคงที่ที่กฎสร้างขึ้น ผู้เขียนยังกำหนดการดำเนินการที่กฎนั้นจะสร้างด้วย แต่ละการดำเนินการจะประกาศอินพุตและเอาต์พุตของตัวเอง
เรียกใช้ไฟล์ที่เรียกใช้งานได้ที่เฉพาะเจาะจงหรือเขียนสตริงที่เฉพาะเจาะจงลงในไฟล์ และสามารถ
เชื่อมต่อกับการดำเนินการอื่นๆ ผ่านอินพุตและเอาต์พุต ซึ่งหมายความว่าการดำเนินการ
คือหน่วยที่ประกอบได้ระดับต่ำสุดในระบบบิลด์ โดยการดำเนินการสามารถทำ
อะไรก็ได้ตราบใดที่ใช้เฉพาะอินพุตและเอาต์พุตที่ประกาศไว้ และ
Bazel จะดูแลการจัดกำหนดเวลาการดำเนินการและแคชผลลัพธ์ตามความเหมาะสม
ระบบไม่ได้ป้องกันข้อผิดพลาดได้ทั้งหมด เนื่องจากไม่มีวิธีหยุดไม่ให้นักพัฒนาแอป ดำเนินการบางอย่าง เช่น การนำกระบวนการที่ไม่แน่นอนมาใช้เป็นส่วนหนึ่งของ การดำเนินการ แต่ในทางปฏิบัติแล้วเหตุการณ์นี้ไม่ค่อยเกิดขึ้น และการผลักดัน ความเป็นไปได้ในการละเมิดไปจนถึงระดับการดำเนินการจะช่วยลด โอกาสที่จะเกิดข้อผิดพลาดลงอย่างมาก กฎที่รองรับภาษาและเครื่องมือที่ใช้กันทั่วไปหลายอย่างมี ให้ใช้งานอย่างแพร่หลายทางออนไลน์ และโปรเจ็กต์ส่วนใหญ่ไม่จำเป็นต้องกำหนดกฎของตัวเอง แม้แต่สำหรับกฎที่ต้องใช้คำจำกัดความ ก็จำเป็นต้องกำหนดไว้ในที่เดียวในที่เก็บ ซึ่งหมายความว่าวิศวกรส่วนใหญ่จะใช้กฎเหล่านั้นได้โดยไม่ต้องกังวลเกี่ยวกับการใช้งาน
การแยกสภาพแวดล้อม
การดำเนินการดูเหมือนอาจพบปัญหาเดียวกันกับงานในระบบอื่นๆ คุณยังคงเขียนการดำเนินการที่ทั้งเขียนไปยังไฟล์เดียวกันและขัดแย้งกันได้ใช่ไหม อันที่จริง Bazel ป้องกันไม่ให้เกิดความขัดแย้งเหล่านี้ได้โดยใช้แซนด์บ็อกซ์ ในระบบที่รองรับ การดำเนินการทุกอย่างจะแยกจากการดำเนินการอื่นๆ ทั้งหมดผ่านแซนด์บ็อกซ์ของระบบไฟล์ กล่าวคือ แต่ละการดำเนินการจะเห็นเฉพาะมุมมองที่จำกัดของ ระบบไฟล์ซึ่งรวมถึงอินพุตที่ประกาศไว้และเอาต์พุตที่สร้างขึ้น ซึ่งบังคับใช้โดยระบบต่างๆ เช่น LXC ใน Linux ซึ่งเป็นเทคโนโลยีเดียวกับที่อยู่เบื้องหลัง Docker ซึ่งหมายความว่าการดำเนินการจะขัดแย้งกันไม่ได้เนื่องจากอ่านไฟล์ที่ไม่ได้ประกาศไม่ได้ และระบบจะทิ้งไฟล์ที่เขียนแต่ไม่ได้ประกาศเมื่อการดำเนินการเสร็จสิ้น นอกจากนี้ Bazel ยังใช้แซนด์บ็อกซ์เพื่อจำกัดการสื่อสารผ่านเครือข่ายของ Actions ด้วย
การทำให้ทรัพยากร Dependency ภายนอกเป็นแบบดีเทอร์มินิสติก
แต่ก็ยังมีปัญหาหนึ่งที่ยังคงอยู่ นั่นคือ ระบบบิลด์มักจะต้องดาวน์โหลด
การขึ้นต่อกัน (ไม่ว่าจะเป็นเครื่องมือหรือไลบรารี) จากแหล่งที่มาภายนอกแทนที่จะ
สร้างโดยตรง คุณดูตัวอย่างได้ผ่าน@com_google_common_guava_guava//jar dependency ซึ่งจะดาวน์โหลดไฟล์ JAR จาก Maven
การอ้างอิงไฟล์ที่อยู่นอกพื้นที่ทำงานปัจจุบันมีความเสี่ยง ไฟล์เหล่านั้นอาจมีการเปลี่ยนแปลงได้ทุกเมื่อ ซึ่งอาจทำให้ระบบบิลด์ต้องตรวจสอบอยู่ตลอดเวลาว่าไฟล์เป็นเวอร์ชันล่าสุดหรือไม่ หากไฟล์ระยะไกลมีการเปลี่ยนแปลงโดยไม่มีการเปลี่ยนแปลงที่สอดคล้องกัน ในซอร์สโค้ดของพื้นที่ทำงาน ก็อาจทำให้สร้างบิลด์ซ้ำไม่ได้เช่นกัน ซึ่งหมายความว่าบิลด์ อาจทำงานได้ในวันหนึ่งและล้มเหลวในวันถัดไปโดยไม่มีเหตุผลที่ชัดเจนเนื่องจากการเปลี่ยนแปลงการอ้างอิงที่ไม่ได้สังเกตเห็น สุดท้ายนี้ การพึ่งพาภายนอกอาจทำให้เกิดความเสี่ยงด้านความปลอดภัยอย่างมากเมื่อเป็นของบุคคลที่สาม หากผู้โจมตีสามารถแทรกซึมเซิร์ฟเวอร์ของบุคคลที่สามนั้นได้ ก็จะสามารถแทนที่ไฟล์การพึ่งพาด้วยสิ่งที่ออกแบบเอง ซึ่งอาจทำให้ผู้โจมตีควบคุมสภาพแวดล้อมการสร้างและเอาต์พุตได้อย่างเต็มที่
ปัญหาพื้นฐานคือเราต้องการให้ระบบบิลด์รับรู้ไฟล์เหล่านี้ โดยไม่ต้องเช็คอินไฟล์เหล่านั้นลงในระบบควบคุมแหล่งที่มา การอัปเดตการขึ้นต่อกัน ควรเป็นการเลือกที่ตั้งใจ แต่การเลือกนั้นควรทำเพียงครั้งเดียวในที่ส่วนกลาง แทนที่จะให้วิศวกรแต่ละคนจัดการหรือให้ระบบจัดการโดยอัตโนมัติ เนื่องจากแม้จะใช้โมเดล "Live at Head" เราก็ยังต้องการให้บิลด์ เป็นแบบดีเทอร์มินิสติก ซึ่งหมายความว่าหากคุณเช็คเอาต์คอมมิตจากสัปดาห์ที่แล้ว คุณควรเห็นการขึ้นต่อกันตามที่เคยเป็น ไม่ใช่ตามที่ เป็นอยู่ในปัจจุบัน
Bazel และระบบบิลด์อื่นๆ บางระบบแก้ปัญหานี้ด้วยการกำหนดให้มีไฟล์ Manifest ระดับพื้นที่ทำงานที่แสดงรายการแฮชการเข้ารหัสสำหรับทรัพยากร Dependency ภายนอกทุกรายการในพื้นที่ทำงาน แฮชเป็นวิธีที่กระชับในการแสดงไฟล์อย่างไม่ซ้ำกันโดยไม่ต้องเช็คอินไฟล์ทั้งหมดลงในการควบคุมแหล่งที่มา เมื่อใดก็ตามที่มีการอ้างอิงการขึ้นต่อภายนอกใหม่จากพื้นที่ทำงาน ระบบจะเพิ่มแฮชของการขึ้นต่อดังกล่าวลงในไฟล์ Manifest ไม่ว่าจะด้วยตนเองหรือโดยอัตโนมัติ เมื่อ Bazel เรียกใช้บิลด์ ระบบจะตรวจสอบแฮชจริงของทรัพยากร Dependency ที่แคชไว้กับแฮชที่คาดไว้ซึ่งกำหนดไว้ใน Manifest และจะดาวน์โหลดไฟล์อีกครั้งก็ต่อเมื่อแฮชแตกต่างกัน
หากอาร์ติแฟกต์ที่เราดาวน์โหลดมีแฮชแตกต่างจากที่ประกาศไว้ใน ไฟล์ Manifest บิลด์จะล้มเหลว เว้นแต่จะมีการอัปเดตแฮชในไฟล์ Manifest ซึ่งสามารถทำได้โดยอัตโนมัติ แต่การเปลี่ยนแปลงดังกล่าวต้องได้รับการอนุมัติและตรวจสอบใน การควบคุมแหล่งที่มาก่อนที่บิลด์จะยอมรับการอ้างอิงใหม่ ซึ่งหมายความว่า ระบบจะบันทึกเวลาที่อัปเดตการอ้างอิงไว้เสมอ และการอ้างอิงภายนอก จะเปลี่ยนแปลงไม่ได้หากไม่มีการเปลี่ยนแปลงที่สอดคล้องกันในแหล่งที่มาของพื้นที่ทำงาน นอกจากนี้ยังหมายความว่าเมื่อตรวจสอบซอร์สโค้ดเวอร์ชันเก่ากว่า การสร้างจะรับประกันได้ว่าจะใช้การขึ้นต่อกันเดียวกันกับที่ใช้ ณ จุด ที่เวอร์ชันนั้นได้รับการเช็คอิน (หรือจะล้มเหลวหากการขึ้นต่อกันเหล่านั้น ไม่พร้อมใช้งานอีกต่อไป)
แน่นอนว่าปัญหานี้อาจเกิดขึ้นได้หากเซิร์ฟเวอร์ระยะไกลไม่พร้อมใช้งานหรือ เริ่มแสดงข้อมูลที่เสียหาย ซึ่งอาจทำให้บิลด์ทั้งหมดล้มเหลว หากคุณไม่มีสำเนาของทรัพยากร Dependency นั้น เราขอแนะนำให้คุณทำมิเรอร์การอ้างอิงทั้งหมดของโปรเจ็กต์ที่สำคัญไปยังเซิร์ฟเวอร์หรือบริการที่คุณเชื่อถือและควบคุมได้ เพื่อหลีกเลี่ยงปัญหานี้ ไม่เช่นนั้น คุณจะต้องพึ่งพาบุคคลที่สามเสมอในเรื่องความพร้อมใช้งานของระบบบิลด์ แม้ว่าแฮชที่เช็คอินจะรับประกันความปลอดภัยก็ตาม