Önceki sayfalara bakarken bir tema tekrar tekrar geçiyor: "yönetmek" kodunuz oldukça basittir, ancak onun bağımlılıklarını yönetmek daha zor olabilir. Çeşitli bağımlılık türleri vardır: Bazen bir göreve (ör. "Sürümün tamamlandığını işaretlemeden önce dokümanları gönderin") bazen de bir yapıya (ör. "Kodu derlemek için bilgisayar görüşü kitaplığının en son sürümüne sahip olmam gerekiyor") bağımlılık vardır. Bazen kod tabanınızın başka bir bölümüne, bazen de başka bir ekibin (kuruluşunuzda veya üçüncü taraf) sahip olduğu kod veya verilere harici bağımlılıklarınız vardır. Ama her halükarda, “Ben buna ihtiyaç duydum.” sözleriyle sürekli olarak karşılaşıyoruz. ve bağımlılıkları yönetmek muhtemelen en önemli temel işi olabilir.
Modüller ve Bağımlılıkları Ele Alma
Bazel gibi yapıya dayalı derleme sistemleri kullanan projeler, bir dizi modüle ayrılır. Bu modüller, BUILD
dosyaları aracılığıyla birbirlerine olan bağımlılıkları ifade eder. Bu modüllerin ve bağımlılıkların doğru şekilde düzenlenmesi hem derleme sisteminin performansı hem de sürdürülmesi için gereken iş yükü üzerinde büyük bir etkiye sahip olabilir.
Ayrıntılı Modülleri ve 1:1:1 Kuralını Kullanma
Yapıya dayalı bir derleme oluştururken ilk soru, tek bir modülün ne kadar işlev içermesi gerektiğine karar vermektir. Bazel'de modüller, java_library
veya go_binary
gibi derlenebilir bir birimi belirten bir hedefle temsil edilir. Bir uç noktada, köke bir BUILD
dosyası yerleştirilerek ve söz konusu projenin tüm kaynak dosyaları yinelemeli olarak gruplandırılarak projenin tamamı tek bir modüle dahil edilebilir. Diğer taraftan
neredeyse her kaynak dosya kendi modülüne dönüştürülebilirdi ve bu nedenle
her dosyanın, bağlı olduğu diğer tüm dosyalarda BUILD
dosyasında listelenmesi gerekir.
Çoğu proje bu iki uç nokta arasında bir yerdedir ve seçim, performans ile sürdürülebilirlik arasında bir denge kurmayı gerektirir. Projenin tamamı için tek bir modül kullanmak, harici bağımlılık eklediğiniz durumlar dışında BUILD
dosyasına hiç dokunmanız gerekmediği anlamına gelebilir. Ancak bu durumda, derleme sisteminin her zaman projenin tamamını tek seferde oluşturması gerekir. Bu, kullanıcının
paralel yapmayacak veya dağıtmayacak ya da parçalarını önbelleğe alamaz
üzerine düşünün. Dosya başına bir modülde ise durum tam tersidir: Derleme sistemi, derlemenin önbelleğe alma ve planlama adımlarında maksimum esnekliğe sahiptir ancak mühendislerin, hangi dosyaların hangisine referans verdiğini değiştirdiklerinde bağımlılık listelerini korumak için daha fazla çaba göstermesi gerekir.
Kesin ayrıntı düzeyi dile göre değişse de (ve genellikle
Google, diğerlerine kıyasla çok daha küçük modülleri tercih ediyor.
göreve dayalı derleme sistemleri kullanır. Tipik bir üretim ikili programı
Google genellikle on binlerce hedefe dayanır ve hatta orta ölçekli
ekip, kod tabanında yüzlerce hedefe sahip olabilir. Java gibi güçlü bir yerleşik paketleme anlayışına sahip diller için her dizin genellikle tek bir paket, hedef ve BUILD
dosyası içerir (Bazel'e dayalı başka bir derleme sistemi olan Pants, buna 1:1:1 kuralı adını verir). Daha zayıf ambalaja sahip diller
kuralları genellikle her BUILD
dosyası için birden fazla hedef tanımlar.
Daha küçük derleme hedeflerinin avantajları, daha hızlı dağıtılan derlemelere ve hedefleri yeniden oluşturma ihtiyacının daha seyrek olmasına yol açtığı için ölçekte gerçekten kendini göstermeye başlar.
Daha ayrıntılı hedefler, derleme sisteminin yalnızca belirli bir değişiklikten etkilenebilecek sınırlı sayıda test çalıştırması anlamına geldiğinden, test devreye girdikten sonra avantajlar daha da ilgi çekici hale gelir. Google, daha küçük hedefler kullanmanın sistemsel avantajlarına inandığından, geliştiricilerin yükünü hafifletmek için BUILD
dosyalarını otomatik olarak yönetecek araçlara yatırım yaparak olumsuz yönleri azaltma konusunda bazı adımlar attık.
buildifier
ve buildozer
gibi bu araçlardan bazıları, Bazel'de buildtools
dizininde kullanılabilir.
Modül görünürlüğünü en aza indirme
Bazel ve diğer derleme sistemleri, her bir hedefin bir görünürlük belirtmesine olanak tanır.
ona bağlı olabilecek başka hedefleri belirleyen bir mülk. Gizli hedeflere yalnızca kendi BUILD
dosyalarında referans verilebilir. Bir hedef,
açıkça tanımlanmış BUILD
dosyaları listesinin hedefleri için görünürlük veya
çalışma alanındaki her hedefe
ulaşabilirsiniz.
Çoğu programlama dilinde olduğu gibi, görünürlüğü olabildiğince en aza indirmek genellikle en iyi seçenektir. Google'daki ekipler, hedefleri yalnızca şu durumlarda herkese açık hale getirecektir:
bu hedefler Google'daki tüm ekiplerin kullanabileceği yaygın olarak kullanılan kitaplıkları temsil eder.
Kodlarını kullanmadan önce diğer kullanıcıların kendileriyle koordine olmasını gerektiren ekiplerin, hedeflerinin görünürlüğü olarak müşteri hedeflerinin izin verilenler listesi bulunur. Her biri
Ekibin dahili uygulama hedefleri yalnızca dizinlerle sınırlandırılacaktır
ve çoğu BUILD
dosyanın sahibi olmayan tek bir hedefi olur
özel.
Bağımlılıkları yönetme
Modüllerin birbirlerine referans verebilmesi gerekir. Dezavantajı ise
ayrıntılı modüllere ayırmanızı sağladığından, bağımlılıkları
yönetmeniz gerektiğinde
(ancak araçlar bunu otomatikleştirmeye yardımcı olabilir). Bu bağımlılıkların ifade edilmesi, genellikle bir BUILD
dosyasındaki içeriğin büyük kısmını oluşturur.
Dahili bağımlılıklar
Ayrıntılı modüllere ayrılmış büyük bir projede çoğu bağımlılık dahili olması muhtemeldir; yani aynı dilde tanımlanan ve oluşturulan başka bir hedefte kaynak depodur. İç bağımlılıklar, derleme işlemi sırasında önceden derlenmiş bir yapı olarak indirilmek yerine kaynaktan derlendikleri için harici bağımlılıklardan farklıdır. Bu aynı zamanda, bir dönüşüm için ”sürüm” kavramının İç bağımlılıklar vardır. Bir hedef ve tüm iç bağımlılıkları aynı kayıt/düzeltme üzerinde oluşturulur. Yapılması gereken iç bağımlılıklarla ilgili dikkatli bir şekilde ele alınmak geçişli bağımlılıklar (Şekil 1). Hedef A'nın, her bir dönüşüm işleminde ortak kitaplık hedef C'ye bağlıdır. A hedefi, C hedefinde tanımlanan sınıfları kullanabilmeli mi?
Şekil 1. Geçişli bağımlılıklar
Kullanılan temel araçlar söz konusu olduğunda, bunda bir sorun yok. her ikisi B ve C, oluşturulan hedef A'ya bağlanır. Dolayısıyla, burada tanımlanan tüm simgeler C, A tarafından bilinmektedir. Bazel yıllarca buna izin verdi ancak Google büyüdükçe sorunlar görmeye başladı. B'nin, artık C'ye bağımlı olması gerekmeyecek şekilde yeniden yapılandırıldığını varsayalım. Ardından B'nin C'ye olan bağımlılığı kaldırılırsa A ve B'ye olan bağımlılığı aracılığıyla C'yi kullanan diğer tüm hedefler bozulur. Bir hedefin kamu sözleşmesinin bir parçası haline geldi ve güvensiz bir şekilde değiştirildi. Bu da, Google’da bağımlılıkların zamanla birikerek yükselmesi anlamına geliyordu. yavaşlamaya başladı.
Google, sonunda Bazel'de "katı geçişli bağımlılık modu"nu tanıtarak bu sorunu çözdü. Bu modda, Bazel bir hedefin doğrudan bağımlı olmaksızın bir sembole referansta bulunur ve bu durumda hatasını ve desteklenmektedir. Bu değişikliği Google'ın tüm kod tabanında kullanıma sunmak ve milyonlarca derleme hedefimizin her birini bağımlılıkları açıkça listeleyecek şekilde yeniden yapılandırmak yıllar süren bir çalışmaydı ancak buna değdi. Yapılarımız hedeflerin artık daha az gereksiz bağımlılıklara sahip olması ve ihtiyaç duymadıkları bağımlılıkları, bu bağımlılığı hakkında daha fazla bilgi edineceksiniz.
Her zaman olduğu gibi, katı geçişli bağımlılıkları zorunlu kılmak da bir denge gerektiriyordu. Sık kullanılan kitaplıkların artık tesadüfen dahil edilmek yerine birçok yerde açıkça listelenmesinin gerekmesi ve mühendislerin BUILD
dosyalarına bağımlılıklar eklemek için daha fazla çaba harcaması gerektiğinden, derleme dosyaları daha ayrıntılı hale geldi. Başlangıçta
birçok eksikliği otomatik olarak tespit ederek bu yükü azaltan araçlar
ve bunları geliştirici olmadan bir BUILD
dosyasına ekleyerek
izin verilmez. Ancak bu tür araçlar olmadan bile, kod tabanı ölçeklendikçe bu dengenin buna değer olduğunu tespit ettik: BUILD
dosyasına açıkça bağımlılık eklemek tek seferlik bir maliyettir ancak dolaylı geçişli bağımlılıklarla uğraşmak, derleme hedefi var olduğu sürece sürekli sorunlara neden olabilir. Bazel, varsayılan olarak Java kodunda katı geçişli bağımlılıkları zorunlu kılar.
Harici bağımlılıklar
Bir bağımlılık dahili değilse harici olmalıdır. Dış bağımlılıklar derleme sisteminin dışında derlenen ve depolanan yapılar üzerinde çalışan uygulamalardır. Bağımlılık doğrudan bir yapı deposundan (genellikle internet üzerinden erişilir) içe aktarılır ve kaynaktan derlenmek yerine olduğu gibi kullanılır. Şunlardan biri: dış ve iç bağımlılıklar arasındaki en büyük fark, dış bağımlılıkların sürümleri vardır ve bu sürümler projenin kaynak kodundan kaynaklanabilir.
Otomatik ve manuel bağımlılık yönetimi
Derleme sistemleri, harici bağımlılıkların sürümlerinin manuel veya otomatik olarak yönetilmesine izin verebilir. Manuel olarak yönetildiğinde derleme dosyası
yapı deposundan indirmek istediği sürümü açıkça listelediğinde
çoğu zaman anlamsal sürüm dizesi
1.1.4
olarak. Otomatik olarak yönetildiğinde kaynak dosya, kabul edilebilir sürümlerin bir aralığını belirtir ve derleme sistemi her zaman en son sürümü indirir. Örneğin, Gradle, ana sürüm 1 olduğu sürece bağımlılığın tüm küçük veya yama sürümlerinin kabul edilebilir olduğunu belirtmek için bağımlılığın sürümünün "1.+" olarak tanımlanmasına olanak tanır.
Otomatik olarak yönetilen bağımlılıklar küçük projeler için uygun olabilir ancak genellikle önemli boyutlarda veya birden fazla mühendisin üzerinde çalıştığı projelerde felaketin habercisi olur. Otomatik olarak yönetilen bağımlılıklarla ilgili sorun, sürümün ne zaman güncelleneceği üzerinde hiçbir kontrole sahip olmamanızdır. Harici tarafların, anlamsal sürüm kontrolünü kullandıklarını iddia etseler bile çalışmayı durduran güncellemeler yapmayacaklarını garanti etmek mümkün değildir. Bu nedenle, bir gün çalışan bir derleme ertesi gün çalışmayı durdurabilir ve neyin değiştiğini tespit etmenin veya derlemeyi çalışan bir duruma geri döndürmenin kolay bir yolu yoktur. Yapı bozulmasa bile tespit edilmesi imkansız olan üstü kapalı davranışlar veya performans değişiklikleri olabilir.
Aksine, manuel olarak yönetilen bağımlılıklar için kaynakta ve bunların kolayca bulunması ve geri çekilebilmesi sayesinde eski bağımlılıklarla derlemek için deponun daha eski bir sürümüne göz atın. Bazel, tüm bağımlılıkların sürümlerinin manuel olarak belirtilmesini gerektirir. Şu saatte: manuel sürüm yönetiminin getirdiği ek yük, performansın sağladığı istikrar üzerine kuruludur.
Tek Sürüm Kuralı
Bir kütüphanenin farklı sürümleri genellikle farklı yapı taşlarıyla temsil edilir. Bu nedenle, teorik olarak aynı harici bağımlılık için farklı sürümlerin derleme sisteminde farklı adlar altında tanımlanmasının bir sakıncası yoktur. Böylece her hedef, bağımlılığın hangi sürümünü pek de iyi olmadığını unutmayın. Bu, pratikte birçok soruna yol açtığından, Google Tek Sürüm Kuralı bağımlılığınızı kontrol etmektir.
Birden fazla sürüme izin vermenin en büyük sorunu, elmas bağımlılığı sorunudur. A hedefinin B hedefine ve harici bir kitaplığın 1. sürümüne bağlı olduğunu varsayalım. Hedef B daha sonra aynı öğenin v2'sine bağımlılık eklemek için yeniden düzenlenirse artık dolaylı olarak iki kaynağa bağlı olduğundan, A hedefi bozulur emin olmanız gerekir. Hedefin kullanıcılarından herhangi biri zaten farklı bir sürüme bağlı olabileceğinden, bir hedeften birden fazla sürümü olan üçüncü taraf kitaplıklarına yeni bir bağımlılık eklemek hiçbir zaman güvenli değildir. Tek Sürüm Kuralı'na uymak bu çakışmayı imkansız kılar. Bir hedef, üçüncü taraf kitaplığa bağımlılık eklerse mevcut bağımlılıklar zaten aynı sürümde olur. Böylece, bu bağımlılıklar birlikte sorunsuz bir şekilde var olabilir.
Geçişli harici bağımlılıklar
Bir dış bağımlığın geçişli bağımlılıklarıyla başa çıkmak özellikle zor olabilir. Maven Central gibi birçok yapı deposu, ve diğer yapıların belirli sürümlerindeki bağımlılıkları belirlemek için kullanılan seçeceğim. Maven veya Gradle gibi araçlar genellikle her birini tekrarlı bir şekilde indirir varsayılan olarak geçişli bağımlılıktır. Yani projeniz, onlarca yapının indirilmesine neden olabilir. toplamıdır.
Bu çok kullanışlıdır: Yeni bir kitaplığa bağımlılık eklerken, Bu kitaplığın geçişli bağımlılıklarını izlemek zorunda olmak büyük bir zorluk. manuel olarak ekleyebilirsiniz. Ancak çok büyük bir dezavantaj vardır: kitaplıklar aynı üçüncü taraf kitaplığının farklı sürümlerine bağlı olabilir; stratejisi, tek sürüm kuralını ihlal eder ve problemi anlatır. Hedefiniz, aynı bağımlılığın farklı sürümlerini kullanan iki harici kitaplığa bağlıysa hangi sürümün kullanılacağı bilinemez. Bu durum, harici bir bağımlılığın güncellenmesi durumunda yeni sürüm, bağımlılığının bazılarının çakışan sürümlerini çekmeye başlarsa kod tabanında birbiriyle alakalı olmayan hatalar oluşabileceği anlamına da gelir.
Bu nedenle Bazel, geçişli bağımlılıkları otomatik olarak indirmez.
Maalesef sihirli bir değnek de yok. Bazel'in alternatifi,
depodaki tüm harici verileri listeleyen bir global dosya
bağımlılıkları ve bu bağımlılık için kullanılan açık
depodur. Neyse ki Bazel, bir Maven yapı grubuna ait geçişli bağımlılıkları içeren bu tür bir dosyayı otomatik olarak oluşturabilen araçlar sağlar. Bu araç, bir projenin ilk WORKSPACE
dosyasını oluşturmak için bir kez çalıştırılabilir. Ardından, her bağımlılığın sürümlerini ayarlamak için bu dosya manuel olarak güncellenebilir.
Yine burada, kolaylık ve ölçeklenebilirlik arasında bir seçim yapıyoruz. Küçük projelerde, geçişli bağımlılıkları yönetmek zorunda kalmamak tercih edilebilir ve otomatik geçişli bağımlılıklar kullanılabilir. Kuruluş ve kod tabanı büyüdükçe ve çakışmalar ile beklenmedik sonuçlar giderek daha sık ortaya çıktıkça bu strateji giderek daha az cazip hale gelir. Büyük ölçeklerde bağımlılıkları manuel olarak yönetmenin maliyeti otomatik bağımlılığın neden olduğu sorunlarla ilgilenmenin maliyetinden daha düşüktür. üzerine konuşalım.
Harici bağımlılıkları kullanarak derleme sonuçlarını önbelleğe alma
Dış bağımlılıklar çoğu zaman bir şeyi serbest bırakan üçüncü taraflar kaynak kodu sağlamadan kitaplıkların kararlı sürümlerini kullanır. Biraz kuruluşlar, kendi kodlarını da ve diğer kod parçalarının bunlara üçüncü taraf araçlar olarak güvenmesini sağlar. iç bağımlılıklara kıyasla daha uzun bir zamandır. Yapıların derlenmesi yavaş ancak indirilmesi hızlıysa bu, teorik olarak derlemeleri hızlandırabilir.
Ancak bu, aynı zamanda çok fazla ek yük ve karmaşıklığı da beraberinde getirir: bu eserlerin her birini oluşturmak ve bunları sağlamak zorunda olduğundan müşteriler, son teknoloji ürünleri en son sürüme güncelleyin. Çeşitlilik nedeniyle hata ayıklama da çok daha zor hale gelir. ve ekibin farklı noktalarından geliştirilmiştir. ve artık kaynak ağacın tutarlı bir görünümü yoktur.
İnşaatı uzun süren eserler sorununu çözmenin daha iyi bir yolu, daha önce açıklandığı gibi uzaktan önbelleğe almayı destekleyen bir derleme sistemi kullanın. Bu tür bir derleme sistemi, her derlemeden elde edilen yapıları mühendisler arasında paylaşılan bir konuma kaydeder. Bu nedenle, bir geliştirici yakın zamanda başka biri tarafından oluşturulmuş bir yapıya ihtiyaç duyarsa derleme sistemi, yapıyı oluşturmak yerine otomatik olarak indirir. Bu, doğrudan yapı ürünlerine bağlı olmanın tüm performans avantajlarını sağlarken derlemelerin her zaman aynı kaynaktan derlenmiş gibi tutarlı olmasını sağlar. Bu, Google tarafından şirket içinde kullanılan stratejidir ve Bazel, uzak önbelleği kullanacak şekilde yapılandırılabilir.
Dış bağımlılıkların güvenliği ve güvenilirliği
Üçüncü taraf kaynaklardan gelen yapılara bağlı olarak doğası gereği risklidir. Bir de
üçüncü taraf kaynak (örneğin bir yapı deposu) giderse kullanılabilirlik riski
İndirilemezse derlemenizin tamamı durdurulabilir.
bir dış bağımlılık teşkil eder. Ayrıca güvenlik riski de vardır: Üçüncü taraf sisteminin güvenliği bir saldırgan tarafından ihlal edilirse saldırgan, referans verilen yapıyı kendi tasarımlarından biriyle değiştirebilir ve derlemenize keyfi kodlar yerleştirebilir. Her iki sorun da, kullandığınız yapıları yansıtarak
kontrol ettiğiniz ve derleme sisteminizin erişimini engellediğiniz sunuculara bağlıdır
Maven Central gibi üçüncü taraf yapı depoları. Bununla birlikte, bu yansıtıcıların bakımı için çaba ve kaynak gerekir. Bu nedenle, bunları kullanıp kullanmama kararı genellikle projenin ölçeğine bağlıdır. Güvenlik sorunu, her üçüncü taraf yapının karmasının kaynak depoda belirtilmesini zorunlu kılarak da çok az ek yük ile tamamen önlenebilir. Bu durumda, yapıda değişiklik yapılması derlemenin başarısız olmasına neden olur. Sorunu tamamen atlatan bir diğer alternatif de projenizin bağımlılıklarını tedarikçiye aktarmaktır. Bir proje, bağımlılıkları tedarikçiye gönderirken bunları projenin kaynak koduyla birlikte kaynak veya ikili kod olarak kaynak denetimine gönderir. Bu, projenin tüm harici bağımlılıklarının dahili bağımlılıklara dönüştürüldüğü anlamına gelir. Google bu yaklaşımı dahili olarak kullanır ve tüm üçüncü taraf
Google genelinde, kökte bir third_party
dizinine referans verilen kitaplık
temel alandır. Ancak, bu yalnızca Google'da işe yarar çünkü Google'ın
kaynak kontrol sistemi, aşırı büyük monorepo'yu işleyecek şekilde özel olarak tasarlanmıştır.
tedarikçi bulma tüm kurumlar için bir seçenek olmayabilir.