Bağımlılık Enjeksiyonu ne kadardır?


38

Bir sınıfın bağımlılığı olan her şey için (Bahar) Bağımlılık Enjeksiyonunu kullanan bir projede çalışıyorum. Spring konfigürasyon dosyasının 4000 satır kadar büyüdüğü bir noktadayız. Çok uzun zaman önce Bob Amca'nın YouTube'daki konuşmalarından birini izledim (ne yazık ki bağlantıyı bulamadım), ancak birkaç ana bağımlılığa (örneğin fabrikalar, veri tabanları ...) ana bileşenine enjekte etmelerini önerdi. dağıtılmak

Bu yaklaşımın avantajları, DI çerçevesinin uygulamanın çoğundan ayrılmasıdır ve ayrıca fabrikalar daha önce konfigürasyonda olduğundan çok daha fazlasını içereceklerinden dolayı Spring konfigürasyonunu daha temiz hale getirir. Aksine, bu, birçok fabrika sınıfı arasında yaratma mantığının yayılmasına neden olacak ve testler zorlaşabilir.

Bu yüzden benim sorum gerçekten bir veya diğer yaklaşımda gördüğünüz başka avantaj veya dezavantajları. En iyi uygulamalar var mı? Cevaplarınız için çok teşekkürler!


3
4000 satırlık bir yapılandırma dosyasına sahip olmak bağımlılık enjeksiyonunun hatası değildir ... düzeltmek için birçok yol vardır: dosyayı modüler hale getirin, daha küçük dosyalara bölün, açıklamaya dayalı enjeksiyona geçin, xml yerine JavaConfig dosyaları kullanın. Temel olarak, yaşadığınız sorun, uygulamanızın bağımlılık enjeksiyon gereksinimlerinin karmaşıklığını ve boyutunu yönetememektir.
Maybe_Factor

1
@Maybe_Factor TL; DR projeyi daha küçük parçalara böler.
Walfrat

Yanıtlar:


44

Her zaman olduğu gibi, ™ bağlıdır. Cevap, birisinin çözmeye çalıştığı soruna bağlıdır. Bu cevapta, bazı genel motive edici güçleri ele almaya çalışacağım:

Küçük kod tabanlarını destekleyin

4.000 satırlık Spring yapılandırma kodunuz varsa, kod tabanının binlerce sınıfa sahip olduğunu varsayalım.

Bu durumdan sonra çözebileceğiniz bir sorun değil, ancak kural olarak, daha küçük kod tabanlarıyla daha küçük uygulamaları tercih etme eğilimindeyim. Eğer içine iseniz Domain-Driven Design , sen, örneğin, sınırlanmış bağlamda başına bir kod tabanı yapabiliriz.

Bu tavsiyeyi sınırlı deneyimlerime dayandırıyorum, çünkü kariyerimin çoğu için web tabanlı bir iş kolu kodu yazdım. Bir masaüstü uygulaması veya gömülü bir sistem veya başka bir yazılım geliştiriyorsanız, işlerin birbirinden ayrılmasının zor olduğunu hayal edebiliyorum.

Bu ilk tavsiyenin kolayca en az pratik olduğunu fark etmeme rağmen, bunun da en önemli olduğuna inanıyorum ve bu yüzden bunu ekliyorum. Kodun karmaşıklığı, kod tabanının boyutuna göre doğrusal olmayan (muhtemelen üstel olarak) değişir.

Favor Saf DI

Bu sorunun var olan bir durum olduğunu hala fark etmeme rağmen, Pure DI'yi tavsiye ediyorum . DI Konteyneri kullanmayın, ancak kullanırsanız en azından kongre tabanlı kompozisyon uygulamak için kullanın .

Spring ile ilgili pratik bir tecrübem yok, ancak yapılandırma dosyasında bir XML dosyasının ima edildiğini varsayıyorum .

Bağımlılıkları XML kullanarak yapılandırmak her iki dünyanın da en kötüsüdür. İlk olarak, derleme zamanı tür güvenliğini kaybedersiniz, ancak hiçbir şey kazanmazsınız. Bir XML yapılandırma dosyası kolayca değiştirmeye çalıştığı kod kadar büyük olabilir.

Ele almayı düşündüğü sorunla karşılaştırıldığında, bağımlılık enjeksiyon yapılandırma dosyaları, yapılandırma karmaşıklığı saatinde yanlış yer kaplar .

İri taneli bağımlılık enjeksiyonu için durum

İri taneli bağımlılık enjeksiyonu için bir vaka yapabilirim. İnce taneli bağımlılık enjeksiyonu için bir vaka da yapabilirim (bir sonraki bölüme bakınız).

Yalnızca birkaç 'merkezi' bağımlılık enjekte ederseniz, çoğu sınıf şöyle görünebilir:

public class Foo
{
    private readonly Bar bar;

    public Foo()
    {
        this.bar = new Bar();
    }

    // Members go here...
}

Bu hala uyuyor Tasarım Kalıpları 'ın sınıf miras üzerinde iyilik nesne kompozisyonu , çünkü Foooluşturur Bar. Sürdürülebilirlik perspektifinden bakıldığında, bu hala sürdürülebilir olarak düşünülebilir, çünkü kompozisyonu değiştirmeniz gerekirse, sadece kaynak kodunu düzenlersiniz Foo.

Bu bağımlılık enjeksiyonundan daha az bakım gerektirmez. Aslında, Barbağımlılık enjeksiyonuna özgü dolaylı olarak takip etmek yerine, kullanılan sınıfı doğrudan düzenlemenin daha kolay olduğunu söyleyebilirim .

Bağımlılık Enjeksiyonu kitabımın ilk baskısında, değişken ve istikrarlı bağımlılıklar arasında ayrım yapıyorum.

Geçici bağımlılıklar, enjekte etmeyi düşünmeniz gereken bağımlılıklardır. Onlar içerir

  • Derlemeden sonra yeniden yapılandırılması gereken bağımlılıklar
  • Başka bir ekip tarafından paralel olarak geliştirilen bağımlılıklar
  • Deterministik olmayan davranışlara bağlı bağımlılıklar veya yan etkileri olan davranışlar

Öte yandan, istikrarlı bağımlılıklar iyi tanımlanmış şekilde davranan bağımlılıklardır. Bir anlamda, bu ayrımın kaba taneli bağımlılık enjeksiyonu için bir durum oluşturduğunu iddia edebilirsiniz, ancak kitabı yazarken bunu tamamen anlayamadığımı itiraf etmeliyim.

Bununla birlikte, test açısından bakıldığında bu birim testini zorlaştırır. Artık Foobağımsız bir birim test yapamazsınız Bar. As JB Rainsberger açıklıyor , entegrasyon testleri karmaşıklık bir combinatoric patlama muzdarip. 4-5 sınıflarının bile entegrasyonu ile tüm yolları kapamak istiyorsanız, kelimenin tam anlamıyla on binlerce test senaryosu yazmanız gerekecek.

Bunun karşıt argümanı, sık sık sizin göreviniz bir sınıfı programlamak değildir. Göreviniz, belirli sorunları çözen bir sistem geliştirmektir. Davranış Odaklı Gelişme (BDD) arkasındaki motivasyon budur .

Bununla ilgili bir başka görüş, TDD'nin teste bağlı tasarım hasarına yol açtığını iddia eden DHH tarafından sunulmuştur . Ayrıca kaba taneli entegrasyon testinden yana.

Yazılım geliştirme üzerine bu perspektifi ele alırsanız, kaba taneli bağımlılık enjeksiyonu anlamlı olur.

İnce taneli bağımlılık enjeksiyonu için durum

İnce taneli bağımlılık enjeksiyonu, diğer taraftan, her şeyi enjekte etmek olarak tanımlanabilir !

İri taneli bağımlılık enjeksiyonuna ilişkin temel kaygım JB Rainsberger tarafından ifade edilen eleştiri. Tüm kod yollarını tümleştirme testleriyle kapatamazsınız, çünkü tüm kod yollarını kapsayacak şekilde tam anlamıyla binlerce veya on binlerce test senaryosu yazmanız gerekir.

BDD savunucuları, tüm kod yollarını testlerle kapamanız gerekmediği iddiasına karşı çıkacaktır. Sadece iş değeri üretenleri korumanız gerekir.

Bununla birlikte, benim deneyimlerime göre, tüm 'egzotik' kod yolları da yüksek hacimli bir dağıtımda yürütülecek ve test edilmezse, bunların çoğu kusurlu olacak ve çalışma zamanı istisnalarına neden olacaktır (genellikle boş referans istisnaları).

Bu, ince taneli bağımlılık enjeksiyonunu desteklememe neden oldu, çünkü tüm nesnelerin değişmezlerini yalıtılmış olarak test etmemi sağlıyor.

İşlevsel programlamayı tercih edin

İnce taneli bağımlılık enjeksiyonuna yaslanırken, diğer nedenlerin yanı sıra kendimi test edilebildiğim için işlevsel programlamaya vurgu yapıyorum .

SOLID koduna doğru ne kadar fazla hareket ederseniz, o kadar işlevsel hale gelir . Er ya da geç, daldırmayı da alabilirsin. Fonksiyonel mimari Limanlar ve Adaptörler mimarisidir ve bağımlılık enjeksiyonu da bir girişimdir ve Limanlar ve Adaptörler . Ancak fark, Haskell gibi bir dilin, bu mimariyi tip sistemi yoluyla zorlamasıdır.

Statik yazılan işlevsel programlamayı tercih edin

Bu noktada, temelde nesne yönelimli programlamadan (OOP) vazgeçtim, ancak OOP'nin sorunlarının çoğu Java ve C # gibi ana dillerle kavramın kendisinden daha fazla özdeşleştirilmiştir.

Ana akım OOP dilleri ile ilgili sorun, denenmemiş çalışma zamanı istisnalarına yol açan birleşimsel patlama sorununu önlemenin mümkün olmamasıdır. Diğer yandan, Haskell ve F # gibi statik olarak yazılmış diller, yazım sisteminde birçok karar noktasını kodlamanızı sağlar. Bu, binlerce test yazmak yerine derleyicinin, olası tüm kod yollarını ele alıp almadığınızı size söyleyeceği anlamına gelir (bir dereceye kadar; gümüş mermi yoktur).

Ayrıca, bağımlılık enjeksiyonu işlevsel değildir . Gerçek fonksiyonel programlama tüm bağımlılık kavramını reddetmelidir . Sonuç daha basit koddur.

özet

C # ile çalışmaya zorlanırsa, ince taneli bağımlılık enjeksiyonunu tercih ederim çünkü kod bazının tamamını yönetilebilir sayıda test vakası ile örtmeme olanak tanıyor.

Sonunda motivasyonum hızlı geri bildirim. Yine de ünite testi, geri bildirim almanın tek yolu değil .


1
Bu cevabı çok seviyorum ve özellikle Spring bağlamında kullanılan bu ifadeyi seviyorum: "XML kullanarak bağımlılıkları yapılandırmak her iki dünyanın da en kötüsüdür. İlk olarak, derleme zamanı tipi güvenliğini kaybedersiniz, ancak hiçbir şey elde edemezsiniz. dosya kolayca değiştirmeye çalıştığı kod kadar büyük olabilir. "
Thomas Carlisle

@ThomasCarlisle, değiştirmek için koda (hatta derleme) dokunmanız gerekmeyen XML yapılandırmasının amacı değil miydi? Mark'ın bahsettiği iki şey yüzünden hiç kullanmadım (ya da çok az), ancak karşılığında bir şeyler kazanıyorsunuz.
El Mac

1

Büyük DI kurulum sınıfları bir problemdir. Ancak yerine koyduğu kodu düşünün.

Tüm bu hizmetleri başlatmanız gerekiyor, ne yapmalı? Bunu yapmak için gereken kod ya app.main()başlangıç ​​noktasında olacak ve elle enjekte edilecek ya this.myService = new MyService();da sınıfların içinde olduğu gibi sıkıca bağlanacaktır .

Birden fazla kurulum sınıfına bölerek kurulum sınıfınızın boyutunu azaltın ve bunları program başlangıç ​​noktasından çağırın. yani.

main()
{
   var c = new diContainer();
   var service1 = diSetupClass.SetupService1(c);
   var service2 = diSetupClass.SetupService2(c, service1); //if service1 is required by service2
   //etc

   //main logic
}

Bunları diğer CI kurulum yöntemlerine aktarmak dışında servis1 veya 2'ye başvurmanız gerekmez.

Bu, ayarları çağırmanın sırasını zorladığından onları kaptan almaya çalışmaktan daha iyidir.


1
Bu kavramı daha yakından incelemek isteyenler için (sınıf ağacınızı programın başlangıç ​​noktasına yerleştirerek),
aranacak

@Ewan bu cideğişken nedir?
superjos,

CI kurulum sınıfınızı statik yöntemlerle
Ewan

urg di olmalı. 'konteyner'i düşünmeye devam
Ewan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.