Ders 09 / 14
Bağımlılık Riski
Geçişli bağımlılık kütlesinin ölçülmesi, kurulum anında çalışan kodun anlamı, bütünlük doğrulaması, kilitleme disiplini, paket seçim ölçütleri ve terk edilmiş paketlerin yönetimi.
İçindekiler
Önceki dersler bağımlılıkları teknik bir çözümleme sorunu olarak ele aldı: hangi sürüm seçilir, nereye kurulur, kim görür. Bu ders farklı bir soruyu sorar — kurulan kodun tamamına ne kadar güvenilmektedir ve bu güven nasıl daraltılır?
Soru yönetimseldir ama yanıtı tümüyle tekniktir. Ölçülebilir bir büyüklükle başlamak gerekir: bir projenin gerçekte kaç paket çalıştırdığı.
Geçişli Kütle
Bildirimde yazılı paketler, kurulan paketlerin küçük bir bölümüdür. Her bağımlılık kendi bağımlılıklarını getirir; bu ilişki kapanana kadar sürer. Kümenin tamamına bağımlılık kapanışı (dependency closure) denir.
Kapanış, bildirimler üzerinde bir enine aramayla hesaplanır:
// dosya: kapanis.mjs — kayit/<ad>/package.json dosyalarını okur import { readFile } from 'node:fs/promises'; async function bildirim(ad) { return JSON.parse(await readFile(`kayit/${ad}/package.json`, 'utf8')); } const kok = await bildirim('metin-olcer'); const dogrudan = Object.keys(kok.dependencies); const kapanis = new Map(); const kuyruk = [...dogrudan]; while (kuyruk.length > 0) { const ad = kuyruk.shift(); if (kapanis.has(ad)) continue; const paket = await bildirim(ad); kapanis.set(ad, paket.version); kuyruk.push(...Object.keys(paket.dependencies ?? {})); } console.log('doğrudan bağımlılık:', dogrudan.length, '->', dogrudan.join(', ')); console.log('geçişli kapanış:', kapanis.size); for (const [ad, surum] of kapanis) console.log(` ${ad}@${surum}`);
Küçük bir örnek kayıtta — altı paketlik bir dizinde — sonuç şudur:
$ node kapanis.mjs doğrudan bağımlılık: 2 -> bicim-yardimcisi, dizgi-araci geçişli kapanış: 5 [email protected] [email protected] [email protected] [email protected] [email protected]
İki bilinçli seçim, beş paket getirdi. Oran örneğin küçüklüğünden gelmiyor: her düzeyde çarpan etkisi vardır ve gerçek projelerde iki basamaklı doğrudan bağımlılık, dört basamaklı kapanışlar üretebilir.
Bu sayının anlamı şudur: kapanıştaki her paketin kodu programınızın içinde, programınızın yetkileriyle çalışır. Doğrudan seçtiğiniz paketlere karar verdiniz; geri kalanına, onları seçenlerin kararı üzerinden dolaylı olarak güvendiniz. Kapanışın büyüklüğü, bu dolaylı güvenin ölçüsüdür.
Kurulum Anında Çalışan Kod
Güven sınırı, kütüphaneyi çağırdığınız anda başlamaz. Bildirim dosyası, kurulum sırasında çalıştırılacak betikler tanımlayabilir:
{ "name": "ornek-paket", "version": "1.0.0", "scripts": { "postinstall": "node kurulum/hazirla.mjs" } }
Bu alan meşru işler için vardır: yerel derleme, önbellek hazırlama, uyumluluk denetimi. Sonucu ise şudur — bir paketi kurmak, o paketin kodunu çalıştırmakla eşdeğerdir. Paketi hiç içe aktarmadan, yalnızca kurulum komutunu çalıştırarak kapanıştaki her paketin betiğine yürütme hakkı verilmiş olur. Betikler kullanıcının yetkileriyle çalışır; dosya sistemine ve ağa erişebilirler.
Savunma üç adımlıdır:
Kurulum betiklerini varsayılan olarak kapatmak. Kurulum araçları bunu bir seçenekle sunar. Kapalıyken kurulum başarısız olan paketler tek tek incelenir ve gerçekten gerekliyse istisna tanınır.
Yalıtılmış ortamda kurmak. Kurulumun geliştirici makinesinde değil, sınırlı yetkili ve sonrasında atılan bir ortamda yapılması, betiğin erişebileceği alanı daraltır. Linux’a Giriş kursundaki en az yetki ilkesi burada doğrudan uygulanır.
Kilit dosyasını güncelleyen değişiklikleri incelemek. Kilit dosyasındaki bir satırın değişmesi, kurulacak arşivin değişmesi demektir. Bu değişiklikler, kaynak kodundaki değişiklikler kadar dikkatle gözden geçirilmelidir.
Bütünlük Doğrulaması
Kilit dosyasının kaydettiği üçüncü bilgi — bütünlük özeti — belirli bir soruya yanıt verir: indirilen arşiv, kilitlendiği andaki arşivin aynısı mı?
Özet, arşivin baytları üzerinden hesaplanan bir kriptografik sağlamadır. Tek bir baytın değişmesi özeti tümüyle değiştirir:
// dosya: ozet.mjs import { createHash } from 'node:crypto'; import { readFile } from 'node:fs/promises'; const icerik = await readFile(process.argv[2]); const ozet = createHash('sha512').update(icerik).digest('base64'); console.log(`bayt: ${icerik.length}`); console.log(`sha512-${ozet.slice(0, 44)}...`);
// dosya: paket.mjs export function ondalik(sayi, basamak = 2) { return sayi.toFixed(basamak); }
$ node ozet.mjs paket.mjs bayt: 99 sha512-evHnpqY+DudhSUf7VDcRTYA5YiDix19+bqCy3i1OZFYh...
Dosyadaki tek bir karakter — varsayılan basamak sayısı — 3 yapılıp aynı komut yeniden
çalıştırıldığında:
$ node ozet.mjs paket.mjs bayt: 99 sha512-J1VCPrKRAjSDZKJKnyUTtADWFgGDuC9Wqyj1yLZfZ6ty...
Boyut aynı kaldı, özet tümüyle değişti. Betik özeti kısaltarak yazar; gerçek özet daha uzundur ve kilit dosyasında tam hâliyle saklanır.
Doğrulamanın kapattığı yüzey açıktır: aynı ad ve sürümle farklı içerik sunulması. Kapatmadığı yüzey de açıktır: paketin yeni bir sürümü yayımlandığında özet zaten değişecektir. Bütünlük özeti, içeriğin değişmediğini kanıtlar; içeriğin güvenli olduğunu değil.
Yükseltme Disiplini
Kilit dosyası bulunan bir projede kurulum, kilitte yazılı ağacı aynen kurar. Bu, yükseltmeyi bir kaza olmaktan çıkarıp bir işleme dönüştürür. İşleyen bir düzen şu adımları içerir:
- Yükseltme ayrı bir değişiklik olarak yapılır; başka bir düzenlemeyle aynı işlemede birleştirilmez.
- Değişen kilit satırları incelenir: hangi paketler, hangi sürümden hangi sürüme.
- Sınamalar çalıştırılır.
- Yükseltmenin gerekçesi kaydedilir.
Yükseltmeyi geciktirmek de bir risktir: eski sürümde kalmak, düzeltilmiş kusurları taşımaya devam etmek demektir. Denge, düzenli ve küçük yükseltmelerdedir; birikmiş yükseltmeler tek seferde yapıldığında hem inceleme olanaksızlaşır hem de bir arıza durumunda hangi paketin sorumlu olduğu ayırt edilemez.
Paket Seçim Ölçütleri
Bir bağımlılık eklemek bir karardır ve zamana bağlı olmayan ölçütlerle değerlendirilebilir:
Kapanış büyüklüğü. Paketin kendi bağımlılık kapanışı kaç pakettir? Küçük bir işlev için büyük bir kapanış getiren paket pahalıdır.
Arayüz yüzeyi. Paketin kaç işlevini kullanacaksınız? Tek bir işlev için alınan geniş bir kütüphane, hem ağaç sarsmanın hem de incelemenin işini zorlaştırır.
Değiştirilebilirlik. Paket bırakıldığında yerine ne konur? Arayüzü dar ve standart bir paket değiştirilebilir; projeye kendi kavramlarını dayatan bir paket değiştirilemez.
Bakım işaretleri. Bildirilen kusurlara yanıt veriliyor mu, sınamaları var mı, kaç kişi katkı veriyor? Tek kişilik bakım, o kişinin ilgisini kaybetmesiyle biten bir bağımlılıktır.
Lisans. Kullanım ve dağıtım koşulları projeye uyuyor mu?
Kendin yazma maliyeti. İşlev birkaç satırla yazılabiliyorsa, bağımlılığın taşıdığı kurulum, güncelleme ve güven maliyeti buna değmeyebilir. Karşı yönde de aynı ölçü geçerlidir: kriptografi, tarih hesabı veya metin kodlaması gibi ayrıntısı yüksek alanlarda kendi gerçekleştirimini yazmak, olgunlaşmış bir paketi kullanmaktan daha risklidir.
Ad Doğrulama ve Terk Edilmiş Paketler
Paket adları kayıt içinde benzersizdir ama benzerlik serbesttir. Yaygın bir paketin adına bir harf eklenmiş ya da tire konumu değiştirilmiş bir ad, elle yazıldığında fark edilmeden seçilebilir. Savunma yazım disiplinindedir: paket adı belgeden veya bildirimden kopyalanır, ezberden yazılmaz; ekleme sonrası bildirimdeki satır ve paketin kaynak deposu bağlantısı denetlenir.
Terk edilmiş paket ayrı bir sorundur ve tanısı gözlemle konur: kusurlar birikmiş, yayın yapılmıyor, geçişli bağımlılıkları da bakımsız. Seçenekler şunlardır:
Değiştirmek. Aynı işi yapan bakımlı bir paketle değiştirmek. Arayüz yüzeyi darsa uygulanabilir.
Depoya almak. Paketin kaynağını projenin içine kopyalayıp bakımını üstlenmek. Kod küçükse ve dondurulmuş sayılabiliyorsa uygundur; kapanışı da birlikte taşımak gerekir.
Bakımını üstlenmek. Paketi çatallayıp kendi adınızla yayımlamak. Sorumluluk artar, karşılığında denetim tümüyle sizde olur.
Üçünde de ilk adım aynıdır: paketin gerçekten gerekli olup olmadığını yeniden sormak. En güvenli bağımlılık, kaldırılmış olandır.
Özet
- Bağımlılık kapanışı, doğrudan seçilen paketlerden çok daha büyüktür; kapanıştaki her paket programın yetkileriyle çalışır.
- Kurulum betikleri, paketi hiç içe aktarmadan kod çalıştırır; savunma betikleri kapatmak, yalıtılmış ortamda kurmak ve kilit değişikliklerini incelemektir.
- Bütünlük özeti, aynı ad ve sürümle farklı içerik sunulmasını yakalar; içeriğin güvenli olduğunu kanıtlamaz.
- Yükseltme ayrı ve düzenli bir işlem olmalıdır; geciktirmek de bir risktir.
- Paket seçimi kapanış büyüklüğü, arayüz yüzeyi, değiştirilebilirlik, bakım işaretleri ve lisans ölçütleriyle değerlendirilir.
- Terk edilmiş paket için üç yol vardır — değiştirmek, depoya almak, bakımını üstlenmek — ve üçünden önce paketin gerekliliği sorgulanır.
Sonraki Adım
Bağımlılıklar çözümlendi, kilitlendi ve denetlendi. Geriye, bu paketlerin ve kendi modüllerinizin hedef ortama nasıl ulaştırılacağı kalıyor. Sonraki konu, modül çizgesini girdi alıp çalıştırılabilir çıktı üreten araç sınıflarını ele alır; ilk ders, bu üretimin neden gerekli olduğunu ve nasıl yürüdüğünü çalışan bir örnekle gösterir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.