ระบบบิลด์ที่อิงตามอาร์ติแฟกต์

หน้านี้ครอบคลุมระบบการสร้างที่อิงตามอาร์ติแฟกต์และแนวคิดเบื้องหลังการสร้างระบบดังกล่าว Bazel เป็นระบบการสร้างที่อิงตามอาร์ติแฟกต์ แม้ว่าระบบการสร้างที่อิงตามงานจะดีกว่าสคริปต์การสร้าง แต่ก็ให้อำนาจมากเกินไปแก่วิศวกรแต่ละคนโดยอนุญาตให้กำหนดงานของตนเองได้

ระบบการสร้างที่อิงตามอาร์ติแฟกต์มีงานจำนวนเล็กน้อยที่ระบบกำหนดไว้ ซึ่งวิศวกรสามารถกำหนดค่าได้ในขอบเขตที่จำกัด วิศวกรยังคงบอกระบบว่าจะ สร้างอะไร แต่ระบบการสร้างจะเป็นตัวกำหนดวิธี สร้าง ระบบการสร้างที่อิงตามอาร์ติแฟกต์ เช่น Bazel ยังคงมีไฟล์การสร้างเช่นเดียวกับระบบการสร้างที่อิงตามงาน แต่เนื้อหาของไฟล์การสร้างเหล่านั้นแตกต่างกันมาก ไฟล์การสร้างใน Bazel ไม่ใช่ชุดคำสั่งที่จำเป็นในภาษาการเขียนสคริปต์ที่สมบูรณ์แบบของ Turing ซึ่งอธิบายวิธีสร้างเอาต์พุต แต่เป็นไฟล์ Manifest ที่ประกาศไว้ซึ่งอธิบายชุดอาร์ติแฟกต์ที่จะสร้าง ทรัพยากร Dependency ของอาร์ติแฟกต์ และชุดตัวเลือกที่จำกัดซึ่งส่งผลต่อวิธีสร้างอาร์ติแฟกต์ เมื่อวิศวกรเรียกใช้ bazel ในบรรทัดคำสั่ง วิศวกรจะระบุชุดเป้าหมายที่จะสร้าง (อะไร) และ Bazel จะเป็นผู้รับผิดชอบในการกำหนดค่า เรียกใช้ และกำหนดเวลาขั้นตอนการคอมไพล์ (อย่างไร) เนื่องจากตอนนี้ระบบการสร้างควบคุมเครื่องมือที่จะเรียกใช้เมื่อใดได้อย่างสมบูรณ์ จึงสามารถรับประกันได้มากขึ้น ซึ่งช่วยให้มีประสิทธิภาพมากขึ้นมากในขณะที่ยังคงรับประกันความถูกต้อง

มุมมองเชิงฟังก์ชัน

การเปรียบเทียบระหว่างระบบการสร้างที่อิงตามอาร์ติแฟกต์กับการเขียนโปรแกรมเชิงฟังก์ชันทำได้ง่าย ภาษาโปรแกรมที่จำเป็นแบบดั้งเดิม (เช่น Java, C และ Python) จะระบุรายการคำสั่งที่จะดำเนินการทีละรายการ เช่นเดียวกับที่ระบบการสร้างที่อิงตามงานอนุญาตให้นักโปรแกรมกำหนดชุดขั้นตอนที่จะดำเนินการ ในทางตรงกันข้าม ภาษาโปรแกรมเชิงฟังก์ชัน (เช่น Haskell และ ML) มีโครงสร้างคล้ายกับชุดสมการทางคณิตศาสตร์ ในภาษาเชิงฟังก์ชัน นักโปรแกรมจะอธิบายการคำนวณที่จะดำเนินการ แต่จะปล่อยให้คอมไพเลอร์จัดการรายละเอียดเกี่ยวกับเวลาและวิธีดำเนินการคำนวณนั้นๆ

ซึ่งสอดคล้องกับแนวคิดในการประกาศไฟล์ Manifest ในระบบการสร้างที่อิงตามอาร์ติแฟกต์และปล่อยให้ระบบคิดหาวิธีดำเนินการสร้าง ปัญหาหลายอย่างไม่สามารถแสดงออกได้อย่างง่ายดายโดยใช้การเขียนโปรแกรมเชิงฟังก์ชัน แต่ปัญหาที่ทำได้จะได้รับประโยชน์อย่างมากจากภาษาดังกล่าว โดยภาษามักจะสามารถขนานโปรแกรมดังกล่าวได้อย่างง่ายดายและรับประกันความถูกต้องของโปรแกรมได้อย่างมาก ซึ่งเป็นสิ่งที่ภาษาที่จำเป็นทำไม่ได้ ปัญหาที่แสดงออกได้ง่ายที่สุดโดยใช้การเขียนโปรแกรมเชิงฟังก์ชันคือปัญหาที่เกี่ยวข้องกับการแปลงข้อมูลหนึ่งชิ้นเป็นอีกชิ้นหนึ่งโดยใช้ชุดกฎหรือฟังก์ชัน และนั่นคือสิ่งที่ระบบการสร้างทำอย่างแท้จริง โดยทั้งระบบเป็นฟังก์ชันทางคณิตศาสตร์ที่รับไฟล์ต้นฉบับ (และเครื่องมือต่างๆ เช่น คอมไพเลอร์) เป็นอินพุตและสร้างไบนารีเป็นเอาต์พุต ดังนั้นจึงไม่น่าแปลกใจที่การสร้างระบบการสร้างโดยอิงตามหลักการของการเขียนโปรแกรมเชิงฟังก์ชันจึงได้ผลดี

ทำความเข้าใจระบบการสร้างที่อิงตามอาร์ติแฟกต์

Blaze ซึ่งเป็นระบบการสร้างของ Google เป็นระบบการสร้างที่อิงตามอาร์ติแฟกต์ระบบแรก 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) หรืออยู่ในแพ็กเกจอื่นในลำดับชั้นของแหล่งที่มาเดียวกัน (เช่น ทรัพยากร Dependency ของ mylib ใน //java/com/example/common)

เช่นเดียวกับระบบการสร้างที่อิงตามงาน คุณจะทำการสร้างโดยใช้เครื่องมือบรรทัดคำสั่งของ Bazel หากต้องการสร้างเป้าหมาย MyBinary ให้เรียกใช้ bazel build :MyBinary หลังจากป้อนคำสั่งดังกล่าวเป็นครั้งแรกในที่เก็บที่สะอาด Bazel จะดำเนินการต่อไปนี้

  1. แยกวิเคราะห์ไฟล์ BUILD ทุกไฟล์ในพื้นที่ทำงานเพื่อสร้างกราฟทรัพยากร Dependency ระหว่างอาร์ติแฟกต์
  2. ใช้กราฟเพื่อกำหนดทรัพยากร Dependency แบบถ่ายทอดของ MyBinary ซึ่งหมายถึงเป้าหมายทุกรายการที่ MyBinary ขึ้นอยู่กับ และเป้าหมายทุกรายการที่เป้าหมายเหล่านั้นขึ้นอยู่กับแบบเรียกซ้ำ
  3. สร้างทรัพยากร Dependency แต่ละรายการตามลำดับ Bazel จะเริ่มต้นด้วยการสร้างเป้าหมายแต่ละรายการที่ไม่มีทรัพยากร Dependency อื่นๆ และติดตามทรัพยากร Dependency ที่ยังต้องสร้างสำหรับเป้าหมายแต่ละรายการ เมื่อสร้างทรัพยากร Dependency ทั้งหมดของเป้าหมายแล้ว Bazel จะเริ่มสร้างเป้าหมายนั้น กระบวนการนี้จะดำเนินต่อไปจนกว่าจะสร้างทรัพยากร Dependency แบบถ่ายทอดทั้งหมดของ MyBinary แล้ว
  4. สร้าง 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 ทั้งหมดลงในเซิร์ฟเวอร์หรือบริการที่คุณเชื่อถือและควบคุมได้สำหรับโปรเจ็กต์ที่ไม่เล็กจนเกินไป เพื่อหลีกเลี่ยงปัญหานี้ มิฉะนั้นคุณจะต้องพึ่งพาบุคคลที่สามเสมอในเรื่องความพร้อมใช้งานของระบบการสร้าง แม้ว่าแฮชที่เช็กอินจะรับประกันความปลอดภัยของระบบการสร้างก็ตาม