Mikroservis kararının doğru cevabı ekip sayısıyla başlıyor: bağımsız olarak dağıtım yapabilen ekip sayınız birden fazla değilse, mikroservis size bir çözüm değil bir maliyet kalemi. Bu, karşıtların değil, mikroservis literatürünü kuran isimlerin pozisyonu. Martin Fowler'ın 2015'te yazdığı iki kısa metin hâlâ en net ifade: "The majority of software systems should be built as a single monolithic application" ve "don't even consider microservices unless you have a system that's too complex to manage as a monolith". Bu yazı, o karmaşıklık eşiğinin nerede olduğunu, modüler monolitin nasıl kurulduğunu ve ayırmaya karar verdiğinizde ilk neyi ayıracağınızı anlatıyor.
Fowler'ın iki tezi: primi kim ödüyor
MicroservicePremium (13 Mayıs 2015) tek bir fikir üzerine kurulu: mikroservisler kendi başlarına karmaşıklık getiriyor ve bu, projenin maliyetine ve riskine bir prim ekliyor. Bu primi ödemeye değer kılan şey sistemin kendi karmaşıklığı olmalı. Fowler'ın saydığı karmaşıklık kaynakları somut: büyük ekipler, çok kiracılılık, çok sayıda kullanıcı etkileşim modelini desteklemek, farklı iş fonksiyonlarının bağımsız evrilmesi, ve ölçekleme (bkz. Martin Fowler, MicroservicePremium).
MonolithFirst (3 Haziran 2015) daha da keskin: "you shouldn't start a new project with microservices, even if you're sure your application will be big enough to make it worthwhile." Gerekçeleri üç tane. Erken aşamada hız ve hızlı geri bildirim gerekiyor. Servis sınırlarını baştan doğru çizmek çok zor ve monolit içinde yapılan refactor, servisler arası refactor'dan kat kat kolay. Monolit fazı, mikroservis için gereken operasyon altyapısını kurmak için zaman kazandırıyor (bkz. Martin Fowler, MonolithFirst).
İkinci gerekçe pratikte en pahalıya patlayanı. Yanlış çizilmiş bir servis sınırını düzeltmek, iki veritabanını birleştirmek, iki dağıtım hattını birleştirmek ve iki takımı yeniden organize etmek demek. Aynı hatayı monolit içinde düzeltmek bir dizin taşımaktan ibaret.
Shopify vakası: 2,8 milyon satır Ruby, tek monolit, 37 bileşen
Modüler monolitin en iyi belgelenmiş örneği Shopify'ın kendi mühendislik yazıları. 16 Eylül 2020 tarihli "Under Deconstruction: The State of Shopify's Monolith" yazısında ana uygulamayı 2,8 milyon satırdan fazla Ruby kodu ve 500 bin commit olarak tarif ediyorlar. Bu kod tek bir monolit ama içinde 37 bileşen var ve her birinin herkese açık giriş noktaları tanımlı; bağımlılık ihlallerini yakalamak için Packwerk aracını bileşenlerin yaklaşık üçte birinde kullandıklarını yazıyorlar (bkz. Shopify Engineering, Under Deconstruction: The State of Shopify's Monolith).
Ayırma konusundaki tutumları da net: "We are very deliberate about when to split functionality out into separate services, and we only do it for good reasons. That's because splitting a single monolithic application into a distributed system of services increases the overall complexity considerably."
Ayırdıkları iki istisna öğretici, çünkü ikisinin de gerekçesi mimari zarafet değil:
- Storefront rendering — farklı ölçekleme profili. Vitrin trafiği ile yönetim paneli trafiği aynı eğriyi izlemiyor.
- Kredi kartı saklama (vaulting) — hassas veri izolasyonu. Uyum sınırını daraltmak için ayrılmış.
Bu iki gerekçe, ayırma kararı için kullanabileceğiniz en iyi iki testtir: bu parçanın ölçekleme profili gerçekten farklı mı? ve bu parçayı ayırmak bir uyum veya güvenlik sınırını daraltıyor mu? Cevap ikisinde de hayırsa, ayırmayın.
Modüler monolit nasıl kurulur: dört somut kural
"İyi yapılandırılmış monolit" bir niyet beyanı değil, uygulanabilir bir dizi kısıt. Laravel veya benzeri bir çatıda pratik karşılığı:
- Modül sınırını dizin yapısıyla değil, bağımlılık denetimiyle koruyun.
app/Billingiçindenapp/Catalogiçindeki bir sınıfı çağırmak yasaksa, bunu bir CI kontrolü kanıtlamalı. Denetlenmeyen kural, altı ay sonra yok demektir. - Her modülün tek bir giriş noktası olsun. Diğer modüller o modülün servis sınıfını çağırsın; Eloquent modeline doğrudan erişim modül sınırını delip geçiyor.
- Veritabanı tablolarını modüle sahiplendirin. Bir tabloya yalnızca bir modül yazsın. Diğerleri okumak için o modülün arayüzünü kullansın. Bu, ileride ayırmayı mümkün kılan tek şey.
- Modüller arası iletişimi olayla yapın. Sipariş oluştuğunda stok modülünü doğrudan çağırmak yerine bir olay yayınlayın. Bu, modülün ileride ayrı bir servise dönüşmesini tek satırlık bir değişikliğe indiriyor.
Dördüncü madde aynı zamanda bir uyarı taşıyor. Olay tabanlı iletişim, monolit içindeyken bile nihai tutarlılık (eventual consistency) getiriyor. Werner Vogels'ın 2008 tarihli "Eventually Consistent - Revisited" yazısındaki tanım hâlâ standart referans: sistem, nesneye yeni güncelleme yapılmadığı sürece eninde sonunda tüm erişimlerin son güncellenmiş değeri döndüreceğini garanti ediyor (bkz. Werner Vogels, Eventually Consistent - Revisited). Aynı yazı okuma-kendi-yazdığını, oturum tutarlılığı ve monoton okuma gibi ara modelleri de tanımlıyor; hangi modelin gerektiğini iş kuralınız belirliyor.
Dağıtık işlem: primin en pahalı kalemi
Monolitte tek bir veritabanı işlemiyle çözülen "siparişi oluştur, stoğu düş, ödemeyi al" akışı, üç servise bölündüğünde atomik olmaktan çıkıyor. Standart çözüm 1987'ye dayanıyor: Garcia-Molina ve Salem'in SIGMOD '87 bildirisi Saga desenini tanımlıyor (s. 249-259, DOI 10.1145/38713.38742). Uzun süren bir işlemi, her biri kendi telafi işlemine sahip küçük yerel işlemlere bölüyorsunuz (bkz. Garcia-Molina ve Salem, "Sagas", SIGMOD '87).
Pratikte bunun anlamı şu: her yazma işlemi için bir de geri alma işlemi yazmak zorundasınız, ve geri alma işlemi her zaman simetrik değil. Ödemeyi iade edebilirsiniz ama gönderilmiş bir e-postayı geri alamazsınız. Bu, iş kuralına dokunan bir tasarım sorunu; altyapıyla çözülmüyor.
Mikroservis primi hesabı yaparken şu kalemleri de yazın: her servis için ayrı CI hattı, ayrı sağlık kontrolü ve uyarı kuralı, servisler arası kimlik doğrulama, dağıtık izleme (tracing), sürüm uyumluluğu yönetimi, ve her yazma akışı için telafi işlemi. Bunların hiçbiri ürün özelliği değil; hepsi kalıcı bakım yükü.
Karar tablosu
| Durumunuz | Seçim |
|---|---|
| Tek ekip, ürün-pazar uyumu aranıyor | Monolit. Modül sınırlarını baştan çizin, ayırmayın. |
| İki-üç ekip, aynı depoda çalışıyor, dağıtımlar birbirini bekliyor | Modüler monolit + bağımlılık denetimi. Ayırmak için henüz erken. |
| Bir bileşenin ölçekleme profili diğerlerinden gerçekten farklı | O bileşeni ayırın. Diğerlerine dokunmayın. |
| Bir bileşen ödeme kartı veya sağlık verisi işliyor | Uyum sınırını daraltmak için ayırın. |
| Beş ve üzeri bağımsız ekip, olgun DevOps kültürü, ayrı yayın takvimleri | Mikroservis. Primi ödemeye değer. |
| "Ölçeklenebilir olsun" isteniyor ama trafik tahmini yok | Monolit. Ölçek problemi henüz yok. |
Ayırmaya karar verdiyseniz: ilk hangi parça
Yanlış başlangıç noktası "kullanıcı servisi"ni ayırmak. Kullanıcı verisi her yerde kullanılıyor ve ayrıldığı anda her sorgu bir ağ çağrısına dönüşüyor. Doğru başlangıç şu üç özellikten en az ikisini taşıyan bir parça:
- Az bağımlılık. Diğer modüllerden okuduğu tablo sayısı düşük.
- Farklı ritim. Kendi trafiği, kendi yük profili var (rapor üretimi, görsel işleme, bildirim gönderimi).
- Farklı ekip. Sahibi belli ve o ekip kendi takvimiyle çalışmak istiyor.
Ayırma sırası da önemli: önce okuma tarafını ayırın. Bir raporlama servisi, ana veritabanının replikasından okuyarak başlayabilir; yazma yolu değişmediği için geri dönüşü kolay. Yazma tarafını ayırmak, yukarıdaki Saga tartışmasını açıyor.
Efor tarafında gerçekçi olun: tek bir servisin monolitten çıkarılması, kod taşımanın ötesinde dağıtım hattı, gözlemlenebilirlik, kimlik doğrulama ve veri göçü işi. Kendi kapsamınız için bir bant çıkarmak isterseniz proje fiyat hesaplama aracı işinizi görür.
Sırada ne var
Şu sayıyı bulun: kaç ekip, birbirini beklemeden üretime dağıtım yapabiliyor? Cevap birse mimari sorununuz yok, dağıtım hattı sorununuz olabilir. Cevap üçten büyükse ve dağıtımlar birbirini bekliyorsa, önce modül sınırlarını CI'da denetlenen kurallara çevirin. Ayırma kararını ancak o denetim yeşil kaldıktan sonra verin; ayrılamayan bir modül, ayrı bir servis olarak da çalışmaz.
Konteyner ve dağıtım tarafı bu kararın diğer yarısı; oradaki pratik için Docker ile üretime dağıtım yazısına bakabilirsiniz. Altyapı modernizasyonu tarafındaki çalışma biçimimiz DevOps ve altyapı sayfasında ve altyapı modernizasyonu örneğinde. Mevcut bir sistemin değerlendirmesi için iletişim sayfasından yazabilirsiniz.
Atıflar 25 Eylül 2026 tarihinde doğrulanmıştır: Martin Fowler, "MicroservicePremium" (13.05.2015) ve "MonolithFirst" (03.06.2015); Shopify Engineering, "Under Deconstruction: The State of Shopify's Monolith" (16.09.2020) ve "Deconstructing the Monolith" (21.02.2019); Garcia-Molina ve Salem, "Sagas", SIGMOD '87, s. 249-259; Werner Vogels, "Eventually Consistent - Revisited" (23.12.2008). Adam-gün bandı ininia'nın kendi tahmin modelindeki değerdir (300–400 USD/adam-gün) ve bağlayıcı teklif değildir.