Clean Code Principles
Clean Code Principles
Her insan bilgisayarın anlayabileceği kodu yazar. Sadece iyi yazılımcılar insanların
anlayabileceği kodu yazar. Martin Fowler
Temiz kod, basit ve nettir. Temiz kod, iyi yazılmış bir düz yazı gibidir. Grady Booch
1. İSİMLENDİRME
1. İsimlendirmelerin temiz kod prensiplerine uygun olarak açıklayıcı ve anlaşılır
yapılması gerekmektedir.
2. Doğru isimlendirme, yorum satırlarına ve detaylı kod incelemelerine gerek
duymadan ilgili kodun anlaşılmasını sağlayacaktır.
3. Değişkenler ve sabitler gibi içerisinde veri barındıran yapılar isimlendirilirken,
içerisinde barındırdığı verinin ne olduğu ile ilgili net ve açıklayıcı sıfatlarla isim
öbeklerinden oluşan kısa ifadeler kullanılmalıdır. (Örnek : customerName,
userData)
4. İsimlendirme yapılırken daha sonra okunmasını zorlaştıracak gereksiz
kısaltmalardan kaçınılmalı ve telaffuz edilmesi kolay olan isimler
kullanılmalıdır. ( Kötü Örnekler : d (day), hp (hipotenüs )
5. Fonksiyonlar isimlendirilirken ilgili işlevin ne yaptığını net ifade eden fiiller ve
fiil öbeklerinden oluşan kısa ifadeler kullanılmalıdır. ( Örnek : sendMessage )
6. Fonksiyonları isimlendirirken tutarlı olunmalıdır. Örnek olarak veri getirmek
için bir yerde get ön eki kullanılıyor ise bir başka yerde fetch kullanılması
tutarlı olmayacaktır. Aynı konseptte işler için aynı kelime ön ekleri seçilmelidir.
7. İsimlendirme yapılırken aranabilir kelimeler kullanılmalıdır. Örnek olarak
kısaltma olarak kullandığınız d(day) değişkenini düşünelim. Doküman
içerisinde kullanıldığı yerleri bulabilmek için “d” olarak arattığınızda birçok
satırda sonuç bulunacaktır ve aranabilirlik özelliğiniz kaybolacaktır.
8. Sınıflar isimlendirilirken isim veya isim kelime öbekleri kullanılmalıdır. Sınıf
isimlerinde fiil kullanılmamalıdır. ( Doğru Örnek : User, Yanlış Örnek :
Manager, Data)
2. FONKSİYONLAR
1. Fonksiyonlar yazılımın temel taşıdır. Fonksiyonların içeriği ilgili belirlenmiş
olan bazı temiz kod prensipleri vardır.
2. Fonksiyonlar kısa olmalıdır. En uç senaryoda bile satır sayısı 20’yi aşmamalıdır.
Uzayan fonksiyon içerikleri mümkün olduğu kadar parçalanarak fonksiyonlara
ayrılmalıdır.
3. Her fonksiyonun yalnızca tek bir işlevi olmalıdır. Tek bir işlevi olmayan
fonksiyonlar parçalanmalıdır.
4. Switch koşulları kullanılan durumlarda case sayısı sürekli artabileceğinden
sorunlara yok açar. Bu koşulda fonksiyonların içerisinde kullanmak yerine
sınıflar içerisinde polymorphism(çokbiçimlilik) ile kullanılması daha uygun
olacaktır.
5. Fonksiyonlar en uç durumda bile 2 parametreden fazla almamalıdır. En
optimum seçenek hiç parametre almamasıdır.
6. Try Catch blokları kullanırken try catch komutları fonksiyonun içerisinde değil
fonksiyonun çağırıldığı kapsayıcı bir hata ayıklama fonksiyonu içerisinde
kullanılmalıdır.
7. Kod tekrarından mutlak surette kaçınılmalıdır.
8. Koşul durumları ve döngülerin içeriği genellikle tek satırdan oluşmalı ve bu
satırda da ilgili işlemi yapacak fonksiyon çağırılmalıdır.
3. YORUM SATIRLARI
1. Temiz kod prensiplerine göre kod genellikle kendisini yorum satırlarına ihtiyaç
duymadan kendini ifade edebilir ve anlaşılabilir olmalıdır. Ancak burada bazı
istisnai durumlar vardır.
2. Kodların üzerinde geliştirici bilgilerinin paylaşıldığı yorum satırları kullanılabilir.
3. Regex filtreleme yapılan yerlerde ilgili filtrelemenin ne tür bir sonuç
beklediğini yorum satırı olarak ifade edebilirsiniz.
4. Kodlar içerisinde daha sonra yapılacak olan geliştirmeler ile ilgili TODO
yorumları ekleyebilirsiniz.
4. SINIFLAR
1. Sınıflar yazılım mimarisinin önemli unsurlarından biri olarak yazılım kalitesinde
önemli bir yere sahiptir.
2. Sınıfların içeriği mümkün olduğu kadar kısa olmalıdır.
3. Sınıflar SRP(Single Responsibility Principle) prensiplerine uygun kullanılmalıdır.
Yani her sınıfın yalnızca bir sorumluluğu olmalıdır.
4. Sınıflar az sayıda iç değişkene sahip olmalıdır. İçerdiği metodlardan her biri
değişkenlerden bir veya daha fazlasını işlemelidir. Değişkenler birçok yöntem
tarafından kullanılmadığında farklı sınıflara bölünme ihtiyacı doğmuş demektir.
5. Yazılım yaşayan bir sistemdir. Sürekli gelişmesi gerekir. Bu bağlamda, yeni
yapılacak olan değişikliklerin önceki işlevlerin yanlış veya eksik çalışmasına yol
açmaması gerekir. Sınıflar bu değişimde yaşanacak olan riskleri azaltacak
şekilde dizayn edilmelidir.
5. HATA YÖNETİMİ
1. Uygulama içerisinde attığımız tüm exceptionlar hatanın kaynağını ve
konumunu net ifade eden bir bağlam sağlamalıdır. Exception içerisindeki
mesajların içerisinde başarısız olan işlemi ve türünü net bir şekilde ifade
etmelisiniz
2. Uygulamanız içerisinde yabancı bir kütüphane kullanılıyor ise bunun hata
yönetiminde biraz daha karmaşık bir durumla karşılaşıyoruz. Harici
bağımlılığımıza ait bazı özel exception durumları olabilir. Bu durumları çoklu
catch kullanarak kontrol ederek çözebileceğimizi düşünürüz. Ancak daha
sonra ilgili kütüphaneye yeni bir exception eklenme durumunu gözardı
etmemek gerekir. Böyle bir durumda harici bir bağımlılığın hata
kontrolünü yaparken tek bir hata türü ile ilgili kodu sarmalamalıyız.
3. Null değer döndürmemeye dikkat etmeliyiz. Null bir değeri referans alırsanız
NullReferenceException gibi hatalarla sık sık karşılaşırsınız. Örneğin bir
fonksiyonunuzda sepet içeriğini döndüreceksiniz. Sepetin boş olduğu
durumda null yerine boş bir array döndürmeniz bu bağlamda alabileceğiniz
bir önlem olacaktır.
4. Fonksiyonlara null değerler iletmemek için ilgili değişkenlerin kontrolünü
fonksiyonu henüz çağırmadan yapıp, boş olmadığı koşullarda çağırmanız
daha doğru olacaktır.
5. Bir metodun hangi exceptionları atması ve hangilerini yakalaması gerektiğini
tanımlayın. Bunun planlaması aşamasında TDD (Test Driven Development)
kullanabilirsiniz.
6. YATAY VE DİKEY FORMATLAMA
1. Yazılım genellikle bir takım işidir. Takım olarak belli kurallar belirlemeli ve bu
kurallar dahilinde geliştirme yapmalısınız.
2. Bu hem uyum açısından, hem de geliştirme hızı ve anlaşılabilirlik açısından çok
önemli bir önem arz etmektedir. Kuralların belirlenmiş olması ekip içi iletişimi
de güçlendiren bir unsurdur.
3. Dikey formatlama standartlarına göre dosya satır uzunlukları genellikle 200
ve en uç senaryolarda bile en fazla 500 satırdan oluşmalıdır. Büyük dosyaların
okunması zordur ve kodu okumak için işi yapmaktan daha çok vakit harcamak
gerekir.
4. Kaynak kodunu bir gazete makalesi gibi düşünmeliyiz. Bir makaleyi okurken
bilgiler üstte aktarılır ve aşağıya indikte detaylara girilir. Kod yazarken bu
şekilde bir yaklaşım sergilediğimizde değişkenlerin üstte tanımlanmış olması,
isimlerin ilgili pakette neler barındırdığı ile ilgili bilgiler vermesi ve aşağıya
indikte detay fonksiyonların yazılması gerekir.
5. Fonksiyonlar veya sınıf tanımları arasında boş satırlar bulunması önemlidir.
Burada boş satırların bırakılmamış olması kodun okunmasını zorlaştırır.
6. Fonksiyonların içindeki kodların uzun yazılmamış olması dikey uzaklığı
azaltarak burada da fonksiyonlar arası geçişte bize kolaylık sağlayacaktır.,
7. constructor yapıcı metodu standart olduğu üzere en üstte tanımlanmış
olmalıdır.
8. Birbirine bağımlı fonksiyonlar, bulunmasının kolay olması için birbirine yakın
yazılmalıdır.
9. Çağırılan fonksiyon, çağrıyı yapan fonksiyonun altında yazılmalıdır. Çünkü
çağırılan fonksiyon bir yardımcı fonksiyondur. Öncelikli olarak ana
fonksiyonlar yazılmalı ve yardımcı fonksiyonlar altta olmalıdır. Yüksek düzeyli
kod yardımcı kodun üzerinde bulunmalıdır.
10. Yatay formatlama standartlarına göre bir satır en fazla 120 karakter
uzunluğunda olmalıdır.
7. BİRİM TESTLERİ
1. Test Driven Development yaklaşımına göre kod yazılmadan önce test
yazılmalıdır. İlk etapta kodun henüz çalışmadığı dönemde ilgili test hataları
görülmeli ve kod yazıldığında bu hatalar giderilmiş olmalıdır.
2. Test hızlı olmalıdır. Testler yavaş çalıştığında sık sık test çalıştırmak istemeyiz.
3. Testler birbirinden bağımsız olmalıdır. Birbirinden bağımsız bir sıralama ile
çağırılabilmelidir.
4. Testler her ortamda tekrarlanabilir şekilde geliştirilmelidir. Testiniz herhangi bir
ortamda tekrarlanamıyorsa, neden başarısız olduklarına dair her zaman bir
bahaneniz olacaktır.
5. Testlerin zamanında yazılması gerekir. Birim testi, üretim kodundan hemen
önce yazılmalıdır. Daha sonra testler yazarsanız, kodu test etmek zor olabilir.
8. EŞZAMANLILIK
1. Yazılım geliştirirken çoklu görev (multi thread) kod yazılması gereken
durumlarda yaşanabilecek olan hatalar ile ilgili bazı koşullar belirlenmiştir.
2. SRP (Tek Sorumluluk İlkesi) — Her fonksiyon yalnızca tek bir işten sorumlu
olmalıdır. Örneğin bir veriyi değiştirebilen 2 adet fonksiyon içerdiğimizi
düşünelim. Bu fonksiyonların multi-thread olarak çalıştığı istisnai durumlarda
ikinci çağırılan görev, ilk çağırılan görevi durdurur ve işleme devam eder.
Böyle bir durumda iki thread birden aynı veriyi değiştirmeye çalışır. Bu durum
fonksiyonun döneceği veri ile ilgili tutarsızlık oluşturur.
3. Yukarıdaki problemi önlemenin bir adımı olarak değişkenlerin kapsamını dar
tutmayı seçebiliriz. Değişkenlerin birden fazla görevde güncellenebilir
olmasının önüne bu şekilde geçebiliriz.
4. Aynı problemin bir başka çözümü de çağırılan fonksiyonlar içerisinde objenin
kendisinin değil kopyasının kullanılmasıdır.
9. KODUN TEMİZLİĞİNİN ANLAŞILMASI
1. Kod ve dizayn ile ilgili teknik bilgiler dışında değiştirilme tarihi gibi uygunsuz
yorum satırları varsa,
2. Kodda bulunmayan bir alan ile ilgili eski, alakasız veya yanlış yorum satırları
varsa,
3. Kodun kendini açıklayabileceği bir yerde yorum kullanılıyorsa, (Örneğin : i++;
// increment i
4. Eğer yorum zayıf bir dille yazılmışsa ve açıklayıcı değilse.
5. Eğer yorum satırı olarak yazılmış kod blokları varsa,
6. Ürün build etme aşaması için birden fazla adım gerekiyorsa,
7. Test kodlarını koşmak için birden fazla adım gerekiyorsa.
8. Fonksiyonların içerisine fazla sayıda argüman iletiliyorsa.
9. Argüman olarak verilen bir değişken fonksiyon içerisinde değiştirilerek dönüt
olarakta kullanılıyorsa,
10. Boolean olarak argümanlar gönderilerek bu argümandaki true false değerine
göre işlemlerin yapıldığı durumlar varsa,
11. Fonksiyon veya değişken hiçbir yerden çağırılmamış ve kullanılmıyorsa.
12. Bir kod dosyasında birden fazla dil .
13. Sistem içerisinde fonksiyonellik bazında gözden kaçırılmış durumlar varsa,
(Örneğin [Link] objesi bir isimle karşılaştırılırken küçük harfle
çağırıldığında case çalışmıyor ise )
14. DRY(Don’t Repeat Yourself) Prensibine uyulmayan, birden fazla yerde
kullanılmış tekrar eden kodlar var ise,
15. Eğer kullanılan interface ve implementation tutarsız ise.
16. Eğer base sınıfın içinde kendisini extend eden sınıfların referansı var ise.
17. Bir interface’in gereğinden fazla metodu var ise.
18. Hiç bir zaman çalıştırılmayan, örneğin asla sağlanmayacak bir if ifadesinin
içerisine yazılmış ölü kodlar var ise,
19. Değişkenler kullanıldığı yerlere çok uzakta tanımlandıysa,
20. Değişken isimleri tutarlı değilse, biryerde customer olarak kullanılan değişken
başka yerde user olarak geçiyorsa.
21. Kullanılmayan değişkenler, kullanılmayan ve içi boş fonksiyonlar var ise.
22. Static değişkenler, static metodlar ve enum’lar çok fazla yerde kullanılıp bütün
kod bunlarla birbirine bağımlı hale geldiyse.
23. Bir class kendi metod veya değişkenleri yerine başka bir class’ın metod ve
değişkenleri üzerinde işlem yapıyorsa. (Bu durumda ilk class’ın fonksiyonalitesi
diğerinin içine taşınmalıdır)
24. Eğer bir fonksiyon true/false gibi bir boolean alıp çıktısı buna göre değişiyorsa.
25. Bir hesaplama veya metod çağrısı satır satır açıkça yazılmak yerine zincirleme
şekilde tek satırda yazılmışsa.
26. Bir sınıfa kendisine ait olmayan bir sorumluluk verildiyse. Örneğin logların
nereye yazılacağını tutan static değişken User sınıfının içinde tanımlandıysa.
27. Static olmaması gereken bir metod static olarak tanımlandıysa
28. Değişkenlere ne iş yaptılarını açıklayan isimler verilmeyip i, j gibi açık olmayan
isimler verildiyse.
29. Fonksiyon isimlerinden o fonksiyonun ne yaptığı anlaşılmıyorsa.
30. Polymorphism yerine if/else blokları kullanılmışsa.
31. Kodlamada aynı standartlar takip edilmemişse. Örneğin biri parantezleri ({,}) if
else keywordlerini altına koyarken takımdaki başka biri yanına koyuyorsa.
32. Sabit değerler static final olarak tanımlanmayıp kodun heryerine inline yazıldı
ise.
33. Bir fonksiyon birden fazla iş yapıyorsa.
34. Enum kullanılabilecek yerlerde sabit değerler kullanldıysa.
35. Testler yetersiz veya bütün senaryoları kapsamıyorsa.
36. Testler yavaş çalışıyorsa.
37. bu kodda düzeltilecek/iyileştirilebilecek şeyler var demektir.