Mikroservislerde Shared Library Kullanımı
Ortak kullanılan kodu reuse etmek yazılım geliştiricilerin sıklıkla yaptığı bir pratiktir. Peki her zaman geçerli ve fayda sağlayan bir pratik midir?
Mikro servisler “share nothing” mimarisi olarak bilinir. Pragmatik olarak, bunu “mümkün olduğunca az paylaş” mimarisi olarak da düşünebilir çünkü her zaman mikro servisler arasında paylaşılan bir miktar kod olacaktır.
Mikro servislerin en sağladığı en önemli avantajlardan biri bağımsız deploy edilebilme bir diğeri de loosely couple bir yapıda olmalarıdır ki bu da farklı takım ve servisler için hem communication overhead hem de agility açısından önemlidir.
Diğer çoğu jenerik çözüm gibi, mikro servis mimarisi de kendi trade-offlarına sahiptir. Mikro servis mimarisinde bazı şeyler kolaylaşırken bazı şeyler de zorlaşır. Mikro servis mimarisiyle gelen önemli sorulardan biri de shared codeların nereye konacağıdır. Mikro servis mimarisi uygulamanın farklı kısımlarını decouple etmek için ortaya atılan bir mimaridir. Shared ise bunun tersini yapar. Tüm mikro servisler tarafından kullanılan ve paylaşılan ortak kodlardır. Bu da eğer shared librarynizi doğru tasarlamazsanız mikroservislerinizin en önemli faydalarından ödün vermeye başlarsınız demektir.
Bunun yanında shared library kendine bağımlı olan tüm servislerin redeployment edilmesini gerektirir. Bu da uzun build, release ve deployment süreleri demektir. Tüm bunlar oldukça senkron olmayı ve ekipler arasında sıkı iletişim sahibi olmayı gerektirir. Bu sebeple mikro servis mimarisinde shared library kullanmaktan kaçınmak yerinde olacaktır. Ayrıca tüm mikro servisler bir library’e bağlanacağı için bu noktada artık tight coupling ve single point of failure söz konusudur. Ayrıca mikroservislerin en önemli faydası olan teknoloji bağımsızlığını kaybedeceksiniz.
The evils of too much coupling between services are far worse than the problems caused by code duplication.
Shared library tasarlarken sıkça yapılan bazı hatalar vardır
- Kendi spesifik ihtiyaçlarımıza paralel componentleri shared’a eklemek. Bir shared library yaratmadan önce iyi düşünmek gerekir. Yeni bir shared yaratmadan önce bu nasıl değişebilir ve bunu kim kullanabilir diye düşünmek gerekir. Kendi specific ihtiyaçlarınız için yaratmaktan kaçınmalıyız çünkü bu diğer userların bu metotları kullanmasını ve extend etmesini zorlaştırır.
- Domain bazlı herhangi bir componenti shared’a koymak. Örneğin, user adında bir entitymiz var ve bu entity hemen hemen tüm mikroservislerde kullanılıyor olsun. Bunu görür görmez bu entityi shared’a taşıma refleksi gösterebiliriz. Tüm mikroservisler bunu kullansa dahi yine de shared libraryde olmamalıdır. Hatta tüm mikroservisler bunu duplike etse bile. Çünkü bu component ileride mikroservisler tarafından kendi ihtiyaçlarına göre revize edilebilir ve hepsinin aynı User model ile çalışma gibi bir zorunluluğu yok.
- Ortada mikroservisler yokken hazır shared oluşturmak. Daha mikroservisler ortada yokken, neyi share ettikleri tam anlamıyla belli değilken varsayımsal argümanlarla shared oluşturarak mimariyi kurgulamaya başlamak doğru bir yol değildir.
- Çok sık değişen ihtiyaçları shared’a koymak.
- Consumerlar arası coupling yaratan componentleri shared’a koymak.
Tam da bu noktada white-box ve black-box reuse kavramlarına değinmek istiyorum. Black-box reuse kullandığınız componentin iç yapısında ne oldugunu bilmeye ihtiyaç duymadan hatta bilmeden kullandığınız componentlerdir ve tüm sahip olduğunuz interfacelerdir. White-box reuse ise kullandığınız componentin nasıl implemente edildiğini bildiğiniz reuse şeklidir ve genellikle inheritance anlamına gelir.
Shared libraryleri yeniden kullanmaya “White-box reuse” denir. Bu, libraryi doğru bir şekilde kullanmak için genellikle kütüphanenin içindekileri anlamamız gerektiği anlamına gelir. Bu, kütüphanelerin kullanımını zorlaştırır.
Refactoring ve Modernizasyonlarda Shared Kaynaklı Mental Barrier
Bunların yanında, ekipteki developerların shared kütüphanelere kod yazmaktan kaçındığı da bir gerçektir. Bunun sebepleri,
- Korku : Diğer domainlerin yapısının bilinmemesi durumunda shared libraryde değiştirilen bir kodun dağıtık sistemdeki etkilerini öngörmek oldukça zor olabilir. Bu da geliştiricilerin shared library’e kod yazmaya çekinceli davranmasına yol açar.
- Shared library’e kod yazmanın daha fazla eforu olması : Shared library’lere kod yazmanın eforu çok daha fazladır. Shared librarydeki kodu değiştirmek, bunun testini yapmak ya da bu shared libraryi tüm sistemde uygun versiyona getirip tüm sistemi deploy alıp test etmek diye uzar gider.
- Gerekli refactoring ve modernizasyonlardan kaçınmak, kötü çözümlere ve teknik borçlara yol açacaktır. Bu, tüm sistemin genel bakımını ve sürdürülebilirliğini etkiler.
Bütün bunlar sadece reuse’dan kurtulmak için mi? – Buna değmez.
PEKI NASIL BİR YOL İZLEYEBİLİRİZ?
Öncelikle dağıtık sistemlerde shared bir component konseptinin best practice dışı olduğunu bilmek gerekir. Her bir service otonom ve kendi başına bağımsız bir şekilde deploy olabilmelidir.
- Kod tekrarını kabul edebiliriz. Mikro servislerin independent kalabilmesi için kod tekrarı kabul edilebilir.
- Mikro servisleri shared component ihtiyacı minimum olacak şekilde ayrıştırabiliriz
- Shared library yerine shared servis kullanabiliriz. Bu sayede diğer servislerin bağımlılığı library’e kıyasla azalacak ve shared servis de kendi içerisinde build ve deploy edilebilir hale gelecek.
Ancak, bir şekilde edge caselerden sebeple ekip içerisinde shared kullanılma kararı alındıysa yine belli noktaları atlamamak lazım. Öncelikle mikroservislerin tasarımını kafamızda oturtup hatta gerekirse geliştirmelerini yapıp neleri share ettiğini görmekte fayda var. Belki bu noktada yine shared kullanmamanız gerektiği noktasına çıkabilirsiniz ancak yine de bu sayede tüm servislerin tam olarak neleri share ettiğini, nelerin share’da taşınmasının belki avantaj nelerin taşınmaması gerektiği ve coupling yaratacağını çok net bir şekilide görebilirsiniz.