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

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();' > $@",
)

टारगेट का नाम

टारगेट के नामों में पूरी जानकारी होनी चाहिए. अगर टारगेट में एक सोर्स फ़ाइल है, तो आम तौर पर टारगेट का नाम उस सोर्स से लिया गया होना चाहिए (उदाहरण के लिए, chat.cc के लिए cc_library का नाम chat या DirectMessage.java के लिए java_library का नाम 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, _unittest, Test या Tests वाले सफ़िक्स _test टारगेट
  • _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 फ़ाइलों में कई स्ट्रिंग की सूचियां होती हैं. एक कॉमा को भूलना आसान है, जो एक अलग परिणाम देता है. इस गड़बड़ी की वजह से, पहले कई गड़बड़ियां हुई हैं. यह चर्चा भी देखें.

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

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

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