Dependency Injection
Bu bölümün bütün kodlarını burada bulabilirsiniz
Bunun için interfaceler hakkında biraz bilgi sahibi olmanız gerekeceğinden, structler bölümünü daha önce okuduğunuz varsayılmaktadır.
Programlama topluluklarında dependency injection konusunda birçok yanlış anlama var. Umarım, bu kılavuz size nasıl yapılacağını gösterecektir.
Framework'e ihtiyacınız yok
Tasarımınızı karmaşıklaştırmaz
Testi kolaylaştırır
Kullanışlı, harika fonksiyonlar yazmanıza izin verir.
hello-world bölümünde yaptığımız gibi, birini selamlayan bir fonksiyon yazmak istiyoruz ama bu sefer varolan çıktıyı (actual printing) test edeceğiz.
Özetlemek gerekirse, fonksiyon bu şekilde gözüküyor
Fakat bunu nasıl test edeceğiz? fmt.Printf
çıktılarını stdout'a çağırmak, test frameworkü kullanarak yapmamız çok zor.
Yapmamız gereken, yazdırmanın bağımlılığını inject etmektir (bu sadece içeri girmek için süslü bir kelime).
Yazdırma işleminin nerede veya nasıl olduğuna fonksiyonumuz önemsememeli, Bu yüzden concrete tip yerine interface kabul etmeliyiz.
Bunu yaparsak, uygulamayı kontrol ettiğimiz bir şeye yazdıracak şekilde değiştirebiliriz, böylece test edebiliriz."Gerçek hayatta" stdout'a yazan bir şey inject edersiniz.
Eğer fmt.Printf
kaynak koduna bakarsanız bağlanabileceğimiz bir yol görebilirsiniz
İlginç! Printf
altında sadece Fprintf
çağırıyor ve os.Stdout
'u parametre olarak gönderiyor.
Tam olarak os.Stdout
nedir? Fprintf
, 1. argüman için kendisine ne iletilmesini bekliyor?
Bir io.Writer
Buradan os.Stdout
'un io.Writer
implemente ettiğini sonucunu çıkarabiliriz; Printf
, os.Stdout
'u io.Writer
bekleyen Fprintf
'e gönderir.
Daha fazla Go kodu yazdıkça, bu arayüzün çok fazla ortaya çıktığını göreceksiniz çünkü "bu verileri bir yere koymak" için harika, kullanışlı bir interface.
Dolayısıyla, greetingi örtülü bir şekilde bir yere göndermek için nihayetinde Writer
'ı kullandığımızı biliyoruz. Kodumuzu test edilebilir ve daha fazla yeniden kullanılabilir hale getirmek için bu mevcut soyutlamayı kullanalım.
İlk olarak test yaz
bytes
paketindeki Buffer
tipi,Writer
interfaceini implemente eder, çünkü Write(p []byte) (n int, err error)
metoduna sahip.
Onu Writer
olarak göndermek için testimizde kullanacağız Greet
'i çağırdıktan sonra ona ne yazıldığını kontrol edebiliriz.
Dene ve testi çalıştır
Test derlenmeyecektir
Testin çalışması için minimum kodu yaz ve başarısız test çıktılarını kontrol et
Derleyiciyi dinle ve problemi düzelt.
Hello, Chris di_test.go:16: got '' want 'Hello, Chris'
Test başarısız oluyor. Adın yazdırıldığına dikkat edin, ancak stdout'a gidecek.
Testi geçecek kadar kod yaz
Testimizde, greetingi buffera göndermek için writerı kullan. fmt.Fprintf
'in fmt.Printf
gibi olduğunu hatırla ancak string göndermek için Writer
'ı alır, oysa fmt.Printf
varsayılan olarak stdouttur.
Şimdi testten geçiyor.
Refactor
Daha önce derleyici bize 'bytes.Buffer' için pointer göndermemizi söyledi. Bu teknik olarak doğru ama çok kullanışlı değil.
Bunu göstermek için, Greet
fonksiyonunu stdout'a yazdırmasını istediğimiz bir Go uygulamasına bağlamayı deneyin.
./di.go:14:7: cannot use os.Stdout (type *os.File) as type *bytes.Buffer in argument to Greet
Daha önce tartışıldığı gibi, fmt.Fprintf
, hem os.Stdout
hem de bytes.Buffer
implementationını bildiğimiz bir io.Writer
göndermenize izin verir.
Eğer kodumuzu daha kullanışlı bir interface çevirirsek onu hem testlerde hem de uygulamada kullanabilirizi..
io.Writer hakkında daha fazla
io.Writer
kullanarak başka hangi yerlere veri yazabiliriz? Greet
fonksiyonumuz ne kadar kullanışlı?
İnternet
Aşağıdakileri çalıştırın
Programı çalıştırın ve http://localhost:5000 adresine gidin. Greeting fonksiyonunun kullanıldığını göreceksiniz.
HTTP serverlar sonraki konularda bahsedilecek o yüzden detaylar hakkında çok fazla endişe etmeyin.
HTTP handler yazdığınızda, size http.ResponseWriter
istek (request) yapmak için kullanılan http.Request
verilir. Sunucuyu implemente ettiğinizde, writer kullanarak cevabınızı yazarsınız.
http.ResponseWriter
'ın io.Writer
'ı implemente ettiğini tahmin ediyorsunuzdur, bu sayede handlerımızda Greet
fonksiyonumuzu kullanabiliriz.
Özetlersek
Kodumuzun ilk halini test etmek kolay değildi çünkü kontrol edemediğimiz bir yere veri yazıyordu.
Testlerimizden motive olarak kodu refactor ettik, böylece verilerin bir bağımlılık inject ederek nerede yazıldığını kontrol edebildik, bu da bize şunları yapmamızı sağladı:
*Kodu test etme Eğer bir fonksiyonu kolayca test edemiyorsanız, bunun nedeni genellikle fonksiyona veya global bir duruma bağımlılıklarıdır. Örneğin, bir tür hizmet katmanı tarafından kullanılan global bir veritabanı bağlantı havuzunuz varsa, test edilmesi muhtemelen zor olacak ve çalıştırması yavaş olacaktır. DI sizi, testlerinizi kontrol edebileceğiniz, mocklayabileceğiniz veritabanı bağımlılığı (bir interface araclığı ile) inject etmeye motive eder.
Separate our concerns (Bağlantıların ayırma), verilerin nasıl oluştuğu ve nereden nereye gittiği ayrılması.Bir fonksiyonun/metodun çok fazla sorumluluğu olduğunu düşünüyorsanız (veri oluşturma ve db'ye yazma? HTTP isteklerini handle etme ve domain seviyesinde mantık?) DI ihtiyaç duyacağınız araçtır.
Kodumuzun farklı contextlerde yeniden kullanılması Kodumuzun kullanabileceği ilk "yeni" context, testlerin içindedir. Biri sizin fonksiyonlarınıza yeni bir şey denemek isterse, kendi bağımlılıklarını inject edebilir.
Mocking'e ne dersin? DI için buna ihtiyacın olduğunu ve aynı zamanda bunun kötü olduğunu duydum
Mocking detaylıca ileride ele alınacaktır (ayrıca kötü değil). Inject ettiğiniz gerçek şeyleri, testlerinizde kontrol edebileceğiniz ve inceleyebileceğiniz taklit bir sürümle değiştirmek için mockingi kullanırsınız. Bizim durumumuzda, standart kütüphanenin bizim için kullanıma hazır bir şeyi vardı.
Go standard kütüphanesi gerçekten faydalı, üzerinde çalışmak için zaman ayır
io.Writer
interfaceine aşina oldukça, testimizde bytes.Buffer
'ı Writer
olarak kullanabileceğiz ve fonksiyonumuzu komut satırı uygulamasında veya web sunucusunda kullanmak için standart kütüphaneden diğer Writer
ları kullanabiliriz.
Standart kitaplığa ne kadar aşina olursanız, yazılımınızı çeşitli contextlerinde yeniden kullanılabilir hale getirmek için kendi kodunuzda yeniden kullanabileceğiniz bu kullanışlı interfaceleri o kadar çok görürsünüz.
Bu örnek, The Go Programming language kitabından oldukça etkilenmiştir, eğer beğendiyseniz satın alın!
Bu sayfa @bariscanyilmaz tarafından çevrildi.
Last updated