Gelin şu işin adını koyalım
Bu yazıyı Bilgetech’te düzenlediğimiz haftalık etkinlik serisinin ilkinde yaptığım sunuma paralel olarak hazırladım.
Sunum videosuna youtube’dan ve slaytlara slideshare’den ulaşabilirsiniz.
İsimlendirme
İsimlendirme, yazılım ile uğraşan insanların uğraşmayan insanlara kıyasla çok daha sık yapması gereken bir iştir. Öyle ki, ortalama bir developer, günde onlarca kez isimlendirme yapabilir: Proje ismi, paket ismi, sınıf ismi, metod ismi… Hatta belki bir kere kullanacağımız bir değişkene bile isim koymak için düşündüğümüz olur.
Peki, bu kadar sık yapılan bu iş neden hala tam anlamıyla doğru yapılamamakta? Çünkü..
İsimlendirme Zordur
Bir çok insanın Phil Karlton’a ithaf ettiği bir söz var:
There are only two hard things in Computer Science: cache invalidation and naming things.
İsimlendirmenin neden bu kadar zor olduğunu anlamamız için bir nesneye veya bir kavrama neden isim koyduğumuzu anlamamız gerekir. İnsanlar hayatı anlamlandırırken sürekli olarak gruplama, benzetme ve isimlendirme yaparlar. Böylelikle biz aslında sürekli kalıplar halinde öğreniriz. Bu düşünmeyi, kavramayı ve anlamlandırmayı kolaylaştıran bir süreçtir. Bir şeyin adı; onun amacı, görevi veya varoluş sebebi hakkında bilgi verir. Bu yazımın başlığı olan “bir işin adını koymak” deyimi de aslında bu konuda bize ipucu verir. Çünkü bir işin adını koymak, onun, üzerinde uzlaşılmış bir anlama ve sınırlara sahip olması demektir.
Dolayısıyla eğer bir kod parçasının ismi eksik veya yanlış olarak konursa, bir developer o kod parçasının ne iş yaptığını tahmin etmekte zorlanacak, hatta bazen o kod parçasının ismi yanıltıcı olabilecektir. İşte tam da bu sebepten isimlendirme çok önemli ve doğru yapmak çok zordur. Çünkü isimlendirmek aslında OOP mimarisini yönetmek ve encapsulation’ları doğru ayarlamak ile yakından ilişkilidir.
Single Responsibility Principle
SOLID prensiplerin ilki olan SRP (Single Responsibility Principle) der ki:
Her modül veya sınıf, yazılımın tüm işlevselliğinin yalnızca bir parçası üzerinde sorumludur. Ve bu sorumluluğun tamamı o sınıf içerisinde hapsedilmiştir.
Bu da demek oluyor ki, her sınıfın kendine ait bir kaç kelimeyle ifade edilebilen bir işlevi olmalı. Eğer bir sınıfın ne iş yaptığını bir cümlede anlatamıyorsak veya işlevden bahsederken VE bağlacını çok kullanıyorsak, bu durum sınıfımızın yapması gerekenden daha fazla iş yaptığını işaret edebilir. Bu durumda bu sınıftaki metodlar ve değişkenler başka alt sınıflara bölünerek, sınıfın sorumluluğu azaltılabilir.
İsimlendirme yaparken de temelde SRP’ye dikkat edersek aslında işin büyük bir kısmını halletmiş oluyoruz. Çünkü o sınıfın sorumluluğunu belirlemiş oluyoruz.
İsimlendirmede Sık Yapılan Hatalar
İsimlendirme yaparken yapılan yanlışlarla ilgili düşünürken, gerçek örnekler üzerinde konuşmanın daha faydalı olacağını düşündüm ve eski projeleri karıştırdım. Bu Android projelerinde gözüme çarpan bazı yanlış isimlendirmeleri ve nelerin hatalı olduğunu incelemeye çalışacağım.
MyEditTextBook.java
Bu ismi My + EditText + Book veya My + Edit + TextBook şeklinde okuyabiliyoruz. My öneki sınıfın amacını ve işlevini anlatmak adına herhangi bir katkı sağlamıyor. Ayrıca isim bize sınıfın ne olduğuyla ilgili çok bir bilgi vermiyor. Kodlarını incelediğimde bu sınıfın bir custom EditText sınıfı olduğunu (Android’deki text input alanlarına EditText denir) ve fontunun AvenirBook olarak ayarlandığını gördüm. Daha doğru bir isim seçmek istersek belki AvenirBookEditText seçebilirdik.
DRequest.java
Request ismi bize sınıfın işlevi hakkında isim verse de, D harfi anlaşılırlık açısından herhangi bir kolaylık sağlamıyor. Ayrıca proje genelinde kullanılan bir namespace de değil. D’nin anlamını bulmak için kodları baya karıştırdım. En sonunda git geçmişinde sınıfı oluşturan developer’ın isminin D ile başladığını fark ettim. Şu an için en iyi tahminim kendi isminin baş harfini sınıfa vermiş olması :)
getOneDayOfCurrentMonth()
Bu metodun isimlendirilmesindeki hata ise dilin yanlış kullanılması. İlk okunduğunda sanki içerisinde bulunulan aydan -rastgele- bir gün verecekmiş gibi hissettiren method, kodları incelendiğinde aslında içinde bulunulan ayın ilk gününün tarih String’ini dönüyor. E tabi bunu anlamak için fonksiyonun satır satır incelenmesi lazım.
Bu fonksiyonu incelerken başka isimlendirme hataları da fark ettim. Örneğin getCurrentDate() metoduyla alınan güncel tarih, oneOfMonth adlı bir değişkene atanmış. Yani değişkenin ismi ile tuttuğu değerin uzaktan yakından alakası yok.
Şimdi de isterseniz biraz da değişken isimlerine bakıp üzerinde düşünelim.
TextView tv_ab
Bu değişken java’nın camelCase convention’ına uymamasının yanında kriptik isim kullanarak okunabilirliğini de önemli ölçüde azaltıyor. Kodu incelediğimde tv_ab’nin [t]ext [v]iew of [a]ction [b]ar kelimelerinden oluştuğunu fark ettim. Ama bunu bir çırpıda anlayabilmek pek mümkün görünmüyor.
Adapter talepListAdapter
Bu örnekte dikkatinizi çekmek istediğim nokta ise Türkçe-İngilizce karışık isimlendirme. Çok az istisna dışında bence uzak durulması gereken bir yaklaşım. Yoksa aşağıdaki gibi mutant sınıflar ortaya çıkabiliyor :)
isEverytingOk()
Bu metodda bir çok isimlendirme hatası görebiliriz. Yazım hatası, spesifik değil çok geniş anlamlı isim konması vs. vs. İncelemeniz için buraya koyuyorum:
throwError()
Hatalı isimlendirme örneklerimi bu örnek ile bitirmek istiyorum:
Bu iki metodun imzaları ve yaptıkları birebir aynı. Çünkü zaten biri diğerini kendi parametrelerini birebir pass ederek çağırıyor. Ve Override annotation’ı da bulunmuyor. Dolayısıyla kodun içinde throwError veya showAlertDialog metodlarından hangisini çağırdığımızın bir önemi yok, birebir aynı işlevi yerine getiriyorlar. Buna rağmen iki metodun ismi de birbirinden farklı. throwError metodu, ismi itibariyle sanki bir Exception throw edecekmiş gibi. Ama sağ gösterip sol vuruyor ve ekranda bir uyarı diyalogu gösteriyor.
Ne yapabiliriz?
Daha doğru isimlendirme yapabilmek için, öncelikle teknik ingilizceyi, yani bilgisayar bilimlerinde sık kullanılan kavramların ingilizcelerini çok iyi bilmeliyiz.
Bunun yanında sık kullanılan data structure ve soyut kavramlara da aşina olmalıyız. Örneğin requestQueue.pop() kodunu görünce implementasyona bakmadan anlayabilmemiz için, request’in queue’nun ve pop() işleminin kavramsal olarak ne ifade ettiğini bilmemiz gerekir. Terminolojiyi bilmek hem kod okurken hem de yazarken çok faydalı olacak ve nesnelere doğru isimler vermemizi sağlayacaktır.
Ayrıca code-review bir çok faydasının yanında doğru isimlendirmeleri görmek ve yanlış isimlendirmelerin düzeltilmesi için de çok önemlidir. Eğer başka birisi bizim kodumuzu okurken bir sınıfın veya metodun ne yaptığını bir çırpıda anlayamıyorsa isimlendirmeyi gözden geçirmekte fayda var.
Kitaplar
Bu konuyla ilgili kendimizi geliştirmek için okuyabileceğimiz çok bilgi verici başucu kitapları var. Yazımı, bu kitapların da linklerini iliştirerek sonlandırıyorum:
Code Complete: CH 10 - The Power of Variable Names
https://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670
Clean Code: CH 2 - Meaningful Names
https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/
Becoming a Better Programmer: CH 2 - Names
https://www.amazon.com/Becoming-Better-Programmer-Handbook-People/dp/1491905530/