Eski Hataların Yeni Sürümleri: Kodda Geçmişi Taşımanın Laneti

Geriye dönük uyumluluk, yazılım dünyasının en kibar görünümlü hayaletlerinden biridir. Dışarıdan bakınca olgunluk, güvenilirlik ve kullanıcıya saygı gibi görünür. İçeriden bakınca ise bazen kırık bir sandalyeyi müzede sergilemek değil, hâlâ toplantı odasında kullanmak zorunda kalmaktır. Bir zamanlar aceleyle yazılmış, kimsenin tam anlamadığı, fakat milyonlarca sistemin üzerine bina edildiği bir karar; yıllar sonra mimarinin kutsal taşı haline gelir. Çünkü onu kaldırırsanız sadece bir fonksiyonu değil, bir ekosistemi düşürürsünüz.

Programlamada geriye dönük uyumluluk şu basit vaadi verir: Dün çalışan şey bugün de çalışacak. Bu vaat, kullanıcı için huzurdur; geliştirici içinse omuzlara asılmış görünmez bir çuval. İçinde eski API kararları, yanlış isimlendirilmiş parametreler, tuhaf varsayılan değerler, mantıksız veri formatları ve birinin 2009’da cuma akşamı saat 17.43’te yaptığı küçük bir kestirme vardır. O kestirme artık ürünün anayasasına dönüşmüştür.

Hatanın Kültüre Dönüşmesi

Bir bug tek başına teknik bir olaydır; ama yıllarca korunursa kültür olur. Yazılım tarihindeki pek çok gariplik bu yüzden yaşamaya devam eder. Bir alanın adı yanlış yazılmıştır ama düzeltilemez, çünkü müşterinin entegrasyonu ona bağlıdır. Bir fonksiyon mantıksız sonuç döndürür ama değiştirilemez, çünkü bazı sistemler o mantıksızlığa göre davranmayı öğrenmiştir. Hata artık hata değildir; protokoldür. Tıpkı eski bir şehirde yanlış açılmış bir yolun zamanla ana caddeye dönüşmesi gibi.

Burada problem yalnızca teknik borç değildir. Teknik borç, ödenebilir bir borçtur; faizini hesaplar, taksit planı yaparsınız. Geriye dönük uyumluluk ise bazen miras hukukuna benzer: Borcu siz yapmadınız ama tapu sizin üzerinize geçti. Üstelik alacaklılar da haklıdır. Kullanıcı çalışır sistemi sever. Şirket kırılmayan sözleşmeleri sever. Ekosistem istikrar ister. Geliştirici ise temiz, zarif, akılcı bir tasarım hayal eder. İşte çatışma burada başlar: Estetik ile sadakat, doğruluk ile süreklilik, gelecek ile geçmiş aynı kod tabanında kavga eder.

Kırmadan Yenilemenin Sanatı

İyi mühendislik, her şeyi yıkıp yeniden yapmak değildir. Bu, bazen genç geliştiricinin romantik yanılgısıdır. Eski kodu görünce kılıcı çeker: Bunu komple atalım. Fakat gerçek sistemler laboratuvar faresi değildir; canlı organizmadır. İçlerinde müşteriler, veri akışları, alışkanlıklar, sözleşmeler, raporlar, otomasyonlar ve kimsenin dokunmaya cesaret edemediği cron işleri yaşar. Bir şeyi değiştirmek istiyorsanız önce onu kimin neden kullandığını anlamalısınız.

Bu yüzden geriye dönük uyumluluk, disiplin ister. Versiyonlama, açık kullanım dışı bırakma politikaları, geçiş rehberleri, uyarı mekanizmaları, adaptör katmanları ve ölçümleme şarttır. Bir API değiştirilecekse önce eski davranış gözlemlenir. Kim kullanıyor, nasıl kullanıyor, ne kadar kritik kullanıyor? Sonra yeni yol sunulur. Eski yol hemen yakılmaz; üzerine tabela asılır: Bu köprü yaşlandı, lütfen yeni köprüyü kullanın. En sonunda, yeterince zaman ve iletişimden sonra kapatılır. Medeni yazılım budur.

Fakat her şeyi sonsuza dek uyumlu tutmak da erdem değildir. Bazen geriye dönük uyumluluk adı altında sistemin geleceğini rehin alırız. Kimse kırılmasın diye her garip davranışı koruruz; sonra yeni özellik eklemek mayın tarlasında bale yapmaya döner. Kod, geçmiş kullanıcıların anıt mezarlığına dönüşür. Her satırın başında şu yazılıdır: Buraya dokunma, biri bir yerde ağlayabilir.

Cesaret ve Nezaket Dengesi

Sağlıklı yaklaşım iki uçtan da kaçınır. Ne geçmişi kutsallaştırmak gerekir ne de geçmişe savaş açmak. Geriye dönük uyumluluk bir ahlaki sorumluluktur; ama sonsuz itaat yemini değildir. Kullanıcının güvenini korumak önemlidir, fakat sistemin evrim hakkı da vardır. Eski hatayı taşımak bazen merhamettir, bazen korkaklık. Aradaki farkı ölçen şey niyet değil, plandır.

Bir yazılım ekibi kendine şu soruları sormalıdır: Bu uyumluluk kime hizmet ediyor? Eski davranışı korumanın maliyeti nedir? Yeni tasarım gerçekten daha mı iyi, yoksa sadece daha mı yeni? Kullanıcıya geçiş için yeterli araç verdik mi? Kırılma kaçınılmazsa bunu dürüstçe duyurduk mu? Bu sorular cevaplanmadan yapılan her devrim, prod ortamında patlayan bir havai fişektir.

Sonuçta geriye dönük uyumluluk, kodun hafızasıdır. Hafıza olmadan kimlik olmaz; ama travmayı sonsuza dek tekrar etmek de iyileşme değildir. Usta geliştirici, geçmişin hatasını inkâr etmez; onu belgeler, sınırlar, izole eder ve mümkünse onurlu bir emekliliğe gönderir. Çünkü iyi yazılım yalnızca çalışmakla kalmaz; zaman içinde yaşlanmayı da bilir. Asıl mesele, geçmişin kamburunu geleceğin omurgası sanmamaktır.

Kod Neden Pasaport İster: Taşınabilirliğin Küresel Rüyası

Bir programcının en eski dualarından biri şudur: Burada çalıştıysa orada da çalışsın. Kulağa teknik bir istek gibi gelir; oysa içinde küçük bir uygarlık tasarımı saklıdır. Kodun taşınabilirliği, yalnızca bir uygulamanın Windows’tan Linux’a, telefondan buluta, yerel makineden uzak sunucuya nazlanmadan geçmesi değildir. Daha derinde, bir fikrin coğrafyadan, donanımdan, işletim sisteminden ve hatta bazen kültürden bağımsız biçimde var olabilmesi arzusudur.

Bu yüzden portability, yazılım dünyasının küreselleşme felsefesidir. Nasıl ki bir para birimi, bir dil ya da bir ölçü standardı sınırları aşmayı kolaylaştırıyorsa; taşınabilir kod da fikrin gümrükte takılmadan dolaşmasını sağlar. Fakat burada romantizme fazla kapılmayalım: Her yerde çalışan kod, kendiliğinden ortaya çıkan büyülü bir varlık değildir. O, disiplinli soyutlama, dikkatli bağımlılık yönetimi, standartlara saygı ve çevresel farklara karşı paranoyak bir uyanıklık ister.

Makineden Bağımsız Düşünmek

Taşınabilirlik önce zihinde başlar. Kötü programcı yalnızca kendi bilgisayarını evren sanır. İyi programcı ise evrenin klavye düzeninden dosya yoluna, saat diliminden karakter kodlamasına kadar tuzaklarla dolu olduğunu bilir. Bir yerde eğik çizgiyle çalışan dosya yolu, başka yerde ters eğik çizgi ister. Bir sistemde küçük harf-büyük harf farkı önemsizdir, diğerinde kader belirler. Bir ülkede virgül ondalık ayırıcıdır, başka bir yerde nokta. Kod, bu farklılıkları yok saydığında yerel bir lehçeye dönüşür; onları hesaba kattığında ise ortak dile yaklaşır.

Bu ortak dilin en önemli araçları standartlardır. POSIX, Unicode, HTTP, SQL, ECMAScript gibi isimler ilk bakışta sıkıcı teknik tabelalar gibi görünür. Fakat aslında bunlar yazılım medeniyetinin demiryollarıdır. Ray açıklığı herkes için aynıysa trenler kıta boyunca ilerler. Protokoller, dosya biçimleri ve dil standartları da böyledir: Fikirlerin başka makinelerde yeniden doğmasını sağlar.

Taşınabilirlik Bedava Değildir

Elbette her soyutlama bir bedel ister. Taşınabilir kod yazmak çoğu zaman daha fazla planlama, daha fazla test, daha az kestirme yol demektir. Sisteme özel bir özelliği kullanmak hızlıdır; fakat sizi o sisteme zincirler. Taşınabilir bir çözüm ise bazen daha yavaş, daha genel, daha zahmetli olabilir. Burada stratejik soru şudur: Hızlıca yerel bir zafer mi istiyoruz, yoksa uzun vadeli küresel hareket kabiliyeti mi?

Bu sorunun cevabı bağlama göre değişir. Gömülü sistemlerde donanıma yakın optimizasyon hayatidir. Bir oyun motorunda grafik kartının özel yeteneklerinden yararlanmak performans getirir. Fakat bir iş uygulaması, bir kütüphane, bir eğitim aracı ya da açık kaynak projesi geliştiriyorsanız, taşınabilirlik sizi çoğaltır. Kodunuz tek bir makinede çalışan bir not olmaktan çıkar, dünyanın farklı köşelerinde yorumlanan bir besteye dönüşür.

Küreselleşmenin Yazılımcı Versiyonu

Küreselleşme çoğu zaman malların, sermayenin ve kültürün dolaşımı olarak anlatılır. Yazılımda ise dolaşan şey daha soyuttur: yöntem, algoritma, arayüz, deneyim. Bir geliştirici İstanbul’da bir paket yazar, Tokyo’da biri onu projeye ekler, Berlin’de başka biri hata bildirir, Nairobi’de biri çatallayıp geliştirir. Kod taşınabilir değilse bu ağ kırılır. Çalıştırma talimatları büyü kitabına, kurulum süreci çile ritüeline dönüşür.

Docker, sanal makineler, konteynerler ve bulut platformları bu soruna modern cevaplar sunar. İlginçtir: Eskiden kodu ortama uydurmaya çalışırdık; şimdi çoğu zaman ortamı kodla birlikte paketliyoruz. Yani taşınabilirlik yalnızca kodun hafiflemesiyle değil, dünyanın küçük bir kopyasını yanımıza almamızla da sağlanıyor. Bu, dijital çağın valiz felsefesidir: Sadece fikir değil, fikrin yaşadığı iklim de taşınır.

Fakat en büyük risk şudur: Taşınabilirliği yalnızca teknik uyumluluk sanmak. Bir yazılım her cihazda açılabilir ama her insan için anlaşılır olmayabilir. Dil desteği, erişilebilirlik, yerelleştirme, kültürel varsayımlar ve etik tasarım da taşınabilirliğin geniş halkalarıdır. Gerçekten küresel bir kod, yalnızca işlemciler arasında değil, insanlar arasında da çalışır.

Sonuçta taşınabilirlik, programcının egosuna atılmış zarif bir tokattır. Dünya senin bilgisayarından ibaret değildir. Kodunu, başka makinelerin, başka alışkanlıkların, başka saat dilimlerinin ve başka hayatların içinden geçecek bir yolcu gibi tasarla. Çünkü iyi yazılım, doğduğu yere sadık kalırken oraya mahkum olmayan yazılımdır. Bir ortamda yazılan fikrin her yerde çalışması, sadece mühendislik başarısı değil; dijital çağın en pratik özgürlük tanımlarından biridir.