Hướng dẫn văn phong .bzl

Trang này trình bày các nguyên tắc cơ bản về kiểu cho Starlark, đồng thời cung cấp thông tin về macro và quy tắc.

Starlark là một ngôn ngữ xác định cách xây dựng phần mềm. Do đó, đây vừa là ngôn ngữ lập trình vừa là ngôn ngữ định cấu hình.

Bạn sẽ sử dụng Starlark để viết tệp BUILD, macro và quy tắc bản dựng. Macro và quy tắc về cơ bản là các ngôn ngữ meta – chúng xác định cách viết tệp BUILD. Tệp BUILD được thiết kế để đơn giản và lặp lại.

Tất cả phần mềm đều được đọc thường xuyên hơn là được viết. Điều này đặc biệt đúng đối với Starlark, vì các kỹ sư đọc BUILD tệp để hiểu các phần phụ thuộc của mục tiêu và thông tin chi tiết về bản dựng. Việc đọc này thường diễn ra một cách nhanh chóng, vội vàng hoặc song song với việc hoàn thành một số nhiệm vụ khác. Do đó, tính đơn giản và dễ đọc là rất quan trọng để người dùng có thể phân tích cú pháp và hiểu BUILD tệp một cách nhanh chóng.

Khi mở tệp BUILD, người dùng muốn nhanh chóng biết danh sách mục tiêu trong tệp đó; hoặc xem xét danh sách nguồn của thư viện C++; hoặc xoá một phần phụ thuộc khỏi tệp nhị phân Java đó. Mỗi khi thêm một lớp trừu tượng, bạn sẽ khiến người dùng khó thực hiện các tác vụ này hơn.

Tệp BUILD cũng được nhiều công cụ phân tích và cập nhật. Các công cụ có thể không chỉnh sửa được tệp BUILD nếu tệp đó sử dụng các lớp trừu tượng. Việc giữ cho tệp BUILD đơn giản sẽ giúp bạn có được công cụ tốt hơn. Khi cơ sở mã phát triển, bạn sẽ phải thường xuyên thực hiện các thay đổi trên nhiều tệp BUILD để cập nhật thư viện hoặc dọn dẹp.

Lời khuyên chung

Phong cách

Kiểu Python

Khi nghi ngờ, hãy tuân theo hướng dẫn về kiểu PEP 8 nếu có thể. Cụ thể, hãy sử dụng 4 thay vì 2 dấu cách để thụt lề theo quy ước của Python.

Starlark không phải là Python, nên một số khía cạnh của kiểu Python không áp dụng được. Ví dụ: PEP 8 khuyên bạn nên so sánh với các singleton bằng is, đây không phải là toán tử trong Starlark.

Chuỗi tài liệu

Tài liệu về tệp và hàm bằng chuỗi tài liệu. Sử dụng chuỗi tài liệu ở đầu mỗi tệp .bzl và chuỗi tài liệu cho mỗi hàm công khai.

Quy tắc và khía cạnh của tài liệu

Các quy tắc và khía cạnh, cùng với các thuộc tính của chúng, cũng như nhà cung cấp và các trường của chúng, phải được ghi lại bằng đối số doc.

Quy ước đặt tên

  • Các biến và tên hàm sử dụng chữ thường với các từ được phân tách bằng dấu gạch dưới ([a-z][a-z0-9_]*), chẳng hạn như cc_library.
  • Các giá trị riêng tư cấp cao nhất bắt đầu bằng một dấu gạch dưới. Bazel thực thi rằng không thể sử dụng các giá trị riêng tư từ các tệp khác. Biến cục bộ không được sử dụng tiền tố gạch dưới.

Chiều dài dòng

Giống như trong tệp BUILD, không có giới hạn nghiêm ngặt về chiều dài dòng vì nhãn có thể dài. Khi có thể, hãy cố gắng sử dụng tối đa 79 ký tự trên mỗi dòng (theo hướng dẫn về kiểu của Python's style guide, PEP 8). Không nên thực thi nghiêm ngặt nguyên tắc này: trình chỉnh sửa phải hiển thị hơn 80 cột, các thay đổi tự động sẽ thường xuyên tạo ra các dòng dài hơn và con người không nên mất thời gian để chia các dòng đã dễ đọc.

Đối số từ khoá

Trong đối số từ khoá, bạn nên sử dụng dấu cách xung quanh dấu bằng:

def fct(name, srcs):
    filtered_srcs = my_filter(source = srcs)
    native.cc_library(
        name = name,
        srcs = filtered_srcs,
        testonly = True,
    )

Giá trị boolean

Ưu tiên các giá trị TrueFalse (thay vì 10) cho các giá trị boolean (chẳng hạn như khi sử dụng thuộc tính boolean trong một quy tắc).

Không sử dụng hàm print() trong mã sản xuất; hàm này chỉ dành cho việc gỡ lỗi và sẽ gửi thư rác cho tất cả người dùng trực tiếp và gián tiếp của tệp .bzl. Ngoại lệ duy nhất là bạn có thể gửi mã sử dụng print() nếu mã đó bị tắt theo mặc định và chỉ có thể bật bằng cách chỉnh sửa nguồn – ví dụ: nếu tất cả các lần sử dụng print() đều được bảo vệ bằng if DEBUG: trong đó DEBUG được mã hoá cứng thành False. Hãy lưu ý xem các câu lệnh này có đủ hữu ích để biện minh cho tác động của chúng đối với khả năng đọc hay không.

Macro

Macro là một hàm khởi tạo một hoặc nhiều quy tắc trong giai đoạn tải. Nói chung, hãy sử dụng quy tắc bất cứ khi nào có thể thay vì macro. Biểu đồ bản dựng mà người dùng nhìn thấy không giống với biểu đồ mà Bazel sử dụng trong quá trình bản dựng – macro được mở rộng trước khi Bazel phân tích biểu đồ bản dựng.

Do đó, khi có sự cố, người dùng sẽ cần hiểu cách triển khai macro của bạn để khắc phục sự cố bản dựng. Ngoài ra, kết quả bazel query có thể khó diễn giải vì các mục tiêu hiển thị trong kết quả đến từ việc mở rộng macro. Cuối cùng, các khía cạnh không nhận biết được macro, vì vậy, công cụ phụ thuộc vào các khía cạnh (IDE và các công cụ khác) có thể không thành công.

Một cách sử dụng an toàn cho macro là xác định các mục tiêu bổ sung nhằm được tham chiếu trực tiếp tại Bazel CLI hoặc trong tệp BUILD: Trong trường hợp đó, chỉ người dùng cuối của các mục tiêu đó cần biết về chúng và mọi vấn đề về bản dựng do macro gây ra đều không bao giờ xa cách việc sử dụng chúng.

Đối với các macro xác định mục tiêu được tạo (thông tin chi tiết về việc triển khai macro không được tham chiếu tại CLI hoặc phụ thuộc vào các mục tiêu không được khởi tạo bởi macro đó), hãy làm theo các phương pháp hay nhất sau:

  • Macro phải lấy đối số name và xác định mục tiêu có tên đó. Mục tiêu đó trở thành mục tiêu chính của macro đó.
  • Các mục tiêu được tạo, tức là tất cả các mục tiêu khác do macro xác định, phải:
    • Có tên được tiền tố bằng <name> hoặc _<name>. Ví dụ: sử dụng name = '%s_bar' % (name).
    • Có khả năng hiển thị bị hạn chế (//visibility:private) và
    • Có thẻ manual để tránh mở rộng trong các mục tiêu ký tự đại diện (:all, ..., :*, v.v.).
  • name chỉ được dùng để lấy tên của các mục tiêu do macro xác định, chứ không dùng cho bất kỳ mục đích nào khác. Ví dụ: không sử dụng tên để lấy phần phụ thuộc hoặc tệp đầu vào không do chính macro tạo.
  • Tất cả các mục tiêu được tạo trong macro phải được ghép nối theo một cách nào đó với mục tiêu chính.
  • Giữ cho tên tham số trong macro nhất quán. Nếu một tham số được truyền dưới dạng giá trị thuộc tính đến mục tiêu chính, hãy giữ nguyên tên của tham số đó. Nếu tham số macro có cùng mục đích với thuộc tính quy tắc chung, chẳng hạn như deps, hãy đặt tên như bạn đặt tên cho thuộc tính (xem bên dưới).
  • Khi gọi macro, chỉ sử dụng đối số từ khoá. Điều này nhất quán với các quy tắc và cải thiện đáng kể khả năng đọc.

Các kỹ sư thường viết macro khi Starlark API của các quy tắc liên quan không đủ cho trường hợp sử dụng cụ thể của họ, bất kể quy tắc đó được xác định trong Bazel bằng mã gốc hay trong Starlark. Nếu bạn đang gặp phải vấn đề này, hãy hỏi tác giả quy tắc xem họ có thể mở rộng API để đạt được mục tiêu của bạn.

Theo nguyên tắc chung, macro càng giống với các quy tắc thì càng tốt.

Xem thêm macro.

Quy tắc

  • Các quy tắc, khía cạnh và thuộc tính của chúng phải sử dụng tên lower_case ("snake case").
  • Tên quy tắc là danh từ mô tả loại cấu phần phần mềm chính do quy tắc tạo ra, từ quan điểm của các phần phụ thuộc (hoặc đối với các quy tắc lá, người dùng). Đây không nhất thiết là hậu tố tệp. Ví dụ: một quy tắc tạo ra các cấu phần phần mềm C++ nhằm được sử dụng làm tiện ích Python có thể được gọi là py_extension. Đối với hầu hết các ngôn ngữ, các quy tắc điển hình bao gồm:
    • *_library – một đơn vị biên dịch hoặc "mô-đun".
    • *_binary – một mục tiêu tạo ra tệp thực thi hoặc đơn vị triển khai.
    • *_test – một mục tiêu kiểm thử. Mục tiêu này có thể bao gồm nhiều bài kiểm thử. Dự kiến tất cả các bài kiểm thử trong mục tiêu *_test sẽ là các biến thể trên cùng một chủ đề, ví dụ: kiểm thử một thư viện duy nhất.
    • *_import: một mục tiêu đóng gói cấu phần phần mềm được biên dịch sẵn, chẳng hạn như .jar hoặc .dll được sử dụng trong quá trình biên dịch.
  • Sử dụng tên và loại nhất quán cho các thuộc tính. Một số thuộc tính thường áp dụng bao gồm:
    • srcs: label_list, cho phép các tệp: tệp nguồn, thường do con người tạo.
    • deps: label_list, thường không cho phép các tệp: phần phụ thuộc biên dịch.
    • data: label_list, cho phép các tệp: tệp dữ liệu, chẳng hạn như dữ liệu kiểm thử, v.v.
    • runtime_deps: label_list: phần phụ thuộc thời gian chạy không cần thiết cho quá trình biên dịch.
  • Đối với mọi thuộc tính có hành vi không rõ ràng (ví dụ: mẫu chuỗi có các phép thay thế đặc biệt hoặc các công cụ được gọi với các yêu cầu cụ thể ), hãy cung cấp tài liệu bằng đối số từ khoá doc cho khai báo thuộc tính (attr.label_list() hoặc tương tự).
  • Hàm triển khai quy tắc hầu như luôn là hàm riêng tư (được đặt tên bằng dấu gạch dưới ở đầu). Một kiểu phổ biến là đặt tên cho hàm triển khai của myrule_myrule_impl.
  • Truyền thông tin giữa các quy tắc bằng giao diện nhà cung cấp được xác định rõ . Khai báo và ghi lại các trường của nhà cung cấp.
  • Thiết kế quy tắc của bạn theo hướng có thể mở rộng. Hãy cân nhắc rằng các quy tắc khác có thể muốn tương tác với quy tắc của bạn, truy cập vào nhà cung cấp của bạn và sử dụng lại các hành động mà bạn tạo.
  • Tuân theo nguyên tắc về hiệu suất trong các quy tắc của bạn.