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

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 नियम, underlying 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 स्टाइल गाइड में यह तय नहीं किया गया है. हालांकि, इसमें एक जैसा तरीका इस्तेमाल करने का सुझाव दिया गया है. इसलिए, हमने सिर्फ़ डबल कोट वाली स्ट्रिंग का इस्तेमाल करने का फ़ैसला किया है. कई भाषाओं में, स्ट्रिंग लिटरल के लिए डबल कोट का इस्तेमाल किया जाता है.

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