دليل نمط التصميم

يتّبع تنسيق الملفات BUILD النهج نفسه الذي يتبعه تطبيق Go، حيث تتولى أداة موحّدة معظم مشاكل التنسيق. Buildifier هو أداة تحلّل رمز المصدر وتصدره بنمط عادي. لذلك، يتم تنسيق كل ملف BUILD بالطريقة الآلية نفسها، ما يجعل تنسيق المشكلة خاليًا من المشاكل أثناء عمليات مراجعة الرموز. يسهّل هذا الإجراء أيضًا على الأدوات فهم ملفات BUILD وتعديلها وإنشاؤها.

يجب أن يكون تنسيق ملف BUILD مطابقًا لإخراج buildifier.

مثال على التنسيق

# Test code implementing the Foo controller.
package(default_testonly = True)

py_test(
    name = "foo_test",
    srcs = glob(["*.py"]),
    data = [
        "//data/production/foo:startfoo",
        "//foo",
        "//third_party/java/jdk:jdk-k8",
    ],
    flaky = True,
    deps = [
        ":check_bar_lib",
        ":foo_data_check",
        ":pick_foo_port",
        "//pyglib",
        "//testing/pybase",
    ],
)

بنية الملف

الاقتراح: استخدِم الترتيب التالي (كل عنصر اختياري):

  • وصف الحزمة (تعليق)

  • كل كشوفات الحساب load()

  • الدالة package().

  • استدعاءات القواعد ووحدات الماكرو

يفرّق أداة Buildifer بين تعليق مستقل وتعليق مرفق بعنصر. إذا لم يتم إرفاق تعليق بعنصر محدد، استخدم سطرًا فارغًا بعده. والتمييز بينهما مهم عند إجراء تغييرات مبرمَجة (مثل الاحتفاظ بتعليق أو إزالته عند حذف قاعدة).

# Standalone comment (such as to make a section in a file)

# Comment for the cc_library below
cc_library(name = "cc")

مراجع للأهداف في الحزمة الحالية

يجب أن تتم الإشارة إلى الملفات من خلال مساراتها بالنسبة إلى دليل الحزمة (بدون استخدام أي مراجع مرجعية مطلقة، مثل ..). ويجب أن تكون الملفات التي تم إنشاؤها مسبوقة بعلامة ":" للإشارة إلى أنها ليست مصادر. يجب ألا تسبق ملفات المصدر :. يجب أن تسبق القواعد :. على سبيل المثال، بافتراض أن الملف x.cc هو ملف مصدر:

cc_library(
    name = "lib",
    srcs = ["x.cc"],
    hdrs = [":gen_header"],
)

genrule(
    name = "gen_header",
    srcs = [],
    outs = ["x.h"],
    cmd = "echo 'int x();' > $@",
)

تسمية مستهدفة

ويجب أن تكون الأسماء المستهدفة وصفية. إذا كان الهدف يحتوي على ملف مصدر واحد، يجب أن يكون الهدف بشكل عام اسم مشتق من هذا المصدر (على سبيل المثال، يمكن تسمية cc_library للنطاق chat.cc باسم chat، أو java_library في DirectMessage.java بدلاً من direct_message).

يجب أن يوفّر الهدف الذي يحمل الاسم نفسه لحزمة (الوجهة التي تحمل الاسم نفسه لدليل الدليل) الوظائف التي يصفها اسم الدليل. وإذا لم يكن هناك مثل هذا الاستهداف، لا تنشئ استهدافًا متماثلاً.

أفضّل استخدام الاسم المختصر عند الإشارة إلى استهداف يحمل الاسم نفسه (//x بدلاً من //x:x). إذا كنت تستخدم الحزمة نفسها، ننصحك باستخدام المرجع المحلي (:x بدلاً من //x).

تجنّب استخدام &"محجوزة"أسماء هدف ذات معنى خاص. ويشمل ذلك all و__pkg__ و__subpackages__، وتحمل هذه الأسماء دلالاتً خاصةً، ويمكن أن تتسبب في حدوث التباس وسلوكيات غير متوقعة عند استخدامها.

وفي حال عدم توفّر أي اصطلاح سابق للفِرق، إليك بعض الاقتراحات غير المُلزِمة التي يتم استخدامها على نطاق واسع في Google:

  • بوجه عام، استخدِم "snake_case"
    • بالنسبة إلى java_library باستخدام واحد src، هذا يعني استخدام اسم ليس مطابقًا لاسم الملف بدون الامتداد
    • بالنسبة إلى قاعدتي Java *_binary و*_test، استخدِم "Upper CamelCase". يسمح ذلك للاسم المستهدَف بأن يتطابق مع أحد src. بالنسبة إلى java_test، يمكن أن يتم استنتاج السمة test_class من اسم الهدف.
  • إذا كانت هناك صيغ متعددة لاستهداف معيّن، أضِف لاحقة لتمييزها (مثل :foo_dev أو :foo_prod أو :bar_x86، :bar_x64)
  • اللاحقة _test المستهدفة باستخدام _test أو _unittest أو Test أو Tests
  • تجنَّب لاحقات لا معنى لها، مثل _lib أو _library (ما لم يكن ذلك ضروريًا لتجنُّب أي تعارضات بين هدف _library و_binary المقابل له)
  • بالنسبة إلى الاستهدافات ذات الصلة بالنموذج الأولي:
    • يجب أن تحتوي أسماء proto_library المستهدفة على أسماء تنتهي بالأرقام _proto
    • يجب أن تتطابق قواعد *_proto_library الخاصة بلغات معيّنة مع البروتوكول الأساسي، ولكن يجب استبدال _proto بلاحقة لغة معيّنة، على سبيل المثال:
      • cc_proto_library: _cc_proto
      • java_proto_library: _java_proto
      • java_lite_proto_library: _java_proto_lite

مستوى العرض

يجب أن يكون نطاق الرؤية محدودًا قدر الإمكان، مع السماح في الوقت نفسه بالوصول عن طريق الاختبارات والاعتماديات العكسية. استخدِم __pkg__ و__subpackages__ على النحو المناسب.

تجنَّب ضبط الحزمة default_visibility على //visibility:public. يجب ضبط //visibility:public بشكل فردي فقط للأهداف في واجهة برمجة التطبيقات الخاصة بالمشروع. قد تكون هذه المكتبات المصممة للاعتماد عليها في المشاريع الثنائية أو البرامج الثنائية التي يمكن استخدامها في مشروع إنشاء خارجي.

المهام التابعة

يجب أن تقتصر المهام التابعة على التبعيات المباشرة (الاعتماديات التي تحتاج إليها المصادر المدرجة في القاعدة). لا تُدرِج العناصر التابعة.

يجب إدراج التبعيات المحلية للحزمة أولاً والإشارة إليها بطريقة متوافقة مع القسم المراجع المستهدفة في الحزمة الحالية أعلاه (وليس حسب اسم الحزمة المطلقة).

أفضِّل إدراج التبعيات مباشرةً كقائمة واحدة. يؤدي وضع عامل التشغيل "common" بعدة أهداف متعددة في متغيّر إلى تقليل قابلية الحفاظ عليه، ويجعل من الصعب على الأدوات تغيير تبعيات الهدف، ويمكن أن يؤدي إلى تبعيات غير مستخدَمة.

كرات أرضية

الإشارة إلى "لا أهداف&quot& مع []. لا تستخدم الكرة الأرضية التي لا تتطابق مع أي شيء: فهي أكثر عرضة للخطأ وأقل وضوحًا من القائمة الفارغة.

متكرر

لا تستخدِم الكرات متكرّرة لمطابقة الملفات المصدر (مثل glob(["**/*.java"])).

تجعل الملفات العاكسة المتكررة الملفات BUILD مهمة يصعُب الإجابة عنها لأنّها تتخطّى الأدلة الفرعية التي تحتوي على ملفات BUILD.

تكون الكرات الغنائية المتكررة أقل فعالية بشكل عام من توفّر ملف BUILD لكل دليل مع رسم بياني للاعتمادية يحدده، ما يتيح إمكانية التخزين المؤقت عن بُعد والتوازي.

من المفيد كتابة ملف BUILD في كل دليل وتحديد رسم بياني تابع له.

غير متكرر

وتكون الكرات غير المتكرّرة مقبولاً بشكل عام.

اصطلاحات أخرى

  • استخدِم الأحرف الكبيرة والشرطات السفلية للثوابت (مثل GLOBAL_CONSTANT) واستخدِم الأحرف الصغيرة والشرطات السفلية لتعريف المتغيرات (مثل my_variable).

  • يجب عدم تقسيم التصنيفات مطلقًا، حتى إذا كانت أطول من 79 حرفًا. يجب أن تكون التصنيفات عبارة عن سلاسل حرفية كلما أمكن ذلك. الأسباب: تُسهّل هذه الميزة العثور عليها واستبدالها. كما يحسِّن مستوى سهولة القراءة.

  • يجب أن تكون قيمة سمة الاسم سلسلة ثابتة حرفية (باستثناء وحدات الماكرو). الأسباب: تستخدم الأدوات الخارجية سمة الاسم لإحالة قاعدة. وهم بحاجة إلى العثور على قواعد بدون الحاجة إلى تفسير الرمز.

  • عند ضبط سمات النوع المنطقي، استخدِم القيم المنطقية، وليس القيم الصحيحة. لأسباب قديمة، لا تزال القواعد تحوّل الأرقام الصحيحة إلى قيم منطقية حسب الحاجة، لكن لا ننصح بذلك. الأسباب: قد يُخطئ flaky = 1 في قول أنّه &quot:قلِّل هذا الهدف من خلال إعادة تشغيله مرة واحدة&quot. يقول flaky = True بوضوح

الاختلافات مع دليل أسلوب Python

على الرغم من أن التوافق مع دليل أسلوب Python هو هدف، إلا أنّ هناك بعض الاختلافات:

  • ليس هناك حد أقصى لطول السطر. غالبًا ما يتم تقسيم التعليقات الطويلة والسلاسل الطويلة إلى 79 عمودًا، ولكنها ليست مطلوبة. ويجب ألا يتم فرضه على مراجعات الرموز أو النصوص البرمجية قبل الإرسال. الأسباب: يمكن أن تكون التصنيفات طويلة وتتجاوز هذا الحد. من الشائع أن يتم إنشاء ملفات BUILD أو تعديلها باستخدام أدوات، وذلك لا يتوافق مع حدّ طول السطر.

  • تسلسل السلسلة الضمني غير متاح. يمكنك استخدام عامل التشغيل +. الأسباب: تحتوي ملفات BUILD على العديد من قوائم السلاسل. من السهل حذف الفاصلة، التي تؤدي إلى نتيجة مختلفة تمامًا. وقد أدى ذلك إلى حدوث العديد من الأخطاء في الماضي. الاطّلاع أيضًا على هذه المناقشة

  • استخدم المسافات حول العلامة = لوسيطات الكلمات الرئيسية في القواعد. الأسباب: الوسيطات المُعنونة أكثر تكرارًا من Python وتكون دائمًا في سطر منفصل. تسهم مساحات العمل في تحسين إمكانية القراءة. تم استخدام هذه الاتفاقية منذ وقت طويل، ولا يستحق تعديل جميع ملفات BUILD الحالية.

  • حسب الإعدادات التلقائية، يمكنك استخدام علامات الاقتباس المزدوجة للسلاسل. الأسباب: لم يتم تحديد ذلك في دليل نمط Python، ولكنه يقترح الاتّساق. لذلك، قررنا استخدام سلاسل ذات علامات اقتباس فقط. تستخدم العديد من اللغات علامات الاقتباس المزدوجة للحرف اليدوية للسلسلة.

  • استخدِم سطرًا فارغًا واحدًا بين تعريفَين على المستوى الأعلى. الأسباب: لا تشبه بنية ملف BUILD ملف Python العادي. يتضمّن فقط كيانات المستوى الأعلى. يؤدي استخدام سطر واحد فارغ إلى اختصار BUILD ملف.