Yazılım Nasıl Geliştirilir? Ekleyerek mi Çıkararak mı? – I

Danışmanlık yaptığım yerlerin birinde var olan kod üzerinde çalışırken 979 tane metodu olan bir sınıf gördüm. Evet yanlış okumadınız, 979 metodu olan bir sınıf 🙂  Bu durumu yanımda oturan ve o projede çalışan bir yazılımcıya söylediğimde bana “Akın bey, o sınıf ilk yazılırken o kadar büyük değildi, sonradan eklene eklene bu hale geldi” dedi. Söylediği şey açıkçası bizim yazılım geliştirmeyle ilgili en temel yanlışlarımızdan birini ifade ediyordu. Biz yazılım geliştirmeyi sadece “eklemek”ten ibaret biliyoruz. Dolayısıyla işin başında belki 100 civarında metottan oluşan bu sınıf 2 senenin sonunda 979 metoda sahip hale gelmişti. Tabi ki bir sınıfın 100 metoda sahip olması da sorgulanacak bir durumdur ama benim bu yazıda vurgulamak istediğim şey, yazılımı geliştirmenin devamlı olarak ekleme yapmaktan ibaret olduğunu düşünmemizdir. Aslında yazılım satır sayısı olarak büyürken yazılımdaki soyutlamaların küçülmesini gereklidir.

Bence önce şunu belirtmemiz gerekli. Biz dilimizde yazılımı geliştirmekten ya da kod, program yazmaktan bahsederiz. “No Silver Bullet” isimli makalesinde F. Brooks, hayatı boyunca yazılımla alakalı olarak önceleri “writing” yani “yazma” kelimesini kullanırken 1958 yılında (!) bir arkadaşından duyarak “building” yani “bina etme, geliştirme” terimini kullanmaya başladığını, sonrasında ise, tecrübesine dayanarak bu durumu en iyi ifade eden kelimenin “growing” yani “büyüme” olduğuna karar verdiğini yazar. Dolayısıyla yazılım tabiatı icabı, aynen organizmalarda ya da mühendislik yapılarında olduğu gibi büyür ve büyütülür.

Yazılım, proje boyunca büyür. Sonrasında proje biter ama yazılım hala büyümeye devam eder. Muhtemelen yazılımlar, çöpe atılacağı tarihe kadar büyümeye devam ederler. Öte yandan, biliyoruz ki yazılım temelde soyutlamalardan oluşan bir yapıdır. Yazılımların büyümesi, o yazılımlardaki soyutlamaların da büyümesi anlamına gelir mi? Yoksa yazılımların büyümesi daha çok içindeki soyutlamaların sayıca artması ve çeşitlenmesi anlamına mı gelmelidir? Daha açık bir ifadeyle, projenin başında 20 metoda sahip olan bir sınıf, 2 sene sonra projenin sonunda kaç metoda sahip olması beklenmelidir? Hala 20 mi? 15 mi? yoksa 100 mü?

Benim gördüğüm, bir refactoring kültürünün olmadığı yazılım geliştirme ortamlarında ve takımlarında, yazılımın büyümesinin en temel şekli eklemektir. Yeni soyutlamalar eklenir ama var olan soyutlamalardan herhangi bir şey çıkarılmaz. Örneğin bir pakete yeni sınıflar ekleriz ya da bir sınıfa yeni metotlar ekleriz ya da var olan bir metoda yeni “if” blokları ekleriz. Tüm bu eklemeleri boşuna yapmıyoruz, sonuçta bir ihtiyacı gideriyoruz. Ama her ihtiyacın, var olan yazılıma sadece yeni kod eklemeyle giderilmesi, kod eklenirken herhangi bir düzenleme yapılmaması anlamına geliyor. Bu durumda da yerine getirilecek ihtiyacı gerçekleştirecek kod parçasının, var olan kod yapısına nasıl monte edileceği, yeni kodun neresinin var olan yazılımda nereye oturacağı, tüm bunlar için var olan soyutlamalarda herhangi bir düzenlemeye gidilip gidilmeyeceğini genelde es geçiyoruz. Bundan dolayı sadece ekliyoruz. Hatta çoğu zaman eklerken, var olan kodlardan bazı parçaları “copy” ile alıp “paste” ile yeni eklenen yere monte ediyoruz. Bu da kod tekrarlarına sebep oluyor. Aslında yapılması gereken sadece eklemek değildir, çünkü eklemek refactoringde çoğunlukla tek yapılan şey değildir, hatta ilk yapılan bile değildir. Aslolan yazılımı, önce çıkarıp sonra ekleyerek, yani organizasyonel değişikliklerle büyütmektir.

Önce çıkarmak sonra eklemek nasıl olur? Ekleme yapacağınız yer bir metodun içinde ise, en basitinden ekleme yapılacak parçayı ayrı bir metot olarak soyutlayabilirsiniz. Hatta bu şekilde metottan kod parçası çıkarıp ayrı bir metot olarak soyutlamak, benzer şekilde bazı metotları var oldukları sınıf ya da arayüzden, yeni yaratılan sınıf ya da arayüzlere taşımak gibi refactoring çalışmalarına da gidebilecektir.

Bir yazılıma yapılacak değişikliklerin doğrudan eklenmek yerine, refactoring yani yazılımın mimarisi ve kodunda iyileştirici düzenlemeler yaparak gerçekleştirilmesi için göz önünde bulundurulması gereken iki yaklaşım vardır: İlki tasarım kalıplarının kullanılması, ikincisi de bu konuda çok iyi bir eser olan Martin Fowler‘ın Refactoring isimli kitabının iyice okunması ve sindirilmesidir.

Tasarım şablonlarının ciddi bir kısmı, örneğin Strateji, State, Command ve Proxy, genelde bir metot içinde toplanan pek çok karar yapısını soyutlayıp, bir arayüzü yerine getiren sınıflara bölmek fikri üzerinedir. Bu sayede gittikçe sayıları artan karar mekanizmalarına sahip kocaman metotlar yerine, her bir kararın kendisine ait metotta ifade edildiği, odaklı, daha basit ve anlaşılır yapılar oluşur.

Martin Fowler ise Refactoring isimli kitabında, farklı durumların nasıl iyileştirileceğini pek çok örnekle sistematik olarak anlatır.

Bu şekilde çıkarıp eklemelerle, yeni organizasyonlarla ilerlemek, copy-paste yerine cut-paste kullanarak var olan kod parçalarını tekrar tekrar düzenleyerek, her yeniliğin sisteme nasıl girmesi gerektiğini düşünerek yazılımı büyütmek, yazılımdaki satır sayısını, sınıf, metot vb. soyutlamaların sayısını arttırırken, bu soyutlamaların daima makul büyüklükte kalmalarını da temin edecektir. Bu da yazılımın büyüse bile karmaşıklığının olabildiğince kontrol edilebilir düzeyde kalmasını sağlar.

Bu şekilde, yazılımlardaki soyutlamaların, proje süresince ve sonrasındaki bakım sürecinde, eklenerek büyümesi yerine, mitoz ve mayoz bölünmelerle küçülmesi, en azından çok büyümemesi sağlanır. İşte böyle bir refactoring algısına sahip olunmayan bir yerde proje ilerledikçe, bir sınıftaki metot sayısı 979lara kadar gelir. Çünkü bu sınıfın sorumluluklarıyla igili olarak hem yanlış bir algı dolayısıyla da soyutlama vardır çünkü 979 sayısına gelinmiştir, hem de o ortamda refactoring kültürü yoktur, çünkü bu sayıya zaman içinde, metot ekleyerek gelinmiştir. Nitekim ben 979 sayısını bulduktan yaklaşık 2 ay kadar sonra aynı sınıfa baktığımda metot sayısı 1000’i geçmişti 🙂

Eskiden bu yana çok sevdiğim bir sözü buraya almak istiyorum. Hem yazar, hem şair hem de bir pilot olan Fransız aristokrat Antoine de Saint-Exupery şöyle demiş:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.

Yani

Mükemmellik, eklenecek bir şey olmadığında değil, çıkarılacak bir şey olmadığında başarılır.

Mühendisler mükemmeli değil, uygun olanı ararlar. Dolayısıyla daha yumuşak bir şekilde, yazılım soyutlamalarımızı uygun karmaşıklık düzeyinde tutmak için onlara eklemeler yapmak yerine onlardan çıkarma yapmayı düşünmeliyiz.

Bu konudaki pratik örnekleri bir sonraki yazıya bırakalım.

Toplam görüntülenme sayısı: 1559