Bağımlılık enjeksiyonunun kodu nasıl daha kolay test edilebilir, yeniden düzenlenebilir ve genişletilebilir hale getirdiğini öğrenin. Pratik desenler, örnekler ve sık yapılan hatalardan kaçınma yollarını keşfedin.

Bağımlılık Enjeksiyonu (DI) basit bir fikir: bir kod parçası ihtiyaç duyduğu şeyleri kendi yaratmak yerine, onlara dışarıdan verilir.
Bu “ihtiyaç duyulan şeyler” onun bağımlılıklarıdır—örneğin bir veritabanı bağlantısı, bir ödeme servisi, bir saat, bir logger veya bir e-posta gönderici. Kodunuz bu bağımlılıkları kendisi oluşturuyorsa, sessizce nasıl çalıştıklarını da sabitlemiş olur.
Bir ofisteki kahve makinesini düşünün. Makine suya, kahve çekirdeğine ve elektriğe bağımlıdır.
DI, ikinci yaklaşıma benzer: “kahve makinesi” (sınıfınız/fonksiyonunuz) işine (kahve yapmak) odaklanır; “malzemeler” (bağımlılıklar) kurulum yapan tarafından sağlanır.
DI, belirli bir framework kullanma zorunluluğu değildir ve bir DI konteyneriyle aynı şey değildir. Bağımlılıkları parametreler (veya constructor) aracılığıyla elle geçirerek DI yapabilirsiniz.
DI ayrıca “mocklama” değildir. Mocklama, testlerde DI kullanmanın bir yolu olabilir; ama DI kendisi yalnızca bağımlılıkların nerede yaratılacağına dair bir tasarım tercihidir.
Bağımlılıklar dışardan sağlandığında, kodunuz farklı bağlamlarda (üretim, birim testleri, demolar, gelecekteki özellikler) çalıştırması daha kolay olur.
Aynı esneklik modülleri daha temiz yapar: parçalar tüm sistemi yeniden kablolamadan değiştirilebilir. Sonuç olarak testler daha hızlı ve daha net olur (çünkü basit yedeklerle değiştirebilirsiniz) ve kod tabanı daha kolay değiştirilebilir (çünkü parçalar daha az iç içe geçmiştir).
Sıkı bağlılık, bir kod parçasının diğer parçaların hangisini kullanacağını doğrudan belirlemesiyle oluşur. En yaygın biçim basittir: iş mantığının içinde new çağrısı.
Kasada new StripeClient() ve new SmtpEmailSender() gibi çağrılar yapan bir checkout fonksiyonunu düşünün. İlk bakışta kullanışlıdır—ihtiyacınız olan her şey oradadır. Ama aynı zamanda checkout akışını bu belirli implementasyonlara, yapılandırma detaylarına ve hatta oluşturma kurallarına (API anahtarları, zaman aşımı, ağ davranışı) kilitler.
Bu bağlılık “gizlidir” çünkü yöntem imzasından belli olmaz. Fonksiyon sadece bir siparişi işliyor gibi görünür, ama gizlice ödeme sağlayıcılarına, e-posta sağlayıcılarına ve belki bir veritabanı bağlantısına bağımlıdır.
Bağımlılıklar sabit kodlandığında, küçük değişiklikler bile dalga dalga yayılır:
Sabit kodlu bağımlılıklar birim testlerin gerçek iş yapmasına neden olur: ağ çağrıları, dosya I/O, saatler, rastgele ID'ler veya paylaşılan kaynaklar. Testler izole olmadıkları için yavaş ve zamanlamaya, dış hizmetlere veya yürütme sırasına bağlı oldukları için kırılgan olur.
Eğer şu desenleri görüyorsanız, sıkı bağlılık muhtemelen zaten size zaman maliyeti çıkarıyor demektir:
new kullanımıBağımlılık Enjeksiyonu, bağımlılıkları açık ve değiştirilebilir hale getirerek bunları ele alır—iş kurallarını her değiştirdiğinizde yeniden yazmadan.
Dependency Injection (DI), kodunuzun ihtiyaç duyduğu şeyleri (veritabanı, logger, saat, ödeme istemcisi gibi) içerden oluşturmak yerine dışarıdan alması anlamına gelir.
Pratikte bu genellikle bağımlılıkların bir constructor'a veya fonksiyon parametresine geçirilmesi şeklinde olur; böylece bağımlılıklar açık ve değiştirilebilir olur.
Kontrolün Tersine Çevrilmesi (IoC), bir sınıfın ne yaptığıyla ilgilenmesi gerektiği fikridir, iş ortaklarını nasıl elde edeceğiyle değil.
DI, bağımlılık yaratımını dışarıya taşıyarak IoC'yi sağlamanın yaygın bir yoludur.
Eğer bir bağımlılık iş mantığının içinde new ile oluşturuluyorsa, onu değiştirmek zorlaşır.
Bunun sonuçları:
DI, testlerde gerçek dış sistemler yerine test çiftleri enjekte etmenize izin vererek testlerin hızlı ve deterministik kalmasını sağlar.
Yaygın değişimler:
Bir DI konteyneri isteğe bağlıdır. Küçük/orta ölçekli uygulamalarda manuel DI (bağımlılıkları açıkça geçirmek) ile başlayın:
Konteyneri, wiring tekrar etmeye başladığında veya yaşam döngüsü yönetimi (singleton/per-request) gerektiğinde düşünün.
Constructor injection: bağımlılık nesneyi oluşturmak için gerekliyse ve birden fazla metotta kullanılıyorsa tercih edin.
Method/parameter injection: yalnızca tek bir çağrı için gerekiyorsa (istek-scope değeri, tek seferlik strateji).
Setter/property injection: gerçekten geç bağlama gerekiyorsa kullanın; eksikse hızlıca hata vermek için doğrulama ekleyin.
Composition root, uygulamanın birleştirildiği yerdir: implementasyonları oluşturup onları ihtiyaç duyan servislere verdiğiniz yer.
Genellikle uygulama başlatma noktasına yakın tutulur; böylece geri kalan kod tabanı davranışa odaklanır, wiring değil.
Test seam, davranışın kasıtlı olarak değiştirilebildiği bir noktadır.
Seam için iyi yerler:
Clock.now())DI, testlerde farklı bir implementasyon enjekte etmenize izin vererek seam'ler oluşturur.
Yaygın hatalar:
container.get() çağrısı bağımlılıkları gizler; parametrelerle açıkça geçirmek daha iyidir.Küçük, tekrarlanabilir bir refaktör ile başlayın:
Her adımı ayrı ayrı uygulayarak devam edin; istediğiniz noktada durabilirsiniz.