Temiz Kod Prensipleri (Clean Code Principles) Bölüm 2

Uğur Can Çeribaşı
Finartz
Published in
6 min readMar 15, 2021

Yazının bir önceki bölümünde Temiz Kod Prensiplerinin ilk 4 maddesi olan İsimlendirme, Fonksiyonlar, Yorum Satırları ve Sınıflar konularının açıklaması yapılmıştı. Önceki yazıya buraya tıklayarak ulaşabilirsiniz. Bu bölümde Hata Yönetimi, Yatay ve Dikey Formatlama, Birim Testleri, , Eşzamanlılık ve Kodun Temizliğinin Anlaşılması konuları ile devam edeceğiz.

1 — HATA YÖNETİMİ
Hata yönetimi yazılımın en kritik birimlerinden biridir. Tarihte hata yönetiminin yanlış veya eksik yapılması nedeniyle yaşanan bir çok problem olmuştur. 1996 yılında Ariane 5 isimli roket hata yönetiminde yapılan bir exception hatasından kaynaklı patlamıştır. Aşağıdan ilgili olayın videosuna ulaşabilirsiniz.

Yazılım sektöründe bu kadar öneme sahip olan Hata Yönetimi konusu ile ilgili belirlenmiş temiz kod prensipleri şunlardır.

  • Hata yakalarken geçmiş dönemlerde try catch fonksiyonları henüz yokken, hata kodlarını return eden fonksiyonlar yazılırdı. Bu kullanımın tercih edilmemesi gerekir. Çünkü o kullanımda çokça if veya switch ifadeleri kullanılır. Bunların kontrol edilebilmesi ve okunabilmesi oldukça zordur. Try catch metodlarını kullanmalısınız.
  • 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
  • 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.
  • 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.
  • 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.
  • Bir metodun hangi exceptionları atması ve hangilerini yakalaması gerektiğini tanımlayın. Bunun planlaması aşamasında TDD (Test Driven Development) kullanabilirsiniz.

2 — YATAY VE DİKEY FORMATLAMA

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. 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.

  • 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.
  • 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.
  • 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.
  • 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.,
  • constructor yapıcı metodu standart olduğu üzere en üstte tanımlanmış olmalıdır.
  • Birbirine bağımlı fonksiyonlar, bulunmasının kolay olması için birbirine yakın yazılmalıdır.
  • Ç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.
  • Yatay formatlama standartlarına göre bir satır en fazla 120 karakter uzunluğunda olmalıdır.

3 — BİRİM TESTLERİ

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. Temiz kod kavramına göre test yazarken de bir kaç kural vardır.

  • Test hızlı olmalıdır. Testler yavaş çalıştığında sık sık test çalıştırmak istemeyiz.
  • Testler birbirinden bağımsız olmalıdır. Birbirinden bağımsız bir sıralama ile çağırılabilmelidir.
  • 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.
  • 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.

4 — EŞZAMANLILIK

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.

  • 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.
  • 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.
  • 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.

5 — KODUN TEMİZLİĞİNİN ANLAŞILMASI

Robert C. Martin’in yazmış olduğu “Clean Code: A Handbook of Agile Software Craftsmanship” kitabının son bölümü olam “Smells and Heuristics” bölümünde kodun temizliğinin anlaşılması ve hangi durumlarda kodun temiz olmadığı ile ilgili aşağıdaki ipuçları paylaşılmıştır.

  • Kod ve dizayn ile ilgili teknik bilgiler dışında değiştirilme tarihi gibi uygunsuz yorum satırları varsa,
  • Kodda bulunmayan bir alan ile ilgili eski, alakasız veya yanlış yorum satırları varsa,
  • Kodun kendini açıklayabileceği bir yerde yorum kullanılıyorsa,
    (Örneğin : i++; // increment i
  • Eğer yorum zayıf bir dille yazılmışsa ve açıklayıcı değilse.
  • Eğer yorum satırı olarak yazılmış kod blokları varsa,
  • Ürün build etme aşaması için birden fazla adım gerekiyorsa,
  • Test kodlarını koşmak için birden fazla adım gerekiyorsa.
  • Fonksiyonların içerisine fazla sayıda argüman iletiliyorsa.
  • Argüman olarak verilen bir değişken fonksiyon içerisinde değiştirilerek dönüt olarakta kullanılıyorsa,
  • Boolean olarak argümanlar gönderilerek bu argümandaki true false değerine göre işlemlerin yapıldığı durumlar varsa,
  • Fonksiyon veya değişken hiçbir yerden çağırılmamış ve kullanılmıyorsa.
  • Bir kod dosyasında birden fazla dil .
  • Sistem içerisinde fonksiyonellik bazında gözden kaçırılmış durumlar varsa,
    (Örneğin Day.MONDAY objesi bir isimle karşılaştırılırken küçük harfle çağırıldığında case çalışmıyor ise )
  • DRY(Don’t Repeat Yourself) Prensibine uyulmayan, birden fazla yerde kullanılmış tekrar eden kodlar var ise,
  • Eğer kullanılan interface ve implementation tutarsız ise.
  • Eğer base sınıfın içinde kendisini extend eden sınıfların referansı var ise.
  • Bir interface’in gereğinden fazla metodu var ise.
  • Hiç bir zaman çalıştırılmayan, örneğin asla sağlanmayacak bir if ifadesinin içerisine yazılmış ölü kodlar var ise,
  • Değişkenler kullanıldığı yerlere çok uzakta tanımlandıysa,
  • Değişken isimleri tutarlı değilse, biryerde customer olarak kullanılan değişken başka yerde user olarak geçiyorsa.
  • Kullanılmayan değişkenler, kullanılmayan ve içi boş fonksiyonlar var ise.
  • 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.
  • 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)
  • Eğer bir fonksiyon true/false gibi bir boolean alıp çıktısı buna göre değişiyorsa.
  • 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.
  • 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.
  • Static olmaması gereken bir metod static olarak tanımlandıysa
  • Değişkenlere ne iş yaptılarını açıklayan isimler verilmeyip i, j gibi açık olmayan isimler verildiyse.
  • Fonksiyon isimlerinden o fonksiyonun ne yaptığı anlaşılmıyorsa.
  • Polymorphism yerine if/else blokları kullanılmışsa.
  • Kodlamada aynı standartlar takip edilmemişse. Örneğin biri parantezleri ({,}) if else keywordlerini altına koyarken takımdaki başka biri yanına koyuyorsa.
  • Sabit değerler static final olarak tanımlanmayıp kodun heryerine inline yazıldı ise.
  • Bir fonksiyon birden fazla iş yapıyorsa.
  • Enum kullanılabilecek yerlerde sabit değerler kullanldıysa.
  • Testler yetersiz veya bütün senaryoları kapsamıyorsa.
  • Testler yavaş çalışıyorsa.

bu kodda düzeltilecek/iyileştirilebilecek şeyler var demektir.

--

--