22 Ocak 2013 Salı

Kodlama Kuralları (Coding Conventions)


Sizlere bir önceki yazımda da bahsettiğim kodlarda okunabilirlik ve anlaşılabilirlik konusuna ek olarak bu yazıyıda paylaşmak istiyorum. Eğer kodlama kurallarını çok iyi bir şekilde uygularsak, okunabilirlik ve anlaşılabilirliğin nasıl hızlı bir şekilde iyileştiğini gözlemleyebiliriz. Ve böylelikle kodumuzun kalitesi hızlı bir şekilde artacaktır.

Yazının devamında kodun şablonundaki genel durumlara, isimlendirmenin nerelere ve nasıl bir şekilde etkili kullanılacağına ve yorum satırlarından maximum sonuç alabilmek için özel kullanımlarına değindim.

Konunun içeriği özet olarak:


  • Kodun Şablonu
    • Koşul durumları ( if - else kullanımı )
    • for ve while döngüsü
    • switch komutunun kullanımı
    • continue ve break kullanımı
    • ?: ifadesinin kullanımı
  • İsimlendirmenin Etkisi
    • Değişkenlerin isimlendirilmesi
    • İyi fonksiyon isimleriyle yorumları azaltmak
    • Tırnak bitimine yorumlar eklemek
  • Yorum Satırları
    • Yan yorumlar
    • Tırnak bitimleri
    • Genel kullanımı
    • Fonksiyonlarda kullanımı

Kodun Şablonu

Burada kodun şablonu olarak genel ifadelerin kullanış biçimlerine yer verdim. Bazı ifadelerin yüzeysel olarak üzerinde durdum ve diğer ifadelerle kullanımdaki benzerliğini belirterek bu yüzeyselliği en aza indirmeye çalıştım.

Takip edilebilirlik için kodun şablonunda uygulayacağımız kurallara örnekler ile bakalım.




Koşul durumları ( if - else kullanımı )


Prantezler arasındaki boşluk tercihe bağlıdır. Fakat else alt satırda kullanılmalıdır. Basit koşul durumda iki adet kabul edilebilir format vardır. Birincisi koşul durumunun parantezleri arasına boşluklar eklenerek gösterimi diğeri ise parantezin eklenmeden kullanımıdır.

En yaygın form parantez içine boşluk eklememektir. Her ikisinide kullanabilirsiniz fakat tutarlı olmalısınız.

Eğer bir dosyayı değiştiriyorsanız zaten bizlere sunulmuş olan formatlama olayını kullanabiliriz fakat yeni bir dosyada sıfırdan başlangıç yapıyorsak, projede kullanılan veya dizininizdeki diğer dosyaları formatlayabilirsiniz. Eğer bir şüpheniz varsa ve henüz kişisel bir tercihiniz bulunmuyorsa boşluk kullanmayın.


if (kosul) {  // parantezler arasında boşluk yok
  ...  // 2 karakter girinti.
} else if (...) { // Burada else küme parantezinin kapatıldığı yerde başlamış
  ...
} else {
  ...
}


İsterseniz parantezler arasına boşluk ekleyebilirsiniz:

if ( kosul ) {  // parantez içerisinde boşluklar bulunuyor - yaygın değil
  ...  // 2 karakter girinti.

} else {  // Burada else küme parantezinin kapatıldığı yerde başlamış

  ...
}

Bu iki örnekte de if ile parantez arasında boşluk bırakılmıştı. Şimdi değineceğimiz konu if durumunun son parantezi ile küme parantezi arasında da boşluk olmasının gerekliliğidir.

if(kosul)     // Kötü - if ten sonra boşluk eksik.
if (kosul){   // Kötü - { den once boşluk eksik.
if(kosul){    // Berbat.
if (kosul) {  // Iyi - IF ten sonra ve { den önce boşluk bırakılmış.


Kısa koşul durumları eğer okunabilirliği arttıracaksa yazılabilir. Bunu sadece satır kısa olduğunda ve else koşulu olmadığında uygulamalısınız.

if (x == kFoo) return new Foo();
if (x == kBar) return new Bar();


If koşulu eğer else ile birlikte kullanılıyorsa buna izin verilmemektedir:

// Hatali
if (x) bunu_yap();
else sunu_yap();

Genel olarak küme parantezleri tek satırlık durumlarda gerekli değildir ama isterseniz kullanabilirsiniz.
Karmaşık koşullarda veya durumlarda koşullar veya döngüler küme parantezleriyle daha okunaklı olabilir.
Bazı projelerde if her zaman beraberindeki ayracıyla olmalıdır.

if (koşul)
  bisey_yap();  // 2 karakter girinti.

if (kosul) {
  bisey_yap();  // 2 karakter girinti.
}

Bununla birlikte if-else koşulunun bir kısmında küme parantezi bulunuyorsa diğer kısımda da kullanmalısınız:

// İzin verilmez - küme parantezi if de var fakat else de yok
if (koşul) {
  foo;
} else
  bar;

// İzin verilmez - küme parantezi else de var fakar if te yok
if (koşul)
  foo;
else {
  bar;
}
// Kume parantezi IF ve ELSE ' in her ikisi icin de gereklidir
// Çünkü en az bir koşulda küme parantezi bulunmaktadır.
if (kosul) {
  foo;
} else {
  bar;
}

For ve While Döngüleri


Genel olarak yazım şekli IF durumunun yazımına benzemektedir. Parantez araları veya küme parantezleri çok benzerdir. Bununla ilgili aşağıda örnekler ile gerekenleri açıklamaya çalıştım.


Örnek:

int i; 
while ( i >= 0 ) {
    string1[i] = string2[i];
    i--;
}

Sayaç değeri başlangıçta sıfırdan farklı bir sayıdır ve sıfır olana kadar döngü dönmektedir.
FOR döngüsünde ise 3 işlem daha kolay ve anlaşılır bir şekilde yapılır.
  1. Değer tanımlama
  2. Koşul
  3. Değer arttırma/azaltma
Örnek:

for ( i = space = tab = 0; i < MAX; i++ ) {
    if ( line[i] == ' ' )
        space++;
    if ( line[i] == '\t' ) {
        tab++;
        line[i] = ' ';
    }
}

switch Komutunun Kullanımı
switch kullanımıyla ilgili birkaç ipucu bulunuyor:
  • Belirttiğimiz durumlara diğer durumlara girmeden önce yorumlar ekleyebiliriz.
  • default durumu daima diğer durumların tam tersi veya hatayı tetikleyecek bir durum olması işinizi kolaylaştıracaktır.
  • Eğer değişken oluşturmaya ihtiyac duyuyorsanız kod buloğunun içine yerleştirebilirsiniz.
  • Birden fazla durum için küme parantezi kullanabilirsiniz.
Örnek:

   switch (...) {
      case 1:
         ...
      /* yorumlar */

      case 2: {        
         int v;
         ...
      }
      break;

      default:
   }


  • Continue ve Break kullanımı
continue ve break goto'nun kılık değiştirmiş halleri olarak tanınırlar.
Kodda sihirli bir etki yaratarak ve de temkinli kullanılması gerektiğinden dolayı goto etiketine çok benzerler. Basit bir anlatımla koda bağımlı bir şekilde istenilen durumdan ışınlanmaya yararlar.

Continue döngüde kullanıldığında sadece o anki durumu atlar döngüye kaldığı yerden devam eder.Break ise tüm döngüsonlandırarak döngüden çıkartır.

Continue' nin kullanıldığı 2 ana problem:

  1. Test koşulunu atlamak için
  2. Arttırma/eksiltme ifadesini atlayabilmek için

Kısaca break ise içinde bulunulan durumu veya döngüyü terketmeye yarar

İki probleminde bulunduğu bu koda örnek olarak bakabilirsiniz.


Örnek kod:
while (TRUE) {
   ...
   /* Bir cok kod parcasi */
   ...
   if (/* bazi kosullar */) {
      continue;
   }
   ...
   /* Bir cok kod parcasi */
   ...
   if ( i++ > SON_DEGER)
      break;
}


Not: "Bir cok kod parcasi" problemin neren kaynaklandığını bulmanı açısından kafanızı karıştırabilir. Bu nedenle break ve continue ifadelerinin döngü içerisindeki kullanımı birbiriyle karıştırılmamalıdır. Bu olay büyük sorunlara neden olabilir.

?: ifadesinin kullanımı

İki olaydan birisinin koşula göre gerçekleşmesini sağlamak için kullanılır. Sorunlar genellikle ? ve : arasına çok fazla kod sıkıştırmaya çalışmasından dolayı kaynaklanmaktadır.
  • Olabilirse yapılacak olaylar fonksiyon halinde olmalıdır.
  • Durumlar uzunsa satırlara bölünerek yazılmalıdır.

Örnek kod:

   (kosul) ? func1() : func2();

 veya

   (condition)
      ? uzun durum
      : diğer uzun durum;









İsimlendirmenin Etkisi

******** Burada asıl hedeflenen amaç yazdığımız değişken ve fonksiyon isimleri gibi isimlendirebileceğimiz yapılardaki hatalı isimlendirmenin ortadan kaldırılmasındır. Örnek olarak detaylı bir şekilde hazırlanmış isimlendirme ile çok hızlı bir anlaşılabilirlik yakalanır. Eğer isterseniz kodunuzda i, j, k,.. veya kısaltma değerlerini kullanarak da aynı işlevi yerine getirebilirsiniz. Fakat bunların ne işleve yaradığını bulmak takım arkadaşınızın zaman kaybına yol açacaktır. Bu sebepten dolayı i, j, k,.. veya kısaltmalar gibi bu tarz isimler yerine daha anlamlı olanlarını tercih ederiz. 

  • Değişkenlerin isimlendirilmesi: Genel olarak  C dilinde değişkenlere isim verirken arasına " _ " işareti koyulur ve değişkenler türkçe karakterler içermez.

    Örnek olarak
     int birinci_degisken; bu şekilde anlaşılabilirlik arttırılmış olur.

  • İyi fonksiyon isimleriyle yorumları azaltmak: Kodumuzdaki yorumların azaltılabilceği konusunda bir takım öneriler bulunmaktadır.
    Kodu çeşitli fonksiyonlara ayırarak ve bu fonksiyonlara da anlaşılabilir fonksiyon isimleri vererek yorum satırlarını ciddi oranda azaltabilirsiniz.
         
Örnek olarak ben de aynı hataya defalarca düştüm, bazı yeni başlayan programcılar mterbilal() şeklinde kısaltmalar içeren fonksiyon isimleri kullanıyorlar fakat başka birisi bunu anlayabilmek için tüm kodu tekrardan yorumlamak zorunda kalacak ve hata ayıklama yaparken ciddi bir zaman kaybına yol açacaktır. Eğer fonksiyon  musteriTercihBilgileriAl() şeklinde olursa hem anlaşılır olmuş olacaktır hem de gereksiz yorum satırlarından kurtulunacaktır. Bunu yaparken şu kurallar daha etkileyici fonksiyon isimleri vermemize olanak sağlar:
  1. Fonksiyonun isminin küçük harfle başlaması
  2. Kullanılabilirlik açısından fonksiyonun tek bir şeyi belirtmesi (içerisinde " ve " bağlacının kullanılmaması).
  3. Fonksiyon isminin mastar eki ile bitmesi( örnek: ...Al(),  ...veriCek(),  ...secimGonder() gibi,...)

Yorum Satırları

Yorumlar okunabilirliğe büyük derecede etki etmektedir çünkü kodda bir kod parçasına bakıldığında ilk olarak bulundurduğu yorumlara bakılır ve neyi yapmaya çalıştığı tahmin edilir ve daha sonra kodun derinlemesine analizi kolay bir şekilde gerçekleşmektedir. Ama çoğu kişi kodun kolayca anlaşılabilmesini sağlayacak kadar yorumları kullanmamaktadır. Fakat kodu okuyan kişiyi boğacak kadar da yorum yapılmamalıdır. Yeterli miktarda kullanırsanız harikulade sonuçlar alırsınız.

Eğer koda baktığınıza ne yaptığınızı anlamıyorsanız yorumlar yazmak yerine kodu gözden geçirmek ve de gerekirse kodu yeni baştan daha temiz ve açık yazabilmek daha avantajlı olacaktır.

Yanlış veya yanıltıcı yorumlar sizin çok fazla zaman kaybetmenize, gereksiz yere acı çekmenize neden olmaktadır yorumlarınızın doğru yerde ve doğru anlamda kullanıldığına emin olun.

Yorumların Kullanılacağı Güzel Yerler
  • Bir modüle başlarken geniş açıyla bakabilmek amacıyla
  • Global değişkenlerin anlamını kavrayabilmek amacıyla
  • Veri yapısını açıkça tanımlamak için kullanılabilir
  • Fonksiyonun başlangıcına işlevini belirtmek için olabilir
  • Fonksiyon içerisindeki yanıltıcı adımları açıklamak amacıyla
Yorumlarda fantezi şekiller çıkararak dikkat dağıtmaktan kaçınmalıyız. Ve tabiki güzel bir yorum yaptığınızda kendinizle övünebilirsiniz, ego tatmini açısından değil, takım arkadaşınızın ilk bakışta hataları daha rahat anlayabildiğini görmek sevindirici bir durum.


Genel kullanımı

/* tek satırlık yorumlar bu şekilde gösterilir */


/*
 * Önemli tek satırlık yorumlar birden fazla yorum satırıyla gösterilir
 */


/*
 * Birden fazla satır içeren yorumlar bu şekilde gösterilir.
 * Başlangıç ve bitişe yorum satırları koyun ve asla türkçe karakter
 * kullanmamalıyız. İngilizce cümle yapılarına, büyük küçük harf uyumuna ve
 * noktalama işaretlerine dikkat ederek güzel anlaşılır cümleler yazmalıyız.
 */


/* ancak tek satılı yorumlarda büyük harfe ve noktalama işaretlerini ihmal edebiliriz */


// tek satırlık yorumları bu şekilde de gösterebilirsiniz.

Fonksiyonlarda kullanımı

/ ile başlayan tüm yorumlar aynı seviyede bulunmalıdır, örnek:



if (fonksiyon()) {
 /*
  * Fonksiyonunuzun ne işe yaradığını nasıl kullanıldığını ve nelerin yapı-
  * lmaması gerektiğini yazabilirsiniz. Okuyan kişinin yerine kendimizi
  * koyarak nerelerde hata yapabileceğini kestirmemiz ve bu kusımları açıkça 
  * belirtmemiz gereklidir. 
  */
 ...
}


Yan yorumlar

Eğer kodun bulunduğu satıra yorum yazmak istiyorsak birkaç tab aralık bırakıp yazabiliriz.


printf("hi\n");  /* ziyaretci karsilamasi */

Tırnak bitimleri

    Tırnakların bitimine yorumlar eklemek kodu kolayca okumaya yardımcı olmaktadır ve nerede başlayıp bittiğine odaklanmamıza yardımcı olmaktadır.
    while(1) {
       if (valid) {
      
       } /* if valid */
       else {
       } /* not valid */
    
    } /* end forever */
    
    
    

    Kaynaklar:

    1. http://www.cprogramming.com/tutorial/style.html
    2. http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
    3. http://users.ece.cmu.edu/~eno/coding/CCodingStandard.html
    4. http://www.gnu.org/prep/standards/standards.html
    5. http://www.jetcafe.org/jim/c-style.html

    Hiç yorum yok:

    Yorum Gönder