Yazılım Projelerini Modernize Etmek

Kadri Demir
FLO Teknoloji
Published in
5 min readSep 23, 2023

Yazılım projelerinin kullanım ömrünü uzatmak, uygulamanın sürekli gelişim sürecini canlı tutmayı, eskiyen kısımlarının güncellenmesi, yeni ihtiyaçlarının eklenmesi, ve artık yetersiz kalan kısımlarının yeniden yazılması ile mümkün olmaktadır.

Uygulama geliştirme süreçlerinde çoğu firma ve yazılım ekibi; projeye yeni özellikler ekleme ve var olan eksiklikleri giderme noktasında aktif bir süreç ilerletirken; projelerin bağımlı olduğu yazılım dillerinin, kullanılan framework ve 3. parti uygulamalarının ve işletim sistemlerinin versiyonlarını güncelleme noktasında pasif kalabilmektedirler. Bu temel unsurların güncelleme süreçlerinde; “Çalışıyorsa dokunma”, “Zaman kısıtlı”, “O versiyon yeni çıktı henüz stabil değil” veya “Bu versiyonun açıkları ve eskikleri henüz yeterince test edilmedi” gibi sebeplerle çoğu zaman eski versiyonda kalma yönünde kararlar alınır; ilerleyen zamanlarda güncelleme hayalleri kurulur, fakat çoğu zaman bu hayata geçirilmeden ilerlenmeye çalışılır.

Günümüzde sürekli artan hızda gelişmekte olan teknolojiler, yazılım projelerinin ve işletim sistemlerinin gelişim hızını arttırmaktadır. Kullanılan bu uygulamalara sürekli yeni versiyonlar çıkmakta, güvenlik açıkları kapatılmakta ve yeni özellikler eklenmektedir. Hatta bir süre sonra eski versiyonlara verilen destek sonlandırılır, güvenlik yaması seviyesine çekilir ve bir süre sonra da o süreç de sonlandırılır.

Peki biz bu unsurları güncellemezsek ne olur?

İşletim sistemini güncellemezsek; bir süre sonra güvenlik açıklarımız artar, uygulamalarımızın ihtiyaç duyduğu yeni paketleri veya varolan paketlerin yeni sürümlerini bu eski işletim sistemleri desteklenmediği için kuramayız. Daha da vahim olanı bu işletim sistemi bazen uygulamanızın çalışmasını bloklayabilir. Örneğin; varolan işletim sisteminin 32bit bir işletim sistemi olduğunu düşündüğünüz bir ortamda, dosya limitlerinizden tutunda kullanabileceğiniz bellek miktarına kadar bir sürü limite takılmaya başlarsınız. Yada eski bir işletim sistemi kullandığınızda; ssl versiyonlarında çıkan açığı kapatmak için çıkarılan yamaları sisteminize uygulamazsınız ve bu nedenle uygulamlarınız ssl bağlantılarında sorun yaşayıp açılamayabilirler.

Yazılım dilleri de zamanla gelişmekte ve kendilerini sürekli güncel ihtiyaçlara göre geliştirmeye çalışırlar. Bu nedenle yazılım dilleri eskiye göre daha sık versiyon güncellemeleri yayınlamaktadırlar.

Kullandığımız framework ve üçüncü parti uygulamlar da; sürekli gelişim göstermekte ve günümüz ihtiyaçlarına daha iyi çözüm sunabilmek için sürekli yeni özellikler ve yeni mimari yaklaşımlar ile gelişmeye çalışırken; bir yandan da performanslarını ve kaynak kullanımlarını optimize etmeye devam ederler. Bu faydalardan istifade edebilmek için de bu güncellemeleri alabiliyor olmamız gerekiyor.

Bu gereksinimler, genellikle birbirini mecbur kılıyor, yani bir zincirin halkaları gibi birbirine bağlıdır. Örneğin kullandığımız 3. parti uygulama veya bir bundle paketi güncel bir framewrok’ü; güncel framewrok’ler güncel bir yazılım dili versiyonunu; güncel yazılım dili versiyonları da çoğu zaman daha güncel işletim sistemlerine ihtiyaç duyarlar.

Yukarıda genel sebeplerini yazıdığım sebepler nedeniyle uygulamalarımızı güncel işletim sistemlerinde ve güncel yazılım dil versiyonlarında ve güncel framwork versiyonları ile çalışabilecek hale getirmeye karar verdik.

Peki biz bu sürece nasıl ve neden girdik?

Yukarıda bahsettiğim nedenleri önemli bir kısmı ile biz de karşı karşıya kaldık.

  • Bazı projelerimizde kullandığımız yazılım dili 1 major ve bir kaç minor versiyon geride kalmaya başlamış ve end-of-life olmaya başlamak üzereydi. Bu yazılım dilinin versiyonun eski olması nedeniyle güvenlik taramalarında sürekli karşımıza açık madde olarak çıkmaktaydı.
  • Community’lerin sağladığı güzel ve faydalı paketlerin son zamanlarda çıkanları genelde güncel dil versiyonuna göre hazırlandığı için eski versiyonlarda kullanılamıyordu ve biz bunlardan faydalanmak istedikçe bize engel oluşturuyordu. Bu tür durumlarda bu uygulamaları forklayıp modifiye etmek veya alternatiflerini güncellemek zorunda kalıyorduk.
  • Kullandığımız framework sürekli bir gelişim içerisinde olup modern teknolojileri daha fazla ve daha doğru kullanmamız için gelişiyor fakat biz eski versiyonda olduğumuzdan bundan mahrum kalıyorduk.
  • En önemli sebeplerden birisi de; kullandığımız bazı docker image’larının bu versiyon eskimelerinden dolayı desteklerinde sorun yaşamaya ve sürekli work-around çözümlerle zaman harcamak zorunda kalıyor olmamızdı.

Geçiş planı ve uygulama

  • Geçiş yaparken ara versiyonları tek tek upgrade etmek yerine hem framework’ün hem de yazılım dilinin son stabil versiyonlarına geçmeye karar verdik. Bu kendi içinde riskler barındırıyordu aslında. Çok fazla değişiklik içerdiği için süre çok uzun olabilir, başarısızlıklada sonuçlanabilirdi. Fakat aradaki minor ve major versiyon geçişlerini sırayla hem framewrok hem de yazılım dili seviyesinde yapmak çok daha uzun ve riskli bir süreç içerecek ve bu riskleri her defasında yaşamamıza da neden olacaktı.
  • Geçiş sürecinde mevcut projenin veritabanından bir kopya oluşturduk. Ve Projenin bulunduğu versiyonlama sisteminde yeni bir branch açarak tüm değişiklikleri orada toplamaya karar verdik.
  • Test ortamı için ikinci bir test ortamı hazırlayıp yeni bir işletim sistemi ve programlama dilinin güncel versiyonunda çalışacak halde hazırlığını yaptık.
  • Development ortamında da bu yeni versiyonlarla çalışabilecek ortamı hazırladık.
  • Geçiş aşamasında yeni branch üzerinde; uygulamayı yeni framework versiyonu bağımlığına yükselttik. Ve gerekli configurasyon güncellemelerini yaptık ve framework’un migration tool’larını çalıştırdıktan sonra gerekli olan bazı operasyonları development ortamında manuel olarak ilerletmeye çalıştık. Bu esnada uygulama tabi ki uygulamanın içinde çalışır durumda olan kısımların bazıları çalışmamaya başladı. bazı kısımlar ise çalışmaya devam eder durumdaydı. Bu beklediğimiz bir durumdu.
  • Framework ve dil versiyonu yükseldiği için kullandığımız unit-test framework’unu de dolayısıyla daha güncel bir versiyona almak durumunda kaldık.
  • Bu aşama da işimiz en çok kolaylaştıran şey; daha önce uygulamada bol bol unit-testler yazmış olmamızdı.
  • Bu versiyonları güncellediğimizde daha önce kullandığımız bazı 3. parti paketler veya community paketlerinin de versiyonlarını yükseltmiş olduk. Hatta bazıları için güncel versiyon bulamadık. Bazılarını alternatif paketler ile yer değiştirdik bazılarını da forklayıp güncelledik (Bunu mümkün mertebe çok zorunlu hallederde ve z sayıda yaptık). Bu esnada artık ihtiyacımız kalmayan paketlerin bağımlığını kaldırıp code-base’den kaldırdık.
  • Bu aşamadan sonra iki yönlü ilerleme ile devam ettik. Bir yandan yazılım dili versiyonu değiştiği için kaldırılan method ve class’ları replace ettik, depraceted olanları temizlemeye çalıştık ve kullanım davranışı değişen kısımları dilin change-log’larına bakarak güncellemeye ve adapte etmeye çalıştık. Burada işimizi en çok kolaylaştıran etkenlerden birisi de gelişmiş IDE’ler oldu. Burada kodlama esnasında namespace’leri ve annotation’ları ne kadar düzgün ve doğru kullandıysak o kadar işimizi kolaylaştırdı ve bu dil güncellemelerini o kadar hızlandırdı.
  • İkinci yön olarak da; yazdığımız yüzlerce unit-testi çalıştırmaya çalıştık. Öncelikle unit-test kütüphanemizi de güncel versiyona aldığımız için bazı assert methodları değişmiş, bazı kullanım yönetmlerinde yenilemeler olmuştu. Burada da IDE’lerin nimetlerinden yararlanıp hızlıca code analizleri yaptırıp güncelleyerek ilerledik. unit-test’lerdeki dil versiyonu değişikliği nedeniyle etkilenen yerleri de codebase ile birlikte güncelledik. Sonrasında testleri çalıştırarak patlayan yerleri düzelterek ilerledik.
  • Kod seviyesinde belirli bir olgunluğa gelip; testleri geçer hale getirdikten sonra da uygulamayı yeni açtığımız test ortamına deploy ederek; kullanıcı testlerine ve otomasayon testlerine tabi tuttuk. Oradan gelen bulguları da fixleyerek ilerlemeye devam ettik.
  • Sonrasında Preprod ve Prod geçişi için planlama yaparak süreci canlıya anlık.

Kolaylıklar

  • Gelişmiş IDE’ler kodu refaktör etmede ve dil ile uyumsuz hale gelen kodları tespit etmede işimizi çok kolaylaştırdı.
  • Daha önce bol bol unit-test yazmış olmamız geçiş sürecinde elimizi en çok güçlendiren unsur oldu diyebilirim.

Karşılaştığımız Sorunlar

  • Deneyimli ekibimizin de süreci hızlandırma ve sonuçlandırma konusunda emek ve katkılarını anmadan geçemeyeceğim.
  • Dil versiyonu ile birlikte daha strict hale gelen bazı kullanımlar ve deprecated özellikleri temizlemeye çalışmak süreç içerisinde en yorucu kısımlardan birisi oldu.
  • Template engine’nin davranışı gereği fırlattığını warning’leri gidermek de ikinci derecede yorucu olan kısımdı diyebilirim.

Sonuç:

Yukarıda yazdığım gerekçeler ve uyguladığımız plan ile kısa sürede 4 tane micro servisimizi en güncel işletim sistemi ve en güncel framework versiyonuna taşıdık ve bundan sonraki süreçte mümkün olduğunca güncel versiyonlarda kalmak için versiyonları çok atlamadan belirli periyotlarda kullanmaya başlayarak güncel bir şekilde ilerlemeye devam etmeyi prensip haline getirmeye çalışacağız.

--

--