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

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

डिपेंडेंसी

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

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

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

ग्लोब

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

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

सोर्स फ़ाइलों से मैच करने के लिए, बार-बार होने वाले ग्लोब का इस्तेमाल न करें. जैसे, 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 फ़ाइलें छोटी हो जाती हैं.