in

Legacy Yazılım Modernizasyonu: Yeniden Yazım mı, Strangler mi?

'Sistemi baştan yazalım' kararı, kurumsal yazılımda en pahalı ve en sık pişman olunan karardır. Beş modernizasyon yaklaşımını risk, süre ve maliyetle karşılaştırıyor; kesintisiz geçişi mümkün kılan strangler fig desenini adım adım, en zor kısım olan veri katmanı stratejisiyle birlikte anlatıyoruz.

Eski sistemin önüne konan geçit üzerinden yeteneklerin adım adım yeni modüllere taşınmasını gösteren strangler fig şeması

On beş yıllık bir sistem, artık desteklenmeyen bir uygulama sunucusu, kaynak kodunu bilen tek bir geliştirici ve her sürümde bir şeyin bozulduğu bir dağıtım süreci. Bu noktada masaya gelen cümle hep aynıdır: "Baştan yazalım." Kurumsal yazılımda en pahalı ve en sık pişman olunan karar budur; iki yıl sonra ortada iki sistem, yarım kalmış bir geçiş ve eski sistemde hâlâ çalışan gizli iş kuralları vardır.

Bu yazıda önce doğru teşhisi — sistemin gerçek sorunu ne? — sonra beş modernizasyon yaklaşımını risk, süre ve maliyetle karşılaştırıyor; yeniden yazımın neden çoğunlukla yanlış olduğunu, kesintisiz geçişi mümkün kılan strangler fig desenini adım adım, en zor kısım olan veri katmanı stratejisini ve sahada gördüğümüz hataları anlatıyoruz.

Önce teşhis: neyi çözmeye çalışıyorsunuz?

Belirti

Asıl sorun genellikle

Uygun ilk adım

Küçük bir değişiklik haftalar sürüyor

Test yok, dağıtım elle, kod spagetti

Test ve dağıtım otomasyonu; kod değişmeden

Platform desteği bitti (JDK 8, eski uygulama sunucusu)

Güvenlik ve uyumluluk riski

Rehost/replatform: kod aynı, altyapı yeni

Bilen tek kişi var

Bilgi riski, doküman yok

Karakterizasyon testleri ve mimari kayıt

Yeni özellik eklenemiyor, iş bekliyor

Mimari değişimi taşıyamıyor

Strangler fig: yeni özellikler yeni modülde

Lisans ve operasyon maliyeti yüksek

Ticari altyapıya bağımlılık

Replatform ya da paket değişimi

"Legacy" bir yaş değil, bir durumdur: değiştirmesi riskli ve pahalı olan sistem. Teşhis yapılmadan seçilen yöntem, yanlış soruna doğru cevap verir.

Beş yaklaşım

Yaklaşım

Ne yapılır

Risk

Süre

Ne zaman

Rehost / replatform

Kod aynı; konteyner, güncel JDK, yönetilen veritabanı

Düşük

Haftalar–aylar

Platform riski ana sorunsa; her yolun ilk adımı

Yerinde refactor

Testler eklenir, modüller ayrıştırılır, kod temizlenir

Düşük–orta

Sürekli

Kod tabanı kurtarılabilir durumdaysa

Strangler fig

Yetenekler tek tek yeni sisteme taşınır; eski sistem küçülerek emekliye ayrılır

Orta, adım başına düşük

6–24 ay, her ay değer üretir

Büyük, canlı, kritik sistemlerde varsayılan yol

Yeniden yazım (big bang)

Yeni sistem sıfırdan; bir gün geçiş

Yüksek

12–36 ay, değer sonda

Küçük sistem, ölü platform, net şartname

Paket / SaaS ile değiştirme

Özel sistem yerine hazır ürün

Orta

6–18 ay

Süreç standart, farklılaşma yoksa (bkz. özel yazılım mı hazır paket mi)

Yeniden yazım neden genelde yanlış?

  • Özellik eşitliği tuzağı: Eski sistemde on beş yılda birikmiş binlerce iş kuralı vardır ve çoğu yazılı değildir. "Aynısını yapan" yeni sistem, canlıya alındığı gün eksik çıkar.

  • Değer sonda gelir: İki yıl boyunca iş hiçbir şey almaz; bu arada eski sisteme eklenen her özellik yeni sisteme de eklenmelidir — iki hedef birden hareket eder.

  • İkinci sistem etkisi: "Bu sefer her şeyi doğru yapalım" hırsı, yeni sistemi ilkinden karmaşık yapar.

  • Tek günlük geçiş: Geri dönüşü zor, riski en yüksek an; veri göçü, eğitim ve entegrasyonlar aynı gece.

Yeniden yazım doğru olduğunda: sistem küçüktür (birkaç ay), platform gerçekten ölmüştür (kaynak kod yok, çalıştırılamıyor) ya da iş süreci zaten değişiyordur ve eski davranış korunmayacaktır.

Strangler fig: adım adım

Desen adını, ev sahibi ağacın etrafında büyüyüp onu zamanla saran incir türünden alır: yeni sistem eskisinin etrafında büyür, yetenekleri tek tek devralır, eski sistem sonunda boşalır. Kesintisiz, geri alınabilir ve her adımda değer üreten tek yol budur.

Adım 0: Eski sistem                       istemci ──► [eski sistem] ──► [eski DB]

Adım 1: Geçit öne konur                   istemci ──► [geçit] ──► [eski sistem] ──► [eski DB]

Adım 2: İlk yetenek taşınır               istemci ──► [geçit] ─┬─► [eski sistem] ──► [eski DB]
                                                                └─► [yeni: fiyatlandırma] ──► (eski DB / kendi DB'si)

Adım N: Eski sistem boşalır               istemci ──► [geçit] ──► [yeni modüller] ──► [yeni DB]
  1. Geçidi öne koyun. Tüm trafik bir API geçidinden ya da ters vekilden geçer; yönlendirme kuralı yol, kiracı ya da özellik bayrağı bazlıdır. Bu adım eski sistemi değiştirmez ve tek başına geri alınabilir.

  2. Karakterizasyon testleri yazın. Eski sistemin gerçek girdi-çıktılarını kaydedin (altın kayıtlar): "bu 500 sipariş için fiyatlandırma bu sonuçları veriyor". Yeni modül aynı testlerden geçmelidir. Şartnamenin olmadığı yerde davranışın kendisi şartnamedir.

  3. Dikişi seçin. İlk taşınacak yetenek: iş değeri yüksek, bağımlılığı düşük, sınırı net (fiyatlandırma, bildirim, raporlama, yeni bir kanal). En zor modülle başlamayın; ilk döngü ekibin yöntemi öğrenmesi içindir.

  4. Yeni modülü kurun ve yönlendirin. Önce gölge modda (her iki sistem çalışır, sonuçlar karşılaştırılır, yalnızca eski cevap döner), sonra kademeli trafik (%5 → %50 → %100), geri alma tek bayrak.

  5. Eskiyi emekliye ayırın. Taşınan yeteneğin kodu eski sistemden silinir; silinmeyen kod "yedek" değil, iki kat bakımdır.

  6. Tekrarlayın. Her döngü 4–8 hafta; her döngünün sonunda üretimde çalışan yeni bir parça.

# Spring Cloud Gateway: fiyatlandırma yeni modüle, geri kalan eski sisteme
spring:
  cloud:
    gateway:
      routes:
        - id: fiyatlandirma-yeni
          uri: http://fiyatlandirma-servisi
          predicates:
            - Path=/api/fiyat/**
            - Header=X-Canary, true          # önce iç kullanıcılar; bayrak kalkınca herkes
        - id: eski-sistem
          uri: http://legacy-app
          predicates:
            - Path=/**
// Karakterizasyon testi: eski sistemin kaydedilmiş sonuçları yeni modülün sözleşmesidir
@ParameterizedTest
@MethodSource("altinKayitlar")                                   // 500 gerçek sipariş + eski sistemin verdiği fiyatlar
void yeniFiyatlandirmaEskiyleAyniSonucuVerir(SiparisOrnegi ornek) {
    FiyatSonucu yeni = fiyatlandirma.hesapla(ornek.girdi());
    assertThat(yeni).usingRecursiveComparison().isEqualTo(ornek.eskiSonuc());
}

Veri katmanı: en zor kısım

Kodu taşımak kolay, veriyi ayırmak zordur; çoğu strangler projesi burada tıkanır. Üç aşamalı yol:

  1. Paylaşılan veritabanı (geçici): Yeni modül eski tabloları okur ve yazar. Hızlı başlangıç, ama şema eski sisteme bağlı kalır. Kural: yeni modül eski şemaya kendi anti-corruption katmanıyla erişir; entity'lerini eski tablolara doğrudan bağlamaz.

  2. Sahiplik devri: Taşınan yeteneğin tablolarının tek yazarı yeni modül olur; eski sistem yalnızca okur (ya da bir görünüm üzerinden erişir). "Bir tablonun tek sahibi" ilkesi.

  3. Ayrı veritabanı ve senkronizasyon: Yeni modül kendi şemasına geçer; eski sistemin hâlâ ihtiyaç duyduğu veri, değişiklik yakalama (CDC, örneğin Debezium) ya da olaylarla eski şemaya yansıtılır. Çift yazma (iki veritabanına aynı anda yazmak) tutarsızlık üretir; kaçının.

Veri göçü büyük patlama yerine yetenek bazında ve prova edilerek yapılır; her taşınan yetenek kendi verisini götürür.

Yönetişim: nasıl ölçülür, ne zaman durulur?

  • Metrikler: Yeni sistemde işlenen trafik yüzdesi, değişiklik teslim süresi (fikirden üretime), üretim olayı sayısı, eski sistemde kalan kod satırı. Sunum değil, pano.

  • Zaman kutusu ve çıkış kriteri: Her döngü için tarih ve "bitti" tanımı; iki döngü üst üste hedefi kaçıran program yeniden planlanır, sessizce uzamaz.

  • Eski sisteme değişiklik politikası: Yeni özellik yalnızca yeni modüle; eski sisteme yalnızca hata düzeltme ve mevzuat. Bu kural olmadan hedef sürekli kaçar.

  • İş katılımı: Her dikişte iş sahibi kabul testinin parçasıdır; gizli kurallar en çok bu görüşmelerde ortaya çıkar.

Sahada sık yapılan hatalar

  1. Her şeyi modernize etmek. Değişmeyen ve çalışan modül (yıllık bordro hesabı) olduğu gibi kalabilir; modernize edilmesi gereken, iş değişikliği talep eden bölümlerdir.

  2. Testsiz taşımak. Karakterizasyon testi olmadan "aynı davranış" iddiası doğrulanamaz; hatalar canlıda müşteriden öğrenilir.

  3. Geçit olmadan başlamak. İstemciler doğrudan eski sisteme bağlıysa yönlendirme yapılamaz; her geçiş bir istemci dağıtımı ister.

  4. Veriyi sona bırakmak. "Kodu taşıyalım, veriye sonra bakarız" — sonra hiç gelmez, paylaşılan veritabanı kalıcı olur.

  5. Eski kodu silmemek. İki sistemin de bakımı sürer; strangler'ın amacı eskinin küçülmesidir.

Sık sorulan sorular

Strangler fig modüler monolit ile uyumlu mu?

Evet ve çoğu zaman en iyi hedef budur: yeni yetenekler ayrı servisler yerine iyi sınırlı modüller olarak tek bir yeni uygulamada toplanır; dağıtık sistem karmaşıklığı olmadan modernizasyon. Sınırlar sonradan servise dönüştürülebilir.

Eski sistemin kaynak kodu yoksa?

Geçit ve karakterizasyon testleri yine mümkündür: davranış dıştan (API, ekran, veritabanı çıktıları) kaydedilir. Kod olmadığı için yerinde refactor seçeneği düşer; strangler fig ya da paket değişimi kalır.

Ne kadar sürer?

Orta boy bir kurumsal sistemde 12–24 ay; ama ilk üretim değeri ilk 6–8 haftada gelir ve program her an durdurulabilir — o güne kadar taşınanlar üretimde kalır. Yeniden yazımda bu iki özellik de yoktur.

Sonuç

Modernizasyon bir proje değil, bir programdır: doğru teşhis, platform riskini önce kapatan replatform, sonra geçit ve karakterizasyon testleriyle desteklenen strangler fig döngüleri, yetenek bazında veri sahipliği devri ve eski kodun gerçekten silinmesi. Yeniden yazım istisnadır; kesintisiz ve geri alınabilir geçiş kuraldır.

Mevcut sisteminizin modernizasyon teşhisi ve strangler fig yol haritası için yazılım tasarımı ve mimari ile bakım ve destek hizmetlerimize göz atabilirsiniz. Keşif görüşmesi ücretsizdir.