Temiz Kod Nasıl Yazılır? – Basitlik İlkesi – III

Daha önceki iki yazıda, burada ve burada, basit kodun iki farklı özelliğinden bahsetmiştik. Basit kod, hem standarttır hem de odaklıdır demiştik. Standart kod, rahat okunur, anlaşılırdır, odaklı kod ise hem anlaşılırdır hem de kısadır demiştik. Bu noktada, basit kodun, kendimiz ve başkaları tarafından, zorluk çekmeden, rahatlıkla anlaşılabilecek kod olduğunu vurguluyoruz. Zaten kodun standart yapıda olması ve anlaşılır isimler içermesi, daha önce de belirttiğimiz gibi, basit kodun şekil şartıdır. Ama kodu aslen basit yapan şey, şekilden ziyade içeriğidir. İçerik şartı da odaklı olmasıdır, odaklı kod belli bir soyutlama seviyesinde, sadece bir şeyle ilgilenir, bir şeyi halleder, bundan dolayı zihni dağıtmaz ve rahat kavranır.

Odaklı kod denince benim aklıma, “efradını cami, ağyarını mani” olarak ifade edilen nefis Osmanlıca tabir geliyor. Bu söz aslen “tanım”ın tanımıdır. Tanım denen şey, bir şeyle alakalı en temel bileşenleri içermeli ama alakasız olan her şeyi de dışlamalıdır. Yazılım yapılarımız da “efradını cami, ağyarını mani” olmalıdır. Dolayısıyla odaklı koda, ekleyerek değil, çıkararak ulaşılır. Yani bir kod parçasını en odaklı hale getirmek için, önümüze geleni ona eklemeyi değil, onunla ilgili olmayan kısımları çıkarıp, sadece ona has kısımları bırakmamız gerekir. Bu kod parçası bazen bir framework, bazen bir kaç paketten oluşan bir bileşen (component), bazen bir paket, bazen bir sınıf ya da arayüz, bazen bir metot, bazen bir metottaki bir blok, bazen de bir satırdır. Odaklı olmanın, bu sayılan soyutlama seviyeleri için farklı anlamları vardır.

Odaklanmak, işin aslını içermek, asıl olmayan kısımlarını, yani eski deyişle fürüatını atmak olduğundan, kısaltıcıdır. Ben bu şekilde kodu kısaltmaya, budamak diyorum. Budamak, asıl anlamı itibariyle, bitkilerin daha sağlıklı büyümelerini sağlamak için hastalıklı, zayıf, kurumuş dallarının kesilmesine verilen isimdir. Mühendislik açısından ise budamak, yapılacak şeyi sadece ve sadece gerekli parçalarıyla yapmak, gereksiz olanları ise çıkarmak demektir. Basitlik, yukarıda da belirtildiği gibi, gelişi güzel budamayla değil, asıl olanı teferruattan, gerekli olanı gereksiz ve süsten ayırt ederek elde edilir. Yani odaklı koda, bir seferde değil, ancak süreç içinde budayarak ulaşabiliriz ki bu da refactoring dediğimiz iyileştirici çalışmanın bir parçasıdır.

Fransız yazar Antoine de Saint-Exupery‘ın şu sözü mükemmel olmanın en temel özelliği olan minimalliği, fazlalıklardan arınmış olmayı yani budanmışlığı çok güzel bir şekilde ifade etmektedir: “Mükemmellik, eklenecek bir şey olmadığında değil, çıkarılacak bir şey olmadığında başarılır.” (Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.)

Basitlik için gerekli olduğunu ifade ettiğimiz odaklılık ve nihayetinde kodun kısa olması öyle kolayca elde edilecek bir şey değildir. Meşhurdur, Pascal, “The Provincial Letters” isimli eserinin 16. mektubunda şöyle der: “Bu mektubu böyle uzun yapabildim çünkü kısa tutmak için zamanım yoktu.”  (“I have only made this letter longer because I have not had the time to make it shorter.”).

Benzer şeyleri ben de hayatımda sıklıkla yaşıyorum. Örneğin zaman zaman danışmanlık verdiğim yerlerde benden, üst yönetime sunmak için rapor isteniyor. Ben, 2 ay çalıştığım bir yerde, gördüğüm sıkıntıları ve çözüm önerilerini, kendileriyle irtibatta olduğum çalışanlara 20-30 sayfa olarak, hatta istenen detay seviyesine bağlı olarak, daha geniş bir şekilde sunabilirim. Fakat bu kişiler benden, üst yönetimlerine sunmak üzere bir rapor istediklerinde, farklı bir anlayış ve yapıyla, çok daha odaklı ve kısa olan bir rapor yazmam gerektiğini düşünürüm. Bu şekilde bir raporu yazdığımda çoğu zaman ilk seferde üç sayfanın altına düşemem. Sonrasında, muhtemelen üzerinden iki defa daha geçerim ve her geçişte pek çok detayı atarım, cümlelerimi daha odaklı hale getiririm ve raporu gittikçe kısaltıp, 1 sayfa civarına indiririm. İşte bahsettiğim budamak budur.

Bu durumu kod açısından ifade etmek gerekirse, sadece kod yazmaya odaklandığımızda hiç bir zaman ilk ve bir seferde basit kod yazamayız. Basit kod yazmak için düşünmek gereklidir. Kod ancak, gereklilikleri çok iyi anlaşıldığında ve çözümü üzerine kafa patlatıldığında basit yazılabilir. Ne olması gerektiği iyi bir şekilde kavranmamışsa ne sağlıklı bir çözüm bulunabilir ve tasarım yapılabilir ne de odaklı olarak kodlanabilir.

Bir önceki yazıda verdiğim “login” metodu örneğine geri dönelim. Muhtemelen bu metodun en uzun hali, bir seferde yazılmamıştır. O metodun orijinal halinde muhtemelen sadece müşteriyi getirmek ve sonra da password kontrolü yapmak vardır. Yeni iş süreçleri ve kuralları keşfedildikçe, “login” süreci ve ilgili iş kuralları bu metoda eklenmeye başlamış ve bu yüzden metot 3-4 farklı işi yapar hale gelmiştir. Budamak ise, yeni iş kurallarını sisteme kazandırırken, metoda yeni bloklar ve if cümleleri eklemek yerine, metodun odağının kaybolması tehlikesinden dolayı, metodu bölmektir. Bu anlamda yazılımlar, satır sayısı olarak artar ve büyürken, metot, tip vs. soyutlamaları açısından da zenginleşmelidir ki soyutlamalar makul karmaşıklıkta kalsınlar. Burada konuda, “Yazılım Nasıl Geliştirilir? Ekleyerek mi Çıkararak mı?” başlıklı yazıya bakabilirsiniz.

Kodu kısa yazmak demek, şekil açısından kısaltmak demek değildir. Kodu kısa yazmak demek, yukarıda da anlatıldığı gibi odaklanmak demektir. Yoksa örneğin, bir sürü operatör kullanarak, anlaşılmayı zorlaştıracak şekilde karmaşık bir iş bir satırda yapılıyorsa, kısa kod yazmaktan kasıt yanlış anlaşılmış demektir. Bakın, aşağıdaki kod parçası kısadır ama anlaşılır değildir, çünkü odaklı değildir:

double rs = a + ++b * c/a * b;

Bu kod kısadır ama odaklı olduğundan kısaltılmış bir kod değil, işgüzarlıktan kısaltılmış bir koddur. Bu koddaki problem, sonucun ancak operatör önceliğiyle belirlenecek olması ve dahası “++” operatörünün en öncelikli olmasından dolayı “b”nin bir artması ve nihayetinde ifadenin en sağındaki “b”nin de yeni değeriyle işleme katılacak olmasıdır. Yani a = 5, b = 6 ve c = 10 değerleriyle rs, 103 değerini alacaktır. Lakin pek çok programcı “rs”nin alacağı değerle ilgili yanlış hesap yapabilir. Örneğin ilk “b”nin artıştan sonra 7 olmasına karşın ikinci “b” hala 6 olarak hesaba katılabilir. Bu gibi hatalara yol açacak şekilde kısaltılmış olan kod sadece ve sadece anlaşılmayı zorlaştırır. Çünkü kod, odaklı değildir. Bu kod odaklı olarak yazılacak olsa şöyle olurdu:

double rs = 0.0;
{
   b++;
   double d = c / a;
   rs = a + (b * d * b);
}

Odaklanma açısından bu kodun yukarıdaki tek satırlık halinden ne farkı vardır? “rs”nin hesaplanması, bu haliyle bir satırda odaklı olarak yapılabilecek bir şey değildir. Bu hesap tek satırda yapıldığında, “b”yi arttırmak, “c/a”yı hesaplamak ve nihayetinde “rs”yi hesaplamak şeklinde atomik olarak yapılması en iyi olacak üç farklı işlemi, tek satıra sığdırmış oluyor. Aslen bu kod en iyi şekilde, bir blokta halledilebilir. Bu yüzden yukarıdaki ikinci hal, yani bloklu hal, tek satırlık haline göre daha uzun ama anlaşılırdır, çünkü odak problemi yoktur.

(Bu noktada “++b” paranteze alınır diye itiraz edilebilir ama bu durum ikinci “b”nin değerindeki karmaşayı gidermez. Ya da “++b” yerine (b+1) olsaydı yine bu şekilde blok olarak mı yazmak gerekirdi diye sorulabilir. Bu durumda da blok olarak yazmak daha rahat olurdu ama yazılmasa da ikinci “b”nin değeriyle ilgili sıkıntı çıkmazdı, çünkü “++b” ile “b+1” farklı şeylerdir, ilki b’nin değerini arttırırken, ikincisi “b”nin değerini değiştirmez.)

Dolayısıyla her odaklı kod kısadır ama her kısa kod odaklı değildir. Ve asıl amaç odaklılıktır, kısalık ise sonuçtur.

Yukarıdaki anlamda basitlik ve  küçüklük çoğu zaman ya çok çalışmayla ya da dahilik ile ortaya çıkar. Çok çalışma, tecrübedir. Dahiliğin ise hem doğuştan gelmesi hem de çalışarak elde edilmesi söz konusudur. Matematiksel bir örnek vermek istersek, bir sayıya kadar olan asal sayıları bulmak için o sayıya kadar olan her tek sayının asal olup olmadığına bakmak, biraz matematikten anlayan herkesin yapabileceği türden bir işlemdir. Ama bu şekilde bulunabilecek olan yöntemler, dahilerin bulduklarından kesinlikle daha uzun ve karmaşıktır. Örneğin, Eratosthenes’in ortaya koyduğu algoritma (http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes) ile bir sayıya kadar olan asal sayıları bulmak, dahiliktir. Unutmayalım ki dahi doğmasak bile çok çalışarak dahi olabiliriz.

Özetlersek, basit kod yazmak sanıldığı kadar basit değildir. Basit kod, standart ve odaklıdır. Bundan dolayı kod anlaşılır ve kısa olur. Programcı daima yazdığı kod hakkında “en basiti bu mudur?” diye sormalıdır. Basit kod yazabilecek kadar iyi programcı olabilmek dileğiyle…

Bu yazı toplam 818 defa görüntülenmiştir.