24 Ocak 2013 Perşembe

Kodun tekrar kullanılabilirliği (Code Reusability)

Giriş
Tekrar kullanılabilir kod yazmanın özü harcadığınız eforu çoğaltmak yerine ondan kaçınmanızdan geçer. Sıfırdan bileşenler yazmak yerine , bir programcı var olan kod parçasını düzenleyerek kendisine uyarlamalıdır. Tekrar kullanılabilir kod gözle görülür bir oranda performans artışı getirecektir. Böylece kullanılabilirliğin tanımı iki veya daha fazla program arasında harcanılan eforu azaltmamızda saklıdır.

Tekrar kullanılabilirliğin çeşitleri 

Motivasyon ve yürütme ile ilgili kavramlarda tekrar kullanılabilirlik:

Fırsatçılık: Projeye başlamaya hazır olduğunuzda; ekip arkadaşınız tekrar kullanabileceği bir kod parcasının olduğunun farkına varmalıdır.

Planlama: Stratejik olarak bir ekibin ilerideki projeler için tekrar kullanabileceği bir component tasarlaması.

Fırsatları değerlendirmek açısından yeniden kullanılabilirlik:

Dahili yeniden kullanım: Ekibiniz kendi componentlerini kullanır. Ekip olarak proje için kritik bir bileşeni kontrol etmek isteyebilirsiniz çünkü bu siz ve ekibiniz için bir şirket kararı olabilir.

Harici yeniden kullanım:  Ekibiniz third-party component lisansını tercih edebilir. Third-party componentini lisanslama tipik bir şekilde ekibin geliştirmek için mal olacağı fiyatın yüzde 1 ile 20 arasında bir tutara mal olur. Ebiniz tabikide componenti bulmak, öğrenmek ve uygulamanıza entegre edebilmek için geçecek zamanı göze alıp karar vermelidir.

Form veya yeniden kullanım yapısı ile ilgili olarak kod yapısı:

Referanslı: İstemci kodu yeniden kullanılabilir kod ile ilgili bir referans içerir. Böylece farklı yaşam döngüsü ve versiyonlara sahip olabilir.

Çatallı:  İstemci kodu, tekrar kullanılabilir kodun özel veya yerel bir kopyasını içerir. Böylelikle tek bir yaşam döngüsü ve versiyonu paylaşırlar.

---------------------------------------------------------------------------------------------------------------------------------
Tekrar kullanılabilir kod biraz farklı amaçlara hizmet edebilir. Burada zaman temel kavramdır dolayısıyla program için de bu söz konusudur. Yine eforumuzu arttırmaktan kaçarsak, benzer durumda yazdığımız programlarda ciddi bir gelişme olacaktır. 


Programlamada verimliliğinin sırrının kodun tekrar kullanılabilir olmasından doğduğunu düşünüyorum. Bunun için karşıma çıkan sonuç kütüphane kavramıydı. C' de yazarken Standard C Library 'deki çoğu fonksiyonu farklı şekillerde birleştirerek çeşitli işlevleri yerine getiren programlar yazmamız isteniyordu. Tabiki derslerde söylenenlerde de fonksiyonlar oluşturarak bu tarz kütüphaneler' ler oluşturabileceğimizdi. Herkesin ortak kullanacağı fonksiyonları zaten bir kütüphane olarak toplamışlar ve bize düşen ise yazdığımız kodları fonksiyonlara ayırarak onları daha sonra tekrar tekrar kullanabilmemiz olduğunu düşünüyorum. Bu noktada isterseniz kendi kütüphaneniz olarak ta düşünebilirsiniz, önemli olan ayrılan fonksiyonların ileride bir işimize yardımcı olabilmesi. 

Tekrar kullanılabilir kodlar yazmak sadece programlamada bir kodu tekrar icat etmeden yazabilmenin bir parçasıdır ve kritik bir noktaya da değinmek istiyorum: varolan kodu tekrar kullanmaya cesaret ettiren ve ilişkili kod bölümlerini bulan en etkili araçlar, eğer kod bölümleri çok özel durumlar dışında tekrar kullanılabilir olarak yazılmamışsa geçersiz kalacaktır.

Kodları tekrar yazmak beraberinde birçok negatif sonucu da getirebilmektedir. İkinci kez yazışınızda hata yapma oranınız bulunur .....




Daima kod yazarken aklımıza bir fikir gelmesi gerekiyor, o da "Acaba bunu daha sonra kullanabilir miyim ?" sorusudur. Eğer cevabınız "evet" veya "olabilir" ise hemen fonksiyona çevirip ait olduğu dosya grubuna eklemeliyiz. 

Peki ait olduğu grup derken neyi kastediyorum ? Oluşturduğunuz fonksiyonlar en başlarda birbirlerinden bağımsız bir şekilde görünmektedir (açıkçası başlarda benim için böyleydi) daha sonra elinizdeki fonksiyonlar arttıkça birbirleriyle arasında bir ilişkisinin olduğu kanısına vardıkÖrnek olarak: Sıralama Algoritmaları (Sorting Algorithms) aslında az önce anlattığım gibi bir grubu ifade ediyor ve sıralama işlevini yapan çeşitli fonksiyonları kapsıyor. Bizler de yazdığımız çeşitli algoritmada gruplama yaptığımız zaman onları tekrar yazma zahmetine girmemiş oluyoruz. Buna harcayacağımız zamanı fonksiyonlarımızı alıp birleştirmeye verdiğimizde programımızı hızlıca ve sistemli bir şekilde ortaya çıkarabiliriz.




Bunun yanında Fonksiyon Oluşturma' da dikkat edilmesi gereken noktalar bulunuyor. Bulabildiklerimi ve benim yaşadığım hatalardan aldığım dersleri sizlerle paylaşacağım.

İlk olarak yukarıda da bahsettiğim gibi "Acaba bunu daha sonra kullanabilir miyim ?" sorusu geliyor. Daha sonra bu soru olumlu bir cevapla bitiyorsa gerekli kısmı fonksiyona dönüştürmeliyiz. Bunu yaparken de ilk hedefimiz bu kod parçasını ilerde tekrar tekrar kullanmak olmalı. Yani büyük bir kısım kodu seçersiniz ama ileride kullanamazsınız bu da hiçbir işimize yaramaz. Burada fonksiyonu oluştururken dikkat edilmesi gereken ve genel olarak kullanılan birkaç kural var:


  1. Fonksiyon en çok 30 - 35 satırdan oluşmalı. Bir kişi ekrana baktığında tüm kodu ekrana sığmış bir halde görebilmeli.
  2. Fonksiyonda argüman olarak kullanılan değişkenler 3'ü geçmemeli.
  3. Fonksiyona anlaşılması zor olacak yerlere gerekli açıklamalar eklenmeli.
  4. Fonksiyonu oluşturduktan sonra test etmelisiniz.
Test etme aşamasında ise yazdığınız kod parçasının çalıştığından emin olup onu tekrar kullabilmeniz içindir. Burada kod parçasını tes etmeniz için farklı test adında bir header oluşturulur. C için bahsetmeh gerekirse test.h oluşturulur ve kod parçası bağımsız bir şekilde test edilir. 

İlk duyduğum zaman ben çok şaşırmıştım ama bu ortalama değerler gerçekten işlerinize çok yardımcı oluyor. Fonksiyonunuzu ne kadar çok kullanılırsanız işiniz o kadar kolaylaşıyor.

Kaynaklar:

  1. http://www.labri.fr/perso/casteran/distribC/reuse.pdf
  2. http://link.springer.com/chapter/10.1007/978-3-642-31063-8_8
  3. http://www.mcs.vuw.ac.nz/comp/Publications/archive/CS-TR-93/CS-TR-93-12.pdf
  4. http://hoskinator.blogspot.com/2006/06/10-tips-on-writing-reusable-code.html
  5. http://asg.unige.ch/site/papers/Dami91a.pdf
  6. http://en.wikipedia.org/wiki/Code_reuse
  7. http://en.wikipedia.org/wiki/Separation_of_concerns
  8. http://www.cs.toronto.edu/~yijun/ece450h/handouts/lecture8x4.pdf
  9. https://docs.google.com/viewer?a=v&q=cache:uubjrGeL7xwJ:citeseerx.ist.psu.edu/viewdoc/download%3Fdoi%3D10.1.1.83.7716%26rep%3Drep1%26type%3Dpdf+&hl=tr&gl=tr&pid=bl&srcid=ADGEESgy42vY1Wd2RpfyPrDux0cljsae6352LLFurVxjZ4jfzVuqtLR6399kyDFIu9AYXgtO8wcKUav0xZBfDYecvlcja7J_QLetk7xmxv3NYdOuBRh6e31Tw2r9O-oaAT7K31iEc3f2&sig=AHIEtbRn01c5aPmdNFSCh4aSPragNS-aew
  10. http://www.cs.toronto.edu/pub/eric/CAiSE05.pdf







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

    21 Ocak 2013 Pazartesi

    Kodlarda Okunabilirlik ve Anlaşılabilirlik

    Özet
    Bu yazıda benim sıklıkla karşılaştığım bir problem üzerinde hem sizleri bilgilendirmek hem de kendim için birçok kaynaktan topladığım ve daha sonra bakabileceğim bir açıklama oluşturmaya çalıştım. Faydalı olması dileğiyle...

    İlk olarak bu konuyu niçin araştırdığımı yazmak istiyorum. Üniversiteye başladıktan sonra okulda bize öğretilen teknikleri birleştirerek çeşitli yeteneklere sahip programlar ortaya çıkarmamız isteniyor. Bildiğiniz üzere bilgisayar aleminde her geçen gün farklı birçok yeniliklerle karşılaşıyoruz. Buda bize ileride yazacağımız programları nasıl yazacağımızı bilmemizi gerektiriyor. Bu nedenle sonuç odaklı çalışmayıp, programın çalışması kadar ileride güncellenip yeni özelliklere sahip olmasının gerektiğine de dikkat etmemiz gerekiyor.