स्टाइल गाइड बनाएं

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() फ़ंक्शन.

  • नियमों और मैक्रो के लिए कॉल

Buildifier, स्टैंडअलोन टिप्पणी और किसी एलिमेंट से जुड़ी टिप्पणी के बीच अंतर करता है. अगर कोई टिप्पणी किसी खास एलिमेंट से जुड़ी नहीं है, तो उसके बाद एक खाली लाइन का इस्तेमाल करें. ऑटोमैटिक तरीके से बदलाव करते समय, यह अंतर ज़रूरी होता है. उदाहरण के लिए, किसी नियम को मिटाते समय टिप्पणी को बनाए रखना या हटाना.

# 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 से जुड़े टारगेट के लिए:
    • 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 को सिर्फ़ प्रोजेक्ट के सार्वजनिक एपीआई में मौजूद टारगेट के लिए सेट किया जाना चाहिए. ये ऐसी लाइब्रेरी हो सकती हैं जिन पर बाहरी प्रोजेक्ट डिपेंड कर सकते हैं या ऐसे बाइनरी हो सकते हैं जिनका इस्तेमाल बाहरी प्रोजेक्ट के बिल्ड प्रोसेस में किया जा सकता है.

डिपेंडेंसी

डिपेंडेंसी को सीधे तौर पर डिपेंडेंसी तक सीमित रखें. यानी, उन डिपेंडेंसी तक जिनकी ज़रूरत नियम में शामिल सोर्स को होती है. ट्रांज़िटिव डिपेंडेंसी की सूची न बनाएं.

पैकेज-लोकल डिपेंडेंसी को सबसे पहले शामिल किया जाना चाहिए. साथ ही, उन्हें ऊपर दिए गए मौजूदा पैकेज में टारगेट के रेफ़रंस सेक्शन के मुताबिक रेफ़र किया जाना चाहिए. न कि उनके ऐब्सलूट पैकेज नेम से.

डिपेंडेंसी को सीधे तौर पर, एक सूची के तौर पर शामिल करें. कई टारगेट की "सामान्य" डिपेंडेंसी को किसी वैरिएबल में रखने से, मेंटेन करने में मुश्किल होती है. साथ ही, टूल के लिए किसी टारगेट की डिपेंडेंसी में बदलाव करना मुमकिन नहीं होता. इसके अलावा, ऐसी डिपेंडेंसी भी हो सकती हैं जिनका इस्तेमाल न किया जा रहा हो.

ग्लोब

[] से "कोई टारगेट नहीं" दिखाएं. ऐसे ग्लोब का इस्तेमाल न करें जो किसी भी चीज़ से मेल न खाता हो. यह खाली सूची के मुकाबले, ज़्यादा गड़बड़ी वाला और कम साफ़ होता है.

बार-बार होने वाला

सोर्स फ़ाइलों से मेल खाने के लिए, बार-बार होने वाले ग्लोब का इस्तेमाल न करें. जैसे, glob(["**/*.java"]).

बार-बार होने वाले ग्लोब की वजह से, BUILD फ़ाइलों के बारे में तर्क देना मुश्किल हो जाता है, क्योंकि ये BUILD फ़ाइलों वाली सब-डायरेक्ट्री को छोड़ देते हैं.

आम तौर पर, बार-बार होने वाले ग्लोब, हर डायरेक्ट्री के लिए BUILD फ़ाइल के मुकाबले कम कारगर होते हैं. साथ ही, इनके बीच डिपेंडेंसी ग्राफ़ तय किया जाता है. ऐसा इसलिए, क्योंकि इससे बेहतर रिमोट कैशिंग और पैरललिज़म की सुविधा मिलती है.

हर डायरेक्ट्री में BUILD फ़ाइल बनाना और उनके बीच डिपेंडेंसी ग्राफ़ तय करना एक अच्छी प्रैक्टिस है.

बार-बार न होने वाला

आम तौर पर, बार-बार न होने वाले ग्लोब स्वीकार किए जाते हैं.

अन्य तरीके

  • कॉन्स्टैंट तय करने के लिए, अपरकेस और अंडरस्कोर का इस्तेमाल करें. जैसे, GLOBAL_CONSTANT. वैरिएबल तय करने के लिए, लोअरकेस और अंडरस्कोर का इस्तेमाल करें. जैसे, my_variable.

  • लेबल को कभी भी अलग-अलग हिस्सों में न बांटें. भले ही, वे 79 वर्णों से ज़्यादा लंबे हों. लेबल, स्ट्रिंग लिटरल होने चाहिए. वजह: इससे, ढूंढना और बदलना आसान हो जाता है. इससे, कॉन्टेंट को बेहतर ढंग से पढ़ा जा सकता है.

  • नाम एट्रिब्यूट की वैल्यू, लिटरल कॉन्स्टैंट स्ट्रिंग होनी चाहिए. हालांकि, मैक्रो में ऐसा नहीं है. वजह: बाहरी टूल, किसी नियम को रेफ़र करने के लिए, नाम एट्रिब्यूट का इस्तेमाल करते हैं. उन्हें कोड को समझने के बिना ही नियम ढूंढने होते हैं.

  • बूलियन-टाइप एट्रिब्यूट सेट करते समय, बूलियन वैल्यू का इस्तेमाल करें. न कि इंटिजर वैल्यू का. लेगसी की वजह से, नियम अब भी ज़रूरत के हिसाब से इंटिजर को बूलियन में बदलते हैं. हालांकि, ऐसा न करने का सुझाव दिया जाता है. वजह: flaky = 1 को गलत तरीके से "इसे एक बार फिर से चलाकर, इस टारगेट को डिफ़्लेक करें" के तौर पर पढ़ा जा सकता है. flaky = True से साफ़ तौर पर पता चलता है कि "यह टेस्ट फ़्लेकी है".

Python स्टाइल गाइड के मुकाबले अंतर

हालांकि, Python स्टाइल गाइड के साथ काम करने की सुविधा एक लक्ष्य है, लेकिन इसमें कुछ अंतर हैं:

  • लाइन की लंबाई की कोई सख्त सीमा नहीं है. आम तौर पर, लंबे कमेंट और लंबी स्ट्रिंग को 79 कॉलम में बांटा जाता है. हालांकि, ऐसा करना ज़रूरी नहीं है. इसे कोड की समीक्षा या प्रीसबमिट स्क्रिप्ट में लागू नहीं किया जाना चाहिए. वजह: लेबल लंबे हो सकते हैं और इस सीमा से ज़्यादा हो सकते हैं. आम तौर पर, BUILD फ़ाइलें टूल से जनरेट या उनमें बदलाव किए जाते हैं. ऐसे में, लाइन की लंबाई की सीमा लागू करना सही नहीं है.

  • स्ट्रिंग को अपने-आप जोड़ने की सुविधा काम नहीं करती. + ऑपरेटर का इस्तेमाल करें. वजह: BUILD फ़ाइलों में स्ट्रिंग की कई सूचियां होती हैं. कॉमा लगाना भूल जाना आम बात है. इससे, पूरी तरह से अलग नतीजा मिलता है. इससे, पहले भी कई गड़बड़ियां हुई हैं. यह बातचीत भी देखें.

  • नियमों में कीवर्ड आर्ग्युमेंट के लिए, = साइन के आस-पास स्पेस का इस्तेमाल करें. वजह: Python के मुकाबले, नाम वाले आर्ग्युमेंट ज़्यादा बार इस्तेमाल किए जाते हैं. साथ ही, ये हमेशा अलग लाइन में होते हैं. स्पेस से, कॉन्टेंट को बेहतर ढंग से पढ़ा जा सकता है. यह तरीका लंबे समय से इस्तेमाल किया जा रहा है. इसलिए, मौजूदा सभी BUILD फ़ाइलों में बदलाव करना सही नहीं है.

  • डिफ़ॉल्ट रूप से, स्ट्रिंग के लिए डबल कोटेशन मार्क का इस्तेमाल करें. वजह: Python स्टाइल गाइड में यह तय नहीं किया गया है. हालांकि, इसमें एक जैसा तरीका इस्तेमाल करने का सुझाव दिया गया है. इसलिए, हमने सिर्फ़ डबल कोट वाली स्ट्रिंग का इस्तेमाल करने का फ़ैसला किया है. कई भाषाओं में, स्ट्रिंग लिटरल के लिए डबल कोट का इस्तेमाल किया जाता है.

  • टॉप-लेवल की दो परिभाषाओं के बीच, एक खाली लाइन का इस्तेमाल करें. वजह: फ़ाइल का स्ट्रक्चर, आम तौर पर Python फ़ाइल जैसा नहीं होता.BUILD इसमें सिर्फ़ टॉप-लेवल स्टेटमेंट होते हैं. एक खाली लाइन का इस्तेमाल करने से, BUILD फ़ाइलें छोटी हो जाती हैं.