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