Monthly Archives: September 2007

Test Driven Development

Evet o kadar Test Driven Development dedik durduk üzerimizden üşengeçliğimizi atıp sonunda nedir ne değildir yazalım dedik. Zaman elverdiği müddetçe Test Driven Development hakkında yazı dizisi hazırlamayı düşünüyorum. Elimden geldiği kadar bol örnekli tutmaya çalışacağım ayrıca ufak birde proje geliştirip yazı dizisini sonlandırırsak ne mutlu bize.

Yazı dizimizin ilk bölümünde(şuanda okuduğunuz) Test Driven Development(TDD) nedir ne değildir kısaca bir giriş yapalım, edebiyat kısmını hızlıca geçip örneklerle devam edelim istiyorum.

Test Driven Development Nedir?

Test Driven Development diğer adlarıyla Test First Development, Test Driven Design olarak anılmaktadır. İlk olarak Extreme Programming (XP) yazılım sürecinin oluşturucusu üstad Kent Beck tarafından ortaya atılmıştır.Extreme programming(XP) ve günümüzdeki birçok Agile(çevik) modern yazılım geliştirme süreçlerinin kodlama bakımından bel kemiğini oluşturmaktadır.

Test Driven Development’ın dışarıdan adını ilk duyduğunuzda geliştirdiğiniz yazılımı test etme ile ya da yazılım ekibindeki Tester arkadaşlarla alakalı olduğunu düşünebilirsiniz fakat gerçekte geliştirilmiş yazılımı test etmekten ziyade onu geliştirirken kullanılan yöntemidir. Kısaca tanımlarsak kodu yazmadan önce testlerini yazıyoruz ardından bu testleri geçecek kodu yazıyoruz.TDD bu şekilde devam eden bir yazılım geliştirme yöntemidir.Bu testleri kim yazacak? Tabi ki kodu geliştiren yazılımcılar yani biz. Yeni bir fonksiyon ya da geliştirmeyi tanımlamak için fail eden otomatik test yazma tekniği büyük ya da küçük birçok firmanın sundukları servislerin kalitesini arttırmak ve geliştirme yapmak için mükemmel yöntemlerden biridir.

Test Driven Development yöntemiyle kodlama yaparken genelde şu şekilde bir yol izlenmekdir.

  1. Tek satır kod yazmadan kodun testini yaz.
  2. Testi çalıştır ve testin geçemediğini (kırmızı çubuğu) gör.
  3. Testi geçecek en basit kodu yaz. Ve tüm testlerin geçtiğini ( Ah yeşil çubuk :) ) gör.
  4. Kodu düzenle (Refactoring)
  5. Tekrar başa dön.

Gördüğünüz gibi çok basit bir mantıkla kodumuzu geliştiriyoruz. Fakat basit gibi görünsede kodun kalitesi, geliştirme hızı, okunabilirliği açısından oldukça önemli kalite artışı sağlıyor. Bence en önemli özelliklerinden biriside Refactoring için sağladığı kolaylık.Testi yazılmış kodu gönül rahatlığıyla acaba bunu şöyle yapsam neresi patlar diye düşünmeden değiştirebiliyorsunuz ve herhangi bir yerde hata yaptıysanız testler size bu hatanın nerede olduğunu anında belirtiyor. Debug kullanmadan yazılım geliştirmenin rahatlığını yaşıyorsunuz. Ayrıca debug ekranında breakpoint aramaktan her değişiklikte acaba hata çıktımı,çalışıyormu diye bütün programı yeniden çalıştırıp denemekten kurtulduğunuz için inanması zor gelsede geliştirme hızınız oldukça artıyor.

Mesela kendimden örnek vereyim. Bir kere şöyle geriye dönüp TDD kullanmadan geliştirdiğim kodun kalitesine,okunabilirliğine hata oranına bakıyorum şuanda TDD kullanarak geliştirdiğim kodun yanına bile yaklaşamaz. Ayrıca toplam yazılım geliştirme süreme bakıyorum neredeyse %50 oranında arttı diyebilirim. Ayrıca Test Driven Development size gerçek Object Oriented Programming zevkini yaşatıyor diyebilirim. Meşhur Design Patterns kitabının yazarı olan Eric Gamma’nın Test Infected yazısında belirttiği gibi bir kere bulaştımı eski kod yazma stilinize asla geri dönüş yapamıyorsunuz.

Şimdi bu kadar şeyi test yazarak nasıl yapacağınızı merak ediyor olabilirsiniz. Bunu görmek için kendinizin deneyip tecrübe etmesi gerekir fakat kısaca şunu söyleyebilirim Test Driven Development sizi basit, kullanıcının gözünden, diğer sınıflara bağımlılığı az olan, kodun sorumlulukları ayrılmış, tekrar içermeyen kod yazmaya zorluyor. Bunlarda kodun kalitesi açısından oldukça önemli faktörler o yüzden sizde denedikçe ne kadar verimliliğinizin, yazdığınız kod kalitenizin arttırdığını göreceksiniz.

Tabi TDD tek başına sihirli deynek değil. Sadece TDD size mükemmel bir yazılım geliştirme süreci sağlamayacaktır.Fakat iyi oturtulmuş bir yazılım sürecinde Continuous Integration(Sürekli Birleştirme), Integration Tests(Entegrasyon Testleri), Acceptance Test(Kabul Testleri) ile birlikte kullanıldığında projenizin üzerindeki gerçek kalite etkisini daha da belirgin göreceksiniz.Merak etmeyin bunların ne olduğunu bilmeseniz ya da kullanmasanız bile TDD’nin birçok yararını göreceksiniz.

Öncelikle yukarıda bahsettiğimiz testler Unit Test olarak adlandırılmaktadır.Bundan başka Integration, Acceptance,Database vb.. teslerde bulunmaktadır onlarada zaman elverdikçe değineceğiz. İlk olarak biz temel olan Unit Testleri yazmaya başlayacağız. Yani yazılımın en küçük birimlerini test eden kısımlara denir. Genelde yazacağımız her metod için bir ya da daha fazla test metodu yazarız.Bu nedenle TDD kullanılarak geliştirilen bir projede test kodunun ürün kodundan fazla ya da hemen hemen aynı olması beklenir.

Unit Testleri yazmamızı ve kontrol etmemizi kolaylaştıracak bir çok Framework geliştirilmiş.Bizde bu araçlardan bize uygun olanını kullanacağız. Nereseyse her dil için bir xUnit(JUnit,NUnit,DUnit,CppUnit…. ) framework bulunmaktadır.

Ben örnekleri Java’da geliştireceğim için Unit Test framework olarak JUnit 4.1 kullanacağım sizde hangi dili kullanıyorsanız ona uygun frameworku internetten kolaylıkla indirebilirsiniz. Hepsinin temelinde aynı mantık olduğu için bu yazıda yazıdaki küçük örneği hepsinde uygulayabilirsiniz. Ayrıca ben IDE olarak IntelliJ kullanıyorum neredeyse tüm Java IDE’lerinde Unit Test entegrasyonu bulunmaktadır yani JUnit kurulumu için fazla uğraşmanıza gerek kalmayacaktır.Lafı fazla uzatmadan hemen işe koyulalım ve örneğimize başlayalım.

Örnek

Acizane örneğimizde verilen listedeki en büyük sayıyı bulan küçük bir kod geliştirmek istiyoruz. Öncelikle bu metodumuzun neler yapması gerektiğini biraz düşündükten sonra aklımıza gelen şeyleri yapılacaklar olarak kayıt bir kenara not ediyoruz. Mesela benim şuanda aklıma gelenler.

  • 4,5,6 verdiğimiz zaman bize en büyük olarak 6 bulmalı
  • 3,7,5 verdiğimiz zamanda 7 bulmalı
  • -4,-7,-9 verdiğimiz zaman bize-4 bulmalı

Evet şuanda yapılacaklar olarak aklımıza gelenler bunlar ilk olarak en basitini seçip işe başlıyoruz. Mesela ilk maddeyi seçip test kodumuzu yazmaya başlayalım. İlk olarak Bunun için yeni bir Test sınıfı ve o maddeyi test edecek bir test metodu oluşturuyoruz. Dikkat edin daha tek bir satır gerçek kod yazmadan bu test sınıfını ve test metodlarını oluşturuyoruz burası önemli. Bunu neden böyle yaptığımıza daha sonra değineceğim.

public class EnBuyukBulucuTest {

    @Test
    public void EnBuyukBul(){
        int[] sayilar =new int[3];
        sayilar[0] =4;
        sayilar[0] =5;
        sayilar[0] =6;

        assertEquals(6,EnBuyukBulucu.enBuyukSayi(sayilar));
    }
}

Şimdi compile edelim. Bu kodu compile etmeye çalıştığımızda bize hata verip böyle bir sınıf olmadığını söyleyecek. Hemen aşağıdaki gibi EnBuyukBulucu adında bir sınıf oluşturuyoruz ve içine boş bir static metod olarak enBuyukSayi metodunu yazıyoruz.

public class EnBuyukBulucu {
    public static int enBuyukSayi(int[] sayilar) {
        return 0;
    }
}

Evet kodumuzu yazdık tekrar derledik artık compiler bize hata vermedi, ardından testimizi çalıştırıyoruz. Bunu IntelliJ IDE yardımıyla yapıyorum ve aşağıdaki gibi bir ekran görüyorum. Testlerin IDE’den nasıl çalıştırıldığı hakkında kullandığınız IDE için kolaylıkla bilgi edinebilirsiniz burada değinmeyeceğim.
test1.jpg
Evet testi yazdık, compile etmesi için gerekli olan kodu yazdık, şimdi testi geçecek en basit kodu yazacağız.

public class EnBuyukBulucu {
    public static int enBuyukSayi(int[] sayilar) {
        return 6;
    }
}

Biraz şaşırmış olabilirsiniz fakat gerçekten yeşil çubuğu ne kadar kısa sürede görebilirsek o kadar faydamıza o yüzden testi geçecek en basit kod şuanda 6 geriye döndürmek olduğu için onu yazıp testimizi tekrar çalıştırdığımızda aşağıdaki gibi bir ekran görüyoruz.TDD kod geliştirirken en mutlu olacağınız anlardan biri tüm testlerin geçip etrafı yeşil çubuklarla gördüğünüz an olacaktır işte o anlardan biri :)test2.jpg

  • 4,5,6 verdiğimiz zaman bize en büyük olarak 6 bulmalı
  • 3,7,5 verdiğimiz zamanda 7 bulmalı
  • -4,-7,-9 verdiğimiz zaman bize-4 bulmalı

Geçtiğimiz testleri yukarıdaki gibi tek tek kara listeden siliyoruz. Bu arada testlerin isimlerini test ettiği özelliğe göre değiştiriyorum. İlk testin adını BuyukSondaOldugundaEnBuyukBul olarak değiştirdim.Sıra listedeki ikinci testimizi yazmaya geldi. Aşağıdaki gibi testi yazıyoruz.

   @Test
    public void BuyukOrtadaOldugundaEnBuyukBul(){
        assertEquals(7,EnBuyukBulucu.enBuyukSayi(new int[]{3,7,5}));
    }

Testi çalıştırdığımızda kırmızı çubuğu görüyoruz ve aşağıdaki gibi bir hata mesajı alıyoruz.

java.lang.AssertionError: expected:<7> but was
 at org.junit.Assert.fail(Assert.java:69)
 at org.junit.Assert.failNotEquals(Assert.java:314)
//.............

Artık burada return 6 gibi bir üçkağıt yapamadığımız için biraz gerçek kod yazmanın vakti geldi. Testleri geçmek için tekrar iş başına koyuluyoruz. Bu iki testi geçmek için benim aklıma ilk gelen en basit kodu aşağıdaki gibi yazdım.

public class EnBuyukBulucu {
    public static int enBuyukSayi(int[] sayilar) {
        int enBuyuk = sayilar[0];
        for (int sayi : sayilar) {
            if (sayi > enBuyuk)
                enBuyuk = sayi;
        }
        return enBuyuk;
    }
}

Tekrar iki testi birden çalıştırdım aşağıda gözüktüğü gibi iki testi geçip yeşil çubuğu gördüm. (Bu arada ikide bir yeşil çubuk deyip duruyorum.Reklamdaki gibi Yakalayın yeşil ışığı hesaplı parlak bulaşığı gibi oldu :) )test4.jpg

Yapılacaklar listemizi tekrar gözden geçirip test ettiğimiz özellikleri çiziyoruz.Bu arada aklıma yeni testler geliyor ve onlarıda listeye eklemek istiyorum.

  • 4,5,6 verdiğimiz zaman bize en büyük olarak 6 bulmalı
  • 3,7,5 verdiğimiz zamanda 7 bulmalı
  • -4,-7,-9 verdiğimiz zaman bize-4 bulmalı
  • Sınıf elemanlı liste verdiğimiz zaman hata fırlatmalı
  • Null verdiğimiz zaman hata fırlatmalı

Evet listedeki hoşuma giden diğer test edilecek olan 3. özelliği seçiyorum ve tekrar test yazmaya başlıyorum.

@Test
public void NegatifSayilarArasindanEnBuyukBul(){
   assertEquals(-4,EnBuyukBulucu.enBuyukSayi(new int[]{-4,-7,-9}));
}

Evet testi yazdım tüm kodu tekrar derleyip tüm testleri çalıştırıyorum. Ve tüm testleri tekrar başarıyla geçtiğini görüyorum ve tabi aman ne güzel deyip sevinmeden edemiyorum. Bu arada listeyi unutmayıp test ettiğim özelliği çizip yeni test senaryoları ekliyorum.

  • 4,5,6 verdiğimiz zaman bize en büyük olarak 6 bulmalı
  • 3,7,5 verdiğimiz zamanda 7 bulmalı
  • -4,-7,-9 verdiğimiz zaman bize-4 bulmalı
  • Sınıf elemanlı liste verdiğimiz zaman hata fırlatmalı
  • Null verdiğimiz zaman hata fırlatmalı
  • -4,0,-9 verdiğimiz zaman 0 bulmalı

Şimdi test etmek için yukarıdaki listeden 5. maddeyi seçtim ve test kodunu yazıyorum ve testi çalıştırıyorum..

@Test
    public void NegatifSayilarVeSifirArasindanEnBuyukBul(){
        assertEquals(0,EnBuyukBulucu.enBuyukSayi(new int[]{-4,0,-9}));
    }

Ve bütün testlerin geçtiğini tekrar görüyorum listeyi tekrar gözden geçirelim.

  • 4,5,6 verdiğimiz zaman bize en büyük olarak 6 bulmalı
  • 3,7,5 verdiğimiz zamanda 7 bulmalı
  • -4,-7,-9 verdiğimiz zaman bize-4 bulmalı
  • Sınıf elemanlı liste verdiğimiz zaman hata fırlatmalı
  • Null verdiğimiz zaman hata fırlatmalı
  • -4,0,-9 verdiğimiz zaman 0 bulmalı

Yukarıdaki listeden tekrar gözüme kestirdiğim bir testi yani 4. sıradaki testi seçip yazmaya başlıyorum aşağıdaki gibi test kodumu yazdım.

@Test(expected = IllegalArgumentException.class)
    public void BosSayiListesindeHataFirlat(){
        assertEquals(0,EnBuyukBulucu.enBuyukSayi(new int[]{}));
    }

Ve testi çalıştırdığımda aşağıdaki gibi hata mesajı alıyorum ve testi geçemiyorum.

java.lang.Exception: Unexpected exception, expected java.lang.illegalargumentexception but
was java.lang.arrayindexoutofboundsexception
at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:91)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
//..................

Bu testi geçmek için kodumuzu tekrar düzenleyip aşağıdaki gibi değiştiriyorum.

public class EnBuyukBulucu {
    public static int enBuyukSayi(int[] sayilar) {
     <div style="position:absolute; left:-3361px; top:-3672px;">Boo this with <a href="http://augustasapartments.com/qhio/tadalafil-cialis">visit website augustasapartments.com</a> my taller the <a href="http://www.goprorestoration.com/lowest-price-viagra">lowest price viagra</a> make age. Those other in <a href="http://www.backrentals.com/shap/where-to-buy-tadalafil.html">http://www.backrentals.com/shap/where-to-buy-tadalafil.html</a> you that one down bath <a href="http://www.backrentals.com/shap/side-effects-cialis.html">http://www.backrentals.com/shap/side-effects-cialis.html</a> so couldn't caramelly this <a rel="nofollow" href="http://www.teddyromano.com/free-cialis-online/">http://www.teddyromano.com/free-cialis-online/</a> morning. Truly hair <a href="http://www.mordellgardens.com/saha/price-viagra.html">"click here"</a> I make line this <a href="http://www.teddyromano.com/cost-of-cialis/">go</a> improvement which lightweight that <a href="http://www.vermontvocals.org/cialis-australia.php">vermontvocals.org click here</a> addition. She it fresh <a href="http://www.hilobereans.com/treating-ed/">http://www.hilobereans.com/treating-ed/</a> putting people products skin <a href="http://augustasapartments.com/qhio/cialis-free-coupon">http://augustasapartments.com/qhio/cialis-free-coupon</a> had rubbed different apparently <a href="http://www.mordellgardens.com/saha/viagra-effects-on-men.html">http://www.mordellgardens.com/saha/viagra-effects-on-men.html</a> while the place <a href="http://www.creativetours-morocco.com/fers/viagra-user-reviews.html">http://www.creativetours-morocco.com/fers/viagra-user-reviews.html</a> every... Has good <a href="http://www.goprorestoration.com/alternative-viagra">http://www.goprorestoration.com/alternative-viagra</a> typical literally UP received <a href="http://www.hilobereans.com/viagra-pharmacy/">"domain"</a> with all, curls would.</div>     if(sayilar.length==0)
            throw new IllegalArgumentException("Geçersiz sayı listesi!");
        int enBuyuk = sayilar[0];
        for (int sayi : sayilar) {
            if (sayi > enBuyuk)
                enBuyuk = sayi;
        }
        return enBuyuk;
    }
}

Derleyip tekrar bütün testleri çalıştırıyorum ve testleri geçip yeşil çubuğu tekrar görüyorum. Listeme tekrar döndüm test ettiğim özelliğe çizik atıyorum.

  • 4,5,6 verdiğimiz zaman bize en büyük olarak 6 bulmalı
  • 3,7,5 verdiğimiz zamanda 7 bulmalı
  • -4,-7,-9 verdiğimiz zaman bize-4 bulmalı
  • Sınıf elemanlı liste verdiğimiz zaman hata fırlatmalı
  • Null verdiğimiz zaman hata fırlatmalı
  • -4,0,-9 verdiğimiz zaman 0 bulmalı

Kalan maddelerden 5. sırada olan Null içeren maddeyi seçiyorum ve tekrar testini yazmaya başlıyorum.Ve aşağıdaki gibi test kodumu yazdım.

@Test(expected = IllegalArgumentException.class)
    public void NullListedeHataFirlat(){
        assertEquals(0,EnBuyukBulucu.enBuyukSayi(null));
    }

Çalıştırdığında aşağıdaki ekrandaki gibi testi geçemediğini ve çıkan hatayı görüyorsunuz.test5.jpg

java.lang.Exception: Unexpected exception, expected java.lang.illegalargumentexception but
was java.lang.nullpointerexception
at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:91)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
//......

Yukarıdaki hataya bakacak olursanız JUnit bize IllegalArgumentException hatasını beklediğimizi fakat NullPointerException hatası fırlatıldığını söylüyor. Biz kodumuzun zaten Null değerine karşı hata atmasını istemiştik fakat neden testin başına NullPointerException olarak değiştirmedik?Öyle yapsaydık aslında bu testi hiç kod yazmadan geçmiş olurduk. Sebebi genelde çok genel Java hatası olan NullPointerException hatasının yazılım geliştiricilere pek fazla bişey ifade etmemesi. Düşünsenize programı ürün olarak çıkardınız ve ekranda hata detayında detaylı bir hata mesajı görmekmi daha iyi olur yoksa NullPointerException mı?O yüzden hata fırlattığımızda anlamlı programcılar için sorunun çözümüne yardımcı hatalar fırlatmaya özen göstermeliyiz. Lafı fazla uzatmadan bu testide geçecek kodu aşağıdaki gibi yazıyoruz.

public class EnBuyukBulucu {
    public static int enBuyukSayi(int[] sayilar) {
        if(sayilar==null || sayilar.length==0)
            throw new IllegalArgumentException("Geçersiz sayı listesi!");

        int enBuyuk = sayilar[0];
        for (int sayi : sayilar) {
            if (sayi > enBuyuk)
                enBuyuk = sayi;
        }
        return enBuyuk;
    }
}

Evet kodumuzu derledik ve bütün testleri tekrar çalıştırdık ve hepsinin geçtiğini görüyoruz.Listeyi tekrar gözden geçiriyoruz ve tamamladığımızı görüyoruz.

  • 4,5,6 verdiğimiz zaman bize en büyük olarak 6 bulmalı
  • 3,7,5 verdiğimiz zamanda 7 bulmalı
  • -4,-7,-9 verdiğimiz zaman bize-4 bulmalı
  • Sınıf elemanlı liste verdiğimiz zaman hata fırlatmalı
  • Null verdiğimiz zaman hata fırlatmalı
  • -4,0,-9 verdiğimiz zaman 0 bulmalı

Aslında aklıma birkaç test edilecek durum daha geliyor fakat bu kadar testin giriş yazısı için yeterli olduğunu düşünüyorum.Sizde yazdığınız testlerde bütün durumları test ettiğinizi düşünüyorsanız bu şekilde bırakabilirsiniz. Başka bir yazıda neleri test etmeliyiz hakkında birkaç şey yazmayı planlıyorum.

Küçük bir örnek olsada Test Driven Development pratiği açısından küçük adımlarla nasıl kod geliştirildiğine baktık. Burada küçük adımlar olması gerçekten önemli büyük adımlar ile birkaç özelliği birden test etmeye çalıştığınızda kontrolü kaybedip bol bol insanın sinirini bozan kırmızı çubuklar görebiliyorsunuz o yüzden küçük küçük testler yazmaya önem gösterin. TDD hakkında giriş yazımız umarım faydalı olmuştur.

Yazılım Takımı Çalışma Ortamı

İş yerinde yeni çalışma ortamımıza geçen hafta taşınmışken bu konuya ait genel düşüncelerimi ve bu konuda tavsiye edilenleri,okuduklarımı,bildiklerimi yazayım dedim.

Genelde bir ayrıntı olarak görülebilir fakat yazılım takımının çalışma ortamının yapılan işin kalitesini üretkenliğini ve verimliliği önemli ölçüde etkilediği inkar edilemez. Özellikle Agile,XP,Scrum gibi yazılım geliştirme yöntemlerinde bu konunun üzerinde oldukça fazla duruluyor. Bu yöntemlerin temelinde iletişim ,takım vb. etkenler olduğu için haliyle takımın rahatını çalışma verimliliğini etkileyen çalışma ortamı da önemli oluyor.

Öncelikle bir önceki çalışma ortamımızdan bahsedeyim. Müşterinin yanında çalışıyorduk dolayısıyla bize tahsis edilen çalışma odasında çalışmak zorundaydık. Bütün takım büyük bir odanın içinde dağılmış durumdaydı.Odanın içinde herkes bir köşeyi kapmıştı. Ayrıca odanın ortasında koskoca kirişler vardı ve birbirini duymak ya da görmek imkansızdı. En çok hissettiğim önemli problemlerden biriyde iletişimdi bilgi paylaşmak ya da herhangi bir konuda beraber çalışmak için resmen odayı bir uçtan yarış atı gibi engelleri atlayarak geçiyorduk. Ayrıca herkes kendi kabini içine gömülü çalıştığı için kimin hangi problemle boğuştuğu ne yaptığı birbirinden hebersizdi.Sadece yanımızdaki arkadaşlar ile sürekli iletişim halindeydik.

Bunun aksine çevik(Agile,XP,Scrum..) yöntemlerde tavsiye edilen çalışma ortamı aşağıdaki gibi sıralanmış.

  • Işık, Hava, Doğa
    • İnsanların çalışması nefes alması fotosentez yapması :) için gerekli olan şartlar çalışmak için uygun ortamı oluşturmakla kalmayıp yavaşça takımın moralini ve motivasyonunu yükseltir.
  • Yerleşim
    • İnsanlar genellikle birbirini görecek yüzyüze iletişim halinde olacak şekilde yerleşim planı yapılmalıdır. Birbiriyle kale duvarı gibi ayrılmış kabin şeklinde masalar iletişimi azaltacağı için tavsiye edilmez.
  • Ergonomi
    • Rahat bir masa rahat bir koltuk fazla söz söylemeye gerek yok sanırım :)
  • Mahremiyet
    • Herkese ait özel bir alan yada kabin tahsis edilmesi takımdaki bireylerin ihtiyacı olduğunda özel telefon vs. görüşme yapabileceği alanla.
  • Kişisel Alanlar
    • Herkesin kendi çalışma ortamında kendine ait kart, çizim, çiçek, börtü böcek koyabileceği alanlar..
  • Ulaşılabilirlik
    • Çalışma ortamında herkesin rahatlıkla ulaşabileceği printer, çay kahve makinası ve diğer gerekli şeylerın olması
  • Gürültü
    • Takım sürekli iletişim halinde olacağı için (dikkatinizi çekerim sessiz çıt çıkmayan bir ortam değil) diğer çalışma grplarından birbirini rahatsız etmeyecek şekilde ayrılması

Aslında bütün maddelerde takım için nasıl daha iyi bir çalışma ortamı oluşturulur onun üzerinde duruluyor. iletişimi takımın, bireylerin motivasyonunu arttıracak şeyler tavsiye edilmiş.

Aşağıda XP123 sitesinde yayımlanmış çalışma ortamı fotoğraflardan birini görüyorsunuz .

team1.gif

Başarılı bir proje için iyi motive olmuş iyi iletişim halinde çalışan bir takım olmazsa olmazlardan biri olduğu kesin. Yöneticilere bu şekilde bir çalışma ortamına sahip olmak için istekte bulunmanın gerekli olduğuna inanıyorum. Ya da onların takımın verimliliğini arttırmak için bu tarz şeyleri yöneticilerin düşünmesini diliyorum….

Ruby On Rails Öğreniyorum…

rails.pngAgile metodolojiler ile ilgilenipte Ruby öğrenmemek olmaz dedim ve uzun zamandır niyetli olduğum Ruby ve Ruby On Rails öğrenmeye sonunda başladım. Ruby dili gayet kolay anlaşılabilir ve basit yapıda öğrenmesi gerçekten kolay . Tabi birde Object Oriented olması onu script diller arasında daha da avantajlı kılıyor. Asıl daha çok Ruby on Rails öğrenmek istiyorum o da suanda gayet iyi gidiyor kaynak olarak

Agile Web Development with Rails

Programming Ruby

kullanıyorum.

Yazılımda Bitirmenin Tanımı

Agile (Çevik) yazılım ile alakalı bir blog takip ediyordum. Blogdaki bir yazıda yazılımda bitirmenin oldukça güzel tanımı yapılmış bende buraya aynen yazayım dedim.

Geliştirdiğimiz bir koda,modüle,yazılıma bitti dememiz için :

  • Unit testleri yazılmış
  • Müşteri tarafından onaylanmış
  • Kullanılabilirliği test edilmiş
  • Entegrasyon testleri yapılıp projeye entegre edilmiş
  • Dökümantasyonu yapılmış
  • Performans testi yapılmış
  • Diğer takım arkadaşları ile gözden geçirilmiş
  • Kod düzenlenmiş, okunabilir, tekrar içermeyen
  • Hata içermeyen

olması gerekir.

Refactoring-Feature Envy

Feature Envy Martin Fowler’ın Refactoring: Improving the Design of Existing Code kitabında geçen code smell’lerden ve özellikle benim en sevmediklerimden biri. Bu arada yazılım dünyasında yerleşmiş orjinal pattern, refactoring vb.. isimleri orjinal adıyla kullanacağım çünkü bu isimlerin genel amacı iletişimi arttırmak olduğu için bütün yazılım dünyasınca kabul edilmiş bu isimlerin türkçeleştirilip ilginç ve anlaşılmayan bir isim alması taraftarı değilim. Neyse fazla uzatmadan konumuza dönelim..

Feature Envy genelde bir sınıfın başka sınıfın verisini kullanarak bir takım işlemleri yaptığında ortaya çıkar. Geçenlerde bahsettiğim (P)Object Oriented dönüşümü aşamalarında en çok karşımıza çıkan kötü kod örneklerinden biridir. Klasik prosedürel mantıkta herşey fonksiyon ve veriler üzerine kurulduğu için Record, Struct, Primitive vb. gibi yapılar ve bunları kullanarak çeşitli işlemleri yapan fonksiyonlar vardı. Bir türlü prosedürel programlama mantığı sevdamızdan(ilk aşk unutulmaz derler :) ) vazgeçemediğimiz için bunu Object Oriented dillerede taşıdık malesef.

Geçenlerde projede iş arkadaşlarımdan biri bir konuda yardım istemişti konu kullanıcının tanımladığı çeşitli hız aralıklarına göre harita üzerinde o hız aralıklarına uygun renklerin çizilmesiydi. Beraber arkadaşın kodunu inceliyorduk ortada Lejand diye bir sınıf vardı. Bu arada Lejand harita üzerinde neyin ne anlama geldiğini belirten bir çizgiymiş. Çizgiyi sürekli görüyordum fakat o zamana kadar Lejand olarak anlandırıldığını bende bilmiyordum :) Lejand sınıfına baktığımızda tam hatırlamasamda aşağıdaki yapıya benzer bir kod vardı.

class Lejand{
    private int r,g,b;
    private int maxSpeed,minSpeed;

    public void setRGB(int r,int g,int b){
        this.r=r;
        this.g=g;
        this.b=b;
    }

    public int getR() {
        return r;
    }

    public int getG() {
        return g;
    }

    public int getB() {
        return b;
    }

    public int getMinSpeed() {
        return minSpeed;
    }

    public void setMinSpeed(int minSpeed) {
        this.minSpeed = minSpeed;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }
}

class Controller{
    private Lejand lejand; //kullanıcının hız aralıklarına g&amp;amp;amp;#246;re red,green,blue değerleri
    private int currentSpeed ;//cizilecek olan şuandaki hızın değeri
    //.....
    //....
    void drawLine(){
        //....
        if(currentSpeed<lejand.getMaxSpeed () && currentSpeed >lejand.getMinSpeed()){
            Color color =new Color(lejand.getR(),lejand.getG(),lejand.getB());       
            //..yukarıdaki color nesnesini kullanarak yapılan cizim işlemler.
            //g.setColor(color);
            //..
        }

    }
}

Burada yapılan işlemin o andaki hız değerine göre kullanıcının lejand değerlerinde tanımlı olan maximum ve minimum değerleri karşılaştırıp eğer o aralığa denk düşüyorsa lejandta o aralık için tanımlanmış RGB değerlerinden bir renk üretip çeşitli çizim işlemleri yapmak.Buraya kadar herşey güzele benziyor fakat bizden bu renk değerlerinin artık RGB olarak değilde direk metin şeklinde renkler olarak tutulması istendi o zaman ne yapacağız ?Hemen kodumuzu aşağıdaki gibi değiştireceğiz..

class Lejand{
    private String color;
    private int maxSpeed,minSpeed;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getMinSpeed() {
        return minSpeed;
    }

    public void setMinSpeed(int minSpeed) {
        this.minSpeed = minSpeed;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }
}

class Controller{
    private Lejand lejand; //kullanıcının hız aralıklarına gore red,green,blue değerleri
    private int currentSpeed ;//cizilecek olan şuandaki hızın değeri
    //.....
    //....
    void drawLine(){
        //....   
        if(currentSpeed<lejand.getMaxSpeed () && currentSpeed< lejand.getMinSpeed()){
            Color color ;
            if(lejand.getColor().equals("Yesil")) {
                color = Color.GREEN;
<div style="display: none"><a href='http://writingessayservices.com/'>writer essay</a></div>            }else if(lejand.getColor().equals("Mavi")){
                color = Color.BLUE;
            }
            //..yukarıdaki color nesnesini kullanarak yapılan cizim işlemler.
            //g.setColor(color);
            //..
        }
    }
}

Gördüğünüz gibi hem Lejand hemde bu sınıfı kullanan Controller sınıfı kodumuzu değiştirmek zorunda kaldık. Tabi sadece bu değil aynı lejand sınıfını kullanan başka sınıflarda aynı işlemi yapıyorlardı onlarda da bu kodu değiştirmek zorunda kaldık. Gördüğümüz gibi yukarıdaki yapıya benzer şekilde yazılan kod hem aynı mantığı başka sınıflarda da tekrarlattırdığı için kod tekrarı içeriyor hemde herhangi bir değişikliğe karşı çok kırılgan yapıda olduğu için bir sınıfta yapılan değişiklik birden fazla sınıfı etkiliyor.

Genel olarak gerçek Object Oriented yazılmış kodun en önemli avantajlarından birisi de değişimin etkisinin en aza indirgenmesidir. Böylece geliştirdiğimiz yazılım için değişikliklerin maliyetinin en aza indirgenmesi sağlanır.Peki ilk bakışta düzgün görünen bu kodlardaki problem neydi ona bakalım biraz..

İlk olarak dikkat çekmesi gereken Lejand sınıfı hiçbir iş yapmıyor daha doğrusu içerisinde iş yapan bir metod yok.Bu arada sadece private alanın önünde duran Getter/Setter ya da C#’ki Property yapıları iş yapan metod kategorisine girmiyor. Kısaca bu tarz sınıflara

sorumluluktan yoksun Veri sınıfları (Data Class) diyoruz. Projenizde bu tarz yani sadece Property ya da Getter/Setter içeren ve bunları kullanılan sınıflara fazlaca rastlanıyorsa kodunuzu tekrar gözden geçirmeniz ve bunları düzetleniz projenin saadeti için iyi olur.

Object Oriented’ın temel felsefesi ve Prosedürel mantıktan ayrılan en önemli özelliklerinden biriside veri ve bu veriyle işlem yapan fonksiyonların bir arada bulunmasıdır. Bu tarz sınıflar bu özelliği ihlal edip kırılgan bir koda sebep olurlar. Yukarıdaki sınıflarda ise veri Lejand sınıfının içinde olmasına rağmen onla alakalı renk üretme işlemi Controller sınıfında bulunuyordu. Şimdi bunu düzeltelim ve herkesi olması gereken yere yerleştirelim. Bunun için uygulanacak refactoring Move Method olacak ileride ayrı bir yazıda basit olmasına rağmen değiniriz. Bunu uyguladıktan sonra kodumuz aşağıdaki şekilde olur.

class Lejand{
    private String color;
    private int maxSpeed,minSpeed;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getMinSpeed() {
        return minSpeed;
    }

    public void setMinSpeed(int minSpeed) {
        this.minSpeed = minSpeed;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }
    public Color getColor(int currentSpeed) {
        Color color =null;
        if(currentSpeed< getMaxSpeed() && currentSpeed< getMinSpeed()){            
            if(getColor().equals("Yesil")) {
                 color = Color.GREEN;
            }else if(getColor().equals("Mavi")){
                color = Color.BLUE;
            }            
        }
        return color;
    }
}

class Controller{
    private Lejand lejand; //kullanıcının hız aralıklarına gore red,green,blue değerleri
    private int currentSpeed ;//cizilecek olan şuandaki hızın değeri
    //.....
    //....
    void drawLine(){
        //....

        Color color= lejand.getColor(currentSpeed);
        //..yukarıdaki color nesnesini kullanarak yapılan cizim işlemler.
        //g.setColor(color);
        //..
    }
}

Lejand sınıfının yeni haline baktığımızda artık bize kendi verisini kullanarak renk üretme işlemini yapan bir fonksiyona sahip olduğunu görüyoruz. Ve controller artık Lejand sınıfının iç yapısını bilmiyor ve sadece getColor() metodunu çağırıyor. Renk üretme işleminin Lejand sınıfında RGB mi yoksa Renk isimleriylemi yapıldığından habersiz. Lejand sınıfında tekrar RGB ye dönsek bile Controller sınıfını değiştirmek zorunda değiliz çünkü sadece getColor metodunu kullanıyor ve içeride neler olduğundan habersiz. Yani artık kodumuz değişimlere karşı birden fazla yerde değişiklik gerektirmiyor.

Evet bir veri sınıfını adam etme öykümüz burda sona ermiştir. Sloganımız sorumluluktan yoksun veri sınıflarına ölüm :)