<

Legacy PHP Projesini Modernleştirmek: Bir Saha Hikâyesi

Şubattaki ilk toplantıda müşterinin teknik ekibinden bir cümle geldi, aynen not aldım: "Dokunursak çöker, dokunmazsak çürür." Konu, 12 yaşında bir PHP projesiydi. PHP 5.6, test yok, dokümantasyon yok, sistemi yazan iki kişiden biri emekli olmuş, öbürü ulaşılamıyor. Ama sistem çalışıyor ve şirket cirosunun ciddi kısmı üzerinden akıyor. Altı ay sonra bugün aynı sistem PHP 8.2 üzerinde, kritik akışları testli ve haftalık deploy alır durumda. Bu yazıda o altı ayın nasıl geçtiğini, benzer bir yükü sırtında taşıyan herkes için anlatacağım.

Önce şunu bilin: yalnız değilsiniz. Türkiye'de hâlâ eski PHP sürümleriyle dönen, işin belkemiği olmuş sayısız sistem var; bu projeler bize her yıl birkaç kez geliyor ve hikâye hep benzer başlıyor — yazan gitmiş, doküman yok, ama ciro oradan akıyor. Yani bu yazıdaki durum bir istisna değil, bir tür.

Baştan bir itiraf: bu projelerin en zor kısmı teknik değil, psikolojik. Ekip yıllarca "sakın dokunma" kültüründe yaşamışsa, ilk refactor önerisi bile kaygı üretiyor. O yüzden ilk işimiz kod yazmak olmadı; güven üretecek bir emniyet ağı kurmak oldu.

Daha doğrusu ikinci işimiz. İlk hafta yalnızca envanter çıkardık: hangi PHP sürümü, hangi eklentiler, hangi bağımlılıklar (composer.json bile yoktu; bağımlılıklar elle kopyalanmış klasörler halindeydi), hangi cron işleri, hangi sunucular. Sıkıcı bir haftaydı ama getirisi büyük: sistemin gerçek sınırlarını görmeden verilen her süre tahmini, iyimser bir yalandır.

Dokunmadan önce fotoğraf çektik

Emniyet ağının adı karakterizasyon testleri: sistemin bugünkü davranışını — doğru ya da yanlış, olduğu gibi — kayıt altına alan uçtan uca testler. Buradaki incelik şu: bu testler "sistem nasıl çalışmalı"yı değil, "sistem şu an nasıl çalışıyor"u sabitler. Yanlış bilinen bir davranış varsa o da kayda girer; çünkü kim bilir hangi müşteri o "yanlış" davranışa göre iş yapıyordur. (Yapıyordu. Faturalama ekranındaki tuhaf bir yuvarlama davranışına üç bayinin süreç bağladığını sonradan öğrendik.)

Müşteriyle oturup en kritik 20 akışı belirledik — giriş, sipariş oluşturma, fatura kesme, aylık rapor ve benzerleri — ve hepsini otomatikleştirdik. İki haftalık bir yatırımdı. Bu ağ olmadan yapılacak her refactor, kelimenin tam anlamıyla kumar olurdu.

Testlerin bir kısmında "golden master" tekniğini kullandık: kritik ekranların ve raporların mevcut çıktısını olduğu gibi dosyaya kaydettik; her değişiklikten sonra yeni çıktıyı eskisiyle karşılaştırdık. Zarif bir yöntem değil ama son derece etkili — özellikle içine on yıllık iş kuralı gömülmüş hesaplama kodlarında, davranışın kılına dokunmadığınızı bilmenin en hızlı yolu bu.

Haritayı statik analiz çıkardı

12 yıllık bir kod tabanını insan gözüyle haritalamak aylar sürer; biz işi araçlara verdik. PHPStan'ı en alçak seviyeden başlattık: önce seviye 0'daki hataları sıfırladık, sonra seviye seviye tırmandık. Her seviye, kodun başka bir hastalık grubunu görünür kılıyor — ölü kod, ulaşılmayan dallar, hiç tanımlanmamış değişkenler, tip uyumsuzlukları. Birkaç hafta içinde elimizde dürüst bir harita vardı: neresi sağlam, neresi çürük, neresi hiç kullanılmıyor.

Mekanik dönüşümleri de Rector'a bıraktık. Eski sözdizimi, deprecated fonksiyon çağrıları, sürüm atlamalarının getirdiği yüzlerce küçük uyumluluk düzeltmesi — bunların elle yapılması hem yavaş hem hataya açık. Otomatik dönüşüm + karakterizasyon testleri ikilisi, sürüm atlamalarının korkusunu büyük ölçüde aldı. İnsan eli yalnızca gerçekten riskli noktalara değdi; oralarda da acele etmedik.

PHPStan'ın baseline özelliği bu süreçte altın değerindeydi: mevcut hataları bir dosyaya döküp "bunlar bilinen borç" diye işaretliyorsunuz; araç bundan sonra yalnızca yeni eklenen hataları engelliyor. Böylece 12 yıllık borcu bir gecede ödemek zorunda kalmadan, borcun büyümesini ilk günden durduruyorsunuz. Kum torbası dolu diye antrenmanı iptal etmiyorsunuz yani; torbaya yenisini eklemeyi yasaklıyorsunuz.

Sistemi durdurmadan değiştirmek: strangler deseni

Büyük soru hep aynıdır: "Sıfırdan mı yazsak?" Cevabımız neredeyse her zaman hayır. Big-bang yeniden yazım, çalışan işi aylarca dondurur, eski sistemin içine gömülü kurumsal bilgiyi çöpe atar ve bittiğinde (biterse) elinizde yeni hatalarla dolu yeni bir sistem olur.

Onun yerine boğucu sarmaşık (strangler) desenini uyguladık: yeni gelen her istek ve her ciddi değişiklik, modern modüllerde karşılandı; eski kod parça parça arkada bırakıldı. Veritabanı erişimini tek katmanda topladık — ham mysql_* çağrılarından PDO tabanlı repository'lere — ve global değişken ormanını adım adım bağımlılık enjeksiyonuna çevirdik. Her sprint sonunda sistem yayındaydı ve çalışıyordu. Bunu özellikle vurguluyorum çünkü işin sırrı burada: modernleştirme bir proje değil, bir rejim. Diyet gibi; hafta sonu kaçamağı yaptığınız an geri sarıyor.

Bu rejimin görünmeyen kahramanı deploy hattıydı. Üçüncü ayda elle yapılan FTP yüklemelerini emekliye ayırıp basit ama gerçek bir hat kurduk: testler geçmeden hiçbir şey yayına çıkmıyor, her sürüm tek komutla geri alınabiliyor. "Haftalık deploy" dediğimiz konfor cesaretten gelmiyor; bu hattan geliyor.

Altı ayın faturası ve getirisi

Rakamlar tablosu şöyle:

  • PHP 5.6'dan 8.2'ye: yanıt sürelerinde yaklaşık %40 iyileşme; aynı trafik daha az sunucuyla döner hale geldi.
  • Kritik akışlarda test kapsamı %0'dan %85'e; "deploy korkusu" toplantı gündeminden çıktı, haftalık sürüm rutine bağlandı.
  • Bilinen güvenlik açığı taşıyan bağımlılık sayısı 23'ten 0'a.

Ama bence en değerli çıktı rakamlara girmiyor: ekibin sisteme dokunma cesareti geri geldi. Altı ay önce bir CSS değişikliği için bile toplantı yapan ekip, bugün kendi refactor önerileriyle geliyor.

Yönetim katına da bir çift söz: bu işin bütçesini "sıfırdan yazalım" seçeneğiyle kıyaslayarak savunun. Yeniden yazımın gizli maliyetleri — aylarca dondurulmuş özellik geliştirme, kodun içine gömülü iş kurallarının kaybı, iki sistemi paralel yaşatma dönemi — neredeyse her zaman kademeli modernleştirmeden pahalıdır. Bizim altı aylık faturamız, aynı sistem için alınmış sıfırdan yazım teklifinin yarısından azdı; üstelik işletme tek gün durmadı, tek müşteri kaybedilmedi.

Son bir söz, benzer bir sistemin sahibiyseniz: legacy kod bir utanç değil. O sistem yıllarca çalışmış, para kazanmış, şirketi bugüne taşımış — yazılımın "yaşamış" hali bu. Utanılacak olan legacy'ye sahip olmak değil, onu kaderine terk etmek. Doğru stratejiyle, işletmeyi tek gün durdurmadan geleceğe taşınıyor; biz bunu defalarca yaptık. Sizin sisteminiz için nereden başlamak gerektiğini konuşalım isterseniz bize bir mesaj yeter — ilk analizi utandırmadan, yargılamadan yaparız, söz.

📅 Yayınlanma:  ·  Yakup Zengin