Jun 30 2008

Ship It: Bölüm 2

Tag: KitaplarM. Cihat Altuntaş @ 5:34 pm

Tools and Infrastructure

Kitap ikinci bölümün ilk başında güzel bir hikaye anlatmış. Hikayede iki arkadaşın ev yapma hikayesi anlatılıyor. Kısaca isimleri değiştirerek bende anlatayım. Mehmet ve Cihat(kim acaba :) ) adında iki arkadaş aynı anda ev yapmaya başlıyorlar. Mehmet çekicini ve tornavidasını alarak hemen evi yapmaya başlıyor. Fakat Cihat iş için kompresör ,çivi çakma makinası.. gibi işini çok kolaylaştıracak modern araçları alıyor ve bunları öğrenmeye başlıyor. Tabi Mehmet’in evi yavaş yavaş ortaya çıkarken Cihat daha araçları öğrenmeyle uğraşıyor. Cihat araçları kullanmayı öğrendikten sonra onların verdiği avantajla çok hızlı bir şekilde evini bitirip Mehmet’i geçiyor.Cihat Mehmet evini yapmakla uğraşırken o araçları öğrenmeyle kaybettiği vaktini kolayca geri kazanıyor. Tabi bundan sonraki yaptıkları evlerde Cihat doğal olarak öğrenmiş olduğu araçları kullanarak çok hızlı sağlam evler yaparken Mehmet hala eski tekniklerle Cihat’a yetişmeye uğraşıyor.

Sizinde anladığınız gibi yazar yukarıdaki hikayeden yola çıkarak yazılım araçların ve altyapısının geliştirme için eski ilkel yöntemlere göre nasıl avantaj sağladığını,nasıl hızlı ve kaliteli ürünler ortaya çıkardığını anlatıyor.

Develop In A Sandbox

Bu kısımda özellikle yazılım geliştiricilerin dış etkilerden izole edilmiş bir ortamda çalışmalarını gerektiğini anlatıyor.Özellikle Versiyon Kontrol Sistemi ile herkesin kendi bilgisayarlarında diğerlerini etkilemeyecek şekilde çalışmaları gektiğini,her yazılımcının bilgisayarında diğerlerini etkilememek için Veritabanı,Web servisleri.. gibi yazılımların kurulu olması gerektiğini anlatıyor. Eğer geliştiriciler veritabanı lisansları gibi konular yüzünden tek veritabanı üzerinde çalışıyorlarsa bunun riskinide göze almaları gerektiğini söylüyor.

Manage Assets

Bu kısımda yazılımcının en değerli varlığının sadece kod ya da diğer dosyalar olduğunu bununda en iyi şekilde yönetmesi gerektiğini anlatıyor.Bunun versiyon kontrol sistemi ile sağlandığını ve faydalarını anlatıyor.Özellikle yazılım geliştirmek için tüm gerekli kütüphaneler grafik dosyaları xml dosyaları kısacası geliştirme ortamında kullanılan herşeyin Versiyon kontrol sisteminde olması gerektiğini anlatıyor.

Bunu daha önceden tecrübe ettiğim için iyi biliyorum. Herşeyi Versiyon kontrol sistemine atmadığınız zaman kodu sistemden çektiğinizde sürekli eksik dosyalar eksik kütüphaneler… ile uğraşmak zorunda kalıyorsunuz. Özellikle aklınızda bulunsun geliştirme ortamınızda kullanacağınız herşeyi ama herşeyi Versiyon kontrol sistemine atın.

Script Your Build

Bu bölümde geliştirdiğiniz programın çalışabilir hale getirmek için el ile yaptığınız adımları otomatik build scriptlerini kullanarak yapmanızı öneriyor. Özellikle çoğu kullanıcının Build denince kullandığı IDE nin build işlemi aklına geliyor. Fakat burada tamamen IDE den bağımsız o olmadan komut satırından çalıştırılacak bir komut,yada bir buton ile (ant build,make all.. gibi) yazılımın çalıştırılabilir bir sürümünün çıkarılma işlemini otomatikleştirmeyi anlatıyor.Yazarda benim yaşadığım aynı tecrübeleri kitaba aktarmış.

IDE kullanılarak yapılan Build işlemini anlatmış.IDE ile yapılan build işlemini hepiniz bilirsiniz. Önce kodu derleriz ardından başka bi dizine kopyalarız ardından biryerden bazı kütüphaneleri unutmuş oluruz onları kopyalarız. O dizinden çalıştırıp problem olmadığından emin oluruz… diye devam eden bir süreç. Otomatik build script ile sadece tek tuşla bunların hepsini yapmayı sağlayabiliriz. Kendim bizzat acısını çekerek otomatik build işlemine geçtiğimde daha önceden bu eziyeti neden çekiyormuşum kendime hayret etmiştim.

Burada yazarın en önemli vurgusu şu. Herhangi bir makina yazılımı hatasız build edebilmelidir. IDE ile build işlemi yapıldığında en çok karşılaşılan hatalardan biri build işlemini yapan developer ın makinasında çalışıp diğer makinalarda çalışmamasıdır(It works on my machine). Sebebide gelende developer makinasında olan kütüpane ayar gibi şeylerin diğer makinalarda olmaması eksik olması bu işlemlerin en ile yapılması hatanın asıl sebebidir malesef.Otomatik build scriptleri ile bunun önüne kolaylıkla geçebilirsiniz.

Build Automaticly

Bu kısımda otomatik build scriptlerinin bir sonraki adımı olan sürüm otomasyonu ve sürekli bütünleştirmeden(Continuous Integration) bahsediyor. Continuous Integration’ın temel felsefesi ayrı bir build server’da versiyon kontrol sistemindeki her kod değişikliğinden sonra bütün build işleminin tekrar yapılması ardından sonuçlarının çeşitli şekillerde geliştiricilere kullanıcılara sunulmasıdır. Bunun sağladığı en büyük fayda farklı makinalarda geliştirililen yazılımın entegre edilmesi sırasında bir sürü hata ortaya çıkması ve bu işlemin uzun süre almadı. Continuous Integration ile sürekli entegrasyon yapıldığı için hatalar anında yakalanabiliyor. Böylelikle geliştiriciler hatalı bir commit sonucunun build işleminde probleme yol açtığını kodu gönderdikten hemen sonra anlayabiliyor. Ayrıca bu sisteme testlerinde çalıştırılmasını eklediğinizde hataların ne kadar azaldığını düşünün.

Burada Continuous Integration aracı olarak meşhur open source CruiseControl’dan bahsetmiş. Bu kategoride birçok araç bulabilirsiniz ama unutmayın araçlar önemli değil önemli olan yapılış şekli herhangi bir aracıda kullanabilirsiniz.

Track Issues

Bu kısımda geliştirdiğiniz yazılım için hataların isteklerin takibi için Issue Trackler sisteminin bulunmasının önemini anlatıyor.Bu sistemde hatanın içeriği tüm detaylarıyla sisteme kayıt ediliyor.  Yazarın dediği Biz yazılım geliştiriciler unutkan insanlarız o yüzden yapmamız düzeltmemiz gereken önemli bug ve istekleri bu tarz bir sistemle veritabanında tutmazsak birgün mutlaka unutacağız. Ayrıca bununla alakalı yaşadığı bir anıyı anlatıyor. Müşterinin yapılmasını istediği önemli bir özellik yapılmayınca müşteri doğal olarak pek memnun olmuyor. Bu özelliği yapması gereken yazılımcı ise böyle bir istediğin gelmediğini söylüyor.Bu  Bir gün ofiste kağıda yazılı çok önemli unutma notunda o özelliğin açıklamasını yerde buluyorlar. Buda bu tarz bir sistemin gerekliliğini anlatıyor.

Bu tarz bir sistem sayesinde ayrıca yazılımcı neleri yapması gerektiğini sürekli görebiliyor. Yazılımda neler eksik hangi hatalar mevcut sürekli şeffaf izlenilebilir bir yapıda olduğu için önünüzü çok daha kolay görebiliyorsunuz.

Track Features

Bu kısımda da hataların izlenildiği gibi yazılıma eklenmesi gereken özelliklerin ya da özellik isteklerininde bu tarz bir sistemde tutulması gerektiğini anlatıyor. Gelen isteklerin önceliklerinin,sürelerinin belirlenip sisteme kayıt edilmesi önünüzde bir yapılacaklar listesi oluşturup sizin önünüzü görmenizi sağlıyor.

Use a Testing Harness

Evet en sevdiğim kısıma geldik.  Yazarın benimleaynı fikirleri paylaştığı için çok memnunum :) . Bu kısımda test yazmanın faydaları ve en önemlisi bunun otomatik olarak yapılmasının önemi anlatılıyor. El ile yapılan testler çok zaman aldığı ve hataya daha açık oldukları için zamanda faydadan çok zarar getirmeye başlarlar. Bu yüzden iyi bir test otomasyon sistemi(JUnit,NUnit,EasyMock….)otomatikleştirilmesi anlatılıyor. Çeşitli test türlerinden de ayrıca bahsetmiş. Unit Test,Integration Test,Smoke Test,Functional Test, Acceptance Test leri kısaca anlatmış.

On Choosing Tools

Burada geliştirdiğimiz yazılımda araçların seçiminin önemi anlatılmış. Dikkat edin araçları kendiniz yazın demiyor :) Genelde yazılım dünyasına yeni atılanların en büyük heveslerinden biride herşeyi kendilerinin yazmak istemeleridir(itiraf ediyorum benimde öyleydi). Başkasının yazdığı aracı mümkünse kullanmayayım kendim baştan yazayım tarzı bir felsefe vardır. Burada bu bakımdan araçları ve  araçların seçiminin önemini anlatmış.Özellikle sizi illa kendisini kullanmaya zorlayan araçları kullanırken iki kere düşünmenizi tavsiye etmiş.Bencede tamamen haklı.

When Not to Experiment

Bu kısımda da araçları seçerken dikkatli olmamızı ve bunları sırf havalı yeni teknolojileri öğrenmek için değil gerçekten işe yaradığının kanıtlanıp ondan sonra kullanılmasını tavsiye ediyor.

Kitabın ikinci kısmı bu şekilde. Gördüğünüz gibi kısa kısa bahsettim aslında herbiri kendi başlığı altında ayrı bir kitap oluşturucak kadar detaylı konular. Genel başlıkları ile en iyi pratikleri vermeye çalışmış.Dikkat ederseniz zaten yukarıdaki yöntemler modern yazılım geliştirme tekniklerinin bel kemiğini oluşturuyor. Bu bakımdan başarılı bir proje için herkesin bu maddeleri gözden geçirmesi bence iyi olur. Bu arada kitabı bitireli baya oldu ama vakit ayırıp ancak yazabildim. Gerçekten çok güzel bir kitap.Sıraca 3. bölüm var onuda fırsat bulduğum vakit yazacağım….


Jun 22 2008

State Based Testing

Tag: Test Driven DevelopmentM. Cihat Altuntaş @ 9:07 am

Uzun zamandır Test Driven development ile alakalı yazı yazmıyordum. Açıkçası en çok önem verdiğim konu hakkında vakit bulupta yazamamak beni oldukça rahatsız ediyordu. En azından herkesin faydalanması için bu tarz kaynaklara çok fazla ihtiyaç olduğu fikrindeyim.Test Driven Development hakkında yazacağım önümüzdeki birkaç makale için daha önce hiç denemediğim ve doğaçlama olarak küçük bir Hesap Makinası uygulaması yapacağız.Uygulama .NET C# kullanarak geliştireceğiz.

Öncelikle hesap makinası için yapmamız gereken şeyleri Windows’un kendi hesap makinasını inceleyerek öğrenebilirsiniz.Bu yüzden liste halinde yazmıyorum.Aslında bu örnekte hem state based testing nedir nasıl yapılır ona değinmek istiyorum hem de sizin doğaçlama olarak uygulamanın Test Driven Development mantığıyla nasıl geliştirildini görmenizi istiyorum. Şuanda bu satırları yazarken bende bu konuda tamamen bilgisizim uygulamanın ne tasarımını yaptım ne de hangi sınıf olmalı birbiriyle nasıl ilişki halinde olmalıdır diye kurguladım. Bu yazıyı yazılım geliştirirken düşüncelerimin yazıya aktarılmış hali olarak düşünebilirsiniz. Ayrıca Test Driven Design  ın nasıl yapıldığınıda görmüş olacağız.

Öncelikle geliştirme ortamımızı hazır edelim. İlk olarak .NET için en popüler Unit Test framework olarak kullanılan NUnit(2.0 binary zip sürümü) i indiriyorum. Ardından Visual Studio için olmazsa olmazlardan Resharper 4.0 ı indiriyorum. Sebebini soracak olursanız kod geliştirirken üretenliğinizi oldukça arttıran, Testleri kolaylıkla çalıştırmak,Refactoring yapmak için mükemmel bir araç. Zaten bu konuda ödüllü olduğu için bunu başka bir yazı konusu olarak sonraya bırakıyorum. Sadece kurun ve kullanın ne demek istediğimi çok iyi anlayacaksınız. Benim geliştirme ortamım bu arada VS.NET 2008. NUnit ve Resharper VS.NET 2005′de de çalışacaktır.

Ortamı hazırladık.İlk olarak VS.NET de yeni bir Class Library projesi oluşturuyorum.Adına HesapMakinesi dedim. Ardından ilk yaptığım şey test kodunu yazmak olacak bunun için projeye HesapMakinesiTest adında bir sınıf ekledim. Öncelikle aşağıdaki gibi test kodlarını görüyorsunuz.

using NUnit.Framework;
namespace HesapMakinesi
{
    [TestFixture]
    public class HesaplayiciTest
    {
        private Hesaplayici hesaplayici;

        [SetUp]
        public void Setup()
        {
            hesaplayici = new Hesaplayici();
        }

        [Test]
        public void Olustur()
        {
            Assert.IsNotNull(hesaplayici);
        }

        [Test]
        public void IntegerToplama()
        {
            hesaplayici.Islem = "Toplama";
            hesaplayici.Sayi1 = 3;
            hesaplayici.Sayi2 = 2;
            Assert.AreEqual(5,hesaplayici.Hesapla());
        }

        [Test]
        public void DoubleToplama()
        {
            hesaplayici.Islem = "Toplama";
            hesaplayici.Sayi1 = 3.123;
            hesaplayici.Sayi2 = 4.567;
            Assert.AreEqual(7.69, hesaplayici.Hesapla());
        }

        [Test]
        public void IntegerCikarma()
        {
            hesaplayici.Islem = "Cikarma";
            hesaplayici.Sayi1 = 6;
            hesaplayici.Sayi2 = 5;
            Assert.AreEqual(1, hesaplayici.Hesapla());
        }

        [Test]
        public void DoubleCikarma()
        {
            hesaplayici.Islem = "Cikarma";
            hesaplayici.Sayi1 = 3.432;
            hesaplayici.Sayi2 = 5.123;
            Assert.AreEqual(-1.691, hesaplayici.Hesapla(),0.001);
        }

        [Test]
        public void IntegerBolme()
        {
            hesaplayici.Islem = "Bolme";
            hesaplayici.Sayi1 = 10;
            hesaplayici.Sayi2 = 5;
            Assert.AreEqual(2,hesaplayici.Hesapla());
        }

        [Test]
        public void DoubleBolme()
        {
            hesaplayici.Islem = "Bolme";
            hesaplayici.Sayi1 = 8;
            hesaplayici.Sayi2 = 5;
            Assert.AreEqual(1.6, hesaplayici.Hesapla());
        }

        [ExpectedException(typeof(SifiraBolmeHatasi))]
        [Test]
        public void SifiraBolme()
        {
            hesaplayici.Islem = "Bolme";
            hesaplayici.Sayi1 = 8;
            hesaplayici.Sayi2 = 0;
            hesaplayici.Hesapla();
        }
    }
}

Yukarıdaki test kodunu yazdıktan sonra testi geçecek aşağıdaki gibi HesapMakinesi sınıfı içindeki kodu yazdık.

namespace HesapMakinesi
{
    public class Hesaplayici
    {
        private string islem;
        private double sayi1;
        private double sayi2;

        public string Islem
        {
            get { return islem; }
            set { islem = value; }
        }

        public double Sayi1
        {
            get { return sayi1; }
            set { sayi1 = value; }
        }

        public double Sayi2
        {
            get { return sayi2; }
            set { sayi2 = value; }
        }

        public double Hesapla()
        {
            double sonuc = 0;
            if (Islem == "Toplama")
                sonuc = Sayi1 + Sayi2;
            else if (Islem == "Cikarma")
                sonuc = Sayi1 - Sayi2;
            else if (Islem == "Bolme")
            {
                if(Sayi2==0)
                    throw new SifiraBolmeHatasi("Sifira bolunemez");
                sonuc = Sayi1 / Sayi2;
            }

            return sonuc;
        }
    }
}

Burada ritimi hissedin diye söylüyorum.Burada kodun hepsini bir arada görüyorsunuz fakat geliştirirken öncelikle bir özelliği edecek test metodu yazdık ardından sadece o testi geçecek kodu yazdık.Yazı fazla uzamasın diye testlerin ve kodların bu şekildeki tüm halini yapıştırdım.Yukarıdaki koda baktığınızda string olarak Toplama işlemi için karşılaştırma yapmışız. Bana bir code smell gibi geliyor.Şimdilik böyle bırakalım ileride Refactoring yaparak bunu düzeltiriz.

Şimdi test metodlarından herhangi birini daha yakından inceleyelim.

	[Test]
        public void DoubleBolme()
        {
            hesaplayici.Islem = "Bolme";
            hesaplayici.Sayi1 = 8;
            hesaplayici.Sayi2 = 5;
            Assert.AreEqual(1.6, hesaplayici.Hesapla());
        }

Yukarıdaki test kodlarına baktığınızda test etmek istediğimiz hesaplayici sınıfını öncelikle oluşturup ardından ona yapmak istediğimiz işlemi atıyoruz. Ardından hesaplanacak sayılarıda verdikten sonra nesnenin test etmek istediğimiz özelliğinin sonucunu Assert.AreEqual(1.6, hesaplayici.Hesapla())… gibi Assert metodlarıyla test ediyoruz.Yani bu şekilde nesnenin durumundaki değişiklikleri Assert metodlarıyla test etmeye State Based Testing denir. Klasik test metodu olarak en çok kullanılan test metodu State Based Testing’dir.Bu test metodu genellikle nesnelerin diğer nesnelerle ilişkisinin az olduğu ya da hiç olmadığı durumlarda daha çok kullanılır.Eğer test etmek istediğimiz sınıflar veritabanı,network,GUI… gibi test ortamında oluşturulması zor olan şeyler ise bu test metodunu kullanmak daha zor olabilir tabi imkansız değildir.Bu tarz durumlarda da Stubs adı verilen sınıflarla yine State Based testing yapabiliriz.

Şimdi aklınıza diğer test metodu nedir diye bir soru gelmiştir. Cevabı diğer yazımızda Interaction Based Testing’i örneğimize kaldığımız yerden devam ederek bu test metodunu inceleyeceğiz.


Jun 19 2008

Command-Query Separation Principle

Tag: Patterns,PrinciplesM. Cihat Altuntaş @ 5:01 pm

Nesneye yönelik programlamanın önemli prensiplerinden olan Command Query Seperation Prensibini küçük bir örnekle inceleyeceğiz.Bu konuda yine örnekleri gerçek dünyadan olsun diye eski kodlarımı baya bir karıştırdım. Eski kodlarda her türlü bad smell bulabiliyorum ne mutlu bana :) Öncelikle bu prensibi ihlal eden aşağıdaki kodumuza bakalım.Bunu C# da Property olarak yazmışım. Java içinde aynı kodu getter olarak yazabiliriz. İki koduda aşağıda görüyorsunuz.

C# Versiyonu
public Resim KapakResim
{
	get
		{
		if(kapakResim!=null)
			return kapakResim;
		else
		{
			bosResim.KayitYolu  =bosResim.ServerDizini+"yok.gif";
			bosResim.Kaydet();

			return null;
		}

	}
}
Java Versiyonu
public Resim getKapakResim()
        {
            if (kapakResim != null)
                return kapakResim;
            else
            {
                bosResim.KayitYolu = bosResim.ServerDizini + "yok.gif";
                bosResim.Kaydet();

                return null;
            }
        }

Şimdi yukarıdaki koda baktığınızda hiçbir problem görmüyor olabilirsiniz. İlk başlarda bende görmüyorum :) Buradaki problem şöyle açıklayalım. Dışarıdan birisi sizin yukarıdaki gibi yazdığınız kodu alıp kullandığında masum bir fikirle aşağıdaki gibi kodunun içinde kullanacak

  • C# da Resim resim =resimlistes.KapakResim
  • Java da Resim resim=resimListesi.getKapakResim();

Sınıfı kullanan bunun basit bir get metodu olduğunu yani sadece bir nesneyi bize geri döndürdüğünü düşünüyor fakat arka planda boş resim oluşturup dosya olarak kayıt ettiğinden haberi yok.Yani kullanıcı sadece yan etkisiz bir nesne almayı beklerken bu getter metodları nesnenin iç yapısında değişiklikler yapıp çeşitli işlemler yapıyor. Yani kodun anlaşılabilirliği oldukça düşük. Çünkü siz getKapakResim dediğinizde içeride boş resim oluşturup kayıt ettinden haberiniz olmuyor. Buda hata yapmaya oldukça açık bir yapı.

Bu yüzden ilk olarak bu prensibi Bertrand Meyer ortaya atıyor.Ne demiş şöyle özetleyelim. Nesnelere ait metodlar anlaşılabilir bir kod yapısı için şu şekilde olmalıdır.

  • Query Metod : Nesnenin içinde hiçbir değişiklik yapmadan hiç bir yan etkisi olmadan sadece geri dönüş tipinde bir nesne geri döndürür.(nesne.getResim(),nesne.Resim….gibi)
  • Command Metod : Nesnenin içinde çeşitli işlemler yapan durumunu değiştiren genelde dönüş tipi void olan metodlardır. (nesne.kaydet(),nesne.yap()…gibi)

Şimdi yukarıdaki koda baktığımızda problemi daha iyi görebiliyoruz.Bu kodda nesne.KapakResim yada nesne.getKapakResim() çağırıldığında hem nesnenin durumunda değişiklikler yapılıyor hemde geri bir nesne dönülüyor. Yani Command ve Query aynı metod içinde yapılmış. Bu metodu aşağıdaki aşağıdaki gibi Command ve Query olarak ikiye ayırırsak kodun anlaşılabilirliği daha da artacaktır.

	public Resim getKapakResim()
        {
            return kapakResim;
        }

	public void bosResimKaydet()
        {
            bosResim.KayitYolu = bosResim.ServerDizini + "yok.gif";
            bosResim.Kaydet();
        }

Yukarıdaki gibi kodumuzu ikiye ayırdık.Yani Query metodu getKapakResim sadece hiçbirşey yapmadan geri resim döndürüyor. Diğer Command metodu olan bosResimKaydet metodu ise nesnenin içinde çeşitli işlemler yapıyor. Tabi üstteki if kontrolü nereye gitti diyebilirsiniz. Dışarıda kodu kullanan da şu şekilde kodu kullanıyor.

        public void arabaKaydet()
        {
            if (resimListesi.KapakResim == null)
                resimListesi.bosResimKaydet();
            else
                Resim kapakResim = resimListesi.gerKapakResim();
        }

Kısaca özetlersek bu prensibe uymanız kodunuzun hata oranını azaltacak anlaşılabilirliğini oldukça arttıracaktır. Tabi herzaman mutlaka uyacaksınız diye bir şey yok ama çoğu durumda metodları Command ve Query olarak ayırmak oldukça faydalı..Prensiplere uyalım uymayanları uyaralım :)


Jun 12 2008

Ship it! A Practical Guide to Successful Software Projects

Tag: KitaplarM. Cihat Altuntaş @ 1:50 pm

prj

Hafta başında çok sevdiğim Pragmatic Programmer serisinden Ship It kitabını okumaya başladım. Bölüm bölüm okuduğum faydalı şeyleri burada sizlerle paylaşmaya çalışacağım.

Kitabın birinci bölümünde yol haritası niteliğinde bilgiler verilmiş. Özellikle Agile pratikler açısından iyi bir giriş olmuş. Özellikle bölümün başındaki güzel söz çok hoşuma gitti.

We are what we repeatedly do.
Excellence, then, is not an act, but a
habit.
Aristotle

 

 

Ayrıca kitapta yer alan faydalı pratiklerin posterini hemen internetten indirip masaüstü arka planına koydum.Burayada sizler için yerleştireyim.Posterde gerçekten yazılım geliştirmede çok önemli olan anahtar pratikler verilmiş. Özellikle Agile pratiklerin çoğunu aşağıdaki resimde görebilirsiniz.Sizi posterle başbaşa bırakıyorum. Ben kitabı okumaya kaçar :) ….

keyPractices


Jun 11 2008

Baker’s Dozen

Tag: AgileM. Cihat Altuntaş @ 4:23 pm

baker - Copy

Bugün nedense posterlere taktım kafayı o yüzden daha önceden mutlaka göndermeliyim diye düşündüğüm posteri uzun zaman sonra bulup gönderme fırsatı bulabilidim. Posterde Agile pratiklerin çok güzel özetini ve bu yazıda açıklamasını görüyorsunuz. Her masaüstünde arka plan olarak ya da  en azından geliştirme ortamınızda bir adet bulunması çok güzel olur bence. Çevirmekten benim gibi üşenenler için kısaca türkçe olarak çevireyim dedim.Yanlışlarım varsa kusura bakmayın :)

  • Ortak vizyon oluşturun
  • Sürece değil amaca odaklanın
  • Büyük düşünün küçük başlayın
  • Sabit bütçe,Sabit zaman,değişebilen proje kapsamı,asla kaliteden taviz verme
  • Çalışan kod herşeyden önemlidir
  • Müşterinin bakış açısından görün
  • Küçük kararlar verin
  • Detayların zamanla ortaya çıkmasına izin verin
  • Çalıştır,Doğru çalıştır, Hızlı çalıştır
  • Geribeslemeyle öğren,sürekli geliştir
  • Küçük takımlar oluşturun
  • Yeterli olmaktansa verimli olun

Jun 10 2008

Interface nedir,ne zaman kullanılır?

Tag: Yazılım MühendisliğiM. Cihat Altuntaş @ 12:45 pm

 

Interface içinde sadece kendisinden türeyen sınıfların içini doldurmak zorunda olduğu içi boş metod tanımlarının yapıldığı bir yapıdır. Kısacası kendisini kullanacak sınıflar için bir yerine getirmeleri gereken metodları belirten bir kontrat gibidir. Java ve C# dillerinde aşağıdaki gibi kullanılır.

interface Rapor{
    public void hazirla(Fatura fatura);
}

Bu interface kendinden türeyen tüm sınıfların public void hazirla(Fatura fatura) adında bir metoda sahip olmalarını zorunlu kılar aksi taktirde derleyici hata verecektir. Aşağıdaki gibi bir sınıfın bu interface’i nasıl uyguladığını gösteren koda bakalım.

class PdfRapor implements Rapor{
    public void hazirla(Fatura fatura) {
        //Faturayı pdf formatında hazırlayan kodlar
    }
}

Gördüğünüz gibi interface’den türeyen sınıflar bu şekilde interface’in belirttiği kurallara uyup içindeki metodları kendileri yazmak zorundadır.Kısacası interface’ler sınıfların yapabildiği şeyleri belirten kontratlardır diyebiliriz. Aklımıza gelmişken interface’lerin diğer özelliklerini de yazalım.

  • Interface’ler de Abstract sınıflar gibi new ile oluşturulamazlar
  • İçi dolu metod bulunduramazlar
  • public static final değişkenler dışında herhangi bir değişken bulunduramazlar
  • Bir sınıf birden fazla interface’den türeyebilir

Şimdi asıl önemli soruya geldik. Az önceki durumda neden interface kullandık?Aslında bunun sebebi tamamen bizden geliştirmemiz istenen yazılımın özelliklerine bağlı. "Yukarıdaki gibi bir kod yazmamızın ne gereği var?, Direk PdfRapor sınıfını interface’den türetmeden yazamazmıydık?" gibi sorular aklınıza gelmiş olabilir. Evet yazabilirdik tabi, fakat yazmamamızın sebebini şöyle açıklayalım.Öncelikle daha önceden müşteri ile konuştuğumuzda bizden şöyle bir talepte bulunmuştu: "Geliştireceğiniz yazılımda ben faturalarımı Pdf,Word,Excel formatlarında hazırlayabilmek istiyorum. Ayrıca ileride belki yeni formatlarda da sizden fatura isteyebilirim" diye daha önceden bizle konuşmuştu.Durum böyle olduğu için daha önceden Dependency Inversion makalesinde yazdığım gibi kodumuzun değişikliklerden etkilenmemesi, içinde bolca if-else yapılarının olmaması ve daha esnek olması için değişen kısmı bir interface kullanarak kodumuzdan soyutladık.Kodun içinde sadece aşağıdaki gibi interface kullanıldığı için ileride eklenecek yeni rapor formatlarından da etkilenmeyecektir.

class FaturaRaporFormu {
        private List calisanlar;
        private Fatura seciliFatura;
        private Rapor rapor;

        public FaturaRaporFormu(Rapor rapor){
               this.rapor = rapor;
       }

        public void FaturayaAitRapor(){
                this.rapor.hazirla(seciliFatura);
        }
}

Ayrıca interface ya da abstract sınıfların en büyük güzelliklerinden biride Polymorphism diyebiliriz. Interface ya da Abstract sınıfları kodun herhangi bir yerinde bir metoda parametre ya da metodun dönüş değeri,bir değişken, bir dizi tanımlamasında… gibi yerlerde kullanabiliriz. Ve bu kullanılan yerlerde Abstract ya da Interface’den türeyen herhangi bir sınıfı bu metoda,değişkene parametre olarak gönderdiğimizde ya da değişkene atadığımızda kod aynen çalışmaya devam edecek Java,C# dilleri Interface ya da Abstract sınıftan türeyen bütün alt sınıflara aynı şekilde tavranacaktır.

Gördüğünüz gibi interface kullanmak kodun esnekleğini arttırıyor. Fakat geliştirdiğimiz yazılımda ileride değişmeyecek bir kavramı sırf esneklik olsun diye interface kullanarak soyutlamakda kodu daha anlaşılması zor ve karmaşık hale getirecektir.Unutmayın yazılımın ve kodun basit ve sadece müşterinin ihtiyaçlarını karşılayanı makbuldür.Basitlik yazılım geliştirirken daima aklımızın bir köşesinde bulunmalı. Bu yüzden eğer müşteri bizden tek tip rapor isteseydi bu sefer interface kullanmamıza gerek kalmazdı.

Kısaca özetlersek Interface geliştirdiğimiz yazılımda aynı kavramın birden farklı şekilde uygulandığında bu kavramı soyutlayarak kodun esnekliğini,okunulabilirliğini arttırmak ve değişimin etkisini en aza indirmek için kullanılan yapılardır.Genelde Interface’den türeyen sınıflar arasında CAN-DO(yapabilir) ilişkisi vardır.Yukarıda neden kullanmamız gerektiğini umarım anlatabilmişimdir.


Jun 03 2008

Agile Manifesto

Tag: AgileM. Cihat Altuntaş @ 4:08 am

O kadar Agile yöntemler üzerinde konuşuruz ama asıl ilk yazılması gereken başlığı sona bırakmışım galiba. Çevik yöntemlerin özünü ustalarımız http://agilemanifesto.org/ adresinde bizim için çok iyi özetlemiş.

  • Individuals and interactions over processes and tools
  • Working software over comprehensive documentation
  • Customer collaboration over contract negotiation
  • Responding to change over following a plan

Sizi çevirme zahmetinden kurtarmak için Türkçesini yazacak olursak

  • Süreç ve araçlar yerine Bireyler ve İlişkiler
  • Kapsamlı dökümantasyon yerine Çalışan Yazılım
  • Kontrat görüşmeleri yerin Müşteri İle Birlikte Çalışma
  • Plan izleme yerine Değişikliğe Cevap Verme

Kalın harflerle vurguladığım yerler bir yazılım için başarının anahtarları diyebiliriz. Tabi bu anahtarları kullanıp kullanmamak bizim elimizde..


Jun 02 2008

Abstract nedir, ne zaman kullanılır?

Tag: Yazılım MühendisliğiM. Cihat Altuntaş @ 5:35 am

Abstract sınıflar içerisinde normal yani içi dolu metodların,değişkenlerin ve interface’lerdeki gibi abstract (boş) metodların tanımlanabildiği yapılardır.Bu sınıflar new kelimesi ile oluşturulamazlar.

Hemen uygulamaya geçelim örnek olarak arabalarla alakalı geliştirdiğimiz bir uygulamamız olsun. Sistemimizde bulunan çeşitli marka arabalara ait bazı özellikleri ekranda göstersin. Arabaların ağırlık,renk,model gibi ortak özellikleri ve cant kalınlığı,devir sayısı gibi kendilerine has özellikleri mevcut. Bunu ifade eden aşağıdaki gibi kodumuzu yazalım.

class Araba{
    private int agirlik;
    private String renk;
    private String model;

    public int getAgirlik() {
        return agirlik;
    }
    public void setAgirlik(int agirlik) {
        this.agirlik = agirlik;
    }
    public String getRenk() {
        return renk;
    }
    public void setRenk(String renk) {
        this.renk = renk;
    }
    public String getModel() {
        return model;
    }
    public void setModel(String model) {
        this.model = model;
    }
}
class Mercedes extends Araba{
    private int cantKalinligi;

    public int getCantKalinligi() {
        return cantKalinligi;
    }
    public void setCantKalinligi(int cantKalinligi) {
        this.cantKalinligi = cantKalinligi;
    }
}
class Ford extends Araba{
    private int devirSayisi;

    public int getDevirSayisi() {
        return devirSayisi;
    }
    public void setDevirSayisi(int devirSayisi) {
        this.devirSayisi = devirSayisi;
    }
}
class KullaniciEkrani{
    public void goster(Araba[] arabalar){
        for (int i = 0; i < arabalar.length; i++) {
            Araba araba = arabalar[i];
            System.out.println("Agirlik : "+araba.getAgirlik());
            System.out.println("Model : "+araba.getModel());
            System.out.println("Renk : "+araba.getRenk());
        }
    }
}
class AnaProgram{
    public static void main(String[] args) {
        Araba ford =new Ford();
        ford.setAgirlik(1000);
        ford.setModel("Fiesta");
        ford.setRenk("Gri");
        Araba mercedes=new Mercedes();
        mercedes.setAgirlik(2000);
        mercedes.setModel("E200");
        mercedes.setRenk("Siyah");

        Araba arabalar[]=new Araba[]{mercedes,ford};
        KullaniciEkrani ekran =new KullaniciEkrani();
        ekran.goster(arabalar);
    }
}


Yukarıdaki kodda gördüğünüz gibi Polymorphism sayesinde KullaniciEkrani sınıfı arabaların markalarından habersiz hepsini gösterebiliyor. Araba sınıfından türeyen her sınıf KullaniciEkrani sınıfında gösterilebiliyor.Buraya kadar gayet güzel. Şimdi müşteri bizden bu ekranda araçların saatte kaç litre benzin yaktıklarını da göstermemizi istedi.Fakat burada şöyle bir problem var her marka arabanın kaç litre benzin yaktığı kendi ağırlığına göre farklı hesaplanıyor.Araba sınıfına saatte yaktığı litre diye değişken eklesek olmayacak çünkü Mercedes bunu hesaplamak için farklı katsayı ile çarpıyor Ford farklı sayı ile çarpıyor.İşte bu noktada yardımımıza Abstract kavramı yetişiyor ve kodumuzu şöyle değiştiriyoruz.

abstract class Araba{
    private int agirlik;
    private String renk;
    private String model;

    public int getAgirlik() {
        return agirlik;
    }
    public void setAgirlik(int agirlik) {
        this.agirlik = agirlik;
    }
    public String getRenk() {
        return renk;
    }
    public void setRenk(String renk) {
        this.renk = renk;
    }
    public String getModel() {
        return model;
    }
    public void setModel(String model) {
        this.model = model;
    }

    public abstract int saateYaktigiBenzinLitresi();
}
class Mercedes extends Araba{
    private int cantKalinligi;

    public int getCantKalinligi() {
        return cantKalinligi;
    }
    public void setCantKalinligi(int cantKalinligi) {
        this.cantKalinligi = cantKalinligi;
    }

    public int saateYaktigiBenzinLitresi() {
        return getAgirlik()*2;
    }
}
class Ford extends Araba{
    private int devirSayisi;

    public int getDevirSayisi() {
        return devirSayisi;
    }
    public void setDevirSayisi(int devirSayisi) {
        this.devirSayisi = devirSayisi;
    }

    public int saateYaktigiBenzinLitresi() {
        return getAgirlik()*1;
    }
}
class KullaniciEkrani{
    public void goster(Araba[] arabalar){
        for (int i = 0; i < arabalar.length; i++) {
            Araba araba = arabalar[i];
            System.out.println("Agirlik : "+araba.getAgirlik());
            System.out.println("Model : "+araba.getModel());
            System.out.println("Renk : "+araba.getRenk());
            System.out.println("Yaktigi Lt. Benzin : "+araba.saateYaktigiBenzinLitresi());
        }
    }
}
class AnaProgram{
    public static void main(String[] args) {
        Araba ford =new Ford();
        ford.setAgirlik(1000);
        ford.setModel("Fiesta");
        ford.setRenk("Gri");
        Araba mercedes=new Mercedes();
        mercedes.setAgirlik(2000);
        mercedes.setModel("E200");
        mercedes.setRenk("Siyah");

        Araba arabalar[]=new Araba[]{mercedes,ford};
        KullaniciEkrani ekran =new KullaniciEkrani();
        ekran.goster(arabalar);
    }
}

Gördüğünüz gibi yukarıdaki kodda Araba sınıfına public abstract int saateYaktigiBenzinLitresi(); adında bir soyut metod ekledik. Bir sınıfın abstract metod bulundurabilmesi için Abstract bir sınıf olması gerekir. İkinci olarak Araba sınıfını abstract olarak değiştirdik. Bunu yapmamızın sebebi Araba sınıfı tarafından bu hesaplama işleminin nasıl yapılacağının bilinmemesidir. Yani bu hesaplamayı kendi yapmayıp kendinden türeyen sınıfların yapmasını şart koşmuştur. Bu hesaplamayı gördüğünüz gibi her marka araba sınıfı kendi katsayılarına göre kendi içinde yapıyor. Yukarıda Mercedes ve Ford sınıflarında saateYaktigiBenzinLitresi() metodunun nasıl farklı şekillerde yazıldığını gördünüz.Bu sayede KullaniciEkrani sınıfında Araba sınıfındaki saateYaktigiBenzinLitresi() metodunu çağırdığında her marka araba için kendi içlerinde yazdıkları saateYaktigiBenzinLitresi() metodu çalışacaktır.

Dikkat ederseniz uygulamamızada new kelimesi ile Araba nesnelerini zaten oluşturmuyorduk. Bizim oluşturduğumuz nesneler new Merceses,Ford gibi nesnelerdi.O yüzden Araba sınıfını normal sınıf tanımlamak tasarım bakımından zaten anlamsız.Burada Araba sınıfı kodun diğer kısımlarından Mercedes ve Ford gibi belirgin sınıfları soyutlamak ve sınıflarındaki ortak özellikleri(agirlik,renk,model) kodu tekrar yazmamak için oluşturulmuş bir soyut sınıf.Kod olarak baktığımızda KullaniciEkrani sınıfı Mercedes ve Ford sınıflarından habersiz sadece Araba sınıfını biliyor.

Gördüğünüz gibi Abstract sınıflar daha çok nesneler arasındaki ortak özelliklerin veya metodların bir üst sınıfta toplanarak kod tekrarını önlemek ve kodu diğer sınıflardan soyutlayarak değişimin etkisini en alt düzeye indirmektir.

Aklınızda bulunsun herhangi bir sınıfı Abstract bir sınıftan türetmek istediğinizde genel olarak dikkat etmeniz gereken durum aralarında IS-A özelliği olmasıdır.Yani Mercedes bir Arabadır, Ford bir Arabadır diyebiliriz.

Kısaca özetleyecek olursak Abstract sınıflar aralarında IS-A(..dır,..dir) ilişkisi olan sınıflardaki ortak özelliklerin ve metodların soyut üst sınıfda toplanması ondan sonra uygulamada bu soyut sınıfın kullanılarak uygulamanın diğer sınıflarından habersiz halde çalışmasını sağlamaktır. Nesneye yönelik tasarımda uygulamayı iyi soyutlamalar üzerine kurmak oldukça önemlidir. Uygulamada soyutlama oluşturmak için kullanılan önemli kavramlardan olan Abstract sınıfları küçük bir örnekle inceledik. Yakında diğer soyutlama mekanizması olan Interface kavramına değineceğiz. Tekrar görüşmek üzere…