2 điểm bởi GN⁺ 2024-11-30 | 1 bình luận | Chia sẻ qua WhatsApp
  • Ninja, được công bố năm 2011, khởi đầu là một hệ thống build tương tự Make và đã trở thành một ví dụ thành công tiêu biểu của mã nguồn mở, lan rộng sang Chrome, một phần Android, Meson và các dự án dựa trên CMake
  • Trục quyết định thành bại không nằm nhiều ở bản thân mã nguồn, mà ở kiến trúc, và xa hơn là các vấn đề xã hội như bảo trì và kỳ vọng của người dùng
  • Ninja đọc các lệnh, input và output được ghi trong ninja.build, kiểm tra thời điểm sửa đổi tệp rồi chạy song song các tác vụ cần thiết, tập trung vào việc làm cho incremental build của các dự án lớn trở nên nhanh
  • Lựa chọn thiết kế lớn nhất là không tự ôm các tính năng build cấp cao, mà chỉ đóng vai trò bộ thực thi action graph, tách phần phán đoán phức tạp cho generator đảm nhiệm
  • Tích hợp CMake, hỗ trợ Windows và mặc định chạy song song đã giúp Ninja lan rộng, nhưng các yêu cầu và đóng góp xung đột với mục tiêu thiết kế vẫn là gánh nặng lớn trong bảo trì mã nguồn mở

Bối cảnh khiến Ninja được dùng rộng rãi

  • Ninja là một hệ thống build tương tự Make, được công bố khoảng 9 năm trước; ban đầu chỉ là một dự án phụ được chia sẻ một cách có phần ngượng ngùng, nhưng về sau đã được sử dụng rộng rãi
  • Các trường hợp sử dụng chính gồm:
    • Chrome cuối cùng đã loại bỏ toàn bộ các kiểu build không dùng Ninja
    • Android dùng Ninja cho một số thành phần lớn của hệ thống
    • Dự án Meson dùng Ninja và có vẻ đang trở thành một hệ thống build ngày càng phổ biến trong thế giới phần mềm tự do
    • Nhiều dự án cũng dùng Ninja cùng với CMake, và hướng dẫn build Swift cũng yêu cầu cài Ninja
  • Ninja được phát hành năm 2011, quyền sở hữu dự án được chuyển giao vào năm 2014, rồi sau đó tiếp tục được chuyển cho maintainer chính thứ ba
  • Kinh nghiệm cốt lõi rút ra trong bài hồi tưởng này là kiến trúc có ảnh hưởng lớn hơn mã nguồn, và các vấn đề xã hội còn có ảnh hưởng lớn hơn kiến trúc

Cách hoạt động cơ bản để build nhanh

  • Việc Ninja làm tương đối đơn giản
    • Người dùng ghi vào tệp ninja.build các lệnh cần chạy, các tệp mà mỗi lệnh tiêu thụ và các tệp mà lệnh tạo ra
    • Ninja đọc tệp này và kiểm tra thời điểm sửa đổi của nhiều tệp
    • Ninja chạy song song các lệnh cần thiết để đưa mọi thứ về trạng thái mới nhất
  • So với Make, ngôn ngữ build đầu vào có ít tính năng hơn, và cấu trúc tập trung vào việc thực hiện thật nhanh một số ít tính năng
  • Luồng thực thi được chia thành ba bước
    • Parse và diễn giải tệp build
    • Kiểm tra thời điểm sửa đổi của các tệp đầu vào
    • Chạy các lệnh cần thiết
  • Mục tiêu là đi tới bước thứ ba nhanh nhất có thể, ngay cả với các dự án lớn có hơn 100.000 tệp đầu vào
  • Một ví dụ tối ưu hóa là Ninja ánh xạ đường dẫn tệp đầu vào thành các đối tượng bộ nhớ duy nhất sớm nhất có thể, rồi về sau dùng so sánh con trỏ để so sánh tính đồng nhất của đường dẫn
  • Các chi tiết hiệu năng cấp thấp hơn được đề cập trong chương Ninja của The Performance of Open Source Software
  • Trong nhiều năm cũng đã xuất hiện các bản tái triển khai Ninja
    • llbuildShake hỗ trợ dùng tệp Ninja làm đầu vào
    • samurai là một dự án gần như triển khai lại theo từng tệp; mã nguồn ít hơn nhưng tính năng cũng ít hơn và không có test
  • Làm một bản triển khai 20% thú vị thì dễ, nhưng 80% còn lại có rất nhiều chi tiết; hiện chưa có bản triển khai nào nhanh hơn được biết đến

Những lựa chọn quan trọng trong thiết kế

  • Biểu diễn đồ thị

    • Make không xử lý tốt trường hợp một quy tắc build tạo ra nhiều tệp
    • Ninja không dùng đồ thị giữa các tệp, mà dùng đồ thị hai phía giữa tệp và lệnh
    • Các nút tệp trở thành cạnh đi vào nút lệnh, và nút lệnh lại có cạnh đi ra tới các tệp output
    • Cấu trúc này nắm bắt hình thái thực tế của build tốt hơn
    • Nếu một trong các input thay đổi, lệnh trở nên lỗi thời; khi lệnh chạy, toàn bộ output được cập nhật
    • Một tệp cụ thể chỉ có thể có tối đa một cạnh đầu vào
    • Bản thân dòng lệnh cũng có thể được xem như một input của nút lệnh, nên nếu các flag dòng lệnh thay đổi thì lệnh và output cũng trở nên lỗi thời
  • deps log và phụ thuộc C header

    • Để xử lý chính xác phụ thuộc C header, cần tiêu thụ dữ liệu phụ thuộc bổ sung do trình biên dịch C tạo ra
    • Sau khi cân nhắc giữa việc đưa vào cơ sở dữ liệu và tính đơn giản, định dạng biểu diễn deps log đã được tạo ra
    • Định dạng này khá cô đọng, nhưng vẫn còn sai ở một số điểm quan trọng
  • Thiết kế end-to-end / crash-only

    • Ninja không phải là daemon process chạy liên tục, mà mỗi lần chạy đều bắt đầu lại từ đầu
    • Lựa chọn này là một cấu trúc chịu ảnh hưởng của end-to-end principlecrash-only software
    • Nếu làm cho đường dẫn chạy từ đầu đủ nhanh, không cần tạo thêm một đường dẫn mã “online” riêng
    • Các dự án có thể cư trú trong bộ nhớ rốt cuộc thường có xu hướng bỏ bê hiệu năng khởi động
  • Kiểm tra trạng thái tệp

    • Một lý do khiến người ta kỳ vọng công cụ build phải cư trú trong bộ nhớ là để cache trạng thái tệp trên đĩa
    • Trên thực tế, kernel đã cache thông tin này trong bộ nhớ, và việc cache lại ở user space không tiết kiệm được nhiều
    • Trên Linux, thao tác lấy trạng thái tệp rất nhanh, và Ninja xử lý việc này trên một luồng duy nhất
    • Ngay cả trên một máy “nhanh” theo tiêu chuẩn 10 năm trước, cũng có thể thực hiện stat cho 30.000 tệp trong vài chục mili giây
  • Đánh đổi giữa quy mô và đặc tả

    • Theo kinh nghiệm, mở rộng quy mô 2 lần có thể làm bằng tối ưu hóa, nhưng mở rộng 10 lần thì cần tái kiến trúc
    • Ninja được thiết kế xoay quanh build Chrome, khi đó có khoảng 30.000 bước build
    • Hiện nay Ninja cũng được dùng trong các môi trường nhỏ hơn, nhưng trong các trường hợp đó lợi thế tốc độ có thể không cần thiết
    • Trong các môi trường lớn hơn như build Android, Ninja đang chạm tới giới hạn về khả năng scale và có thể cần một cách tiếp cận khác
    • Để chạy song song, Ninja cần người dùng cung cấp đủ thông tin, nhưng không ép họ phải biết hoàn toàn toàn bộ build
    • Có các đánh đổi giữa tính đúng đắn, sự tiện lợi và hiệu năng; trong toàn hệ sinh thái, một công cụ hy sinh một phần tính đúng đắn để đổi lấy tiện lợi đôi khi có thể tạo ra kết quả đúng hơn so với một công cụ chính xác hơn nhưng bất tiện

Sự tách biệt do ẩn dụ “assembler” tạo ra

  • Các hệ thống build cung cấp nhiều tính năng cấp cao khác nhau, và phạm vi cách mỗi công cụ tự mô tả bản thân rộng tới mức khó so sánh với nhau
  • Insight cốt lõi của Ninja là dù cung cấp tính năng cấp cao nào, cuối cùng hệ thống build cũng phải cấu thành một action graph để giữ cho các tệp ở trạng thái mới nhất
  • Ninja chỉ chạy action graph này, còn việc đặt generator nào lên trên nó thì để người dùng quyết định
  • Sự tách biệt giữa hai chương trình này ban đầu được tạo ra vì nó phù hợp với dự án Chrome, nhưng về sau trở thành đóng góp quan trọng nhất của Ninja
  • Có hai ưu điểm
    • Bản thân Ninja được giữ đơn giản và nhanh
    • Các thao tác tốn kém như glob *.c được đẩy sang phía generator
  • Khác với các hệ thống build khác xử lý mọi thứ trong một lần, cấu trúc của Ninja buộc action graph đã tính toán được lưu xuống đĩa dưới dạng snapshot
  • Kết quả là action graph được cache giữa các lần build
  • Generator có thể cấp cao tùy ý
    • Ví dụ, cũng có thể glob toàn bộ cây nguồn rồi tìm các tệp có test trong tên để xem là test
  • Lập trình viên phải tự quyết định mình muốn trả chi phí cho điều gì
    • Generator có thể glob toàn bộ đĩa, nhưng khi đó lý do build chậm cũng rõ ràng hơn
  • Sự tách biệt giữa generator và action graph thực ra không đơn giản, và ngay cả trong Ninja cũng có nhiều chi tiết xoay quanh việc tầng nào đảm nhiệm việc gì
  • Về lý thuyết, các hệ thống build của Xcode hay Visual Studio cũng có thể làm theo cùng cách: tính trước rồi snapshot kết quả, nhưng tác giả cho rằng việc này không hiệu quả vì có cám dỗ muốn trộn lẫn các tầng
  • Make đã cố bao gồm mọi tính năng hướng tới lập trình viên như globbing, mở rộng biến, substring và hàm; nó trở thành một ngôn ngữ quá yếu để biểu đạt mọi tính năng cần thiết, nhưng đủ mạnh để viết ra những Makefile chậm
  • Ninja đã cố tránh hướng đi này

Giá trị mặc định chi phối hiệu năng cảm nhận

  • Theo mặc định, Ninja chạy song song các lệnh mong muốn
  • Make cũng có thể chạy song song bằng flag -j, nhưng mặc định là chạy tuần tự
  • Makefile dễ được viết trong trạng thái không an toàn cho chạy song song vì không khai báo đủ phụ thuộc
  • Ninja luôn chạy song song ngay cả trên hệ thống một lõi, nên các lỗi như vậy lộ ra sớm hơn
  • Chương trình phù hợp với Ninja thường cũng trở nên an toàn với parallel build
  • Ninja không có hệ thống nâng cao để phát hiện phụ thuộc sai; cấu trúc của nó là các build sai xảy ra thường xuyên hơn, nhờ đó vấn đề lộ ra
  • Vì người dùng thường quên hoặc không biết flag chạy song song của Make, chỉ riêng một giá trị mặc định cũng có thể khiến Ninja trong thực tế được cảm nhận là “nhanh hơn hơn hai lần” so với Make
  • Những tối ưu hóa mà người dùng không thật sự trải nghiệm thì ít ý nghĩa

Các chỉ số quan trọng về tốc độ

  • Hiệu năng của hệ thống build có nhiều nghĩa
    • Build toàn bộ từ đầu mất bao lâu
    • Sau khi đã build, sửa một tệp rồi build lại mất bao lâu
  • Ninja tập trung vào việc làm nhanh vòng lặp edit-compile trong incremental build của codebase lớn
  • Khi lần đầu tạo Ninja, vì ký ức rằng blaze, tức bazel, rất nhanh nên tác giả muốn bắt kịp tốc độ đó
  • Về sau nhìn lại, blaze không đặc biệt nhanh ở chỉ số mà tác giả quan tâm, và vì là chương trình Java nên ngay cả việc in trợ giúp cũng chậm
  • Lý do ám ảnh với incremental build là tác giả cho rằng thời gian lặp lại ảnh hưởng lớn đến mức độ hài lòng của lập trình viên
  • Ninja được dùng trong vòng lặp edit-compile, nơi sự khác biệt giữa 1 giây và 4 giây là quan trọng
  • Ý nghĩa của “nhanh” khó truyền đạt tới người dùng, và manual của Ninja cảnh báo rằng với dự án nhỏ, hiệu ứng tốc độ có thể hầu như không cảm nhận được
  • Nhưng “nhanh” là một cách diễn đạt dễ bán, nên cả những người dùng ứng dụng nhỏ thất vọng vì thiếu tính năng cũng muốn dùng Ninja
  • Ninja tập trung vào incremental rebuild, nhưng một số người dùng cũng báo cáo rằng hiệu năng build toàn bộ được cải thiện
    • Vì Ninja gần như không làm gì cả nên dùng ít CPU trong lúc build, và ít tranh CPU hơn với công việc build thực sự
  • Output cũng rất ngắn gọn
    • Một build thành công hầu như chỉ in một dòng
    • Các hệ thống build khác in nhiều bước và thông tin timing, nên có thể tạo cảm giác nặng nề
  • Cấu trúc ít nói khiến Ninja có cảm giác “như không tồn tại” hơn

Tích hợp CMake và hỗ trợ Windows đã thúc đẩy lan rộng

  • CMake

    • Ninja ban đầu được tạo ra để dùng cùng hệ thống build đặc thù của Chrome
    • Peter Collingbourne đã thực hiện công việc kết nối Ninja với hệ thống build CMake được dùng rộng rãi hơn
    • Việc tích hợp này bắt đầu vì công việc với LLVM, và phải thêm semantic mới không chỉ vào CMake mà cả phía Ninja
    • Peter được xem là người có công lớn nhất đối với thành công của Ninja trong thế giới thực
    • Sau đó, các tác giả CMake đã tiếp quản phần tích hợp, nhưng chưa đáp ứng đầy đủ các yêu cầu và lo ngại
    • Nhà phát triển cho đến nay chưa từng trực tiếp dùng CMake
  • Windows

    • Vì Chrome cũng nhắm tới Windows, Ninja cũng được làm để chạy trên Windows
    • Một phần lớn hỗ trợ Windows do một contributor viết
    • Về mặt kỹ thuật, hỗ trợ Windows là một phiền toái lớn
    • Chạy process và capture output là loại khác biệt buộc phải học API theo từng nền tảng
    • Thiết kế của Ninja dựa vào đặc tính có thể lấy nhanh thời điểm sửa đổi cuối cùng của tệp đã được kernel cache, nhưng trên Windows điều này không đúng
    • Dù vậy, Windows là một nền tảng có quy mô nhà phát triển lớn
    • Với công cụ hay cho Linux, người ta có thôi thúc mạnh mẽ muốn chia sẻ; còn với công cụ cho Windows, thôi thúc bán lại mạnh hơn, nên các công cụ được cung cấp tự do tương đối ít
    • Việc có nhiều người dùng Windows trong nhóm người dùng Ninja thời kỳ đầu từng gây ngạc nhiên, nhưng vì số lượng nhà phát triển Windows rất lớn, chỉ cần một phần nhỏ quan tâm cũng đã xuất hiện thành người dùng

Hiểu các công trình liên quan

  • Vì Ninja ban đầu bắt đầu như một bản hack demo cuối tuần, tác giả tiếc rằng đã không khảo sát đủ các công trình liên quan trước khi làm
  • Khi tạo ra thứ gì đó, việc thực sự hiểu không gian thiết kế là rất quan trọng
  • Thuật ngữ “action graph” không phải là cách diễn đạt tác giả dùng khi tạo Ninja, mà được lấy từ hệ thống build của Google là blaze/bazel
  • bazel giải thích rằng đồ thị target cấp cao như “library”, “binary” tạo ra action graph, tức đồ thị của các lệnh
  • Ý tưởng xem văn bản dòng lệnh như một input giống tệp là một trường hợp của incremental computation
  • Incremental computation không chỉ liên quan đến hệ thống build mà còn liên quan đến tính incremental của UI
  • Blog Jane Street có bài giới thiệu Incremental, cũng liên hệ với các cách cấu thành UI như React
  • "Build Systems à la Carte" là một bài báo thảo luận về incremental computation trong bối cảnh hệ thống build, và được xem là tài liệu mà tác giả ước gì đã tồn tại trước khi viết Ninja

Gánh nặng bảo trì mã nguồn mở

  • Trải nghiệm làm maintainer mã nguồn mở không đặc biệt vui vẻ
  • Cảm xúc với dự án là sự pha trộn giữa niềm tự hào khi có ai đó nói lời tốt đẹp và một cảm giác thất vọng lớn hơn
  • Do công bố miễn phí, thỉnh thoảng cũng có người yêu cầu lịch sự, nhưng thường xuyên hơn là người dùng tức giận đưa ra đòi hỏi, còn lời cảm ơn thì hiếm
  • Cũng nhiều lần có người đe dọa sẽ fork nếu yêu cầu của họ không được chấp nhận
  • Những đóng góp hợp lý nhưng xung đột với mục tiêu thiết kế cũng là một khó khăn khác
    • Khi phải từ chối đóng góp của một người tử tế và thông minh, tác giả muốn đáp lại bằng lời giải thích đầy đủ, và bản thân việc giải thích đó đã rất mệt mỏi
  • Tác giả bước vào lập trình thông qua phần mềm tự do và viết mã vì muốn trả lại những gì đã nhận, nhưng phần mềm tự do ngày nay có xu hướng không còn là sự chia sẻ giữa những người ngang hàng, mà là người dùng tự xem mình như khách hàng và đối xử với tác giả như một đối tượng để phàn nàn với quản lý
  • Động lực hiện tại gần với việc gây ấn tượng với, hoặc đáp ứng kỳ vọng của, một số ít hacker mà tác giả kính trọng hơn là thành công rộng rãi
  • Thành công của Ninja đã giúp tác giả học được nhiều điều, nhưng ông cho rằng có lẽ chỉ cần một thành công nhỏ hơn cũng đã có thể học được tương tự

Maintainer và contributor

  • Nico Weber là một cộng tác viên thận trọng và đã đảm nhiệm vai trò maintainer Ninja trong nhiều năm
  • Jan Niklas Hasse tiếp quản dự án sau Nico và có vẻ đang làm tốt
  • Ngoài ra, còn nhiều contributor của Ninja khác đã tham gia dự án

1 bình luận

 
GN⁺ 2024-11-30
Ý kiến trên Hacker News
  • Cách diễn đạt rằng “lập trình nghe như là viết code, nhưng trên thực tế kiến trúc quan trọng hơn code, và các vấn đề xã hội còn quan trọng hơn kiến trúc” đã nói đúng điều tôi nghĩ trong lòng từ lâu

    • Rất đồng ý. Peopleware 1987 [1] cũng nói điều tương tự
      Chương 1 của cuốn sách lập luận rằng “những vấn đề chính trong công việc của chúng ta mang tính xã hội học nhiều hơn là kỹ thuật”, và bàn về các vấn đề xã hội·chính trị như chemistry và sự gắn kết của đội ngũ, “thời gian tập trung”, môi trường làm việc yên tĩnh, chi phí nghỉ việc
      [1] https://en.wikipedia.org/wiki/Peopleware:_Productive_Project...
    • Lập trình và các công cụ của nó là dành cho con người, không phải máy tính, và trừ những việc rất nhỏ nhặt thì để tạo ra thứ gì đó chạy trên máy tính cần nhiều người
      Vì vậy tôi cho rằng kỹ nghệ phần mềm gần với khoa học xã hội hơn rất nhiều so với mức nhiều người thừa nhận hoặc cảm thấy thoải mái. Khoa học xã hội linh hoạt và khó dự đoán hơn khoa học tự nhiên, nên dường như có xu hướng né tránh phần xã hội hoặc chỉ xử lý nó ở mức rất sơ khai. Dù ám ảnh với các chi tiết nguyên tử của công nghệ, sản phẩm mà đội ngũ tạo ra lại quá thường xuyên trở nên tệ hại
    • https://en.wikipedia.org/wiki/Conway's_law
      “Các tổ chức thiết kế hệ thống chắc chắn sẽ tạo ra những thiết kế sao chép cấu trúc giao tiếp của chính tổ chức đó.” — Melvin E. Conway, How Do Committees Invent?
    • Theo kinh nghiệm của tôi, khoảng 80% vấn đề kỹ thuật phát sinh vì hai người hoặc hai đội chỉ đơn giản là ngại ngồi đối diện và nói chuyện với nhau
    • Nhưng không phải là sự phân đôi rạch ròi. Kiến trúc tốt vừa đáp ứng những gì con người yêu cầu ở hệ thống, vừa giữ cho nó con người có thể hiểu được
  • Khi đó cũng đã được thảo luận:
    The Success and Failure of Ninja - https://news.ycombinator.com/item?id=23157783 - tháng 5/2020, 38 bình luận
    Sau khoảng 1 năm thì đăng lại cũng không sao, còn liên kết tới thread cũ là dành cho độc giả muốn tìm hiểu thêm

  • Phần “Android dùng Ninja cho một thành phần lớn nào đó của hệ thống, nhưng tôi chưa bao giờ hiểu chính xác là gì” khá buồn cười
    Ninja thực sự chiếm tỷ trọng lớn trong AOSP. Hệ thống build ban đầu dùng Makefile, nhưng nhanh chóng trở nên phức tạp vì soong, một hệ thống build khai báo tùy biến, và cuộc migration sang Bazel bị thất bại·dừng lại. Google đã tạo kati(https://github.com/google/kati) để chuyển Makefile thành file build Ninja, và kết quả thật sự khổng lồ:
    λ wc -l out/build-qssi.ninja
    3035442 out/build-qssi.ninja
    Quá trình đi từ Makefile/soong sang Ninja rất đau đớn và mất vài phút ngay cả trên máy hiện đại, nhưng sau khi Ninja nhận vào thì nó chạy cực nhanh

    • Tôi chưa từng dùng Ninja, nên tò mò nó có ưu điểm gì so với Makefile
      Tôi cũng nghi ngờ liệu có đáng đưa thêm một công cụ nữa vào chỉ để dịch từ công cụ này sang công cụ khác hay không. Đặc biệt càng như vậy nếu file Ninja lớn đến thế và có thể khó đọc với con người
  • Ở đoạn “tôi tin rằng lập trình viên cảm nhận được độ trễ, và dù bản thân không nhận ra thì tâm trạng cũng bị ảnh hưởng. Google gần đây đã nghiên cứu lĩnh vực này và phần nào xác nhận niềm tin của tôi”, tôi tò mò liệu nghiên cứu về độ trễ đó có thật sự được công bố hay chưa

  • Ninja khá phổ biến trong giới nhà phát triển game
    Câu “Windows vẫn là một nền tảng khổng lồ xét từ phía developer, và các developer đó đang thiếu thốn công cụ” khá thú vị. Từ góc nhìn của người chủ yếu phát triển trên Windows, tôi lại cảm thấy các developer Linux sống thiếu Visual Studio, một debugger tốt, hay Superluminal, một profiler, mới là những người thiếu thốn công cụ. Gần đây khoảng cách giữa hai nền tảng dường như đang ngày càng thu hẹp, và tôi cũng thích các tiện ích Rust nói chung chạy đa nền tảng

    • Mỗi khi ai đó đặt Visual Studio và “tốt” trong cùng một câu, tôi lại có cảm giác kỳ lạ rằng vũ trụ này là một mô phỏng và những người khác đến từ vũ trụ khác
      Tôi không nghĩ ra tương tác nào với Visual Studio có thể gọi là “tốt”. Tôi có thể nghĩ ra vài thứ “tạm ổn một cách chật vật”, nhưng debugging thì không nằm trong số đó. Tuy nhiên trong bản 2022, debugger không còn đầy lỗi nữa, nên có lẽ họ đang nói về chuyện đó
    • Tôi không biết trong thế giới nào Visual Studio debugger được xem là tốt. Có thể nếu cuối cùng họ đã sửa được thì khác, chứ lần cuối tôi dùng, nó chậm đến mức không chịu nổi, bước từng dòng mất vài giây
    • Có những cộng đồng xem UNIX là toàn bộ công cụ dành cho developer, và vì vậy có vẻ họ chỉ thấy rừng mà bỏ lỡ từng cái cây
      Tôi biết rõ UNIX đến mức đã dùng nhiều biến thể từ sau khi tiếp xúc với Xenix năm 1993, nhưng gần như không dùng WSL ngoài mục đích chạy container Linux Docker
  • Một vài thứ trước đây vẫn dùng Ninja thì tôi đã chuyển sang samurai, và nó được cải thiện ở mọi mặt có thể
    Dù vậy, tôi vẫn nghĩ kiểu hệ thống build này đi sai hướng. Điều tôi muốn ở một hệ thống build là băm nội dung của mọi đầu vào bắc cầu, rồi tra xem kết quả đó có trong registry hay không

    • Đúng vậy. Các hệ thống build hỗ trợ cache phân tán về cơ bản dùng digest thay vì timestamp để kiểm tra thay đổi: Bazel, Pants, Buck, v.v. đều như vậy
      Tuy nhiên tất cả đều cực kỳ phức tạp. Nếu chỉ xét build cục bộ, tôi biết SCons và Waf cũng dùng hash để phát hiện thay đổi
    • Có thể bạn sẽ quan tâm đến n2, do tác giả Ninja tạo ra
    • Tôi nghĩ đó là ý tưởng của NetKernel
      Tôi đã làm một thư viện Deno tương tự tên là “TDAR”[1] và nó hoạt động tốt, nhưng để bọc các công cụ dòng lệnh vốn giả định chạy trên một filesystem có thể thay đổi sao cho trông như đang gọi các hàm thuần túy thì cũng hơi mất công
      [1] Vẫn chưa tách riêng khỏi dự án cấp trên[2], nhưng tôi đã nói về nó trong video YouTube này: https://youtu.be/sty29o8sUKI
      [2] Nếu bạn quan tâm đến những thứ như vậy, có thể thúc tôi công khai mã nguồn. togos zero zero at gee mail dot comb
    • Tôi tò mò Samurai tốt hơn ở điểm nào. Tôi cứ nghĩ nó là một tập con tương thích của Ninja
      Và “không phải thứ tôi muốn” không đồng nghĩa với “sai”. Vì trên đời cũng có những người có gu khác nhau
    • Không biết Samurai còn sống không. Tôi đã gửi một pull request cải thiện xử lý signal, nhưng nó đã bị bỏ mặc hơn nửa năm
  • Để dùng module C++20 trong CMake thì cần Ninja, nên Ninja chắc sẽ còn tồn tại khá lâu

  • Phần thú vị nhất với tôi là đoạn “thường phải đánh đổi giữa tính đúng đắn và sự tiện lợi hoặc hiệu năng, và cần có ý thức về việc mình chọn điểm nào trên dải liên tục đó”
    Một số lập trình viên nhìn động lực này quá cứng nhắc, cho rằng một giá trị hiển nhiên phải được ưu tiên. Nhưng trên thực tế, sự tương tác khá tinh tế. Ví dụ, một công cụ hy sinh một phần tính đúng đắn để chọn sự tiện lợi có thể tạo ra kết quả đúng hơn cho toàn bộ hệ sinh thái so với một lựa chọn thay thế đúng hơn nhưng kém tiện lợi hơn. Điều đó xảy ra khi các lập trình viên tránh dùng lựa chọn sau

    • Đây đúng là một mỏ vàng về insight. Vì thế Python, Go, TypeScript/JavaScript phổ biến hơn Haskell/OCaml rất nhiều
  • “Xin tha thứ cho cái tên đáng xấu hổ” ư, cái tên đó tuyệt mà
    Tái bút: Nếu triển khai cái này thì cũng có thể làm nó nhanh hơn: https://github.com/ninja-build/ninja/issues/2157 Tuy nhiên như bài viết đã giải thích, công cụ này cố ý không có trạng thái, kể cả những gợi ý rất nhỏ từ lần chạy trước