Bağımlılık Yönetimi

Sorun bildirme Kaynağı görüntüleme Nightly · 7.4 . 7.3 · 7.2 · 7,1 · 7,0 · 6,5

Ö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?

Geçişli bağımlılıklar

Ş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.