Cumartesi, Mayıs 29, 2010

Kod Kalite Ölçümleri ve Sık Kullanılan Metrikler

Bütün programcılar yazdıkları kodun iyi olmasını ister ancak iyinin neye karşılık geldiğini bulmak zordur genelde. Bu noktada günlük hayattan aldığımız birtakım dersler vardır aklımızda kalan.

Örneğin yazdığımız kodda mümkün olduğunca az hata çıksın isteriz, eğer hata çıkarsa da en kısa zamanda bizim veya başka bir programcının hatayı çözebilmesini isteriz, ürünümüzde bir değişiklik yapacaksak bunu ürünümüzün diğer bileşenlerini mümkün olduğunca az etkilemesiniz isteriz.

Bütün bunlar kurumsal dilde, yazdığımız kodun hatasız, esnek, kararlı, anlaşılır, düşük bakım maliyetine sahip olması demektir. Ancak normal şartlarda bunları ancak yazdığımız kod ürün haline gelip piyasaya çıktığında görebiliyoruz.

İşte tam bu noktada yazılım metrikleri devreye giriyor. Geliştirme esnasında sürekli ölçüm ve iteratif düzeltmeler ile yazılım metriklerini geliştirme sürecinin bir parçası haline getirdiğimizde tasarım ve geliştirme sırasında bize ileride daha büyük maliyetler getirecek pek çok hatadan kurtuluyoruz.

Yazılım mühendisliği ve yazılım kalitesinin ölçümü başlığı altında pek çok kod ölçüm metodu bulunuyor. Bunların hepsini uygulamak pratik olarak çok olası değil, öyleyse bizde piyasada en çok kullanılan metrikleri dikkate alarak bir orta yol bulabiliriz.

Koda dayalı ölçümler


1- Code Coverage
     Yazılan testlerin kodun ne kadarını kapsadığını ölçer. Code coverage için %80 gibi bir oran oldukça iyi görünse de aslında az sayıda basit test yazarak dahi bu orana ulaşılabildiği gözlemlendiği için hedeflenen oranın %100 olması önerilir. (Oran hakkında detaylı bilgi için [1] )

2- Cohesion
    Bu ölçüm sınıfın sorumlu olduğu işlerin kendi içindeki uyumluluğunu ölçer. Her sınıfın tek bir sorumluluğu olmalıdır. [3] [4]. Uyumluluk LCOM (Lack of Cohesion in Methods) adı verilen ölçüt ile bulunur. Değişik türleri bulunan LCOM sınıfta yer alan alanlara metodların ortak erişim sayısını temel alan bir ölçümdür. LCOM3 için bu değer 0 ile 2 arasında değişir ve 1'in üzerindeyse sınıf bölünmelidir. [5]

3- Coupling
    Bir nesnenin diğeri ile etkileşime girmesine denir. Program içerinde mutlaka etkileşim olacaktır, ancak bu ilişkinin nesnelerin implementasyon detaylarından mümkün olduğunca bağımsız olması istenir. Farklı ilişki türleri üzerinden ölçülebilir. En çok kullanılanlardan birisi CBO'dur.
Coupling Between Objects (CBO): Miras alınan sınıflar hariç, sınıfın çalışmak için ihtiyaç duyduğu sınıf sayısıdır. (kısaca importları say :)) Kütüphanelerde bu sayı yüksek olabilir ancak çalıştırılabilir sınıflarda 6 ile 10 arası makul kabul edilebir. [6][9]

4- Cyclomatic Complexity
    Bir metodun içerisinde yer alan karar noktalarının (if, else vb.) sayısıdır. Kabul edilen eşik değer 10'dur.[6] [7] Bunun yanı sıra Essential Complexty denilen bir metrik daha mevcuttur ancak Cyclomatic Complexity'nin daha etkili bir metrik olduğu belirtilmektedir.  [8]

5-  Cyclomatic Density
     Koddaki karar noktalarının toplam çalıştırılabilir koda oranıdır. 0.14 ile 0.42 arasındaki değerler için kodun basit ve anlaşılabilir olduğu kabul edilir.[6]

6- Response For Class (RFC)
    Bir sınıfta yazılan ve çağırılan toplam metotların sayısıdır. Bu değer yükseldikçe kodun bakımı zorlaşır. Önerilen eşik değer 55 dir. [9]

7- Weighted Methods for Class (WMC)
    Bir sınıfta yazılan toplam metot sayısıdır. Eşik değeri olarak 6 ile 33 arasında değişik rakamlar önerilmektedir. Ancak Cohesion değeri WMC'ye kıyasla daha önemlidir. [6] [9]

8-  Class Hierarchy Level veya Depth of Inheritance Tree (DIT)
     Miras ilişkisinde sınıfın üzerinde kaç tane atası olduğunu gösterir. 6'nın üzerinde ise test edilebilirliği çok düşük olduğunu, 2 nin altında ise OO ilkerinin fazla kullanılmadığına işaret eder. Uygulamanın genelinde 2 ve 3 düzeyinde olması hedeflenmelidir. [6]

9-  Number of Methods in Class (NOM)
     İdeal değerler 6 ile 20 arasında değişse de 40'ın üzerinde sınıf kesinlikle bölünmelidir. [6] Ancak tek başına bir gösterge olmaktan çok LCOM ile birlikte değerlendirilmelidir.

10- Specialization Index (SIX)
      Kod karmaşıklığını ve bakım maliyetlerini arttırmasından dolayı overload edilmiş fonksiyon sayısının mümkün olduğunca az olması istenir. Bundan dolayı SIX = (Overload Edilmiş Metot Sayısı * DIT) / NOM şeklinde hesaplanır. 1.2 (veya %120)'ye kadar normal kabul edilir.

* Bunların dışındaki ölçülerden metot başına düşen satır sayısının 7-9 arasında olması tavsiye edilse de Cyclomatic Complexty'nin bundan daha önemli olduğu belirtilmektedir. ([2])

Dizayna dayalı ölçümler [11]

1- Afferent Couplings (Ca)
İncelenen paketin dışında yer aldığı halde söz konusu pakete bağımlı paketlerin sayısıdır. Paketin değişmesi halinde etkilenecek paket sayısını gösterir. Bunu paketin sorumluluğun ölçüsü olarak da düşünebiliriz.

2- Efferent Couplings (Ce)
İncelenen paketin kendi dışında kaç tane pakete bağımlı olduğunu gösterir. Paketin yeniden kullanılabilirliğinin ölçüsüdür.

3- Abstractness (A)
İncelenen pakette yer alan soyut sınıfların ve arayüzlerin sayısının paketteki toplam sınıf sayısına oranıdır. 0 ile 1 arasında değişen bu oran 1'e yaklaştıkça paketin esnekliği artar.

4- Instability (I)
I = Ce / (Ce + Ca) şeklinde hesaplanır. 0 ile 1 arasında değişen bu oran 1'e yaklaştıkça paketin kararlılığı azalır. (Yani paketin değişimi sistemdeki başka pek çok paket üzerinde değişiklik yapmayı gerektirir.)

Devam etmeden küçük bir not girelim araya. Karalılık genelde iyi yönde yorumlansa da bir paketin tamamen kararlı olması demek paketin değiştirilebilirliğinin de minimum düzeyde olması anlamına gelir. Bu durumda hangi paketlerin esnek hangi paketlerin daha az esnek ama kararlı yapıda olmasını istediğimizi sorgulamalıyız. Bu konuda cevabı bize "Open/Closed Principle" veriyor. Buna göre yazılımı oluşturan birimler geliştirilmeye açık ancak değiştirilmeye kapalı olmalıdır. Bu noktada hangi tür sınıflar geliştirilmeye açık diye bakarsak soyut sınıfları ve arayüzleri görürüz.

Sonuca bakarsak; Abstractness = 1 ve Instability = 0 olduğu durumda hem kararlı hem de değiştirilebilir paketleri buluruz. Aynı biçimde Abstractness = 0 ve Instability = 1 olduğu durumda ise kararsız ancak değişime kapalı (ve böylece başka paketlerin değişimini gerektirmeyecek) durumdaki paketleri buluruz.

Ancak incelediğimiz paketler her zaman bu iki ideal durumdan birinde olmazlar. Bu durumda bu iki değerin dengede olması yani ;(A,I) = (1,0) dan (0,1) e gittikçe aynı miktarda değişmesi tasarımımız için optimal çözüm olarak görülebilir. Bunu grafiksel olarak ifade edersek;


Main Sequence denilen bu çizgi üzerinde yer alan bütün noktaları ideal noktalar kabul ettiğimize göre bunların dışında elde ettiğimiz değerleri bu çizgiye olan uzaklıklarına göre değerlendirebiliriz. Tasarım veya yeniden yapılandırma sırasındaki amacımız paketlerimizin bu çizgi üzerinde ve çizgiye en yakın durumda olmasıdır.

5- Distance from the Main Sequence (D)
D = |A+I-1| ile hesaplanır ve 0 ile 1 arasında değişir. 0 olması analiz edilen pakete ait değerin Main Sequence çizgisinin üzerinde olması demektir.

Bunların yanı sıra kod tekrar sayısı ile dizayn ve kod izlenebilirliği de dikkate alınması gereken unsurlardır. Kod tekrarı için bütün proje içerisinde kod tekrarı yapılan bölümler tesbit edilerek uygun biçimde (ortak sınıflar, soyut sınıflar, arayüzler) yeniden tasarlanmalıdır. Dizayn ve Kod izlenebilirliği ise (Tasarım belgelerinde yer alan birimlerin, uygulamadaki birimlere (sınıf,modül vb.) oranı) de yazılımın kalitesini belirleyenbir unsur olarak görülebilir.

[1] http://codebetter.com/blogs/patricksmacchia/archive/2009/06/07/high-test-coverage-ratio-is-a-good-thing-anyway.aspx

[2] http://stackoverflow.com/questions/312642/how-many-classes-per-package-methods-per-class-lines-per-method

[3] http://www.cihataltuntas.com/?p=111

[4] http://en.wikipedia.org/wiki/Single_responsibility_principle

[5] http://javaboutique.internet.com/tutorials/coupcoh/

[6] http://www.mccabe.com/pdf/McCabeCodeQualityMetrics-OutsourcedDev.pdf

[7] http://javaboutique.internet.com/tutorials/metrics/

[8] http://www.nasa.gov/centers/ivv/ppt/172536main_Mike_Chapman_The_Relationship_of_Cyclomatic_Complexity_Essential_Complexity_and_Error_Rates.ppt

[9] http://www.issre2009.org/archive/2006_supplemental/student_papers/An_Investigation_of_CK_Metrics_Thresholds.pdf

[10] http://support.objecteering.com/objecteering6.1/help/us/metrics/metrics_in_detail/specialization_index.htm

[11] http://www.objectmentor.com/resources/articles/oodmetrc.pdf