Sayfalar

Object Oriented Programming etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Object Oriented Programming etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

Nesne Yönelimli Yazılımda Dizayn Prensipleri

                                                                                                                                                    
    Uzunca bir süre önce yazdığım bir yazıyı güncelliğini koruduğunu düşündüğüm için aynen yayınlıyorum.

Esen Kalın .
  
     Sistem içerisinde  detaylara girildikçe olaylar gittikçe karmaşık bir hal almaya başlar ve kolaylıkla kontrolü kaybedilebilir. Walker Royce’un ”The Rational Edge”'de yayınlanan bir  makalesinde yer alan şu istatistikler ilginçtir :
  • Yazılım projelerinde geliştirme için harcanan her bir dolarlık maliyete karşılık bakıma iki dolar harcanmaktadır
  • Geliştirme eforunun sadece %15’i doğrudan programlamaya harcanmaktadır

     Bu istatistikler bize bakıma , geliştirmenin iki katı süre harcadığımızı söylemektedir.Açıkça bakım maliyetlerini düşürmek için bir çözüme ihtiyaç vardır.Nesne yönelimli programlama bu maliyeti azaltsa da ne yazıkki sıfırlayamamaktadır.Şu örnek olayı daha iyi kavramamızı sağlıyacaktır :

A ve B sınıfları tarafından yeniden kullanılan bir R sınıfı düşünelim.Eğer A sınıfı ; R sınıfının davranışlarında bir yenilik  yada değişiklik ihtiyacı duyarsa bu aynı zamanda B sınıfını da etkileyecektir.Bu durumdayken eğer B bu yeni davranışa ihtiyaç duymazsa ne olur ? Ya da değişiklik B için olumsuz bir durum yaratıyorsa ? Bu durum yeniden kullanımın olduğu ancak bakımın sorun olduğu bir örnek teşkil eder.

           Nesne yönelimli programlamanın en önemli avantajı sağladığı yeniden kullanım olanaklarıdır.Ancak sırf bu amaç uğruna körü körüne başlanılan projeler bir süre sonra rahatlıkla kördüğüm halini alabilir.Yukarıda bahsedilen problemin çözümü için pek çok yol öne sürülebilir , ancak kuşkusuz en doğru yaklaşım bunun bir dizayn sorunu olduğunu kabul etmektir.Doğru prensipler doğrultusunda geliştirilen dizaynlar bu tip problemleri en aza indirirler.

Sınıf Dizayn Prensipleri


   Dizayn prensiplerinin İlk bölümünde sınıf dizaynı ile ilgili prensipler ele alınmıştır.Ancak bu prensipler modul gibi diğer bileşenlere de uygulanabilir prensipler olarak algılanmalıdır.

Açık Kapalıdır Prensibi (The Open Closed Principle - OCP)

   Bu prensip kısaca “bir modul genişlemeye açık ancak değişikliğe kapalı olmalıdır” şeklinde özetlenebilir.Belki de tüm prensiplerin en önemlisi olan bu prensip “Bertrand Meyer”’in çalışmalarına dayanmaktadır.Prensip kısaca kodlarımızı değişikliğe gerek kalmadan genişletebilmemiz gerektiğini söyler.Bir başka deyişle modulümüzün yeteneklerini var olan kodları değiştirmeden geliştirebilmeliyiz.Bu ilk başta biraz karışık görünse de bu prensibi yerine getirebilmek için çeşitli tekniklere sahibiz.Bu tekniklerin tümü de aslında nesne yönelimli programlamanın temel prensiplerinden soyutlama’ya (abstraction) dayanmaktadır.Örneğin elimizde bulunan modem sınıfımız “Hayes” ve “Ernie” tipi modemler için kodlanmış olsun ve methodlarına dışarıdan belirtilen modem tipine göre davransın.

Bu dizaynda sisteme eklenecek her yeni modem tipi var olan sınıfın değişikliğini gerektirecektir.Ancak modem sınıfını soyut hale getirerek bu sorunu kolaylıkla aşabiliriz.Bu durumda  sisteme eklenecek her yeni modem tipi , modem soyut sınıfını gerçekleştirecek ve sadece kendi kodunu içerecektir.Ancak bu durum mevcut sınıfların hiçbirine dokunulmadan yerine getirilebilecektir.



 OCP prensibi mimari olarak bize değiştirmeden geliştirebileceğimiz moduller kurma olanağı sağlar.Bu erişilmesi oldukça güç bir hedeftir.

Liskov’un Yerine Koyma Prensibi(The Liskov Substitution Principle - LSP )


    Bu prensip Barbar Liskov tarafından ortaya konmuştur.Kısaca alt sınıfların üst sınıflara uygun olması gerektiğini söyler.İlk bakışta nesne yönelimli yazılımın bunu doğası gereği sağladığı düşünülse de durum biraz daha karmaşıktır.Bu prensip aynı zamanda temel sınıfın gösterdiği davranışların alt sınıflar tarafından da aynen yerine getirilmesi gerektiğini söyler.Durum bir örnekle daha kolay anlaşılabilecektir.Örnek olarak elips ve daire şekillerini ele alalım.Daire aslında elipsin bir cinsidir , tek farkı dairede ; elipsin iki merkezinin tek noktada buluşmasıdır.




Durum sınıfların özellikleri ve davranışları devreye girdiğinde biraz daha karışık bir hal alacaktır.Ekli şeklide görüldüğü üzere elipsin üç niteliği vardır.İlk ikisi merkezleri , üçüncü nitelik ise eksenin boyunu  gösterir.Eğer daire elipsten türerse bu üç  niteliğe de sahip olmak zorundadır.Ancak daire sadece merkez noktası ve çapa ihtiyaç duyar.



Elips’in merkezleri belirleyen setFoci metodu muhtemelen şu şekilde olacaktır :

Public void setFoci(Point a , Point b) {
 focusA = a;
 focusB = b;
}

Daire ise tek merkeze sahip olağından bu methodu şu şekilde değiştirebilir :

Public void setFoci(Point a , Point b) {
 focusA = a;
 focusB = a;
}

    Bu durumda daire fazladan gereksiz bir niteliğe sahip olsa da her iki sınıfta görevlerini tam olarak yerine getirebilecektir.Sistem sorunsuz gibi görülebilir.Ancak bu durum sadece elips ve daireden oluşan bir sistem söz konusu olsa geçerli olurdu.Ne yazıkki bu sınıflar başka sınıflar ile bir arada çalışmak zorundadırlar ve sundukları her davranış ya da nitelik dış dünya ile bir kontrat niteliği taşır.Ve bu kontrat hiç bir şekilde bozulmamalıdır.Örneğin dışarıda şu şekilde bir method bulunduğunu var sayalım.

void f(Ellipse e){
   Point a = new Point(1,0);
   Point b = new Point(-1,0);
    e.setFoci(a,b);
   e.setMajorAxis(3);
   assert (e.getFocusA() == a);
   assert (e.getFocusB() == b);
   assert (e.getMajorAxis() == 3);

}

Bu durumda method elipse ile çalıştığını varsayıyordur ve elips sınıfı kullanıldığı sürece bir hata üretmez.Ancak bu methoda elips yerine daire gönderildiğinde hataya yol açacaktır.Elips sınıfı setFoci() metoduyla açıkca bir kontrat imzalamıştır ve bu kontrat gönderilen belirtilen noktaların sınıfın iki noktası olarak belirleneceğini söyler.Ancak daire sınıfı bu kontratı açıkca ihlal etmektedir.
  Neyazıkki LSP ihlalleri sistem içerisinde oldukça geç farkedilir .Örneğin elips / daire örneğinde olduğu gibi ilgili  method daire ile deneninceye kadar bu durum ortaya çıkmaz.Durumun telaffisi eğer orjinal sınıfların değişikliği de zor bir durumda iken farkedilirse oldukça istenmeyen şekillerde çözülür.Sıklıkla rastlanılan bir şekilde if/else – switch/case gibi ifadelerle durum çözülmeye çalışılır.

void f(Ellipse e){
  if(typeID(e) == typeID(Ellipse) ){
     Point a = new Point(1,0);
     Point b = new Point(-1,0);
     e.setFoci(a,b);
     e.setMajorAxis(3);
     assert (e.getFocusA() == a);
     assert (e.getFocusB() == b);
     assert (e.getMajorAxis() == 3);
  }else{
     Point a = new Point(1,0);
     Point b = new Point(-1,0);
     e.setFoci(a,b);
     e.setMajorAxis(3);
     assert (e.getFocusA() == a);
     assert (e.getMajorAxis() == 3);
  }

}

  Ancak bu gibi çözümler de OCP genellikle prensibini  ihlal ederler.Yukarıdaki durumda yeni bir elips sınıfı türetildiğinde f fonksiyonunun da doğruluğu kontrol edilmeli yada değişikliğe uğratılmalıdır.
  Bu gibi ihlallerin ortaya çıkmaması için özellikle temel sınıfların
  • Kontratları iyice kontrol edilip alt sınıfların uyamıyacağı kontratları içermemesi sağlanmalı
  • Alt sınıfların üst sınıf kontratlarına harfiyen uyması sağlanmalı
  • Sistemde bir başka temel sınıfın varlığının gerekliliği iyice sorgulamalıdır.



Bağımlılığın Çevrimi Prensibi ( The Dependency Inversion Principle - DIP )


  Soyut eşleme (abstract coupling) olarak da adlandırılan bu prensip kısaca bileşenler arası eşlemelerin (ya da bağımlılıkların) somut sınıflar üzerinden değil soyut sınıflar üzerinden yapılması gerektiğini söyler.Eğer OCP prensibini nesne yönelimli mimarinin hedefi sayıcak olursak DIP prensibini bunu sağlıyacak  temel mekanizma olarak adlandırabiliriz. COM,CORBA,EJB gibi bileşen teknolojileri gücünü bu prensipten alırlar.

  Procedürel dizaynlar bir parça bağımlılık yapısı gösterirler.Üst seviye moduller uygulamanın üst seviye politikalarına bağımlıdırlar.Bu politikalar uygulamanın alt seviye modulleri , onların implemantasyonu ile ilgilenmezler.Ancak procedürel yapılar bunun tam tersi yukarıdan aşağıya doğru bir bağımlılık gösterir.(Örneğin C dilinde hazırlanmış bir grafik kütüphanesi , alt seviyelerde grafik objeleri içeren detay kütüphaneler , sistem kütüphaneleri vb. bir yapı düşünün).


  Nesne yönelimli mimariler ise bambaşka bir bağımlılık yapısı gösterirler.Üst seviye moduller soyut sınıflar ile politikaları içerirken alt seviyelere gittikçe bu politikaların gerçekleştirimleri elde edilir.Bağımlılık tam tersine dönmüş gibidir.


  
   DIP bize genişleyebilir ve esnek bir mimari kurma olanağı sağlar.Geliştirmenin ilk safhalarında gereksiz hatta külfet gibi görünen bu prensip ilerleyen yaşam evrelerinde hayat kurtarıcı olabilir.
  Örneğin C dilinde yer alan string.h kütüphanesi somut fakat esnek olamayan bir yapı sergiler.ANSI standarlarında oldukça iyi çalışan kütüphane projenin örneğin UNICODE standardına dönmek istemesiyle oldukça baş belası bir durum oluşur.
   DIP presinbinin uygulanmasında karşımıza çıkacak en büyük sorun nesne oluşturulmasıdır.Yaratılan soyut sınıflar üzerinden nesneler yaratılamaz.Bu durumun en güzel çözümü GOF paternleri arasında yer alan “Abstract Factory” paterninin uygulanması ile aşılabilir.

Arabirimin Ayrılması Prensibi ( The Interface Segregation Principle – ISP  )


  Bu prensip bize genel içerikli büyük arayüzler yerine , istemcilere yönelik pek çok arayüzün tercih edilmesini tavsiye eder.Bu prensibin özü oldukça basittir.Eğer farklı farklı istemciler için genel bir arayüz tasarlarsanız bu istemcilerin herhangi biri için gereken değişiklik pek çok yeri etkileyecektir.



    Yukarıdaki örnekte servis üç istemci için methodlar barındırmaktadır.Örneğin istemci A methodları üzerinde yapılacak bir değişiklik , hiçbir ilgileri bulunmadığı halde diğer iki sınıfıda ilgilendirecek ; bu iki sınıfında yeniden gözden geçirilimesi gerekecektir.
    Servisin direk parçalanması söz konusu olabileceği gibi aşağıdaki şekilde olduğu gibi servisin farklı arayüzlere bölünmesi de kullanışlı bir tekniktir.


  ISP her istemci için bir arabirim yapılmasını önermemektedir.Bu prensipten bu çıkarılmamalıdır.Aksine bu durum oldukça sağlıksız ve ağır bir sistem yaratır.Bunun yerine istemciler kategorilerine ayrılmalı ve arabirimler bu kategoriler doğrultusunda yaratılmalıdır.

Birleşik Yeniden Kullanım Prensibi ( The Composite Reuse Principle - CRP )

   Bu prensip diğer prensiplere göre daha tartışmalı ve kesin olmayan bir prensiptir.Alt sınıf methodlarının gurplar halinde birbirine benzeştiği durumlar için uygun bir taktik sayılabilir.Bu prensibin temel fikri nesne yönelimli programlamada polimorfizm’e kalıtım  yerine birleştirme ile de gidilebileceğidir. Polimorfizm alt sınıfların ana sınıftan farklı özellikler gösterebileceğini belirten deyimdir.
 
abstract class Animal {
  abstract void talk();
}
 
Class Dog extends Animal {
  public void talk() {
    System.out.println("Scooby dooby Doo");
  }
}
 
Class Cat extends Animal {
  public void talk() {
    System.out.println("Meow....");
  }
}

   Örnek kodda “Animal “ ana sınıfının alt sınıfları “Dog” ve “Cat” ana sınıftan farklı konuşma davranışları sergilemektedir , başka bir deyişle polimorfik yapıdadırlar.Yine bu örnekte kalıtım özelliği ile kolayca polmorifzm’e ulaşılmıştır.Ancak pratikte bazı durumlarda bu özellik esnek olmıyan ve etkisiz yapılar kurulmasına yol açabilir.
  Örneğin bir bordro sistemi tasarladığınızı varsayalım.Yılbaşına yakın bir zamanda göreviniz personelin ikramiyelerini hesaplıyacak bir sistem hazırlamak olsun.Şirketin üç tip personeli kalıcı ; geçici ve yarı-zamanlı olsun.
  

  
  Muhtemelen ilk dizaynınız yukarıdaki gibi olacaktır.Belli bir zaman sonra müdür yarı zamanlı personelin prim hesaplamasını değiştirmek istesin.Bu durumda tek yapacağınız yarı zamanlı personel sınıfında primHesapla  methodunu basitçe üzerini ezerek değiştirmek olacaktır.
  Bir süre sonra müdür danışman olarak çalışanların prim hesaplama şeklini  yarı zamanlı personel gibi değiştirmek istesin.Bu durumda :
  • Yarı zamanlı personelin bir alt sınıfı olarak danışman sınıfı yaratabilirsiniz.Ancak bu sınıf hiyerarşisinde bir sorun olacaktır.Bu dizayn olmadığı halde danışmanların ; yarı zamanlı personel olduğunu ilan eder.Örneğin ileride danışmanlara ; kalıcı personel oranında prim verilmek istendiğinde sınıf hiyerarşisi bunu zorlaştırır.
  • Danışman sınıfını direk çalışan sınıfının alt sınıfı olarak yaratabilir ve primHesapla metodunu yarı zamanlı personelden kopyalabilirsiniz.Ancak bu yeniden kullanım hedefimizi zedeler ve aynı kodun çift olarak yaratılmasına yol açar.
  Burada hata çalışan sınıfının tasarlanması sırasında ortaya çıkmıştır.Prim hesaplama metodunun sık değişmeyen ve herkeze uygun bir method olduğu düşünülmüştür.Ancak gerçekte bu method her çalışan tipine göre değişiklik gösterebilir ve oldukça sık değişebilir bir method’dur.Kalıtım  yalnızca alt sınıfların üst sınıfa tam olarak uygun olacağı durumlarda kullanışlı bir yöntemdir.Ana sınıfın methodlarının sürekli olarak üzerinin ezilmesi kalıtım ilişkisini anlamsız kılar.Bu durumda üst sınıfta ; alt sınıflar gibi özelleşmiş bir sınıf olmaktan öte gidemez.

   Bu durum soyut bir prim hesaplama sınıfı yaratılarak zarif bir şekilde halledilebilir.



  Bu çözümde PrimHesalayıcı tüm çalışan tipleri için birleştirilmiş (composite) bir yapı sunmaktadır ve bu yapı oldukça esnek bir polimorfik yapı sergilemektedir.
  Bu örnek CRP seçimi için oldukça uygun bir örnektir.Bu örnekte kalıtım sizi her alt sınıfta yeni bir geliştirme yapmaya zorlar.
 

En Az Bilgi Prensibi ( The Principle of Least Knowledge - PLK)


   Bu prensip bize kullandığımız bir nesnenin içinden direk olarak başka nesnelere ulaşmamamızı salık verir.Bunun yerine sadece bildiğimiz nesne bize tüm methodları sunmalı ; iç yapısındaki başka nesnelerle ilgilinememiz gereksiz kılınmalıdır. Aksi takdirde nesnenin karmaşık yapısına kendimizi bağlamış oluruz.Aynı zamanda nesne de bir başka nesneyi dışarıya sunduğu için bir sözleşme imzalamış olur . Ekli örnekte PLK prensibine uymayan bir method ve uygun hali görülmektedir :
Hatalı
Doğru
public void test (AClass o){
  AnotherClass ao = o.get();
  ao.doSomething();
}

public void test (AClass o){
  o.doSomething();
}


  PLK’nın ana dezavantajı sınıflara pek çok ek metodun yüklenmesidir.Örnekte PLK prensibine uymak için sınıf başka bir sınıfın metodunu kendine almak zorunda kalmıştır.Bu açıkça çok yüklü ve hantal sınıfların doğmasına yol açabilir.Ancak bu durum sınıfın dışarıya somut sınıf referansları değil de arabirim referasları sunmasıyla halledilebilir.Yani kısaca bir sınıftan dışarıya verilen referaslar soyut sınıflar üzerinden olmalıdır diyebiliriz.Bu şekilde sınıfımızı bir başka somut sınıf ile eşlemeden DIP ve OCP prensiplerine de uygun olarak çözümler geliştirebiliriz.Java örneğine bakıldığında bu şekilde hazırlanmış onlarca sınıf görülebilir.

Tek Sorumluluk Prensibi ( The Single Responsibilty Principle - SRP)


  Bu prensip aynı zamanda uyumluluk (cohesion) prensibi olarak da tanınır.Bu prensibi kısaca “bir sınıfın değiştirilmesi için birden fazla sebep olmamalı “  şeklinde özetleyebiliriz.Bu aynı zamanda bir sınıf birden fazla sorumluluk taşımamalı şeklinde de özetlenebilir.Çünki her sorumluluk aynı zamanda değişimin ana sebebidir.İstekler değiştiğinde o isteği yerine getiren sınıflar değiştirilerek istek yerine getirilir.Eğer bir sınıf birden fazla sorumluluk taşıyorsa , o sınıfın değişmesi için birden fazla sebep var demektir.



   Örneğin alan hesaplama ve çizim methodlarını içeren bir dikdörtgen sınıfını ele alalım.Grafik ve geometri hesap uygulaması olmak üzere İki değişik uygulama bu sınıfı kullansın.Bu durumda dikdörtgen sınıfı iki sorumluluk yüklenmiş olur .Birincisi alan hesabı yapmak , ikincisi ise dikdörtgenin grafik çizimini yapmak.Halbuki bu uygulamayı kullanan uygulamalar bu fonksiyonalitenin sadece birine ihtiyaç duymaktadırlar.Bu durum iki soruna yol açmaktadır :
  • Geometri hesap uygulaması hiç ihtiyacı olmadığı halde çalışma sırasında grafik paketine ihtiyaç duyacaktır.
  • İkincisi grafik uygulaması yüzünden dikdörtgen sınıfında olabilecek herhangi bir değişiklik geometri hesap uygulamasınında yeniden derlenmesi , sınanması vb. gereksiz yükler getirecektir.
  Nesne yönelimli dizayn içinde pek çok şekilde bu sorumluluklar birbirinden ayrılabilir.Ekli şekilde bir çözüm örneği sunulmuştur.





 

Paket Dizayn Prensipleri


  Paket dizayn prensipleri sistemin yapılandırılmasında sistem mimarının göz önünde bulundurması gereken temel prensipleridir.Sınıf bazında izlenecek prensipler algılandıktan sonra bunların nasıl organize edileceği , nasıl kategorize edileceği vb. sorunlar bu prensipler yardımıyla çözülürler.

Paket Uyumluluk Prensipleri ( Package Cohesion Principles )


  Bu prenipler sistem üzerinde yapılacak değişikliklerin en az etkiyi göstermesi için tasarlanmıştır.REP ve CRP prensipleri paketlere bağımlı olan kullanıcıların hayatını kolylaştırırken CCP prensibi daha çok değişiklik yapan geliştiricilerin hayatını kolaylaştırır.Bunu yanı sıra CCP paket içeriğini daha çok büyütürken CRP tam tersi bir işlev görür.Mimarinin ilk başlarında daha çok CCP uygulandığı görülürken ilerleyen safhalarda REP ve CRP prensipleri devreye girer.

Sürümün Yeniden Kullanım Eşitliği Prensibi ( The Release Reuse Equivalence Principle  - REP)

  
   Bu prensip bize yeniden kullanım için tasarlanan sınıfların her sürümde geriye doğru uyumlu olması gerektiğini söyler. Bir sınıf eğer yeniden kullanım için tasarlanmış ise doğal olarak pek çok kullananı vardır .Yeniden kullanım için tasarlanan sınıfların üzerinde yapılacak değişiklikler ; bağımlılıklardan dolayı pek çok başka sınıfı etkileyecektir.Dolayısıyla yeniden kullanılabilir olarak tasarlanan sınıflar doğru bir sürüm stratejisiyle geriye doğru uyum göstererek değişebilirler.Sık değişiklik gösteren sınıfların müşterileri bakım maliyetini karşılayamıyacaklarından kullanımdan vazgeçebilirler.
    Sistem de tasarlanan sınıflar her biri bir pakete ait olmak zorundadır.Yeniden kullanım için tasarlanan sınıflarda bu kurala uymak zorundadır.Eğer bir sınıfa bağımlılık var ise aynı zamanda pakete de bağımlılık vardır.Dolayısıyla yeniden kullanılabilir olarak tasarlanan sınıfın bulunduğu paket ve paketin diğer içeriği de buna uygun tasarlanmalıdır.

Genel Toplanma Prensibi ( The Common Closure Principle - CCP)

 
  Beraber değişen sınıflar aynı pakete konulmalıdır.Aksi takdirde paket bağımlılığından dolayı ilerleyen sürümlerde gereksiz sınama ,  derleme vb. yükler  ortaya çıkar.Bu prensip aynı zamanda paketlerin bağımsız sınıflardan daha çok yeniden kullanım parçası olduğu fikrine dayanır.Eğer daha fazla paket değişiklik gösterirse yazılımın daha büyük parçaları bu değişiklikten etkilenecektir.Bu etkiyi minimal tutmak için en iyi çare beraber değişen sınıfların aynı pakette toplanmasıdır.

Genel Yeniden Kullanım Prensibi ( The Common Reuse Principle - CRP)


  Beraber değişmeyen sınıflar aynı pakete konmamalıdır.Bir paket içinde bulunan sınıflar beraber kullanılıyorlar demektir.Bu her değişiklik ve yeni sürümde gereksiz olduğu halde değişmeyen sınıflarında yeniden gözden geçirilmesi , sınanması ve derlenmesi demektir.Bunun değişmeyen sınıflara bağımlı paketler üzerinde de aynı işlemlerin yapılması demek olduğu düşünülürse artan yük açıkça görülür.
  Örneğin bu kurala uymayan işletim sistemlerinde ki değişiklikler sık sık başımızı ağrıtır.İşletim sisteminin yeni bir sürümü çıktığında biz değişikliğin tamamını istesek de istemesek de getirdiği yükü karşılamak zorunda kalırız.





Paket Eşleme Prensipleri (Package Coupling Principles )


   Sonraki üç prensip paket eşleme prensipleri  olarak anılırlar ve paketler arasındaki ilişkilerin nasıl kurulması gerektiği üzerinde dururlar.

Doğrusal Bağımlılık Prensibi ( The Acyclic Dependency Principle - ADP)

  
 Bu prensipte, paketler arasındaki ilişki yapısında çevrimlerin bulunmamasıdır. Bir başka deyişle paketler arası ilişkiler tek yönlü ve doğrusal olmalıdır.




 Şekildeki  yapı oldukça modüler ve kendi içinde uyumlu olan bir mimaridir. Paketler arasındaki tüm ilişkiler tek yönlüdür.

Yukarıdaki şekilde görülen ”Comm Error” paketinde bir değişiklik yapıldığını varsayalım. Bu durumda “Protocol” “Comm” ve “GUI” paketleri dışında sistemin geri kalan kısmı bu değişiklikten etkilenmemiş olur. Ancak bir süre sonra uygulama da “Comm Error” paketinde çıkan hataların bir pencerede kullanıcıya gösterilmek istendiğini var sayalım.Bu değişiklik sonucu “Comm Error” paketinden sınıflar “GUI” paketinden ilgili sınıfları kullanarak bir pencere açıp hata mesajı versin.




    Şekilde de görüldüğü gibi bu mimaride bir tasarım sorunu bulunmaktadır. Buna göre örneğin “Protokol” paketinde yapılacak bir değişiklik bağımlılıklardan dolayı “GUI”,”Comm”,”Modem Control” ve “Comm Error” paketlerini de etkileyecektir. Bu bir döngüdür ve istenmeyen bir durum oluşturur. Bu durum hem değişikliklerden masum paketlerin de etkilenmesine yol açacak hem de değişikliğin daha yavaş olmasına yol açacaktır.(Örneğin derleme performansı düşecektir , test süresi uzayacaktır vb)

Döngünün kırılması :

Bu şekilde oluşan döngüleri kırmak için 2 yol vardır:

1.   Yeni bir paketin yaratılması. Bu durumda hem “GUI” paketinde bulunan “Comm Error” paketi için gerekli olan sınıflar ayrı bir pakete taşınmalıdır. Bu çözümün bir dezavantajı sistemde çok fazla paketin oluşabileceğidir.


2.   Bağımlılığın çevrimi prensibini (DIP) uygulayarak da döngüler kırılabilir. Aşağıdaki şekilde ilk durum iki paket arasında oluşan bir döngüyü ve bu döngüye yol açan sınıfları göstermektedir. Kısaca Y sınıfı üzerinden B sınıfına olan bağımlılık kaldırılmış , bunun yerine B sınıfının Y sınıfı için gerekli parçaları bir “BY” arabirimine konarak , Y sınıfının bağımlılığı bu ara birime kaydırılmıştır. B sınıfı ise bu arabirimi geliştirmek zorunda olduğundan bağımlılık tersine dönmüştür.





Durağan Bağımlılıklar Prensibi ( The Stable Dependencies Principle - SDP)


   Durağanlık yazılımda , değişiklik sıklığı ile ilgili bir kavramdır.Bir paket ne kadar az değişiklik görüyorsa o kadar durağandır demektir.Bu durağanlığı sağlıyan unsurlar içeriğin karmaşıklığı , büyüklüğü , sağlam yapılmış olması vb. sebepler olabilir .Ancak nesne yönelimli dizayn içerisinde paketin durağan olmasını gerektiren en önemli unsur pakete olan bağımlılık sayısıdır.Bir başka deyişle pakete ne kadar bağımlılık var ise paket o kadar durağan olmalıdır.



    Yukarıdaki örnekte görülen X paketine diğer üç paketten bağımlılık vardır.X paketinde yapılacak her değişiklik diğer paketleri de etkileyecektir.Bu yüzden X paketi durağan olmak zorundadır.Bu bağımlılıklardan dolayı X paketi diğer paketlerden sorumlu olarak da anılır.Aynı zamanda X paketinin başka bir yere bağımlılığı olmadığı ve başka yerlerden etkilenmiyeceği için bağımsız olarak da adlandırılır.

   Üstteki şekilde yer alan Y paketi bir önceki örneğin aksine durağan olmıyan bir görüntü sergilemektedir.Bu durumda Y paketi diğer paketlerden sorumlu olmıyan ve bağımlı olarak adlandırılır.
  SDP prensibi bize tüm yazılımın durağan olması gerektiğini söylememektedir.Aksine nesne yönelimli dizayn oldukça esnek ve değişikliklere açık olmalıdır.Ancak bu prensipten anlamamız gereken sistem içinde bağımlılığın fazla olduğu paketleri durağan ilan etmemiz ve öyle olması içinde gayret sarfetmemiz gerektiğidir.Bu durum dizayn sırasında durağan paketlerin dikkatli seçilmesi ve iyi dizayn edilmesini gerektirir.Aynı zamanda geliştirme esnasında da bu paketlere öncelik verilmesi ve bağımlı paketlerin öncesinde geliştirmenin de değişiklik gerektirmiyecek şekilde tamamlanması gerekir.


Durağan Soyutluk Prensibi ( Stable Abstractions Principle - SAP)

  
    Bu prensip bir önceki SDP prensibi ile yakın ilişkilidir.Kısaca durağan paketlerin soyut yapıda olmasını söyler.Bu prensibi OCP ve DIP prensiplerinin paket boyutunda uygulanması olarak adlandırabiliriz.
  Yukarıdaki örnekte durağan  bir paketin içeriğinin soyut yapılarak prensibin uygulanışı gösterilmiştir.Durağan paketin gerçekleştirimi bir başka pakette  yapılarak dizayn esnek bir hale getirilmiştir.



Diğer Dizayn Prensipleri

Kapsülleme Prensibi ( The Encapsulation Principle - EP )


   Nesne yönelimli yazılımda kapsulleme prensibi sınıfların dışarıya gereği kadar bilgi sunmasını , iç yapılarını dışarıya yansıtmamalarını söyler.Bu prensibin paketlere yansıtılmış hali bir paketin içindeki detayların dışa kapalı kalmasıdır. Buna göre bir paketin içindeki sınıflar ne kadar dışarıya kapalı ise kapsulleme o kadar fazladır.Bu prensibe göre paketin iç yapısının dışında dış kullanımda gerekli olmıyacak sınıflar dışarıya kapalı tutulmalıdır.


Sınırlı Boyut Prensibi ( The Limited Size Principle - LSP)


   Bu prensibe göre bir paketin içindeki alt paket ve üst seviye sınıf sayısı belli bir boyutu aşmamalıdır. Üst seviye sınıf kavramı yazılım içinde mimari açıdan önemli sayılan sınıfları ifade eder.Bir sınıfa uygulama içinden bağımlılık ne kadar fazla ise o sınıfın önem derecesi o kadar artacaktır.
   Paketlerin boyunun gereğinden fazla tutulması paketin sorumluluğunun artmasına ve bakımının gittikçe zorlaşmasına yol açacaktır.Paket üzerinde yapılan değişiklikler de buna paralel daha çok yeri etkileyecektir.İyi projelerde paket içeriğindeki alt paket ya da üst seviye sınıf sayısının 10-15 ‘i aşmamasına özen göstermek gerekir.


Kaynakça

 
  • Booch, G., Object Oriented Design with Applications, Redwood City, CA: Benjamin/Cummings, 1991.
  • Robert C. Martin ,”Design Principles and Design Patterns” , Object Mentor Inc.
  • Samudra Gupta , “Fine Tuning Abstraction” , http://javaboutique.internet.com
  • James Rumbaugh , “Object Oriented Modelling and Design “ , Prentice Hall-1991
  • Chidamber, S. R. & Kemerer, C. F., “A Metrics Suite for Object Oriented Design”, IEEE Transactions on Software Engineering, Vol. 20, #6, June 1994.
  • Martin Fowler , “Refactoring :Improving the design of existing code” , 1999

Yazılım Ölçümleme

   Bir önceki yazımda nesne yönelimli yazılımda dizayn prensiplerini işlemiştim.Okurların bu yazıda bahsedilen metriklerin nereden kaynaklandığını daha iyi algılamaları açısından, dizayn prensiplerine göz atmalarını öneririm.

   Yazılım ölçümlemede kullanılan metrikleri temel olarak iki kategoriye ayırabiliriz :

  • Ürün Kalitesi ile ilgili metrikler
    • Kalite , büyüklük , modulerlik vb
  • Süreç maliyet/kaynak planlaması ile ilgili metrikler
    • Efor , zaman cetveli , kaynak gereksinimi
   Bu yazıda nesne yönelimli yazılımda kalite  ölçümlemede  kullanılabilecek metrikler üzerinde durulmuştur.Yazıda nesne yönelimli programlaya özel yöntemlerin yanı sıra geleneksel yöntemlerden ; nesne yönelimli programlamaya aktarılan yöntemler de ele alınmıştır. Nesne yönelimli yazılımlara her ne kadar bir kısım geleneksel ölçme yöntemleri kullanılabilse de genel olarak kullanılabilen metrikler geleneksel yöntemlerden oldukça farklıdır.
  Yapılan araştırmalarda yazılım süreçlerinde bakım maliyetlerinin , geliştirme maliyetlerinin neredeyse iki katı olduğu gözlenmiştir.Bu bize kaliteli yazılım üretmenin zorluğunu göstermektedir.



    Yazılımın kalitesinin garanti altına alınması ve  iyileşme sağlanabilmesi , sürekli ölçümleme ve iyileştirme ile olabilir.Gerekli iyileştirmeler ölçümleme sonucu elde edilen bilgilere dayanılarak yapılabilir.Ölçümleme yapılmadan hazırlanan eylem planları kesinlikle gerekçesiz ve gelişigüzel olacaktır.



Geleneksel Metrikler

 
   Bu bölümde ele alınan metrikler geleneksel metriklerden nesne yönelimli yazılıma uyarlanabilecek olanlardır.

Kod  Büyüklüğü (Lines Of Code LOC)

  
   Geleneksel olarak yazılımın boyutu satır sayısı ile  ölçülür. Satır büyüklüğü çeşitli şekillerde ölçülür :
  • Satır Sayısı  ( Lines Of Code – LOC ) ölçümü programın tüm satırlarının sayılmasıdır.
  •  Yorum ve boşluk içermeyen (Non-comment Non-blank NCNB veya Source Lines Of Code SLOC )  programın yorum satırları ve boş satırlardan arındırılmış halidir.
  • Çalıştırılabilir yordam sayısı (Executable Statements EXEC) program içinde yer alan yordam sayısıdır.

Örneğin aşağıdaki kod :
IF X = 3
// Comment Line
Then
Y = 10
4 LOC , 3 NBC  ve 1 EXEC olarak sayılır

   Satır büyüklüğü pek çok dile uyarlanabildiği için oldukça kullanışlı ve ölçümü beklenen bir metriktir.Ancak satır büyüklüğü üzerine yorum yapmak için dilin karmaşıklığı , projenin karmaşıklığı gibi faktörler de göz önünde bulundurulmalıdır.Yazılım istatistiklerini biriktiren şirketler yeni projelerin faktörlerini göz önüne alarak , kestirimlerde bulunabilirler.

   Satır büyüklüğünün küçük olması yazılım için hedef olmalıdır.

Yorum Oranı (Comment Percentage - CP)


   Yorum oranı (Comment Percentage CP) programın için hazırlanmış yorum satırlarının (kod ile birlikte ya da dışarıda) , toplam programın yorum ve boşluk içermeyen satır sayısına (SLOC) bölümü ile bulunur.Yüksek yorum oranı programların anlaşılabiliğini arttıran ve bakımını kolaylaştıran bir faktördür.

   Yorum oranının %20 ila %30 arası olması tavsiye edilen bir durumdur.

Döngüsel Karmaşıklık (Cyclomatic Complexity -CC)

  
   Thomas J. McCABE  tarafından ortaya konan bu metrik bir methodun içindeki algoritmanın karmaşıklığını ölçmek için kullanılır.Aynı zamanda bir methodun test edilmesi için gerekli test durumu sayısını da verir.

    CC = yollar  – düğümler + 2 

şeklinde hesaplanır.Örneğin bir IF cümlesi iki seçeneğe sahiptir.Eğer şart doğru ise birinci yol test edilmiş olur , hatalı ise ikinci yol test edilir.Aşağıdaki şekilde hesaplanış ile ilgili örnekler verilmiştir.



Methodların düşük karmaşıklığa sahip olması tercih edilir.Bu kodun anlaşılırlığının ve test edilmesinin kolay olduğunu gösterir. Döngüsel karmaşıklık , nesne yönelimli yazılımda kalıtım ilişkisi yüzünden bir sınıfın karmaşıklığını ölçmek için kullanılamaz.Fakat methodların karmaşıklığının toplamı , sınıfın karmaşıklığı olarak kabul edilebilir.Bir method için karmaşıklığın 10’u aşmaması tercih edilmelidir.Ancak 20’ye kadar kabul edilebilir.Bunu aşan değerler anlaşılması oldukça güç kodları gösterir.

 



Nesne Yönelimli Metrikler


Sınıf Temelli Metrikler


   Nesne yönelimli programlamada temel birim sınıftır.Bu bölümde yer alan metrikler sınıf temelli metriklerdir.Sınıf ve onun temel elemanları üzerinden alınan metrikler ile tüm ürün kalitesi hakkında genel fikirler verir.

Sınıf Method Sayısı (Number Of Methods per Class -NOM)


   Sınıf başına düşen method sayısı sınıfın karmaşıklığı açısından bir göstergedir.Aynı zamanda fazla method sayısı arabirimin ayrılması prensibine ( the interface segregation principle ) aykırı durumların da habercisidir.

( Ortalama method sayısı = Toplam Method Sayısı / Toplam sınıf sayısı  formulü ile  ortalam method sayısı elde edilir.)

   NOM değerinin 20 ‘nin altında kalması tercih edilmelidir. 40’dan küçük değerler de kabul edilebilir sınırlar içindedir.Ancak bu değerler sınıfların constructor ,  destructor ve ayrıca mutator (getxxx , setxxx gibi) methodlarının dahil edilmiş hali olarak kabul edilmelidir.Bu tip methodlar ayıklanmış haldeyken sınıfın method sayısının 10’u geçmemesi tercih edilmelidir.

Büyük NOM değerleri anlaşılması , yeniden kullanımı ve bakımı güç sınıflara işaret eder.

Chidamber ve  Kemerer Metrikleri

1.    Sınıf Başına Ağırlıklı Method  (Weighted Methods per Class -WMC)


    Döngüsel  karmaşıklık değerleri toplamının sınıf sayısına bölümü ile bulunur.WMC değerinin 100’ün altında olması tercih edilmelidir.WMC sınıf karmaşıklığı hakkında fikir veren en önemli donelerden biridir.Bu metriğin faydaları sınıf başına ortalama method sayısı gibi değerlendirilebilir.WMC değerinin 100’ün altında olması kabul edilebilir bir değerdir. WMC değeri NOM’dan farklı olarak sınıfın karmaşıklığı hakkında daha net bir fikir verir.

Bu metrik üzerinden genel olarak elde edilebilecek fikirler şu şekilde sıralanabilir :
  • WMC sınıfın karmaşıklığı hakkında fikir verir ve harcanacak geliştirme ve bakım eforları için gösterge sayılabilir
  • Büyük sayıda method içeren sınıfların üzerinde yapılacak değişiklikler , sınıftan türiyen sınıflar üzerinde potensiyel etkiye sahiptir
  • Daha fazla method içeren sınıflar daha uygulamaya özel ve yeniden kullanımı zor sınıflar olarak görülürler

Ekli grafikte örnek bir WMC dağılımı verilmiştir.Bu grafik yardımıyla projenin toplam karmaşıklığı hakkında fikir edinilebilir.WMC değeri 100’ün üzerindeki sınıfların yeniden ele alınması faydalı olacağından bu sınıf sayıları tablodan kolaylıkla seçilmektedir.

 


2.    Kalıtım Ağacının Derinliği (Depth of Inheritance Tree - DIT)

  
   DIT metriği sınıfın ebeveyn sınıflarının sayısını gösterir.Eğer çoklu kalıtım durumu söz konusu ise bu durumda hiyerarşideki en uzun yol kabul edilir.



  Örneğin yukarıdaki şekilde yer alan D sınıfı için DIT değeri 2 olarak kabul edilir.DIT bize kısaca kaç tane ana sınıfın potensiyel olarak sınıfımızı etkileyebileceğini gösterir.

  • Sınıf hiyerarşisinin derinliği arttıkça daha fazla method kalıtım alınır ve sınıfın davranışlarını öngörmek ; anlamak zorlaşır.
  •  Derin hiyerarşiler daha fazla method ve sınıf etkilendiğinden , dizaynı karmaşıklaştırır
  •  Ancak hiyerarşi derinleştikçe kalıtım alınan methodların yeniden kullanım potensiyeli artar

    DIT metriğine destekleyici olarak sınıfın kalıtım aldığı method sayısı (number of methods inhertied NMI) da ölçülebilir.
   DIT için önerilen rakam genellikle 5’in altında olmasıdır. 5’in üzerindeki derinlikler oldukça karmaşık yapılar doğurabilir.DIT’in 0 olması sınıfın kök  olduğunu gösterir.DIT’in ortalam 2-3 arası bir değerde olması yeniden kullanımın iyi seviyede olduğunu gösterir.2’den küçük derinlikler ise yeniden kullanımın zayıf olduğu alanları işaret eder.

Ekli grafikte örnek bir DIT dağılımı gösterilmiştir.


3.    Alt Sınıf Sayısı ( Number of Children - NOC)


   NOC metriği sınıftan türemiş alt sınıflarının sayısını verir.

·       Alt sınıf sayısı çoğaldıkça kalıtım özelliğine bağlı olarak yeniden kullanımın arttığı anlaşılır
·       Alt sınıf sayısının çokluğu  sınıfın hatalı soyutlama yapıldığını , belki de hatalı bir hiyerarşi kurulduğunu gösterebilir.
·       NOC sınıfın nüfus alanı hakkında bir fikir verir.NOC metriği yüksek sınıflar gözden geçirme , test gibi süreçlerin daha dikkatli ve uzun tutulması gereken yerlerdir.

DIT ve NOC metriklerinin kendi içinde getiri ve götürüleri vardır.Yüksek DIT değerleri artan karmaşıklığı gösterirken aynı zamanda artan yeniden kullanıma da işaret eder.Aynı şekilde yüksek NOC değeri artan yeniden kullanıma işaret ederken daha fazla test eforu harcanması gerektiğini gösterir.Ekli şekilde DIT ve NOC metriklerinin bir arada dağılımları gösterilmiştir.Bu tablodan bazı garip durumlar saptanabilir.Örnek şekilde ağacın üçüncü seviyesinde ancak 40 alt sınıfa sahip bir sınıf göze çarpmaktadır.

4.    Nesneler Arası Eşleme (Coupling Between Object Classes - CBO)


  CBO değeri sınıfın kalıtım ilişkisi dışında diğer sınıflar ile kurduğu bağımlılık (eşleme) sayısını gösterir.Örneğin diğer bir sınıfın methodlarının kullanılması ya da diğer sınıfın bir nitelik olarak tanımlanması vb. CBO değeri eşleme yapılmış sınıf sayısını gösterir.Örneğin bir A sınıfı methodları içerisinde diğer B sınıfına dört şekilde mesaj gönderiyor olsun.Bu durumda A ile B sınıfı arasında yalnız bir eşleme vardır.Eşleme sayısı gönderilen mesaj sayısı ile ilgili değil kaç farklı sınıf ile haberleşildiği ile ilgilidir.

·       Sınıflar arası çok sayıda eşlemenin bulunması moduler dizaynı zedeler ve yeniden kullanımı engeller.Bağımsız sınıfların başka uygulamalar içinden yeniden kullanımı daha kolaydır.
·       Modulariteyi ve kapsullemeyi düzenlemek için eşlemeler minimum düzeyde tutulmalıdır.Eşleme sayısının yüksek olması sınıfın değişikliklere karşı daha hassas ve bakımının daha zor olmasına yol açar.
·       CBO değeri dizaynın çeşitli kısımlarında uygulanacak testin ne kadar karmaşık olacağı hakkında bir fikir verir.Yüksek değerler daha zor testlerin yapılacağının göstergesidir.

CBO değeri sınıfın bağımsızlığının göstergesidir.CBO ve DIT değerleri 0 olan sınıflar tamamen bağımsız olarak çalıştırılabilir sınıflardır.

CBO değerinin 5’i aşmaması genellikle tavsiye edilmektedir.Ekli şekil örnek bir CBO grafiğini göstermektedir.






5.    Sınıf Yanıt Sayısı (Response for a Class - RFC)


     RFC sınıfın içindeki method sayısı + methodlar tarafından çağırılan method sayısının  (her method sadece 1 kez sayılmak üzere) toplamıdır. Formulü :
   RFC = |RS|
   RS = { M }È all i { Ri }
( { Ri } = I methodu tarafından çağırılan unique method sayısı ve { M } = sınıfın methodları )

şeklinde ifade edilebilir.RFC sınıf tarafından bir mesaja cevap için potensiyel olarak çalıştırılacak method sayısını verir.Buna sınıf hiyerarşisi içerisinde erişilebilecek tüm methodlar dahildir.Bu metrik sınıfın method sayısı ile diğer sınıflarla kurulan iletişim sayısının toplamı gibi görülebilir.

RFC metriğinin sınıf başına 100’den aşağı olaması kabul edilebilir bir durum olsa da 50’yi aşan bir sınıf genellikle pek görülmez.

  • RFC değerinin yüksek olduğu sınıfların anlaşılması daha zor olacağından  için test ve debug eforları daha fazla olacaktır
  • RFC değeri yükseldikçe sınıfın karmaşıklığı artar
  • RFC değeri ayrılacak test zamanının hesaplanmasına yardımcı olabilir

Aşağıdaki grafikte sınıflara göre RFC dağılımını göstermektedir.

 



RFC / NOM değerinin C++ için 5’i Java için 10’u aşmaması tavsiye edilmektedir.Ekli grafikte bu kurala uyan ve uymayan sınıflar gösterilmeye çalışılmıştır.

RFC > 5 x NOM

6.    Uyumsuzluk (Lack of Cohesion - LCOM)

 

  Uyumluluk nesne yönelimli programlamada oldukça önemli bir kavramdır.Bir sınıf elemanlarının birlikteliğinin derecesini gösterir.İyi bir dizayn yüksek uyumlulukta sınıflar sunmalıdır.

   Uyumluluk bir sınıfın birden fazla  soyutlama yapmamasını gerektirir.Aksi durumda sınıfın başka sınıflara bölünmesi gereklidir.

   Chidamber ve Kemerer’a göre sınıfın aynı değişkenlerine erişen birden fazla method varsa sınıfta bir uyumluluktan bahsedilebilir. LCOM bir sınıfın içindeki hiçbir ortak alanı paylaşmayan method toplamından , en az bir ortak alanı paylaşan method toplamının farkı ile bulunur.Bulunan değer 0’dan küçükse 0 kabul edilir.

C1 sınıfının M1, M2..., Mn şeklinde n tane methodu olsun . {Ii}   kümesinin Mi sınıfının  kullandığı sınıf değişkenleri olduğunu farzedelim .Bu şekilde her method için bir küme olduğunu fazedelim.
P değeri   kesişimleri boş olan kümelerin sayısı ( P = { (Ii,Ij) | Ii Ç Ij = Æ } )  ve  Q’yu kesişimleri boş olmıyan kümelerin sayısı ( Q = { (Ii,Ij) | Ii Ç Ij _ Æ }) olarak kabul edelim.Eğer tüm küme kesişimleri boş ise P değerini 0 kabul edelim.
Bu durumda LCOM = |P| - |Q| olarak kabul edilir.Eğer sonuç negatif ise LCOM = 0 olarak kabul edilir.

Örneğin M1 , M2 ve M3 methodları bulunan bir sınıfı ele alalım. M1’in kullandığı sınıf değişkenleri kümesi {I1} =  {a,b,c,d,e} , M2 methodunun kümesi  {I2} = {a,b,e} ve M3 methodunun kümesi  {I3} = {x,y,z}olsun . Bu durumda {I1} Ç {I2} kesişimi boş olmıyan , ancak  {I1} Ç {I3} ve {I2} Ç {I3} boş kümeler verir.Bu durumda 

P = 2
Q = 1
ve LCOM = P – Q    = 1  olarak bulunur.


·       Methodların uyumsuzsuzluğu sınıfın iyi kapsulleme (encapsulation) sunamadığının göstergesidir
·        Uyumsuzluğu yüksek sınıfların iki ya da daha fazla alt sınıfa bölünmeleri gözden geçirilmelidir
·       Methodlar arası farklılık , sınıf dizaylarındaki çatlakların bulunmasında yardımcı olur
·       Uyumsuzluk karmaşıklığı arttırır ve geliştirme sırasında hata yapılma ihtimalini arttırır

LCOM değeri sınıfın method sayısına bağlı olarak değişir.LCOM değerinin alabileceği sınır değer sınıfın method sayısıdır.Ekli grafikte sınıfların LCOM / NOM değerlerine göre dağılımı gösterilmiştir.
 
 

Paket Temelli Metrikler


   Nesne yönelimli programlamada bir başka temel birim de paket kavramıdır.Sınıflar boşlukta yaşan kavramlar değildir.Her sınıf belli bir pakete üye olmak zorundadır.Paket kavramı sayesinde sistemin temel yapı taşları belirlenebilir , sistem yapılandırılabilir.Sınıflar paketlere gelişi güzel atılamazlar.Paketlemede nesne yönelimli dizayn prensipler sıkı sıkıya uyulması gereklidir.Bu bölümde ele alınan metrikler paket dizaynının kalitesini ölçmeye yönelik olarak hazırlanan metriklerdir.

Kararsızlık (Instability)

  
   Durağanlık yazılımda , değişiklik sıklığı ile ilgili bir kavramdır.Bir paket ne kadar az değişiklik görüyorsa o kadar durağandır demektir.Durağanlığı sağlıyan unsurlar içeriğin karmaşıklığı , büyüklüğü , sağlam yapılmış olması vb. sebepler olabilir .Ancak nesne yönelimli dizayn içerisinde paketin durağan olmasını gerektiren en önemli unsur pakete olan bağımlılık sayısıdır. Bir başka deyişle pakete ne kadar bağımlılık var ise paket o kadar durağan olmalıdır.
   Kararsızlık bir paketin ne kadar kararsız ya da durağan olduğunu gösteren metriktir.Şu şekilde formulize edilebilir :

Ca = İç Eşleme ( Afferent Couplings )
Ce = Dış Eşleme ( Efferent Couplings )

I Kararsızlık  (Instability) .    I  =  Ce / (Ca + Ce) 

İç Eşleme ( Afferent Couplings - Ca)  bir paket içindeki sınıflara bağlı olan paketin dışındaki sınıf sayısıdır.


Dış Eşleme ( Efferent Couplings - Ce)  , bir paket dışındaki Class ’lara bağlı olan paketin içindeki Class sayısıdır.




    Karasızlık metriği 0 ile 1 arası bir değer alır. 0 tamamen durağan bir paketi (ya da sınıfın)  gösterirken değer 1’e doğru yaklaştıkça paketin kararsızlığı artıyor demektir.

Soyutluk (Abstractness)


   Bu metrik ölçümü yapılan paketin ne kadar soyut bir yapıda olduğunu gösterir. Durağan soyutluk prensibi ( Stable Abstractions Principle - SAP) ile yakından ilişkilidir. Bu prensip durağan olması gereken paketlerin soyut yapıda olmasını söyler.Şu şekilde formulüze edilebilir :

Nc Paket içindeki sınıf sayısı.(Soyut sınıflar da dahil)
Na Paket içindeki soyut sınıf sayısı  (arayüzler , soyut sınıflar vb)
A Soyutluk (Abstractness.) :   A = Na / Nc
  
   Bu metrik de kararsızlık metriği gibi 0 ile 1 arası bir değer alır .0 tamamen somut bir paketi gösterirken 1’e doğru yaklaştıkça paketin soyutluğu artıyor demektir.

Kararsızlık – Soyutluk Grafiği

     Durağan Soyutluk Prensibine  ( Stable Abstractions Principle - SAP) göre bir paket ne kadar durağan ise o kadar soyut olmalıdır.Paketin kararsızlık ve soyutluk değerleri üzerinden bir grafik oluşturulduğunda bu prensip görsel bir şekilde anlaşılabilmektedir.SAP prensibine göre eğer bir paket durağan ise (karasızlık 0 durumu) soyutluk o kadar artmalıdır. (soyutluk 1 durumu) .



      Üstteki grafikte SAP prensibine göre olması gereken ana çizgi görülmektedir.Ana çizginin dışında kalan bölgede bulunan paketler sıkıntılara yol açacaktır.

Uzaklık Metriği


   Bu metrik , kararsızlık-soyutluk grafiğinde bahsedilen ana çizgiye göre paketin  uzaklığı belirler.

D’ Normalize Uzaklık (Normalized Distance)  D’ = | A+I –1|
     Bu metriğin 0 çıkması paketin direk ana çizgi üzerinde olduğunu gösterir.1 çizgiden mümkün olan en büyük uzaklıktır.Metriğin değeri 0-1 arasıdır.

D Uzaklık  (Distance)   D =  |A + I – 1|
                                             ----------------
                                                    Ö2
   Bu metrik 0 - ~0,707 arası bir değer üretir.



Doğrusal Bağımlılık Prensibi Metriği (The Acyclic Dependency Principle Metric - ADP/ADPR)


   Doğrusal bağımlılık prensibi paketler arasındaki ilişki yapısında çevrimlerin bulunmaması yani döngüsel bağımlılıklar olmamasını gerektiğini söyler.


    Bu metrik genel olarak bakılan paket ve alt paketleri ile birlik ADP prensibine olan uyumu yüzde cinsinden gösterir.

Ndp  Paketler arası toplam Bağımlılık Sayısı (alt paketler dahil)
Ndac Paketler arası toplam doğrusal bağımlılık sayısı (alt paketler dahil)

ADP = (Ndac / Ndp ) * 100

ADP’ye tam uyumluluk önemlidir.Dolayısıyla bu metriğin %100 çıkması gereklidir.

Bağımlılığın Çevrimi Prensibi Metriği (The Dependency Inversion Principle Metric - DIP)


  Soyut eşleme (abstract coupling) olarak da adlandırılan bu prensip kısaca bileşenler arası eşlemelerin (ya da bağımlılıkların) somut sınıflar üzerinden değil soyut sınıflar üzerinden yapılması gerektiğini söyler.   DIP bir sınıf dizayn prensibi olduğu halde paket yapısı ölçümlemelerinin içinde de bir metrik olarak kullanılabilir.Bu metrik % cinsinden alınır.

  Nddp   Paket içindeki sınıflar arası toplam bağımlılık sayısı (alt paketler dahil)
  Nddac Paket içindeki somut sınıflardan soyut sınıflara toplam bağımlılık sayısı (alt paketler dahil)

  DIP  = (Nddac / Nddp ) * 100

Normal şartlarda bu metriğin vereceği değerlerin yorumu , bakış açısına göre değişir.Ancak genel beklenti uygulama özel paketlerde değerin düşük çıkması daha altyapıya yönelik paketlerde ise değerin yüksek çıkmasıdır. Değerin %100 çıkması tüm bağımlılıkların soyut sınıflara doğru kurulduğunu gösterir.


Kapsulleme Prensibi Metriği ( The Encapsulation Principle Metric  - EP)

  
  İyi kurulmuş moduler bir yapıda ve kapsulleme prensibine uygun yapılarda paket içeriğinin gerçekleştirme detayları dış dünyaya kapalıdır.Bu metriğin yorumu incelenen pakete bağlı olsa da paketin kalitesi hakkında bir fikir verebilir.Metriğin değeri paketin kapsullenme derecesinin yüzde cinsinden ifadesidir.

Ncc Pakette Dışarıya kapalı sınıf sayısı
Nc  Paketteki toplam sınıf sayısı

EP =  ( Ncc / Nc ) * 100

   Bu metrik paket kalitesi hakkında yorum yapmak için kullanılabilir ancak olması gereken değeri üzerinde bir tavsiye verilemez.Paketin yapısına göre yorum yapılmalıdır.

Sınırlı Boyut Prensibi Metriği ( The Limited Size Principle Metric LSP )


   LSP prensibine göre bir paketin içindeki alt paket ve üst seviye sınıf sayısı belli bir boyutu aşmamalıdır.

Nmx Proje için belirlenmiş paket sınırı sayısı (genellikle 10-15 arası)
Ncp      Paket içindeki alt paket ve üst seviye sınıf sayısı
LSP =  (Ncp    / Nmx )  *  100
   Bu metriğin değerinin % 100 çıkması sınır değerine ulaşıldığını gösterir.100’ün üzerindeki değerler paket için aşırı yüklemeyi ifade eder.

Kaynakça



  • McCabe, T.J., "A Complexity Measure", IEEE Transactions on Software Engineering, vol. SE-2, pp. 308-320, 1976.
  • Booch, G., Object Oriented Design with Applications, Redwood City, CA: Benjamin/Cummings, 1991.
  • Karl E. Wiegers  , “A Software Metrics Primer”  Software Development Magazine , July 1999
  • Dr. Linda H. Rosenberg , “Applying and Interpreting Object Oriented Metrics “ , Software Assurance Technology Center (SATC) at NASA
  • Software Quality Metrics for Object Oriented System Environments “ , Software Assurance Technology Center (SATC) at NASA , SATC-TR-95-1001
  • San Diego State University  “Metrics “  Lesson Notes
  • Edward V. Berard  , “Metrics for Object-Oriented Software Engineering “ , The Object Agency  Inc. Web Site
  • Edwin Hautus ,” Improving  Java Software Through  Package Structure Analysis “ , Compuware Europe