Bir “if” sınamasına farklı bakış

29 Oca

Kodalama yaparken karşılaştığım uzunca bir “if” sınaması için farklı bir yaklaşımı sunmak istedim.


public class OperationManager
{
     public IOperation GetOperation(string arg)
     {
        if (arg == "+" ||
            arg == "-" ||
            arg == "*" ||
            arg == "/")
        {
            return new MathOperation();
        }

        return new UnknownOperation();
    }
}

Yukarıdaki ifadenin alternatifi olarak aşağıdaki gibi bir çözüm üretebiliriz. Okunabilirliği arttıran bir yöntem gibi görünüyor. Kod satırları azaldığından göze daha hoş gelen bir yazım biçimi oldu.

public class OperationManager
{
     private readonly string[] operations = { "+", "-", "*", "/" };

     public IOperation GetOperation(string arg)
     {
         if (operations.Contains(arg))
         {
             return new MathOperation();
         }
         return new UnknownOperation();
     }
}

Esri Silverlight Api Özellikleri – Davranışlar ve Eylemler

29 Oca

Behaviors & Actions

Behaviors & Actions konusu altında işlenen API özellikleri harita(Map control) nesnesinin davranışlarını ve eylemlerini kapsamaktadır. Bu yazıdaki örnek uygulamalar, versiyon 3.0 üzerinde yapılmıştır.

Constraint Extent Behavior

ConstraintExtentBehavior adındaki davranış belirleyicisi, haritanın belli bir koordinat sınırının dışına çıkmasını engelleyici özelliğe sahiptir. Bu davranış bir harita nesnesine uygulandığında, düzlem üzerindeki harita, belirlenen sınırların dışına kaydırılamaz.

Örnek uygulama.

Kullanımı:

constraintExtentBehavior

Örnek uygulamada harita sınırları Map kontrolüne eklenen ConstraintExtentBehavior davranışının ConstraintExtent ayarı “-15000000,2000000,-7000000,8000000” değerleri ile sınırlandırılmıştır. Bu sınırlandırma ile harita artık bu sınırların dışına kaydırılamamaktadır.

Maintain Extent Behavior

MaintainExtentBehavior davranış belirleyicisi, haritanın (Map control) yeniden boyutlandırılması (resize) sırasında mevcut Extent’i korur.

Örnek uygulama.

Kullanımı:

maintainExtentBehavior

Örnek uygulamayı incelerken internet tarayıcınızı (browser) büyütüp küçülttüğünüzde harita sınırlarının korunduğunu görebilirsiniz.

Show Coordinates Behavior

ShowCoordinatesBehavior davranış belirleyici tip, mouse imlecinin gezindiği koordinatları gösteren bir davranışa sahiptir.

Örnek uygulama.

Kullanımı:

ShowCoordinatesBehavior

Örnek uygulamayı incelediğinizde mouse imleci harita üzerinde gezindikçe, imlecin bulunduğu koordinatlar, imlecin yanında gözükecektir.

Eylemler (Actions)

Esri Silverlight API içerisinde tanımlanmış olan eylemler (Actions) sayesinde çizim, mekansal sorgu, ölçümler gibi birçok işlemlerin sonucunu harita üzerine yansıtabilmektedir. Eylemler sayesinde grafiksel bir katmana çizim yapma mümkündür. Ayrıca katmanlar üzerinde de eylemler tanımlamak mümkündür. Aşağıda bir örnek uygulama linki verilmiştir.

Örnek Uygulama.

Kullanımı:

GraphicsAction

Bu örnek uygulamada kırmızı çizme eylemi bir butona atanmıştır. Butona tıklandığında harita üzerine mouse yardımıyla kırmızı çizgiler çizilebiliyoruz. GraphicsLayer üzerinde çizim işlemi gerçekleşmektedir.

API Version 3.0 içerisindeki eylemler şunlardır: ClearGraphicsAction, MeasureAction, PanToAction, RedlineAction, SpatialQueryAction, ToggleLayerAction, UpdateFeatureLayerAction, ZoomToAction, ZoomToFullExtenAction, ZoomToLayerAction şeklindedir. Api versiyonuna göre yeni eylemler eklenmiş olabilir.

Grafiksel Eylemler (Graphics Actions)

  • RedLineAction: Harita üzerine çizgi çizme eylemini gerçekleştirir.
  • SpatialQueryAction: Mekansal sorguların sonucunu yapıp grafik katmanına çizdirir.
  • ClearGraphicsAction: Bu eylem ile harita üzerinde belirlenen grafik katmanını temizlenir.

Katmansal Eylemler (Layer Actions)

  • ToggleLayerAction: Belirlenen bir katmanın görünebilirliğini değiştirir.
  • UpdateFeatureLayerAction: Belirlenen FeatureLayer katmanını günceller.
  • ZoomToLayerAction: Belirlenen bir katmana yakınlaştırır.

Araçlar (Utility Action)

  • MeasureAction: Harita üzerinde ölçüm işlemlerini yapmak için bu araç kullanılır. Uzunluk, alan, dairesel yarıçap gibi ölçümler yapmak mümkündür.

Navigasyonel Eylemler (NavigationActions)

  • PanToAction: Haritada belirlenen bir geometrinin olduğu yere haritayı hizalar.
  • ZoomToAction: Haritada belirlenen bir geometriye veya koordinatı yakınlaştırır.
  • ZoomToFullExtent: Haritanın tamamının görüntüsünü verir.

Renk Tabanlı Unit Test Süreci ve Örnek Uygulama

25 Oca

Renklerle ilgili işlemler yapmak, component’lerin renk tabanlı özelliklerini değiştirmek, yazılım geliştirme sürecinde uyguladığımız basit operasyonlardır. Bu kez reklerle ilgili işlemlerin unit test mantığı kullanılarak nasıl gerçekleştirilebileceği incelemeye çalışacağız. Aslında yapacağımız işlem basit olarak bir ana renge ait değişik renk tonlarının oluşturulması şeklinde ilerleyecek. Örneğin “kırmızı” renge ait “N” adet renk tonunu unit test ile oluşturmaya çalışacağız. Daha sonra oluşturulan bu renk tonlarını bir WPF uygulaması içerisinde uygulayacağız. Senaryomuzu basitçe sunduktan sonra işleyişe geçebiliriz. Ortaya çıkan ürün aşağıdaki gibi olacaktır.

colorUnitTest2

Sürecimiz önce testlerin yazılıp daha sonra geçen testlerden kod üretimi şeklinde gelişmektedir. Bunun için öncelikle Visual Studio üzerinde “ColorManager” isimli bir proje başlatarak ilerleyelim.

colorUnitTest1

Devamında “ColorManager.Tests” adında bir proje daha ekleyerek test sürecinin işletileceği bir proje başlatıyoruz.

Bu uygulama için kullanılan Unit Test aracı, Nunit test aracıdır. Nuget Package Manager üzerinden eklenebilen bir referanstır.

İlk testlerimizi aşağıdaki geibi geliştirmeye başlayabiliriz.

[Test]
public void Create_WithClassSize1_ReturnsOneColorInList()
{
      var inputColor = Colors.Red;
      var inputSize = 1;

      ColorToneCreator creator = new ColorToneCreator();

      var result = creator.Create(inputColor, inputSize);

      Assert.AreEqual(1, result.Count);
}

İlk testimizde inputSize olarak yani kaç çeşit renk tonu oluşturulacağını 1 olarak belirleyip, bize dönen listede 1 adet renk tonu oluştuğunu idda ediyoruz.

[Test]
public void Create_WithClassSize1_ReturnsSameColorInList()
{
    var inputColor = Colors.Red;
    var inputSize = 1;

    ColorToneCreator creator = new ColorToneCreator();

    var result = creator.Create(inputColor, inputSize);

    Color color = result[0];

    Assert.AreEqual(255, color.R);
    Assert.AreEqual(0, color.G);
    Assert.AreEqual(0, color.B);

}

İkinci testimizde ise yine 1 çeşit renk tonuna karşılık oluşan rengin RGB değerlerinin ne olacağını idda ediyoruz. Kırmızı rengi gönderdiğimiz için R=255, G=0, B=0 olarak bize geri dönecektir.

[Test]
public void Create_WithClassSize2_ReturnsColorsInList()
{
     var inputColor = Colors.Red;
     var inputSize = 2;

     ColorToneCreator creator = new ColorToneCreator();

     var result = creator.Create(inputColor, inputSize);

     Color color = result[0];

     Assert.AreEqual(255, color.R);
     Assert.AreEqual(0, color.G);
     Assert.AreEqual(0, color.B);

     Color color2 = result[1];

     Assert.AreEqual(255, color2.R);
     Assert.AreEqual(127, color2.G);
     Assert.AreEqual(127, color2.B);
}

Üçüncü testimizde ise kırmızı renge ait iki farklı ton seçeneğini test ediyoruz. Ortaya çıkan iki renkten birincisi için RGB değerleri R=255, G=0, B=0 şeklinde iken ikincisi için R=255, G=127, B=127 şeklinde olacaktır. En yüksek değer 255 olduğundan eşit dağılım olması açısından 255 değeri renk tonu sayısına bölünerek değerler hesaplanmaktadır.

Buraya kadar gelişen test sürecinden üretilen kod ise şu şeklide olacaktır.

public class ColorToneCreator
{
     public List<Color> Create(Color inputColor, int inputSize)
     {
          int rgbFactor = 0;
          int incFactor = 255 / inputSize;

          List<Color> tones = new List<Color>();

          for (int i = 0; i < inputSize; i++)
          {
             byte r = (byte)(inputColor.R + rgbFactor > 255 ? 255 : inputColor.R + rgbFactor);
             byte g = (byte)(inputColor.G + rgbFactor > 255 ? 255 : inputColor.G + rgbFactor);
             byte b = (byte)(inputColor.B + rgbFactor > 255 ? 255 : inputColor.B + rgbFactor);

             tones.Add(Color.FromArgb(255, r, g, b));
             rgbFactor += incFactor;
          }

          return tones;
     }

}

Test sürecinden gelişen üretim kodu bu şeklide oluştuğuna göre artık geriye sadece bu kodu bir uygulama içerisinde kullanmak kallıyor.

Bu kodun kullanılacağı uygulamayı ise WPF uygulaması olarak seçiyoruz. Solution penceremize ColorManagerGUI adında yeni bir WPF projesi ekleyerek devam edebiliriz.

colorUnitTest3

Yeni solution penceresi yukarıdaki şeklinde olacaktır. WPF uygulaması MVVM deseni ile geliştirilmiştir. MainWindow.xaml view penceresinin DataContext’i için MainWindowModel şeklinde bir model sınıfı oluşturulmuştur. Bu sayede kod tarafı ile xaml tarafı birbirinden ayrılmış oldu.

Görüntü katmanında gelişen olaylar, form tasarımı ve bir butona tıklayarak parametrelerin, ColorManager tipine gönderilmesi şeklinde gelişmektedir. Aynı şekilde dönen rek tonları da formda bir ListBox içerisine yerleştirilmektedir.

Uygulamanın kaynak kodlarını ekte sunulmaktadır. Bu yüzden görüntü katmanını uzun uzun anlatmaya gerek duymadım. Zaten burada asıl vurgulanmak istenen, renk tabanlı bir uygulamanın test güdümlü olarak nasıl geliştirildiğidir.

Anafikir:

Bu örnek uygulamada renk tabanlı test güdümlü bir süreç işletilmiştir. Bu yöntemden yola çıkılarak görüntü işleme uygulamaları da test güdümlü olarak gelişitirilebilir. Bellek üzerine döşenmiş bir Bitmap nesnesi üzerinden de RGB tabanlı olarak test güdümlü geliştirmeler yapmak mümkün hale gelmektedir.

Örnek Uygulama:

Kodlara buradan ulaşabilrisiniz.

async/await ile Asenkron Programlama

22 Oca

Asenkron işlmeler

Asenkron çalışma prensibi, yürütülen süreçlerin uzun sürmesinden dolayı, yürütülmesi gereken diğer süreçlerin beklemeden çalışmasına devam edebilmesi için geliştirilmiştir. Bazen wab ortamındaki bir kaynağa erişip istekte bulunmak ve cevap almak uzun sürebilmektedir. Senkron çalışma prensibinde örneğin bir web kaynağından cevap gelene kadar sıradaki işlem yürütülmez.  Ancak asenkron süreçlerde uzun sürebilecek işlemler farklı bir görev olarak tanımlanarak çalıştırılır ve sıradaki işleme geçilir. Böylece uzun süren işlemler arka planda farklı görevler olarak çalışmaya devam eder.

Asenkron progamlama genellikle Windows Forms, WPF ve Silverlgiht gibi uygulamalarda, uzun süren işlemlerde form arayüzlerinin kullanıcıya cevap verememesi gibi sorunların çözümü için kullanılabilir. Grafik arayüzlü(UI) uygulamalarda tüm grafiksel işlemler tek bir thread üzerinden yürütülür. Örneğin veritabanından yüklüce bir veriyi çekip Datagrid gibi bir nesneye yüklemeye çalıştığımızda thread önce veriyi almalıdır ki aynı thread daha sonra aldığı veriyi Datagrid nesnesine bağlayabilsin. Tabi bu süre içerisinde Formu sürüklemek yada Form üzerindeki diğer bileşenlere ulaşmak da engellenmiştir.

Diğer taraftan dosya işlemleri, resim işlemleri, WCF, soket uygulamaları gibi işlemler de asenkron süreçlerin işletilmesine ihtiyaç duyulabilecek işlemlerdir.

.Net Framework 4.5 öncesinde asenkron API’leri şu sırayla gelişmiştir:

  1. Asynchronous Programming Model (APM)
  2. Event based Asynchronous Pattern(EAP)
  3. Task Parallel Library(TPL) tabanlı, Task-based Asynchronous Pattern(TAP).

Bu yazıda üzerinde durduğumuz konu da TAP modeli ile asenkron programlama seçeneğidir.

TAP modeli ile asenkron programlamanın tam merkezine oturmuş olan “async” ve “await” anahtar kelimelerini inceleyerek devam edelim. Bu iki sihirli kelime, senkron çalışan bir süreci asenkron hale çevirebilmek için kullanılırlar.

Anahtar kelimelerin (async/await) kullanımı

“async” anahtar kelimesi, kullanıldığı metod içerisinde “await” anahtar kelimesinin etkinleştirilmesi  için kullanılır. “async” anahtar kelimesinin kullnaılmadığı metodlarda “await” anahtar kelimesi çalışmaz. Yani “async” anahtar kelimesinin kullanıldığı metodu asenkron hale çeviren bir sihiri yoktur.

Async kullanılan metodlar tıpkı diğer metodlar gibi çalıştırılır. Her hangi bir farkı yoktur. Ta ki derleyici “await” ile karşılaşana kadar işlemler senkron olarak işletilir. İşlemler Thread pool içerisinde bir thread ile yürütülür. “async” ve “await” kelimelerinin kullanımı aşağıdaki gibidir.

private async void download(string url)
{
    var down = await Downloader.DownloadString(url);
}

Yeri gelmişken Thread akışını şu şekilde inceleyebiliriz.

Main metod ve download metodu içerisinde “await” kelimesine kadar olan işlemler Thread 1 ile gerçekleştirilmektedir. “await” kelimesinden sonra işlemler Thread Pool içerisinden başka bir thread olan Thread 3 ile yürütülmüştür.

“await” kelimesinin kullanıldığı yerdeki işlem asenkron şekilde yürütülür. “await” kelimesi matematiksel operatorler gibi düşünülebilir. “await” anahtar kelimesi sadece await edilebilir metodlar ile kullanılabilir. Her metodun önüne “await” klimesini kullanamayız, sadece await için uygun metodlar için bu kelimeyi kullanabiliriz.

Yukarıdaki örnekte System.Threading.Tasks.Task tipine ait Run metodu (awaitable) şeklinde düzenlenmiştir. Artık DownloadStringTaskAsync metodu “await” anahtar kelimesi ile kullanılabilir.

Asenkron metodlar için Unit Test

Yukarıda yazılan örnek metod için bir de unit test yazacak olursak.

Eğer “async/await” kelimelerini unit testler yazarken de kullanmalıyız. Aksi taktirde compailer, Downloader.DownloadString() metodu için bir awaitable Task tipi döndüreceğinden metodumuz testten geçemeyecektir.

Bu yazıda kullanılan örnek kodları barındıran uygulamaya SkyDrive üzerinden bu linkten ulaşabilirsiniz.

Tekrar görüşmek dileğiyle.

Testin Gücü

2 Oca

Bu yazıda, Test Driven Development (TDD) ile proje geliştirmenin faydalarından bahsetmeye çalışacağım.

Aşağıdaki resimde bir web projesine ait test sonuçlarını görmekteyiz. Bu test sonuçlarına göre 310 adet test başarılı bir şeklide sonuca ulaşmış(passed) durumda. Testlerin toplam süresi ise sadece 9 saniye.

TestExplorer

Hazırladığım bu proje bir Asp.Net MVC projesidir ve tamamen test edilmeye uygun ve gelişime açık bir şekilde yazılmıştır. Yani  Open Closed prensibine uyulmuştur.

Bu şeklide proje hazırlamanın bize ne gibi faydası olabilir?

Projemizi hiç çalıştırmadan ve web arayüzü oluşturmadan, proje iskeletinin nasıl çalıştığını görebilmekteyiz. Örneğin elimizde hiç web formu bile yokken bir ürün ekleme sınıfının POST ile gelen ürünleri veritabanına ekleyip ekleyemediğini anlayabilmekteyiz. Ekleme, silme güncelleme işlemlerini yapan controller sınıflarını ve action metodlarını, view sayfalarına ihtiyaç duymadan test edebilmekteyiz. Bu sayede iş katmanını tasarım katmanından rahat bir şekilde ayırabilmekteyiz.

Bir diğer önemli özellik ise mocking diye adlandırılan taklit edilmiş nesnelerle çalışabilmektir. Gerçek verilerin veritabanından alınıp test edilmesi biraz uzun bir süreç olabilir. Veritabanınız uzakta olabilir. Ya da test makinesinden erişime kapalı olabilir. Bu gibi durumlarda, veritabanı tablolarını, kendi oluşturduğumuz nesnelerle temsil ederek çalışmak zorunda kalırız. Kendi hazırladığımız nesneleri, veritabanından geliyormuş gibi controller sınıflarına gönderebiliriz. Bu sayede çok hızlı bir sonuç alabiliriz. Test sırasında yüzlerce metodun veritabanı bağlantısını açıp, veri alıp sonra bağlantı kapattığını düşünecek olursak, test süresinin dakikalar alabilieceğini öngörebiliriz. Oysa yukarıdaki test sonucunda taklit (mock) nesneler kullanarak test sonucunun saniyelere indiğini görebilmekteyiz.

CodeCoverage2

TDD yaklaşımı sayesinde hiç teste girmemiş kodumuz olup olmadığını görebilmekteyiz. Hatta bir metodun içerisindeki bir sınamanın bile testten geçip geçmediğini anlayabilmekteyiz. Yukarıdaki resimde Controller sınıflarına ait kod kapsam(code coerage) bilgileri yer almaktadır. Amaç %100 kod kapsamını yakalamaktır. Eğer yakalayamıyorsak, kodlarımızda ya teste uymayan bir mimari vardır ya da testten geçirmeyi unuttuğumuz testler vardır. Yukarıdaki tabloda Not Covered (%Blocks) sütununun sıfırlanırken, Covered(%Blocks) sütunun 100’e çıkarıldığını görüyoruz. Hedefe tam anlamıyla ulaşmış bulunuyoruz.

Umarım TDD adına faydalı bir yazı olmuştur. Bir sonraki yazıda görüşmek dileğiyle.

2012 arkamızda 2013 önümüzde

1 Oca

2012’nin sona erdiği ve koca bir yeni yılın başladığı bir gündeyiz. 2012 yılını tamamen özetlemek yerine bazı önemli noktaları not ederek devam etmek istiyorum.

2012 yılı başlarında kurumumuzda, üzerinde çalıştığımız proje(IKABIS) hakkında hazırlıklara başladık. Genel olarak planlamalar ve hazırlıkların ardından veri hazırlama işlemlerinin tamamlanmasıyla birlikte versiyon 1.0 hayata merhaba dedi.

Bir yandan da kendi MVC projem olan nakliyenoktası start alıyor. Bu proje, tamamen MVC geliştirme yapısını incelemek ve detaylarını uygulamak adına başladığım bir projeydi. Kodlama ve test süreçleri başlıyor. Bir yandan da başımın belası olan tasarım ile uğraşıyorum derken proje 2012 ortalarında başarıyla hayata geçiyor.

2012 yıl sonuna doğru IKABIS versiyon 2.0 tamamlanmak üzere. Bir önceki vesiyona göre, tasarım, kodlama şekli ve geliştirme süreci tamamen değişmiş durumda.

2011 ve 2012 yılında, benim için yazılım tarafında önemli gelişmelerden biri şelale tarzı programlama tekniklerinden Test Driven Development (TDD) ile programlamaya geçiş yapmam oldu. Önümüzdeki aylardaki yazılarımı da TDD üzerine planlamak istiyorum.

2012 yılı evliliğimin ikinci yılıydı. Teknolojik bir insan sürekli yenilikleri takip etmek zorunda olduğundan eşler açısından pek hoş karşılanmaz ancak sağolsun eşim bu konuda bana hep destek olmuştur. Çalışmalarımda her zaman beni destekleyen eşime ve hep arkamızda olan anneme teşekkürlerimi sunuyorum ve onlara nice sağlıklı uzun ömürler diliyorum.

Artık 2013 yılının planlarını yapma zamanı. Hem mesleğim adına hem de sosyal hayatım adına planlar yapma vakti.

Herkese 2013 yılının başarılı ve sağlıklı geçmesini diliyorum. Herşey istediğiniz gibi olsun (istekleri abartmadan :)).