Eski yazılımı sıfırdan yazmak mı, kademeli yenilemek mi?
Eski bir sistemi sıfırdan yazmak, çoğu durumda en pahalı ve en riskli seçenektir. Daha güvenli yol sistemi dilim dilim değiştirmektir: mevcut sistemin önüne bir yönlendirme katmanı koyarsınız, tek bir yeteneği yeni tarafta yazarsınız, trafiğin sadece o kısmını yeni tarafa çevirirsiniz, üretimde doğruladıktan sonra eski kodu kapatırsınız. Martin Fowler bu yaklaşımı boğan incir ağacına (strangler fig) benzeterek adlandırdı: tohum konak ağacın dallarında filizlenir, kökleri aşağıya iner, zamanla ağacı sarar ve yerini alır. Tam yeniden yazma da bazen doğru karardır, ama bunun için belirli koşullar gerekir; yazının sonunda o koşulları tek tek sayıyoruz.
Yeniden yazma kararı neden bu kadar cazip görünür
Karar masaya genellikle teknik bir şikayetle gelir: kod okunmuyor, kimse dokunmaya cesaret edemiyor, iki satırlık değişiklik iki hafta sürüyor. Joel Spolsky'nin Nisan 2000'de yazdığı ve hâlâ dolaşan yazısı bu şikayetin neden yanıltıcı olduğunu anlatır. Kodu okumak yazmaktan zordur. Bir fonksiyonun içindeki o tuhaf, gereksiz duran satırlar çoğu zaman yıllar içinde tek tek ayıklanmış hata düzeltmeleridir; her biri bir zamanlar günler süren bir ayıklama seansının sonucudur ve hiçbiri dokümante edilmemiştir. Sıfırdan yazdığınızda o birikmiş bilgiyi çöpe atar, sonra aynı hataları yeniden bulmak zorunda kalırsınız. Spolsky'nin örneği Netscape'ti: tarayıcıyı 6.0 için baştan yazma kararı, iki büyük sürüm arasında üç yıla yakın bir boşluk açtı ve pazar payı o boşlukta eridi.
İkinci sorun takvimdir. Fowler'ın gözlemi sert: tam yeniden yazmalar çoğu zaman alev alarak düşer, çünkü yıllar sürer ve o yıllar boyunca iş birimi yeni özellik istemeye devam eder. Elinizde iki seçenek kalır. Ya özellikleri dondurursunuz, o zaman rakip önünüzden geçer ve proje şirket içinde düşman kazanır. Ya da aynı özelliği iki yerde birden geliştirirsiniz, o zaman maliyet ikiye katlanır ve hedef çizgisi sürekli kaçar. Kademeli yaklaşımın asıl kazancı burada: yatırım da getiri de küçük parçalar halinde, görünür biçimde dağılır.
Dilim dilim değiştirme pratikte nasıl işler
Microsoft'un mimari kılavuzu deseni dört aşamada tanımlar. Birincisi, istemci ile eski sistem arasına bir vekil katman (facade) girer ve başlangıçta isteklerin neredeyse tamamını eski sisteme yönlendirir. İkincisi, yeni sistemde bir yetenek hazır oldukça vekil o isteklerin adresini değiştirir; eski sistemin sorumluluğu her turda biraz daralır. Üçüncüsü, eski sisteme hiçbir bağımlılık kalmadığında sistem kapatılır. Dördüncüsü, vekil kaldırılır ve istemci doğrudan yeni sistemle konuşur. Kullanıcı bu aşamaların hiçbirinde bir göç yaşandığını fark etmez, çünkü adres ve arayüz aynı kalır.
İlk dilimi seçmek projenin kaderini belirler
Yaygın hata en can sıkıcı parçadan, yani sistemin en karmaşık çekirdeğinden başlamaktır. Bu seçim ilk somut sonucu aylarca öteler; proje henüz hiçbir şey teslim etmemişken bütçe sorgulanmaya başlar. Thoughtworks ekibinin önerdiği ölçüt daha işe yarar: çok kullanılan, ama en karmaşık olmayan bir parça seçin. Çok kullanılması yeni tarafın gerçek trafikle ve gerçek uç durumlarla sınanmasını sağlar. Görece basit olması ilk dilimin haftalar içinde üretime çıkmasını sağlar, o da hem ekibin hem yönetimin güvenini kazandırır. Kupon sorgulama, adres doğrulama, PDF üretimi, bildirim gönderimi gibi kenarda duran ama sık çağrılan uçlar iyi adaylardır.
Şartname yoksa mevcut sistem şartnamedir
Eski sistemlerin ortak özelliği, ne yaptığının hiçbir yerde yazılı olmamasıdır. Bu yüzden kod yazmaya başlamadan önce davranışı ölçün. Üç pratik yol var: sistemi kara kutu gibi ele alan otomatik fonksiyonel testler yazmak, mevcut yanıt sürelerini ve yük profilini kaydetmek, eski koda dokunmadan ara katmanda günlük kaydı toplayıp gerçek kullanımı görmek. Performans temelini ölçmeyi atlamayın: yeni sürüm "çalışıyor" ama üç kat yavaşsa, iş için çalışmıyor demektir.
Çoğu ekip bu aşamada bir sürprizle karşılaşır. Kimsenin bilmediği bir entegrasyon, hâlâ günde birkaç kez çağrılan unutulmuş bir uç, ya da yıllardır kullanılmayan ama silinmeye korkulan bir modül. Kullanılmayan modülleri taşımayın, silin. Taşınmayan kod en ucuz koddur.
En zor kısım kod değil, veri
Eski sistemler tipik olarak birçok iş alanını birden besleyen tek bir merkezi veritabanına yaslanır ve göçün gerçek maliyeti oradadır. Microsoft'un kılavuzu veri tarafı için üç adımlı bir sıra önerir. Önce yeni servis kendi alanının isteklerini karşılamaya başlar, ama okuma ve yazma işlemlerini hâlâ eski veritabanı üzerinde yapar. Sonra o alana ait tablolar ve saklı yordamlar yeni bir veritabanına çıkarılır: geçmiş veri bir ETL işiyle aktarılır, aradaki fark ise değişiklik yakalama (CDC) ile sürekli senkronize edilir. Bu aşamada iki veritabanı yan yana çalışır ve asıl iş kod yazmak değil, tutarlılığı doğrulamaktır. Son adım kesmedir: yeni veritabanı o alanın kayıt kaynağı olur, eski tablolar kaldırılır ve sıra bir sonraki alana gelir.
Bu sıralamanın kritik bir yan etkisi var. Geri dönüş penceresi, eski tablolar silinene kadar açık kalır; bir şey ters giderse trafiği geri çevirebilirsiniz, çünkü veri hâlâ iki yerde de duruyor. Tabloları ve senkronizasyon işlerini kaldırdıktan sonra geri dönmek için silinen nesneleri geri yüklemek ve aradaki değişiklikleri yeniden oynatmak gerekir, yani maliyet birden yükselir. Eski nesnelerin silinmesini her alan için ayrı ve bilinçli bir son adım olarak planlayın, kesme gecesinin bir parçası olarak değil.
Yeni sistemi eski sistemin semantiğinden koruyun
Göç sürerken iki sistem birbirini çağırmak zorunda kalır. Yeni taraf henüz taşınmamış bir işlevi eski taraftan ister, eski taraf da taşınmış bir işlevi yeni taraftan çağırır. Bu çağrıları doğrudan bağlarsanız eski sistemin veri modeli, alan adları ve tuhaf durum kodları yeni sisteme sızar. Çözüm araya bir çeviri katmanı koymaktır; desen literatüründe bozulmayı önleyen katman (anti-corruption layer) adıyla geçer. Bu katman iki tarafın dilini birbirine tercüme eder ve yeni tasarımı eski alışkanlıklardan yalıtır. Atlanması çok kolay, bedeli ağır: iki yıl sonra elinizde eskisinin daha yeni bir kopyası olur.
Geçiş mimarisi bir maliyettir, bütçeye yazın
Vekil katman, çeviri katmanı, çift yazma, senkronizasyon işleri, iki ortamın aynı anda ayakta durması. Bunların hiçbiri nihai üründe kalmayacak; hepsi geçici, atılmak üzere yazılmış kod. Desen literatüründe buna geçiş mimarisi (transitional architecture) deniyor ve doğru soru şu: bu geçici altyapının maliyeti, azalttığı riskin karşılığını veriyor mu? Çoğu kurumsal sistemde veriyor. Ama bunu bütçeye açıkça yazmak gerekir, yoksa altıncı ayda gelen "neden iki sistemin faturasını birden ödüyoruz" sorusu projeyi tam ortasında durdurur.
Vekil katman için iki teknik uyarı. Tek hata noktası olmasın, çünkü artık tüm trafik oradan geçiyor. Darboğaz olmasın, o yüzden eklediği gecikmeyi ilk günden ölçün. Bu katman kimlik doğrulama ve yetkilendirmeyi tek noktada toplamak için de iyi bir yerdir, ama eski sistemin oturum mantığını olduğu gibi yeni tarafa kopyalamayın. Göç, yıllardır ertelenen kimlik doğrulama borcunu kapatmak için ele geçen nadir fırsatlardan biridir; aynı şey koda gömülü sırlar için de geçerli.
Tam yeniden yazma ne zaman doğru karar
Kademeli yaklaşım her sistemde uygulanabilir değil. Microsoft'un kılavuzu desenin uygun olmadığı halleri açıkça sayıyor: eski sisteme gelen istekleri araya girip yakalayamıyorsanız, eski sistemin kaynak koduna erişiminiz yoksa (taşınan özellikleri kapatmak ve içteki çağrıları yönlendirmek için koda dokunmanız gerekir), sistem küçükse ve tamamını değiştirmek zaten basitse, ya da eski çözümü hızla ve tamamen kapatmanız gerekiyorsa. Buna bir madde daha eklemek gerekir: çalıştığı platformun desteği bittiyse takvimi artık siz belirlemiyorsunuz, desteği biten yazılımın riski sizin adınıza belirliyor. Böyle bir durumda bile önce bir sarmalayıcıyla zaman kazanmak, sonra dilimlemeye geçmek, tek adımlık geçişten güvenlidir.
En pahalı sonuç yarım kalmış göçtür
Dilimleme yaklaşımının kendine özgü bir başarısızlık biçimi var: proje ortada durur ve elinizde iki sistem, iki ekip, iki dağıtım hattı ve kimsenin tam olarak anlamadığı bir yönlendirme tablosu kalır. Bunu önlemenin yolu ilerlemeyi niyetle değil sayıyla ölçmektir. İki metrik yeterli: eski sistemin hâlâ karşıladığı isteklerin yüzdesi ve eski sistemde kalan kod miktarı. İkisi de her ay düşmüyorsa göç fiilen durmuştur. Her dilim için kapatma tarihini de baştan yazın, çünkü bir dilim, eski kodu silinmeden bitmiş sayılmaz.
Teknoloji sorunun en fazla yarısı
Thoughtworks'ün legacy yerinden etme desenleri üzerine yazdığı seride tekrarladığı bir cümle var: teknoloji legacy probleminin en fazla yarısıdır, çalışma biçimi, organizasyon yapısı ve liderlik de en az o kadar belirleyicidir. Pratikte anlamı şu: eski sistemi besleyen ekip yapısını olduğu gibi bırakıp yeni sistemi kurarsanız, aynı sınırları yeni kodda yeniden üretirsiniz. Conway yasası kimseyi affetmiyor. Yeni sistemin sahibi kim, hangi ekip hangi dilimden sorumlu, mimari kararı kim veriyor? Bu üç soru, teknoloji seçiminden önce cevaplanmalı.
Bu haftaya sığan ilk adım
Karar vermeden önce üç liste çıkarın. Bir: mevcut sistemin dışa açık tüm giriş noktaları (HTTP uçları, zamanlanmış işler, dosya aktarımları, veritabanına doğrudan bağlanan diğer sistemler). İki: bu uçların son 30 günlük çağrı sayısı. Üç: her ucun kaç tabloya dokunduğu. Bu üç kolonu yan yana koyduğunuzda ilk diliminiz genellikle kendini gösterir: çok çağrılan, az tabloya dokunan bir uç. Yeni tarafın arayüzlerini nasıl tasarlayacağınıza API-first yaklaşımı yazımızda, yenilemek yerine hazır bir ürüne geçmenin ne zaman daha mantıklı olduğuna ise hazır paket mi özel yazılım mı yazımızda bakabilirsiniz.
Bu konuda yardıma mı ihtiyacınız var?