Bağımlılık Yönetimi

Sorun bildirin Kaynağı göster Gece · 7,4 , 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Önceki sayfalara göz atarken bir temanın tekrar tekrar ortaya çıktığını göreceksiniz: Kendi kodunuzu yönetmek oldukça kolaydır ancak bağımlılıkları yönetmek çok daha zordur. Ç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ı tabanlı derleme sistemleri kullanan projeler Birbirine bağımlılığı ifade eden modüllerle birlikte BUILD dosyası olarak da kaydedebilir. Bu modüllerin ve bağımlılıkların doğru şekilde düzenlenmesi, hem de derleme işlemi için gereken çalışma miktarına sağlar.

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 uçta ise neredeyse her kaynak dosya kendi modülüne dönüştürülebilir. Bu durumda, her dosyanın bir BUILD dosyasında bağımlı olduğu diğer tüm dosyaları listelemesi gerekir.

Çoğu proje bu uç noktalar arasında bir yerdedir ve seçim, arasındaki dengeyi konuşacağız. 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, derlemenin bazı bölümlerini paralelleştiremeyeceği veya dağıtamayacağı, ayrıca daha önce derlenmiş bölümleri önbelleğe alamayacak anlamına gelir. 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 yapı hedeflerinin avantajları büyük ölçekte görülmeye başlar çünkü Bu durum, daha hızlı dağıtılan derlemelerin ve hedeflerin yeniden oluşturulma sıklığının daha az duyulmasını sağlar. Test başladıktan sonra avantajları daha da cazip hale geliyor. ve daha ayrıntılı hedefler, derleme sisteminin kullandığı yalnızca belirli bir testten etkilenebilecek belirli bir test alt unutmayın. 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 hedefin bir görünürlük belirtmesine olanak tanır. Bu görünürlük, diğer hangi hedeflerin bu hedefe bağlı olabileceğini belirleyen bir özelliktir. Gizli hedef yalnızca kendi BUILD dosyası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. Genellikle Google'daki ekipler, hedefleri yalnızca Google'daki tüm ekiplerin kullanabileceği yaygın olarak kullanılan kitaplıkları temsil ediyorsa herkese açık hale getirir. 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). Bunları ifade etmek, bağımlılıklar genellikle BUILD dosyasındaki içeriğin çoğunluğunu oluşturur.

Dahili bağımlılıklar

İnce ayrıntılı modüllere ayrılmış büyük bir projede, bağımlılıkların çoğunun dahili olması muhtemeldir. Yani aynı kaynak depoda tanımlanan ve oluşturulan başka bir hedeftedir. İç 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, dahili bağımlılar için "sürüm" kavramının olmadığı anlamına da gelir. Bir hedef ve tüm dahili bağımlılıkları, depodaki aynı taahhüt/düzeltme ile her zaman derlenir. Dahili bağımlılıklarla ilgili dikkatli bir şekilde ele alınması gereken konulardan biri, geçişli bağımlılıkların nasıl ele alınacağıdır (Şekil 1). Hedef A'nın, her bir dönüşüm işleminde ortak kitaplık hedef C'ye bağlıdır. A'yı hedeflemeli ve sınıfları kullanabilme hedef C'de tanımlanıyor mu?

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

Şekil 1. Geçişli bağımlılıklar

Temel araçlar açısından bu konuda bir sorun yoktur. Hem B hem de C, derlendiğinde hedef A'ya bağlanır. Bu nedenle, C'de tanımlanan tüm semboller A tarafından bilinir. Bazel bu duruma yıllarca izin verdi ancak Google büyüdükçe sorunlar görmeye başladık. B'nin yeniden düzenlendiğini varsayalım. gerekiyor. 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. Bu nedenle, bir hedefin bağımlılıkları, herkese açık sözleşmesinin bir parçası haline geldi ve hiçbir zaman güvenli bir şekilde değiştirilemedi. Bu da, Google’da bağımlılıkların zamanla birikerek yükselmesi anlamına geliyordu. yavaşlamaya başladı.

Google, sonunda bu sorunu “katı geçişli geçişli bir şarta bağımlılık modu"nu gönderin. Bu modda Bazel, bir hedefin bir sembole doğrudan bağımlı olmadan referans verip vermediğini algılar ve bu durumda bir hata ve bağımlılığı otomatik olarak eklemek için kullanılabilecek bir kabuk komutu ile başarısız olur. 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. Hedeflerin gereksiz bağımlılıkları daha az olduğu için derlemelerimiz artık çok daha hızlı. Ayrıca mühendisler, kendilerine bağlı hedefleri bozma endişesi olmadan ihtiyaç duymadıkları bağımlılıkları kaldırabiliyor.

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. O zamandan beri, birçok eksik bağımlılık otomatik olarak algılayıp geliştirici müdahalesi olmadan BUILD dosyalarına ekleyerek bu zahmeti azaltan araçlar geliştirdik. Ancak bu tür araçlar olmadan bile dengenin iyi olduğunu gördük. kod tabanı ölçeklendirildikçe buna değer: BUILD dosyasına açıkça bir bağımlılık ekleme tek seferlik bir maliyettir, ancak örtülü geçişli bağımlılıklarla başa çıkmak, devam eden sorunları çözebilir. Bazel, varsayılan olarak Java kodunda katı geçişli bağımlılıkları zorunlu kılar.

Harici bağımlılıklar

Bağımlılık dahili değilse harici olması gerekir. Dış bağımlılıklar derleme sisteminin dışında derlenen ve depolanan yapılar üzerinde çalışan uygulamalardır. İlgili içeriği oluşturmak için kullanılan bağımlılık doğrudan bir yapı deposundan içe aktarılır (genellikle olarak 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 ile ilgili sorun bağımlılıkları, sürümün ne zaman kullanılabileceği konusunda kontrol edemediğiniz güncellendi. Harici tarafların zarara yol açmayacağını garanti etmenin bir yolu yoktur (anlamsal sürüm oluşturmayı kullandıklarını iddia etseler bile) böylece bir gün çalıştıktan sonra bozulabilir ve neyin değiştiğini tespit etmenin kolay bir yolu çalışma durumuna geri döndürebilir. 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 kitaplığın farklı sürümleri genellikle farklı yapılar, Dolayısıyla teoride, aynı harici reklam öğesinin farklı versiyonlarının bağımlılığın her ikisi de derleme sisteminde farklı adlarla tanımlanamıyordu. Böylece her hedef, bağımlılığın hangi sürümünü pek de iyi olmadığını unutmayın. Bu durum uygulamada birçok soruna neden olduğundan Google, kod tabanımızdaki tüm üçüncü taraf bağımlılıkları için katı bir Tek Sürüm Kuralı uyguluyor.

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. B hedefi daha sonra aynı harici kitaplığın v2 sürümüne bağımlılık eklemek için yeniden yapılandırılırsa A hedefi artık aynı kitaplığın iki farklı sürümüne dolaylı olarak bağımlı olduğu için çalışmaz. Etkili bir sisteme bir hedeften birden fazla sürümü olan üçüncü taraf kitaplığına yeni bağımlılıklar, çünkü söz konusu hedefin kullanıcılarından herhangi biri zaten farklı bir sürümünü değil. 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ılığın geçişli bağımlılıklarıyla başa çıkmak için zor oluyor. 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 bunun büyük bir dezavantajı da vardır: Farklı kitaplıklar aynı üçüncü taraf kitaplığının farklı sürümlerine bağlı olabileceğinden bu strateji, bir sürüm kuralını ihlal eder ve elmas bağımlılığı sorununa yol açar. Hedefiniz, aynı bağımlılığın farklı versiyonları varsa, hangi sürümü alın. Bu aynı zamanda bir dış bağımlılığı güncellemenin, yeni sürüm uyumlu olmaya başlarsa kod tabanı boyunca ve bazı bağımlılıklarının çakışan versiyonları olabilir.

Bu nedenle Bazel, geçişli bağımlılıkları otomatik olarak indirmez. Maalesef bu sorunu çözmek için tek bir çözüm yok. Bazel'in alternatifi, deponun harici bağımlılıklarının her birini ve depo genelinde bu bağımlılık için kullanılan açık bir sürümü listeleyen bir genel dosya gerektirmektir. 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.

Burada da seçim, kolaylık ve ölçeklenebilirlik arasındadır. 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ş, bu stratejiye giderek daha az cazip gelir. ve kod tabanı büyür, çakışmalar ve beklenmedik sonuçlar giderek daha da artar. sıklıkla görebilirsiniz. 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, çok fazla ek yük ve karmaşıklık da getirir: Bu yapıların her birini oluşturmaktan ve yapı deposuna yüklemekten birinin sorumlu olması gerekir. Ayrıca istemcilerin en son sürümle güncel kalmasını sağlaması gerekir. Ç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, strateji olarak kullanılır ve Bazel, uzaktan kumandayı önbellek.

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. Üçüncü taraf kaynağı (ör. yapı deposu) devre dışı kalırsa kullanılabilirlik riski vardır. Çünkü harici bir bağımlılık indiremezse derlemenizin tamamı durabilir. Bir de güvenlik riski vardır: üçüncü taraf sistemin, güvenliği bir saldırgan tarafından ele geçirildiğinde, saldırgan, referans verilen rastgele kod yerleştirmelerine olanak tanıyan bu yapı, kendi tasarımlarından biriyle içine ekleyebilirsiniz. Hem bu hem de diğer sorun, bağımlı olduğunuz tüm yapıları kontrol ettiğiniz sunuculara yansıtarak ve derleme sisteminizin Maven Central gibi üçüncü taraf yapı depolarına erişmesini engelleyerek azaltılabilir. 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. Tamamen yeni bir alternatif en önemli iki yanı da projenizin bağımlılıklarını tedarik etmektir. 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'ın kaynak denetimi sisteminin son derece büyük bir monorepoyu işleyebilecek şekilde özel olarak tasarlanmış olması nedeniyle Google'da işe yarar. Bu nedenle, tedarikçi firmalardan hizmet almak tüm kuruluşlar için uygun olmayabilir.