DAMP BUILD dosyalarını DRY dosyalarına tercih et
"Kendini Tekrar Etme" (DRY) ilkesi, kodda gereksiz tekrarları önlemek için değişkenler ve işlevler gibi soyutlamalar sunarak benzersizliği teşvik eder.
Buna karşılık, "Açıklayıcı ve Anlamlı İfadeler" anlamına gelen DAMP ilkesi, dosyaların daha kolay anlaşılması ve korunması için okunabilirliği benzersizliğe tercih eder.
BUILD
dosyaları kod değil, yapılandırmadır. Bunlar kod gibi test edilmez ancak insanlar ve araçlar tarafından korunması gerekir. Bu nedenle DAMP, DRY'den daha iyi bir seçenektir.
BUILD.bazel dosya biçimlendirmesi
BUILD
dosya biçimlendirmesi, standartlaştırılmış bir aracın çoğu biçimlendirme sorununu ele aldığı Go ile aynı yaklaşımı izler.
Buildifier, kaynak kodu ayrıştırıp standart bir stilde yayınlayan bir araçtır. Bu nedenle, her BUILD
dosyası aynı otomatik şekilde biçimlendirilir. Böylece, biçimlendirme işlemi kod incelemeleri sırasında sorun oluşturmaz. Ayrıca araçların BUILD
dosyalarını anlamasını, düzenlemesini ve oluşturmasını da kolaylaştırır.
BUILD
dosya biçimi, buildifier
çıkışıyla eşleşmelidir.
Biçimlendirme örneği
# 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",
],
)
Dosya yapısı
Öneri: Aşağıdaki sırayı kullanın (her öğe isteğe bağlıdır):
Paket açıklaması (yorum)
Tüm
load()
ekstreleripackage()
işlevi.Kurallara ve makrolara yapılan çağrılar
Buildifier, bağımsız yorum ile bir öğeye eklenmiş yorum arasında ayrım yapar. Bir yorum belirli bir öğeye eklenmemişse yorumdan sonra boş bir satır kullanın. Otomatik değişiklikler yaparken (ör. bir kuralı silerken yorumu tutmak veya kaldırmak) bu ayrım önemlidir.
# Standalone comment (such as to make a section in a file)
# Comment for the cc_library below
cc_library(name = "cc")
Geçerli paketteki hedeflere yapılan referanslar
Dosyalara, paket dizinine göre yollarıyla (..
gibi yukarı referanslar kullanılmadan) başvurulmalıdır. Oluşturulan dosyalar, kaynak olmadıklarını belirtmek için ":
" ile öneklenmelidir. Kaynak dosyaların başına :
eklenmemelidir. Kuralların önüne :
eklenmelidir. Örneğin, x.cc
dosyasının kaynak dosya olduğunu varsayarsak:
cc_library(
name = "lib",
srcs = ["x.cc"],
hdrs = [":gen_header"],
)
genrule(
name = "gen_header",
srcs = [],
outs = ["x.h"],
cmd = "echo 'int x();' > $@",
)
Hedef adlandırma
Hedef adları açıklayıcı olmalıdır. Bir hedef tek bir kaynak dosyası içeriyorsa hedef genellikle bu kaynaktan türetilmiş bir ada sahip olmalıdır (örneğin, chat.cc
için cc_library
, chat
olarak adlandırılabilir veya DirectMessage.java
için java_library
, direct_message
olarak adlandırılabilir).
Bir paketin adaş hedefi (içeren dizinle aynı ada sahip hedef), dizin adıyla açıklanan işlevselliği sağlamalıdır. Böyle bir hedef yoksa aynı adlı bir hedef oluşturmayın.
Adını taşıyan bir hedefi belirtirken kısa adı kullanın (//x
yerine //x:x
). Aynı paketteyseniz yerel referansı (:x
yerine //x
) kullanın.
Özel anlamı olan "ayrılmış" hedef adları kullanmaktan kaçının. all
, __pkg__
ve __subpackages__
gibi adlar özel semantiğe sahiptir ve kullanıldıklarında kafa karışıklığına ve beklenmedik davranışlara neden olabilir.
Geçerli bir ekip kuralı yoksa bunlar Google'da yaygın olarak kullanılan, bağlayıcı olmayan bazı önerilerdir:
- Genel olarak "snake_case" kullanın.
- Bir
java_library
için bu, uzantısız dosya adıyla aynı olmayan bir ad kullanmak anlamına gelir.src
- Java
*_binary
ve*_test
kuralları için "Upper CamelCase" kullanın. Bu, hedef adınınsrc
'lardan biriyle eşleşmesini sağlar.java_test
için bu,test_class
özelliğinin hedefin adından çıkarılmasını sağlar.
- Bir
- Belirli bir hedefin birden fazla varyantı varsa ayırt etmek için bir sonek ekleyin (ör.
:foo_dev
,:foo_prod
veya:bar_x86
,:bar_x64
) _test
hedeflerine_test
,_unittest
,Test
veyaTests
ekleyin_lib
veya_library
gibi anlamsız eklerden kaçının (_library
hedefi ile karşılık gelen_binary
arasındaki çakışmaları önlemek için gerekli olmadığı sürece)- Proto ile ilgili hedefler için:
proto_library
hedeflerinin adları_proto
ile bitmelidir- Dile özgü
*_proto_library
kuralları, temel protokolle eşleşmeli ancak_proto
, dile özgü bir sonek ile değiştirilmelidir. Örneğin:cc_proto_library
:_cc_proto
java_proto_library
:_java_proto
java_lite_proto_library
:_java_proto_lite
Görünürlük
Görünürlük, testler ve ters bağımlılıklar tarafından erişime izin verecek şekilde mümkün olduğunca dar kapsamlı olmalıdır. Uygun şekilde __pkg__
ve __subpackages__
özelliğini kullanın.
default_visibility
paketini //visibility:public
olarak ayarlamaktan kaçının.
//visibility:public
yalnızca projenin herkese açık API'sindeki hedefler için ayrı ayrı ayarlanmalıdır. Bunlar, harici projelerin bağımlı olması için tasarlanmış kitaplıklar veya harici bir projenin derleme sürecinde kullanılabilecek ikili dosyalar olabilir.
Bağımlılıklar
Bağımlılıklar doğrudan bağımlılıklarla (kuralda listelenen kaynaklar için gereken bağımlılıklar) sınırlı olmalıdır. Geçişli bağımlılıkları listelemeyin.
Pakete özel bağımlılıklar önce listelenmeli ve yukarıdaki References to targets in the current package (Mevcut paketteki hedeflere referanslar) bölümüyle uyumlu bir şekilde (mutlak paket adlarıyla değil) ele alınmalıdır.
Bağımlılıkları tek bir liste olarak doğrudan listelemeyi tercih edin. Çeşitli hedeflerin "ortak" bağımlılıklarını bir değişkene yerleştirmek, sürdürülebilirliği azaltır, araçların bir hedefin bağımlılıklarını değiştirmesini imkansız hâle getirir ve kullanılmayan bağımlılıklara yol açabilir.
Globs
[]
ile "hedef yok" ifadesini belirtin. Hiçbir şeyle eşleşmeyen bir glob kullanmayın. Bu, boş bir listeden daha fazla hataya neden olur ve daha az belirgindir.
Yinelemeli
Kaynak dosyaları eşleştirmek için yinelemeli glob'lar kullanmayın (örneğin, glob(["**/*.java"])
).
Yinelemeli glob'lar, BUILD
dosyalarını içeren alt dizinleri atladıkları için BUILD
dosyaları hakkında akıl yürütmeyi zorlaştırır.
Özyinelemeli globlar, genellikle dizin başına bir BUILD
dosyası oluşturmaktan daha az verimlidir. Bu dosyalarda, daha iyi uzaktan önbelleğe alma ve paralellik sağlayan bir bağımlılık grafiği tanımlanır.
Her dizinde bir BUILD
dosyası oluşturmak ve bunlar arasında bir bağımlılık grafiği tanımlamak iyi bir uygulamadır.
Özyinelemeli olmayan
Genel olarak, özyinelemeli olmayan glob'lar kabul edilebilir.
Liste kavrayışlarından kaçının
BUILD.bazel
dosyasının üst düzeyinde liste kavrayışlarını kullanmaktan kaçının.
Her bir adlandırılmış hedefi ayrı bir üst düzey kural veya makro çağrısıyla oluşturarak tekrarlayan çağrıları otomatikleştirin. Anlaşılır olması için her birine kısa bir name
parametresi verin.
Liste kavrama, aşağıdakileri azaltır:
- Bakım yapılabilirlik. İnsan bakıcıların ve büyük ölçekli otomatik değişikliklerin liste kapsamlarını doğru şekilde güncellemesi zor veya imkansızdır.
- Bulunabilirlik. Kalıpta
name
parametresi olmadığından kuralı ada göre bulmak zordur.
Liste kavrama kalıbının yaygın bir uygulaması, test oluşturmaktır. Örneğin:
[[java_test(
name = "test_%s_%s" % (backend, count),
srcs = [ ... ],
deps = [ ... ],
...
) for backend in [
"fake",
"mock",
]] for count in [
1,
10,
]]
Daha basit alternatifler kullanmanızı öneririz. Örneğin, bir test oluşturan bir makro tanımlayın ve bunu her üst düzey name
için çağırın:
my_java_test(name = "test_fake_1",
...)
my_java_test(name = "test_fake_10",
...)
...
deps değişkenlerini kullanmayın
Ortak bağımlılıkları kapsüllemek için liste değişkenleri kullanmayın:
COMMON_DEPS = [
"//d:e",
"//x/y:z",
]
cc_library(name = "a",
srcs = ["a.cc"],
deps = COMMON_DEPS + [ ... ],
)
cc_library(name = "b",
srcs = ["b.cc"],
deps = COMMON_DEPS + [ ... ],
)
Benzer şekilde, bağımlılıkları gruplandırmak için exports
ile bir kitaplık hedefi kullanmayın.
Bunun yerine, her hedef için bağımlılıkları ayrı ayrı listeleyin:
cc_library(name = "a",
srcs = ["a.cc"],
deps = [
"//a:b",
"//x/y:z",
...
],
)
cc_library(name = "b",
srcs = ["b.cc"],
deps = [
"//a:b",
"//x/y:z",
...
],
)
Gazelle ve diğer araçların bunları korumasına izin verin. Tekrarlar olabilir ancak bağımlılıkları nasıl yöneteceğinizi düşünmeniz gerekmez.
Tam anlamıyla dizeleri tercih et
Starlark, birleştirme (+
) ve biçimlendirme (%
) için dize operatörleri sağlasa da bunları dikkatli kullanın. İfadeleri daha kısa hale getirmek veya uzun satırları bölmek için ortak dize bölümlerini ayırmak cazip gelebilir. Ancak,
Parçalanmış dize değerlerini bir bakışta okumak daha zordur.
Buildozer ve Code Search gibi otomatik araçlar, değerler bölündüğünde değerleri bulmakta ve doğru şekilde güncellemekte zorlanır.
BUILD
dosyalarında okunabilirlik, tekrardan kaçınmaktan daha önemlidir (DAMP ve DRY karşılaştırmasına bakın).Bu Stil Kılavuzu, etiket değerli dizelerin bölünmesine karşı uyarıda bulunur ve uzun satırlara açıkça izin verir.
Buildifier, birleştirilmiş dizelerin etiket olduğunu algıladığında bunları otomatik olarak birleştirir.
Bu nedenle, özellikle name
ve deps
gibi etiket türü özelliklerde birleştirilmiş veya biçimlendirilmiş dizeler yerine açık ve tam dizeleri tercih edin. Örneğin, şu BUILD
parçası:
NAME = "foo"
PACKAGE = "//a/b"
proto_library(
name = "%s_proto" % NAME,
deps = [PACKAGE + ":other_proto"],
alt_dep = "//surprisingly/long/chain/of/package/names:" +
"extravagantly_long_target_name",
)
daha iyi bir şekilde şu şekilde yeniden yazılabilir:
proto_library(
name = "foo_proto",
deps = ["//a/b:other_proto"],
alt_dep = "//surprisingly/long/chain/of/package/names:extravagantly_long_target_name",
)
Her .bzl
dosyası tarafından dışa aktarılan sembolleri sınırlama
Her genel .bzl
(Starlark) dosyası tarafından dışa aktarılan sembol (kural, makro, sabit, işlev) sayısını en aza indirin. Bir dosyanın yalnızca birlikte kullanılacağından emin olunan birden fazla sembolü dışa aktarması önerilir. Aksi takdirde, her biri kendi bzl_library'sine sahip olacak şekilde birden fazla .bzl
dosyasına bölün.
Aşırı sembol kullanımı, .bzl
dosyalarının geniş sembol "kitaplıklarına" dönüşmesine neden olabilir. Bu da tek bir dosyada yapılan değişikliklerin Bazel'in birçok hedefi yeniden oluşturmasına yol açar.
Diğer kurallar
Sabitleri (ör.
GLOBAL_CONSTANT
) tanımlamak için büyük harf ve alt çizgi, değişkenleri (ör.my_variable
) tanımlamak için küçük harf ve alt çizgi kullanın.Etiketler 79 karakterden uzun olsa bile asla bölünmemelidir. Etiketler mümkün olduğunda dize değişmezleri olmalıdır. Gerekçe: Bul ve değiştir işlemini kolaylaştırır. Ayrıca okunabilirliği de artırır.
Ad özelliğinin değeri, değişmez bir sabit dize olmalıdır (makrolar hariç). Gerekçe: Harici araçlar, bir kurala başvurmak için ad özelliğini kullanır. Kullanıcıların, kodu yorumlamadan kuralları bulması gerekir.
Boole türü özellikler ayarlanırken tam sayı değerleri değil, Boole değerleri kullanın. Eski nedenlerden dolayı kurallar, gerektiğinde tam sayıları hâlâ boole değerlerine dönüştürmektedir ancak bu durum önerilmez. Gerekçe:
flaky = 1
, "Bu hedefi bir kez daha çalıştırarak temizle" şeklinde yanlış okunabilir.flaky = True
, "bu test güvenilir değil" ifadesini net bir şekilde belirtiyor.
Python stil kılavuzuyla farklılıklar
Python stil kılavuzu ile uyumluluk hedefimiz olsa da birkaç fark vardır:
Kesin bir satır uzunluğu sınırı yoktur. Uzun yorumlar ve uzun dizeler genellikle 79 sütuna bölünür ancak bu zorunlu değildir. Kod incelemelerinde veya göndermeden önce çalıştırılan komut dosyalarında zorunlu tutulmamalıdır. Gerekçe: Etiketler uzun olabilir ve bu sınırı aşabilir.
BUILD
dosyalarının araçlar tarafından oluşturulması veya düzenlenmesi yaygın bir durumdur. Bu durum, satır uzunluğu sınırı ile iyi gitmez.Örtülü dize birleştirme desteklenmez.
+
operatörünü kullanın. Gerekçe:BUILD
dosyaları birçok dize listesi içeriyor. Virgülün unutulması kolaydır ve bu da tamamen farklı bir sonuç verir. Bu durum geçmişte birçok hataya neden oldu. Bu tartışmaya da göz atın.Kurallardaki anahtar kelime bağımsız değişkenleri için
=
işaretinin etrafında boşluk kullanın. Gerekçe: Adlandırılmış bağımsız değişkenler, Python'da olduğundan çok daha sık kullanılır ve her zaman ayrı bir satırda yer alır. Boşluklar okunabilirliği artırır. Bu kural uzun süredir kullanılmaktadır ve mevcut tümBUILD
dosyalarını değiştirmeye değmez.Varsayılan olarak dizeler için çift tırnak işareti kullanın. Gerekçe: Bu, Python stil kılavuzunda belirtilmemiştir ancak tutarlılık önerilir. Bu nedenle, yalnızca çift tırnaklı dizeler kullanmaya karar verdik. Birçok dilde, dize değişmezleri için çift tırnak kullanılır.
İki üst düzey tanım arasında tek bir boş satır kullanın. Gerekçe:
BUILD
dosyasının yapısı, normal bir Python dosyasına benzemez. Yalnızca üst düzey ifadeler içerir. Tek bir boş satır kullanmakBUILD
dosyalarını kısaltır.