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

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 से जुड़े टारगेट के लिए:
    • proto_library टारगेट के नाम, _proto पर खत्म होने चाहिए
    • भाषा के हिसाब से *_proto_library नियम, proto से मेल खाने चाहिए. हालांकि, _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 स्टाइल गाइड में यह तय नहीं किया गया है. हालांकि, इसमें एक जैसा फ़ॉर्मैट इस्तेमाल करने का सुझाव दिया गया है. इसलिए, हमने सिर्फ़ डबल कोट वाली स्ट्रिंग का इस्तेमाल करने का फ़ैसला किया है. कई भाषाओं में स्ट्रिंग लिटरल के लिए डबल कोट का इस्तेमाल किया जाता है.

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