Geçenlerde bir junior geliştiricinin “Bu neden böyle?” sorusuyla karşılaştığımda, yirmi yıllık kariyerimde hala bazı şeylerin beni şaşırtan yönleri olduğunu fark ettim. Teknik detaylar, yeni framework’ler veya değişen paradigmalar beni nadiren şaşırtır; asıl şaşırtıcı olan, insan doğasının ve organizasyonel dinamiklerin yazılım projeleri üzerindeki derin etkisidir. Yıllar içinde edindiğim tecrübe bana, en iyi tasarlanmış sistemlerin bile beklemeyeceğim yerden patlayabileceğini gösterdi.
Bu yazıda, bu uzun yolculukta beni hala düşündüren ve şaşırtan birkaç temel noktayı paylaşmak istiyorum. Gördüm ki, işin teknik kısmını çözmek çoğu zaman denklemin sadece bir parçası.
En Karmaşık Sistemler Bile Neden İnsan Faktörüne Takılır?
Yirmi yıldır sistem mimarisi ve yazılım geliştirme alanında çalışırken, en kritik sorunların nadiren koddan kaynaklandığını gördüm. Bir üretim ERP’sinin sevkiyat raporlarının sürekli eksik gelmesi gibi bir problemle karşılaştığımda, ilk başta veritabanı sorgularını, ORM optimizasyonlarını veya sunucu performansını incelerdim. Ancak çoğu zaman, asıl sorun ya raporun beklenen iş akışına uygun çalışmaması ya da farklı departmanların veriyi farklı yorumlamasından kaynaklanıyordu. Bu durum, teknik olarak ne kadar mükemmel bir çözüm sunarsanız sunun, eğer kullanıcılar onu doğru şekilde benimsemez veya süreçler buna uygun değilse, çözümün değerinin kısıtlı kalacağını gösteriyor.
Yazılım mimarisi dediğimiz şeyin, çoğu zaman şirketin organizasyonel akışının bir yansıması olduğunu tecrübe ettim. Bir bankanın iç platformunu geliştirirken, en zorlayıcı kısım teknik kısıtlamalar değil, farklı iş birimlerinin beklentilerini tek bir platformda birleştirmek olmuştu. Bu tür deneyimler, yazılımın sadece teknik bir ürün değil, aynı zamanda sosyal bir inşa olduğunu kanıtlar nitelikte.
”Basit” Çözümler Neden Sıklıkla Göz Ardı Edilir?
Yeni teknolojilere olan düşkünlük ve her şeye “microservice” yakıştırma eğilimi, beni hala şaşırtan bir durumdur. Kendi yan ürünlerimin backend’ini tasarlarken, sıklıkla kendimi en basit, en az hareketli parçaya sahip çözümleri ararken buluyorum. Oysa çoğu projede, daha karmaşık, daha “modern” olduğu düşünülen yaklaşımlar tercih ediliyor. Bu durum, mevcut teknolojiyi en iyi şekilde kullanmak yerine, yeni ve popüler olanı deneme arzusundan kaynaklanabiliyor.
PostgreSQL’de index stratejileri seçimi, Redis’te eviction policy ayarları gibi konularda bile, bazen en bariz optimizasyonlar gözden kaçırılıyor. Çözüm bazen yeni bir araç değil, mevcut olanın derinlemesine anlaşılması ve doğru ayarlanması oluyor. Bir keresinde kendi siteme yaptığım bir finansal hesaplayıcıda, performans sorununu gidermek için karmaşık bir cache mekanizması düşünürken, basit bir SQL sorgu refactor’ının sorunu tamamen çözdüğünü gördüm.
Teknik Borcun Gerçek Bedeli Nelerdir?
Yazılımda “hızlıca halledelim” denilen her geçici çözümün, gelecekte çok daha büyük bir fatura çıkardığını defalarca tecrübe ettim. Bu, beni şaşırtmaktan çok öfkelendiren bir durum aslında. Kernel module blacklist (algif_aead) gibi güvenlik önlemlerini bile “şimdilik” erteleyen kararların, ileride ciddi güvenlik açıkları yaratabildiğini gördüm. Bu tür ertelemeler, kısa vadeli kazançların uzun vadeli risklere dönüşmesinin tipik bir örneği.
Bir üretim ERP’sinde, geçmişte göz ardı edilen PostgreSQL WAL bloat uyarısı, bir süre sonra veritabanının diskini doldurup sistemi durma noktasına getirmişti. Bu tür durumlar, teknik borcun sadece performansı değil, aynı zamanda güvenilirliği ve hatta iş sürekliliğini nasıl etkilediğini gösteriyor. Maalesef, bu “geçici” çözümlerin kalıcı hale gelme eğilimi, yazılım dünyasının değişmez bir gerçeği gibi duruyor ve genellikle en acı dersleri bu yolla öğreniyoruz.
En İyi Niyetli Mimarlar Bile Neden Yanılabilir?
Yirmi yıl önce aldığım mimari kararların bugün geçerliliğini yitirdiğini görmek veya o anki bilgilerimle en doğru olduğunu düşündüğüm bir tasarımın, yıllar sonra yeni gereksinimler altında patlaması beni şaşırtmıyor, daha çok öğretiyor. Geçen ay bir sistemde sleep 360 komutunu bir döngüye koyup, beklenenden daha uzun süre çalışması sonucu bir container’ın OOM-killed olduğunu bizzat deneyimledim. Bu, polling-wait paternine geçmem gerektiğini bana bir kez daha hatırlattı.
Her zaman doğru kararları veremeyiz ve bu da gayet normal. Önemli olan, hatalarımızdan ders çıkarıp, esnek ve adapte olabilir sistemler tasarlayabilmek. Monolith ile başlayıp microservice’lere geçiş, event-sourcing veya CQRS gibi mimarilerde yapılan tercihler, zamanla evrim geçirmek zorunda kalıyor. Bir müşteri projesinde, başlangıçta seçtiğimiz veritabanı partition stratejisinin, veri büyümesiyle birlikte yetersiz kaldığını ve ciddi bir refactor gerektirdiğini gördüm. Bu tür durumlar, “mükemmel” bir mimarinin zamanın testine dayanamayabileceğini gösteriyor.
Sonuç
Yazılımda yirmi yıl geçirdikten sonra, beni hala şaşırtan şeylerin başında teknolojinin kendisi değil, teknolojiyle etkileşimimiz ve onu nasıl uyguladığımız geliyor. İnsan faktörü, basitliğin gücü, teknik borcun sinsi doğası ve mimari kararlarımızın zamanla nasıl evrildiği, bu uzun yolculuğun en değerli dersleri oldu. Her yeni projede, her yeni hata mesajında, hala yeni bir şeyler öğrenmeye devam ediyorum.
Bu yolculukta sizin en çok şaşırdığınız veya size en büyük dersi veren ne oldu? Yorumlarda benimle paylaşırsanız sevinirim.