หน้านี้ครอบคลุมระบบบิลด์ที่อิงตามอาร์ติแฟกต์และแนวคิดเบื้องหลังการสร้างระบบดังกล่าว Bazel เป็นระบบบิลด์ที่อิงตามอาร์ติแฟกต์ แม้ว่าระบบบิลด์ที่อิงตามงานจะเป็นขั้นตอนที่ดีกว่าสคริปต์บิลด์ แต่ระบบดังกล่าวก็ให้อำนาจมากเกินไปแก่วิศวกรแต่ละคนโดยอนุญาตให้กำหนดงานของตนเองได้
ระบบบิลด์ที่อิงตามอาร์ติแฟกต์มีงานจำนวนเล็กน้อยที่ระบบกำหนดไว้ ซึ่งวิศวกรสามารถกำหนดค่าได้ในขอบเขตที่จำกัด วิศวกรยังคงบอกระบบว่าจะ สร้างอะไร แต่ระบบบิลด์จะเป็นตัวกำหนดวิธี สร้าง เช่นเดียวกับระบบบิลด์ที่อิงตามงาน ระบบบิลด์ที่อิงตามอาร์ติแฟกต์ เช่น Bazel ยังคงมีไฟล์บิลด์ แต่เนื้อหาของไฟล์บิลด์เหล่านั้นจะแตกต่างกันมาก ไฟล์บิลด์ใน Bazel ไม่ใช่ชุดคำสั่งที่จำเป็นในภาษาการเขียนสคริปต์ที่สมบูรณ์แบบของ Turing ซึ่งอธิบายวิธีสร้างเอาต์พุต แต่เป็นไฟล์ Manifest ที่ประกาศไว้ซึ่งอธิบายชุดอาร์ติแฟกต์ที่จะสร้าง ทรัพยากร Dependency ของอาร์ติแฟกต์ และชุดตัวเลือกที่จำกัดซึ่งส่งผลต่อวิธีสร้างอาร์ติแฟกต์ เมื่อวิศวกรเรียกใช้ 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: เป้าหมายอื่นๆ ที่ต้องสร้างก่อนเป้าหมายนี้และลิงก์กับเป้าหมายนี้
ทรัพยากร Dependency อาจอยู่ในแพ็กเกจเดียวกัน (เช่น MyBinary's
ทรัพยากร Dependency ใน :mylib) หรืออยู่ในแพ็กเกจอื่นในลำดับชั้นต้นฉบับเดียวกัน
(เช่น mylib's ทรัพยากร Dependency ใน //java/com/example/common)
เช่นเดียวกับระบบบิลด์ที่อิงตามงาน คุณจะดำเนินการบิลด์โดยใช้เครื่องมือบรรทัดคำสั่งของ Bazel หากต้องการสร้างเป้าหมาย MyBinary ให้เรียกใช้ bazel build :MyBinary หลังจากป้อนคำสั่งดังกล่าวเป็นครั้งแรกในที่เก็บข้อมูลที่สะอาด Bazel จะดำเนินการต่อไปนี้
- แยกวิเคราะห์ไฟล์
BUILDทุกไฟล์ในพื้นที่ทำงานเพื่อสร้างกราฟทรัพยากร Dependency ระหว่างอาร์ติแฟกต์ - ใช้กราฟเพื่อกำหนดทรัพยากร Dependency แบบถ่ายทอดของ
MyBinaryซึ่งหมายถึงเป้าหมายทุกรายการที่MyBinaryขึ้นอยู่กับและเป้าหมายทุกรายการที่เป้าหมายเหล่านั้นขึ้นอยู่กับแบบเรียกซ้ำ - สร้างทรัพยากร Dependency แต่ละรายการตามลำดับ Bazel จะเริ่มต้นด้วยการสร้างเป้าหมายแต่ละรายการที่ไม่มีทรัพยากร Dependency อื่นๆ และติดตามทรัพยากร Dependency ที่ยังต้องสร้างสำหรับเป้าหมายแต่ละรายการ เมื่อสร้างทรัพยากร Dependency ทั้งหมดของเป้าหมายแล้ว Bazel จะเริ่มสร้างเป้าหมายนั้น กระบวนการนี้จะดำเนินต่อไปจนกว่าจะสร้างทรัพยากร Dependency แบบถ่ายทอดทั้งหมดของ
MyBinaryแล้ว - สร้าง
MyBinaryเพื่อสร้างไบนารีที่เรียกใช้ได้สุดท้ายซึ่งลิงก์กับทรัพยากร Dependency ทั้งหมดที่สร้างในขั้นตอนที่ 3
โดยพื้นฐานแล้ว สิ่งที่เกิดขึ้นที่นี่อาจดูไม่แตกต่างจากสิ่งที่เกิดขึ้นเมื่อใช้ระบบบิลด์ที่อิงตามงานมากนัก แน่นอนว่าผลลัพธ์สุดท้ายคือไบนารีเดียวกัน และกระบวนการสร้างไบนารีเกี่ยวข้องกับการวิเคราะห์ขั้นตอนต่างๆ เพื่อค้นหาทรัพยากร Dependency ระหว่างขั้นตอนเหล่านั้น แล้วเรียกใช้ขั้นตอนเหล่านั้นตามลำดับ แต่ก็มีความแตกต่างที่สำคัญ ความแตกต่างแรกปรากฏในขั้นตอนที่ 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 ยังใช้แซนด์บ็อกซ์เพื่อจำกัดการดำเนินการจากการสื่อสารผ่านเครือข่าย
การทำให้ทรัพยากร Dependency ภายนอกเป็นแบบกำหนดได้
ยังคงมีปัญหาหนึ่งที่เหลืออยู่ นั่นคือระบบบิลด์มักต้องดาวน์โหลดทรัพยากร Dependency (ไม่ว่าจะเป็นเครื่องมือหรือไลบรารี) จากแหล่งที่มาภายนอกแทนที่จะสร้างทรัพยากร Dependency เหล่านั้นโดยตรง คุณจะเห็นปัญหานี้ในตัวอย่างผ่านทรัพยากร Dependency @com_google_common_guava_guava//jar ซึ่งดาวน์โหลดไฟล์ JAR จาก Maven
การขึ้นอยู่กับไฟล์นอกพื้นที่ทำงานปัจจุบันมีความเสี่ยง ไฟล์เหล่านั้นอาจเปลี่ยนแปลงได้ทุกเมื่อ ซึ่งอาจทำให้ระบบบิลด์ต้องตรวจสอบอยู่เสมอว่าไฟล์เป็นเวอร์ชันล่าสุดหรือไม่ หากไฟล์ระยะไกลเปลี่ยนแปลงโดยไม่มีการเปลี่ยนแปลงที่สอดคล้องกันในซอร์สโค้ดพื้นที่ทำงาน ก็อาจทำให้บิลด์สร้างซ้ำไม่ได้ด้วย โดยบิลด์อาจทำงานได้ในวันหนึ่งและล้มเหลวในวันถัดไปโดยไม่มีเหตุผลที่ชัดเจนเนื่องจากการเปลี่ยนแปลงทรัพยากร Dependency ที่ไม่สังเกตเห็น สุดท้าย ทรัพยากร Dependency ภายนอกอาจก่อให้เกิดความเสี่ยงด้านความปลอดภัยอย่างมากเมื่อเป็นของบุคคลที่สาม หากผู้โจมตีสามารถแทรกซึมเข้าไปในเซิร์ฟเวอร์ของบุคคลที่สามได้ ผู้โจมตีจะสามารถแทนที่ไฟล์ทรัพยากร Dependency ด้วยไฟล์ที่ออกแบบเอง ซึ่งอาจทำให้ผู้โจมตีควบคุมสภาพแวดล้อมบิลด์และเอาต์พุตได้อย่างสมบูรณ์
ปัญหาพื้นฐานคือเราต้องการให้ระบบบิลด์รับทราบไฟล์เหล่านี้โดยไม่ต้องตรวจสอบไฟล์เหล่านั้นในการควบคุมซอร์สโค้ด การอัปเดตทรัพยากร Dependency ควรเป็นการตัดสินใจที่ตั้งใจ แต่การตัดสินใจนั้นควรทำเพียงครั้งเดียวในที่ส่วนกลางแทนที่จะให้วิศวกรแต่ละคนจัดการหรือให้ระบบจัดการโดยอัตโนมัติ เนื่องจากแม้จะมีโมเดล "Live at Head" เราก็ยังต้องการให้บิลด์เป็นแบบกำหนดได้ ซึ่งหมายความว่าหากคุณตรวจสอบคอมมิตจากสัปดาห์ที่แล้ว คุณควรเห็นทรัพยากร Dependency ของคุณเป็นเวอร์ชันที่ใช้ในตอนนั้น ไม่ใช่เวอร์ชันปัจจุบัน
Bazel และระบบบิลด์อื่นๆ แก้ปัญหานี้โดยกำหนดให้มีไฟล์ Manifest ทั่วทั้งพื้นที่ทำงานซึ่งแสดงรายการ แฮชแบบเข้ารหัสสำหรับทรัพยากร Dependency ภายนอกทุกรายการในพื้นที่ทำงาน แฮชเป็นวิธีที่กระชับในการแสดงไฟล์ที่ไม่ซ้ำกันโดยไม่ต้องตรวจสอบไฟล์ทั้งหมดในการควบคุมซอร์สโค้ด เมื่อมีการอ้างอิงทรัพยากร Dependency ภายนอกใหม่จากพื้นที่ทำงาน ระบบจะเพิ่มแฮชของทรัพยากร Dependency นั้นลงในไฟล์ Manifest ไม่ว่าจะด้วยตนเองหรือโดยอัตโนมัติ เมื่อ Bazel เรียกใช้บิลด์ ระบบจะตรวจสอบแฮชจริงของทรัพยากร Dependency ที่แคชไว้กับแฮชที่คาดไว้ซึ่งกำหนดไว้ในไฟล์ Manifest และดาวน์โหลดไฟล์อีกครั้งเฉพาะในกรณีที่แฮชแตกต่างกัน
หากอาร์ติแฟกต์ที่เราดาวน์โหลดมีแฮชแตกต่างจากแฮชที่ประกาศไว้ในไฟล์ Manifest บิลด์จะล้มเหลว เว้นแต่จะมีการอัปเดตแฮชในไฟล์ Manifest การดำเนินการนี้สามารถทำได้โดยอัตโนมัติ แต่ต้องมีการอนุมัติการเปลี่ยนแปลงและตรวจสอบในการควบคุมซอร์สโค้ดก่อนที่บิลด์จะยอมรับทรัพยากร Dependency ใหม่ ซึ่งหมายความว่าระบบจะบันทึกไว้เสมอว่ามีการอัปเดตทรัพยากร Dependency เมื่อใด และทรัพยากร Dependency ภายนอกจะเปลี่ยนแปลงไม่ได้หากไม่มีการเปลี่ยนแปลงที่สอดคล้องกันในซอร์สโค้ดพื้นที่ทำงาน นอกจากนี้ยังหมายความว่าเมื่อตรวจสอบซอร์สโค้ดเวอร์ชันเก่า บิลด์จะรับประกันว่าจะใช้ทรัพยากร Dependency เดียวกับที่ใช้ในตอนที่ตรวจสอบเวอร์ชันนั้น (หรือระบบจะล้มเหลวหากทรัพยากร Dependency เหล่านั้นไม่พร้อมใช้งานอีกต่อไป)
แน่นอนว่าอาจยังคงเป็นปัญหาได้หากเซิร์ฟเวอร์ระยะไกลไม่พร้อมใช้งานหรือเริ่มแสดงข้อมูลที่เสียหาย ซึ่งอาจทำให้บิลด์ทั้งหมดเริ่มล้มเหลวหากคุณไม่มีสำเนาทรัพยากร Dependency นั้นอีก เราขอแนะนำให้คุณทำมิเรอร์ทรัพยากร Dependency ทั้งหมดของโปรเจ็กต์ที่ไม่เล็กนักไปยังเซิร์ฟเวอร์หรือบริการที่คุณเชื่อถือและควบคุมได้ เพื่อหลีกเลี่ยงปัญหานี้ มิฉะนั้นคุณจะต้องพึ่งพาบุคคลที่สามเสมอในเรื่องความพร้อมใช้งานของระบบบิลด์ แม้ว่าแฮชที่ตรวจสอบแล้วจะรับประกันความปลอดภัยของระบบบิลด์ก็ตาม