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

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_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 फ़ाइलें छोटी हो जाती हैं.