1 คะแนน โดย GN⁺ 5 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • Zig ปรับโครงสร้างให้ ตรรกะการจัดการแพ็กเกจ ย้ายไปอยู่ในโปรเซส maker ภายนอกตัวคอมไพเลอร์ ให้สอดคล้องกับแนวทางที่แยก build.zig และระบบบิลด์ออกเป็นคนละโปรเซส
  • คำสั่ง zig build, zig fetch, zig init, zig libc ถูกย้ายไปฝั่ง maker ทำให้โค้ดสำหรับ HTTP, TLS, Git, การบีบอัด และการจัดการ build.zig.zon ถูกแจกจ่ายในรูปแบบ ซอร์สโค้ด
  • โครงสร้างนี้ทำให้สามารถแก้ไขความสามารถด้านการจัดการแพ็กเกจได้โดยไม่ต้องคอมไพล์คอมไพเลอร์ใหม่ และ maker ถูกคอมไพล์ด้วย ReleaseSafe จึงเปิดใช้ การตรวจสอบความปลอดภัย สำหรับงานเครือข่ายด้วย
  • จุดประสงค์ดั้งเดิมคือการเปิดเผย build server protocol เพื่อแก้ปัญหาการเปลี่ยนแปลง --build-runner ที่ขัดขวาง ZLS และใน process tree แบบใหม่ maker จะยังคงเป็น parent ของ configurer ทำให้จัดการการรันคอนฟิกซ้ำได้เสถียรกว่าเดิม
  • แม้ผลกระทบต่อผู้ใช้จะไม่มาก แต่ไฟล์รันไทม์ของ Zig มีขนาดลดลง 4% จาก 14.1MiB เหลือ 13.5MiB และ --maker-opt กับ --zig-lib-dir ถูกแทนที่ด้วยตัวแปรสภาพแวดล้อม ZIG_DEBUG_MAKER และ ZIG_LIB_DIR ตามลำดับ

การย้ายตรรกะการจัดการแพ็กเกจ

  • หลังจากที่ Zig แยกสคริปต์ build.zig ของผู้ใช้กับตัวระบบบิลด์ออกเป็นคนละโปรเซสแล้ว ก็ปรับโครงสร้างให้ ตรรกะการจัดการแพ็กเกจ อยู่ฝั่งระบบบิลด์ด้วย
  • คำสั่งย่อยที่ถูกย้ายไปยังโปรเซส maker มีดังนี้
    • zig build
    • zig fetch
    • zig init
    • zig libc

โค้ดที่ถูกถอดออกจากไฟล์รันไทม์ของคอมไพเลอร์

  • พื้นที่โค้ดขนาดใหญ่ที่ก่อนหน้านี้อยู่ภายในไฟล์รันไทม์ของคอมไพเลอร์ ตอนนี้ถูกแจกจ่ายในรูปแบบ ซอร์สโค้ด
    • ตรรกะการดึงแพ็กเกจ
    • HTTP client และระบบเครือข่าย
    • TLS และการเข้ารหัสที่เกี่ยวข้อง
    • Git protocol
    • xz, gzip, zstd, flate, zip
    • การพาร์ส การตรวจสอบความถูกต้อง และการประมวลผลอื่นๆ ของไฟล์ build.zig.zon
  • ความสามารถเหล่านี้สามารถแพตช์ได้โดยไม่ต้องบิลด์คอมไพเลอร์ใหม่ ทำให้ผู้ใช้และผู้มีส่วนร่วมทดลองได้ง่ายขึ้น
  • ไฟล์รันไทม์ maker ถูกคอมไพล์ในโหมด ReleaseSafe จึงเปิด การตรวจสอบความปลอดภัย สำหรับงานเครือข่ายของระบบจัดการแพ็กเกจ
  • โค้ดเข้ารหัสที่ใช้กับเครือข่ายและการแฮชไฟล์สามารถใช้ คำสั่ง CPU แบบพิเศษ ที่มีอยู่บนเครื่องโฮสต์ได้

โครงสร้างโปรเซสและ build server

  • แรงจูงใจดั้งเดิมคือการเปิดเผย build server protocol เพื่อแก้ปัญหาที่ขัดขวาง ZLS
  • ในโครงสร้างเดิม zig build รับหน้าที่ทั้งคอมไพเลอร์และตัวจัดการแพ็กเกจ ส่วน builder ที่อยู่ด้านล่างบรรจุตรรกะ build.zig ของผู้ใช้และการทำงานของระบบบิลด์
  • หลังการแยก maker/configurer โครงสร้างจะเป็นดังนี้
    • zig build: คอมไพเลอร์ + ตัวจัดการแพ็กเกจ
    • configurer: ตรรกะ build.zig ของผู้ใช้
    • maker: ระบบบิลด์
  • ในโครงสร้างนี้ zig build --watch ที่ทำงานต่อเนื่องนานๆ ต้องรัน configurer ใหม่เมื่อพบการเปลี่ยนแปลงใน build.zig หรือไฟล์ที่เกี่ยวข้อง และเพื่อให้เกิดสิ่งนี้ maker ต้องยุติการทำงาน เพื่อเปิดโอกาสให้ zig build รันตรรกะการจัดการแพ็กเกจซ้ำ
  • ในโครงสร้างใหม่ zig build รับหน้าที่เฉพาะคอมไพเลอร์ ส่วน maker ที่อยู่ด้านล่างจะรับผิดชอบทั้ง ระบบบิลด์และตัวจัดการแพ็กเกจ และ configurer จะเป็น child process ของ maker
  • แม้ต้องรันคอนฟิกใหม่ maker ก็ยังคงอยู่ต่อในฐานะ parent process ได้
  • สำหรับ build server ที่วางแผนไว้ แทนที่ client จะต้องเชื่อมต่อใหม่หลังเซิร์ฟเวอร์ปิดตัว ก็จะสามารถใช้โครงสร้างที่แจ้ง การเปลี่ยนแปลงการตั้งค่า ไปยัง client ได้

การเปลี่ยนแปลงที่สังเกตได้

  • โดยรวมไม่ใช่การเปลี่ยนแปลงที่เข้ากันไม่ได้เป็นส่วนใหญ่ แต่มีความแตกต่างที่ผู้ใช้สังเกตได้
    • ขนาดไบนารีของไฟล์รันไทม์ Zig: ลดจาก 14.1MiB เหลือ 13.5MiB บน ReleaseSmall แบบไม่มี LLVM คิดเป็น ลดลง 4%
    • แฟล็ก --maker-opt ถูกแทนที่ด้วยตัวแปรสภาพแวดล้อม ZIG_DEBUG_MAKER
    • แฟล็ก --zig-lib-dir ถูกแทนที่ด้วยตัวแปรสภาพแวดล้อม ZIG_LIB_DIR

ประเด็นค้างสำคัญก่อน Zig 0.17.0

1 ความคิดเห็น

 
GN⁺ 5 시간 전
ความคิดเห็นจาก Hacker News
  • นักพัฒนา Zig, Go, Python มักจะประกาศเป็นครั้งคราวว่า เอาน้ำหล่อเย็นออกจากถังเชื้อเพลิงแล้ว และผู้สนับสนุนก็ดีใจกันว่าเป็นผลดีกับภาษาและประสิทธิภาพก็น่าจะดีขึ้นมาก
    แต่สิ่งที่น่าสงสัยกว่าคือแต่แรกทำไมถึงเอาน้ำหล่อเย็นใส่ไว้ในถังเชื้อเพลิง

    • ในช่วงต้นของโปรเจ็กต์แบบนี้ มักให้ความสำคัญกับ ความสะดวกของนักพัฒนาแต่ละคน มากกว่าการคิดให้ลึกถึงผลลัพธ์ของการออกแบบ
      การใส่ระบบจัดการแพ็กเกจไว้ในคอมไพเลอร์นั้นสะดวก แต่เมื่อภาษาและเครื่องมือเริ่มถูกใช้อย่างแพร่หลาย ฟีเจอร์ที่เคยเป็นประโยชน์กับคนทำกลับกลายเป็นหนี้ทางเทคนิคที่ขัดขวางการนำไปใช้
      ในหลายโปรเจ็กต์ นักพัฒนามักเลือกทางที่สะดวกเพื่อเลี่ยง “งานยากที่จำเป็นถ้าจะทำให้ถูกต้อง” และเพราะคนอื่นก็ไม่อยากทำงานยากนั้นเหมือนกัน มันเลยกลายเป็นธรรมเนียมไป
    • มุมนี้ก็มีเหตุผลที่ปกป้องได้อยู่
      ถ้าจะทำตัวจัดการแพ็กเกจใน build system แต่ยังอยากให้มันอยู่ในคอมไพเลอร์ด้วย ก็ต้องกำหนดก่อนว่าจะวาง abstraction อะไรไว้ระหว่างคอมไพเลอร์กับ build system
      เรื่องนี้กระทบถึงระบบ import และส่วนพื้นฐานของภาษา ซึ่งเป็นส่วนที่ต้องออกแบบให้ดีและเปลี่ยนทีหลังได้ยาก
      ในช่วงแรก การผูก package management กับคอมไพเลอร์แน่น ๆ แล้วออกแบบย้อนกลับจากประสบการณ์ที่ต้องการให้โปรแกรมเมอร์ได้รับ อาจทำให้ภายหลังเปลี่ยน implementation แล้วกระทบผู้ใช้น้อยกว่า
      โดยเฉพาะระบบ import ของ Python นั้นดูซับซ้อนมากและมีจุดบกพร่องเยอะ เพราะต้องรองรับการจัดการแพ็กเกจที่เกิดขึ้นได้หลายแบบ
      ส่วน Go นั้นออกแบบโดยคำนึงถึง package management มาตั้งแต่แรก ทำให้ไวยากรณ์ที่เกี่ยวกับ import ค่อนข้างเล็กและสะอาด แน่นอนว่าไม่ได้แปลว่าเห็นด้วยกับทุกการตัดสินใจในการออกแบบ
    • ฟังดูเหมือนเป็นความเห็นจากคนที่ไม่เคยสร้างอะไรจริง ๆ
      ต่อให้เป็นผลิตภัณฑ์เล็ก ๆ ก็ยังคาดเดาได้ยากว่าองค์ประกอบแต่ละส่วนจะโต้ตอบกันอย่างไร จนต้องแก้ไปเรื่อย ๆ
      ลองนึกภาพว่าตอนนี้กำลังสร้าง ภาษาทดแทน C แบบ self-hosting ดู
    • เรื่องประสิทธิภาพก็ให้ความรู้สึกแบบเดียวกันเป๊ะ และไม่ได้เกี่ยวกับภาษาโปรแกรมใดภาษาหนึ่งหรือการปรับแต่งของผมเองด้วย
      ยิ่งความเร็วเพิ่มขึ้นมากคนก็ยิ่งเฮกัน แต่ optimization ส่วนใหญ่ไม่ใช่เทคนิคฉลาดล้ำอะไร แค่ใช้ profiler แล้วเจอว่า “เดี๋ยวนะ น้ำหล่อเย็นไม่ควรอยู่ในถังเชื้อเพลิงนี่”
      คอขวดด้านประสิทธิภาพ ส่วนใหญ่มักไม่ใช่ข้อจำกัดเชิงแก่นแท้ของฮาร์ดแวร์หรือของปัญหาเอง
      มันมีปริมาณงานขั้นต่ำที่ต้องทำเพื่อให้ได้ผลลัพธ์อยู่แล้ว แต่สาเหตุที่แอปพลิเคชันช้ามักแทบจะเป็นเพราะของจุกจิกที่ไปพอกทับเพิ่มจากนั้น
    • ผมไม่รู้จัก Zig หรือ Python ดีพอจะตัดสิน แต่กับ Go ไม่เคยรู้สึกแบบนั้นเลย ไม่แน่ใจว่าเคยมีกรณีแบบนั้นตอนไหน
  • การพัฒนา Zig ให้ความรู้สึกว่าเป็นบรรยากาศที่ ดีต่อสุขภาพมาก

    • เวลามอง Zig ทุกวันนี้ มันเหมือนพิสูจน์ว่างานพัฒนาซอฟต์แวร์ในฐานะ craft ยังไม่ตายและยังไม่ได้ถูก LLM มาแทนที่
      ผมใช้ LLM ทุกวัน และยอมรับว่ามันเก่งจนน่าทึ่งกับปัญหาหลายประเภท แต่ผมไม่ต้องการภาษาการเขียนโปรแกรมที่สร้างโดย LLM
      ทุกบรรทัดของโค้ด ทุกการตัดสินใจ และทุก trade-off ในภาษาการเขียนโปรแกรมล้วนสำคัญ
      ภาษาที่ถูกออกแบบและเขียนโค้ดจากแค่อารมณ์หรือบรรยากาศจะกลายเป็นหายนะ
      ยังไม่เคยมีโมเดลไหนแสดงโค้ดที่ทำให้มั่นใจในทางตรงกันข้ามได้เลย แม้แต่ Fable ที่ดีขึ้นจากโมเดลชั้นนำตัวก่อนอย่างชัดเจนก็ยังเหมือนเดิม
      โมเดลไม่ได้มีความต้องการ ไม่มีมุมมองที่มีความหมาย และไม่รู้ว่าความสบายหรือความอึดอัดในภาษานั้นคืออะไร เช่นเดียวกับในอินเทอร์เฟซ GUI หรือ CLI ที่ซับซ้อนพอสมควร
      ภาษาที่อย่าง Zig จะไม่มีทางออกมาจาก LLM ได้ เว้นแต่จะก็อปปี้ Zig มา และต่อให้ก็อปปี้ก็น่าจะเป็นสำเนาที่แย่กว่า
      คำว่าก็อปปี้ด้วย LLM ในที่นี้ไม่ได้หมายถึงการ cp source tree ตรง ๆ แต่หมายถึงให้ LLM ตัวหนึ่งเขียนสเปก แล้วให้อีกตัวนำสเปกนั้นไปสร้างภาษา
    • การทำของด้วย Zig ก็สนุกดีเหมือนกัน
      ผมเคยทำบูตโหลดเดอร์และทำงานกับ UEFI ซึ่งโดยส่วนตัวรู้สึกว่าง่ายกว่าทำด้วย C มาก
      แต่ก็ยอมรับว่าความสนุกจากการได้เรียนรู้อะไรใหม่ ๆ และดูทันสมัยก็ทำให้มีอคติอยู่พอสมควร
  • สงสัยว่านี่ใช่การเปลี่ยนแปลงเดียวกับที่ทำให้ Zig เอา @cImport ออกแล้วโยกไปอยู่ใน build system หรือเปล่า
    ถึงจะเข้าใจว่าเป็นเรื่องประสบการณ์ผู้ใช้ล้วน ๆ และการแยก build system ออกจากคอมไพเลอร์เป็นเรื่องสำคัญสำหรับผู้ดูแล แต่ก็ยังรู้สึกเสียดายอยู่นิดหน่อยที่ เสถียรภาพในการพัฒนา มาก่อนประสบการณ์ผู้ใช้
    เป็นการตัดสินใจที่ถูกต้อง แต่ก็เศร้านิด ๆ เพราะผมมองว่า @cImport เป็นฟีเจอร์เด็ดของภาษานี้

    • ไม่เชิง
      การเปลี่ยนแปลงนี้เกี่ยวกับโค้ดที่ใช้ดาวน์โหลดและแตกไฟล์แพ็กเกจจากบุคคลที่สาม
      การเปลี่ยน @cImport เป็นส่วนหนึ่งของงานที่ต้องการทำให้ การพึ่งพา LLVM/libclang ของ Zig กลายเป็นตัวเลือกในอนาคต และต่อไปอาจแยกออกเป็นแพ็กเกจภายนอกได้ แต่ดูเหมือนไม่ได้เกี่ยวข้องกันโดยตรง
  • เคยอ่านมาจากที่ไหนสักแห่งว่าเป้าหมายระยะยาวคือย้าย build system เข้าไปอยู่ใน WebAssembly VM
    ถ้าใช่ก็น่าทึ่งมาก

    • สงสัยว่ามันมีข้อดีอะไรสำหรับงาน build
  • เป็นการเปลี่ยนแปลงที่ดีกับ Zig
    ผมอยากย้ายจาก Go ไป Zig มากพอสมควร แต่ตอนนี้การยืนดูอยู่ข้าง ๆ ก็สนุกดีเหมือนกัน

    • แล้วแต่ use case ทั้งคู่ใช้ได้ และบางทีควรใช้แบบนั้นด้วย
  • ทุกครั้งที่ภาษาใดภาษาหนึ่งสร้างระบบแพ็กเกจของตัวเองขึ้นมา ผมจะรู้สึกแค่ว่าเราพลาดโอกาสใหญ่อะไรบางอย่างไป
    ข้อยกเว้นเดียวคือ C/C++ ที่ไม่ว่าจะดีหรือร้ายก็ไม่มีอะไรที่ตั้งหลักได้จริงมากพอ
    การเลือกแบบนี้อาจทำให้กระบวนการซับซ้อนมากเมื่อถึงวันที่ต้องผสมหลายภาษาเข้าด้วยกัน
    ระบบแพ็กเกจทำให้การทำงานง่ายขึ้น แต่พอถึงจุดที่ต้องใช้ภาษาอื่น มันกลับทำให้ขั้นตอนหลังจากนั้นซับซ้อนกว่าเดิม

    • อยากรู้ว่าคุณมองว่าเราพลาดอะไรไป
      คุณต้องการ build system เดียวสำหรับทุกภาษาหรือเปล่า? ระบบอย่าง Bazel ก็มีอยู่และก็มักถูกใช้กับโปรเจ็กต์หลายภาษา แต่ในความเป็นจริงดูเหมือนจะพิสูจน์แล้วว่า build system ที่มีความรู้เฉพาะของแต่ละภาษานั้นจัดการได้ง่ายกว่ามาก
    • ผมกลับมองว่าการที่ C++ ไม่มีระบบแพ็กเกจมาตรฐานเป็นเรื่องดี
      เพราะมันบังคับให้คิดให้รอบคอบก่อนเพิ่ม dependency
      dependency แบบนี้มักมี ต้นทุนแฝง อย่างช่องโหว่ด้านความปลอดภัยติดมาด้วย
      ระบบสำคัญจำนวนไม่น้อยเขียนด้วย C++ ดังนั้นการไปพึ่งแพ็กเกจภายนอกที่เข้าถึงได้ง่ายเป็นสิบ ๆ ตัว โดยไม่ได้ตรวจสอบแต่ละแพ็กเกจอย่างเหมาะสม จึงมีความเสี่ยงสูงเกินไป
    • C ควรแก้หลายปัญหาและเพิ่ม package manager หรืออย่างน้อยก็รับรองตัวใดตัวหนึ่งอย่างเป็นทางการ
      Zig กำลังเข้ามาเติมช่องว่างนั้น
    • โลกนี้ยังไม่ได้มาตรฐานไปที่ build system ข้ามแพลตฟอร์มแบบหลายภาษา ที่ดีจริง ๆ
      ในทางปฏิบัติก็มีแค่ Buck กับ Bazel แต่ทั้งคู่ก็แบกภาระจากองค์กรขนาดใหญ่ที่อยู่เบื้องหลังมากเกินไป
      น่าเสียดาย
    • Conan กับ vcpkg ก็ถือว่าตั้งหลักได้ดีพอแล้ว
  • การแยกความรับผิดชอบกันทำได้อย่างน่าเชื่อถือมาก