Strangler Fig ile Legacy Dönüşüm

Eski monolitik sistemleri parçalara ayırmak için strangler fig deseni ile kademeli geçiş stratejisi, risk yönetimi ve önceliklendirme anlatılır.

Strangler Fig ile Legacy Dönüşüm

Strangler Fig Pattern: Legacy Monolith'i Aşamalı Olarak Dönüştürmek

Bir yazılım projesi yıllar içinde büyüdükçe, teknik borç birikir, bağımlılıklar iç içe geçer ve yeni özellik eklemek giderek zorlaşır. Bir noktada, bu "legacy monolith"i yeniden yazmaya karar verirsiniz. Ancak, "big bang" (büyük patlama) şeklinde yeniden yazım, uzun sürer, risklidir ve çoğu zaman başarısız olur. İşte Strangler Fig Pattern (Boğucu İncir Deseni), bu ikilemi çözen, Martin Fowler tarafından popüler hale getirilmiş, eski sistemi kademeli olarak yeni sistemle değiştirme stratejisidir. Bu desen, bir boğucu incir ağacının, konakçı ağacı sararak onu yavaşça gölgelemesi ve sonunda tamamen yerini alması gibi, yeni uygulamanın da eski monoliti parça parça sarmasını ve devre dışı bırakmasını öngörür.


1. Strangler Fig Deseni Nedir?

Strangler Fig, üç temel aşamadan oluşur:

  1. Intercept (Müdahale Et): Yeni özellikleri veya gelen istekleri yakalamak için eski sistemin önüne bir API Gateway, Reverse Proxy (YARP, Ocelot) veya Router yerleştirilir. Bu katman, hangi isteklerin eski sisteme, hangilerinin yeni sisteme yönlendirileceğine karar verir.

  2. Migrate (Göç Et): Monolith içindeki belirli bir modül veya işlevsellik, yeni mikroservis veya modüler sisteme kademeli olarak taşınır. Taşınan her modül, proxy üzerinden yeni sisteme yönlendirilir.

  3. Redirect (Yönlendir): Tüm işlevsellik yeni sisteme taşındığında, eski monolith devre dışı bırakılır (decommissioned) ve proxy doğrudan yeni sisteme yönlendirir.

Bu süreç, aylar veya yıllar sürebilir. Bu süre zarfında, eski ve yeni sistemler paralel olarak çalışır.


2. Strangler Fig Uygulama Adımları

Adım 1: Mevcut Sistemi Anlama ve Önceliklendirme (Domain-Driven Design ile)

Tüm monolith'i aynı anda taşımak imkânsızdır. Taşıma işlemine nereden başlayacağınıza karar vermek için:

  • Bounded Context (Sınırlı Bağlam) Belirleme: Monolith içindeki işlevsel alanları (bounded contexts) belirleyin. Örneğin, Sipariş Yönetimi, Ürün Kataloğu, Kullanıcı Yönetimi, Faturalandırma gibi.

  • Önceliklendirme (Prioritization): Hangi modülü önce taşıyacağınıza karar verin. Kriterler:

    • En Çok Değişen Modül (En Çok Acı Veren):) En sık değişiklik isteği alan, teknik borcu en yüksek modül.

    • Bağımsız (Autonomous) Modül: Diğer modüllere en az bağımlı olan, bağımlılıkları en az olan modül.

    • En Yüksek İş Değeri (Business Value) Sağlayan: Müşteri veya iş için en kritik olan modül.

    • En Düşük Riskli Modül: Pilot uygulama için en uygun, hata riski düşük modül.

Adım 2: Proxy / Gateway Katmanı Oluşturma

Eski ve yeni sistemler arasında trafiği yönlendirecek bir katman kurun.

  • Seçenekler: YARP, Ocelot (API Gateway), Azure Application Gateway, NGINX, veya özel bir routing servisi.

  • Yapılandırma: Hangi URL path'lerinin (örn. /api/orders/*) yeni sisteme, hangilerinin eski sisteme gideceğini tanımlayın.

  • Feature Flag Entegrasyonu: Yönlendirme kararını bir feature flag'e bağlayarak, yeni sistemi anında açıp kapatabilirsiniz (kill switch).

csharp

// YARP ile örnek routing (appsettings.json)
{
  "ReverseProxy": {
    "Routes": {
      "new-orders-route": {
        "ClusterId": "new-orders-cluster",
        "Match": {
          "Path": "/api/orders/{**catch-all}"
        },
        "Filters": [
          {
            "Name": "YeniSistemFeatureFlag", // Özel bir middleware ile kontrol et
            "Parameters": { "Enabled": true }
          }
        ]
      },
      "legacy-route": {
        "ClusterId": "legacy-cluster",
        "Match": {
          "Path": "/{**catch-all}" // Tüm diğer istekler eski sisteme
        }
      }
    }
  }
}

Adım 3: Modülü Yeni Sisteme Taşıma (Migration)

Taşınacak her modül için:

  1. Yeni Mikroservis/Modül Oluşturun: Clean Architecture, CQRS ve DDD prensiplerine uygun, bağımsız bir servis oluşturun.

  2. Veritabanı Geçişi (Database Migration): Veritabanını taşımak en zor kısımdır. İki strateji:

    • Shared Database (Paylaşımlı Veritabanı): Hem eski hem yeni sistem aynı veritabanını paylaşır (geçiş sürecinde). Bu, veri tutarlılığını korur ancak veritabanı şeması değişikliklerini zorlaştırır.

    • Dual Write (Çift Yazma): Yeni sistem, veritabanına yazarken aynı anda eski sisteme de yazar (veya tam tersi). Bu daha karışıktır.

    • Synchronization Job (Senkronizasyon İşlemi): Yeni sistem, eski sistemin veritabanını belirli aralıklarla okuyarak kendi veritabanını günceller. Eventual Consistency (Nihai Tutarlılık) kabul edilir.

    • Strangler Fig + Database per Service: İdeal olan, her mikroservisin kendi veritabanına sahip olmasıdır. Ancak bu, veri göçü sırasında en zor ve riskli adımdır. Veri göçü için ETL (Extract, Transform, Load) araçları kullanılabilir.

Adım 4: Yönlendirmeyi Kademeli Olarak Değiştirme

  • Canary Release (Kademeli Yayın): Yeni sistemi önce test kullanıcılarına, sonra belirli bir yüzdeye (%1, %5, %10) açın.

  • Monitoring ve Observability (İzleme): Yeni sistemin hata oranlarını, yanıt sürelerini ve kaynak kullanımını eski sistemle karşılaştırarak izleyin. (Application Insights, Prometheus, Grafana).

  • Rollback (Geri Alma) Planı: Herhangi bir sorunda, trafiği anında eski sisteme yönlendirebilecek bir mekanizmanız olsun.

Adım 5: Eski Modülü Devre Dışı Bırakma (Decommission)

Tüm trafik yeni sisteme yönlendirildiğinde ve eski modül kullanılmaz hale geldiğinde:

  • Eski modülün kodunu kaldırın.

  • Eski veritabanı tablolarını arşivleyin veya temizleyin.

  • Eski sisteme giden bağımlılıkları (örn. eski API endpoint'leri) kapatın.


3. Risk Yönetimi ve Zorluklar

Risk Çözüm
Veri Tutarsızlığı (Eski/Yeni DB arası) Eski ve yeni sistem aynı veritabanını paylaşırken (shared DB) veya veri göçü sırasında senkronizasyon sağlamak zordur. Çift yazma (dual write) kullanın veya veri tutarlılığını eventual consistency ile kabul edin.
Performans Düşüşü (Proxy/ Gateway ek yükü) Proxy katmanı hafif olmalıdır. YARP veya NGINX gibi yüksek performanslı araçlar kullanın.
Artan Karmaşıklık (Eski + Yeni birlikte) Uygulamanın iki sistemi birden yönetmek operasyonel karmaşıklığı artırır. Otomasyon ve izleme araçları şarttır.
Takım Morali (Uzun süren geçiş) Geçiş süreci uzun ve yorucu olabilir. Küçük, hızlı kazanımlar (quick wins) planlayarak takım motivasyonunu koruyun.

4. Strangler Fig Desenini Uygularken Kaçınılması Gereken 3 Hata

  1. "Big Bang" Zihniyeti: Tüm sistemi bir anda taşımaya kalkışmayın. Her seferinde küçük bir modülü taşıyın.

  2. Eski Sistemi Anlamadan Başlamak: Monolith'in nasıl çalıştığını, bağımlılıklarını, veritabanı şemasını ve iş kurallarını tam olarak anlamadan başlamayın. Bu, geçiş sırasında sürprizlerle karşılaşmanıza neden olur.

  3. Test ve Monitoring'i İhmal Etmek: Yeni sistemin hatasız çalıştığından emin olmadan trafiği yönlendirmeyin. Otomatik testler, canary release ve detaylı monitoring olmazsa olmazdır.

Sonuç:

Strangler Fig Pattern, legacy monolith'leri modern mikroservis mimarisine dönüştürmenin en güvenli, en kontrollü ve en başarılı yoludur. Bu desen, riskleri en aza indirir, sürekli iş teslimine (continuous delivery) olanak tanır ve takımların yeni teknolojileri kademeli olarak benimsemesini sağlar.

Başarılı bir dönüşüm için disiplinli bir yaklaşım, doğru önceliklendirme ve sağlam bir izleme/geri alma planı esastır. Unutmayın, dönüşüm bir yarış değil, bir maratondur. Strangler Fig deseni, bu maratonu kazanmanın anahtarıdır.

Tüm yazılar