Jun 11 2010

Java Dergisi Yayında!

Tag: GenelM. Cihat Altuntaş @ 3:37 pm

Özcan Hocanın öncülük etmesiyle türkiyenin ilk Java Dergisi bayilerde yerini almış bulunuyor tükenmeden kapışın derim :) Gerçekten kaliteli bir içeriğe ve tamamen gönüllülük usülü ile çıkarılan derginin çok başarılı olacağına inanıyorum.
Bu benim içinde bir ilk olmuş oldu çünkü ilk defa bir yazım dergide yayımlandı. İçerisinde acizane çok sevmesem de bir adet Singleton Design Pattern yazım bulunmaktadır:) Neden sevmediğimi dergiden öğrenebilirsiniz.(Okuyucuyu teşvik edelim :) ) Ben daha elime alamadım fakat en kısa zamanda almayı düşünüyorum. Umarım herkes için oldukça faydalı bir dergi olur. Başta Özcan Hoca olmak üzere emeği geçen herkese teşekkür ederim…


May 23 2010

DynaTrace Ajax, Javascript Performans Test Aracı

Tag: Javascript,ToolsM. Cihat Altuntaş @ 9:53 am

High Performance Web Sites kitabının ilk bölümünü okurken aşağıdaki paragrafı okurken yüzüme okkalı bir tokat yemiş gibi hissetmiştim açıkçası.

Most of my web career has been spent as a backend engineer.As such, I dutifully approached each performance project as an exercise in backend optimization, concentrating on compiler options, database indexes, memory management, etc.There’s a lot of attention and many books devoted to optimizing performance in these areas, so that’s where most people spend time looking for improvements.In reality, for most web pages, less than 10–20% of the end user response time is spent getting the HTML document from the web server to the browser.If you want to dramatically reduce the response times of your web pages, you have to focus on the other 80–90% of the end user experience.

Yazar Web sitelerinde harcanan çoğu zamanın aşırı derece kötü performansa sahip değilse Database,Server tarafındaki işlemler,kodlar.. tarafından değil html’in serverdan alındıktan sonra yapılan işlemler tarafından tüketildiğini söylüyordu. Tabi benimde yazar gibi ağırlıklı tecrübem back-end olduğundan bu gerçek beni şaşırtmıştı diyebilirim. Fakat çalıştığım projede bunu yaşayarak doğrulamış olduk.

Html kodunun server tarafından alındıktan sonra browser tarafında işlerden fazla zaman alan şeylerden biride Javascript kodunun yüklenmesi,çalıştırılması.. olduğu için Javascript optimizasyonu ve performans testi daha da önem kazanıyor.Bu konuda bana oldukça yardımcı olan araçlardan biri olan DynaTrace Ajax yazılımından bahsetmeden geçersem hakkını yemiş olurum diye düşündüm. Yazılımın bedava versiyonu mevcut bende bu versiyonu kullandım ve oldukça faydalandım diyebilirim. Özellikle Javascript performans sıkıntılarının belirlenmesinde oldukça yardımcı oldu. Programın şuanda sadece Internet Explorer’a entegre olarak çalışıyor fakat bir sonraki versiyonunda Firefox desteğinin de geleceğini duyurdular. Programın kullanımı oldukça basit ve sitesinde yeride kadar kullanım dökümanı bulunuyor bu yüzden kapsamlı olarak programın nasıl kullanılacağını anlatmayacağım. Programda "Hot Spots" kısmında sayfanızın yüklenirken en çok zaman harcadığı şeyleri görebiliyorsunuz ya da özet kısmında işlemlerin ne kadarının server tarafında ne kadarının client tarafında harcandığını ve bunların kaçının CSS,Resim,Javascript olduğunu grafiksel olarak size kapsamlı şekilde gösteriyor. Aşağıda kendi geliştirdiğim bir projedeki "Hot Spots" kısmından aldığım performans göstergesini görebilirsiniz.

hotspots

Resimde gördüğünüz gibi en fazla zamanı nelerin aldığını gösteriyor. Aşağıda da InitMovieWicket fonksiyonu oldukça vakit almış bunuda bu resmi alırken farkettim bu metodu biraz optimize etmek gerekebilir. :)


May 15 2010

Javascript’in Balyozu Eval ve Array Notasyonu

Tag: GenelM. Cihat Altuntaş @ 1:29 pm

balyoz

Javascript programlama dili içerisinde eval fonksiyonu genellikle dinamik kod çalıştırmak için kullanılıyor. Örnek olarak server tarafından dönen bir JSON formatındaki nesneyi eval fonksiyonu ile Javascript nesnesine kolaylıkla dönüştürebiliriz.

Bunun dışında Javascript kodlarına baktığımda içerisinde eval gördüğüm yerlerin çoğunda kullanım yanlışlığı var ve bunun sebebi Javascript dilini iyi bilmemekten kaynaklanıyor. Eval’in yanlış kullanımına dair sıkça gördüğüm durumlardan bir tanesi şöyle oluyor.Örneğin bir nesnenin bir özelliğinde formu kayıt ederken çalıştırılacak fonksiyon ismi tutuluyor.

var form ={
	name :'Save',
	url : '/Form/Save',
	validation_function :'validateForm':
}
function save(form,element){
    eval(form.validate_function+'(element)');
    //....diger islemler
}

Yukarıdaki kodda formu kayıt ederken nesnenin özelliği olan hangi validasyon fonksiyonuna gireciğini kullanıp bu fonksiyonu çalıştırmak.Bu fonksiyon her nesne için farkı olabileceği için burada sabit bir fonksiyon çağıramıyoruz. Yani yapmak istediğimiz aslında dinamik olarak belirlenen bir fonksiyonu çalıştırmak bunu da yukarıdaki gibi eval kullanarak kodu çalıştırdığımızda Script Engine dinamik kodu tekrar derleyip belleğe yükledikten sonra çalıştırmaktadır. Bu da performans bakımından oldukça masraflı bir işlemdir.Kısacası balyoz ile sinek öldürmek diyebiliriz yani:) Bu yüzden gerçekten gerekmedikçe eval funksiyonundan kaçınmak Javascript performansı için oldukça faydalı olacaktır.

Peki yukarıdaki kodu eval kullanmadan nasıl yazabilirdik? Çok basit Javascript dilinde aşağıdaki iki ifade aynı şeyi yapar.

    nesne.method();
    nesne['method']();

Javascript içerisindeki fonksiyonlara yada nesnenin özelliklerine “.(dot)” notasyonu dışında “[](array)” notasyonu ile de ulaşabilirsiniz. Bunun dışında bilmemiz gereken birşey daha var; tanımlanan bütün fonksiyonlar global window nesnesine aitdir.Yani aşağıdaki 3 satır kod da aynı şeyi yapar

    function taklaAt(){
        //takla at...
    }

    //aynı seyi yapan satirlar
    taklaAt();
    window.taklaAt();
    window[taklaAt]();

Bu bilgileri de öğrendikten sonra ilk kodumuzu aşağıdaki gibi yazabiliriz.

var form ={
	name :'Save',
	url : '/Form/Save',
	validation_function :'validateForm':
}
function save(form,element){
    window[validation_function](element);
    //....diger islemler
}

Yukarıda ne yaptık? Window nesnesine ait olan dinamik fonksiyonumuzu array yani [] ile çağırdık.Javascript gibi performansın gerçekten önemli olduğu bir dilde yukarıdaki yaptığımız işlem oldukça iyi performans kazancı sağlayacaktır. Ayrıca debug ederken eval ile çağırılan fonksiyonların debug edilmesi normallerine göre daha zor olduğu için eval kullandığınız heryeri gözden geçirmenizde fayda olabilir.

Boşuna Eval is Evil dememişler :)


May 03 2010

NHibernate Enum mapping ve kaybolan saatler

Tag: NhibernateM. Cihat Altuntaş @ 4:13 pm

NHibernate ile projemde Entity nesneleri üzerinde Audit logging yapmak için bura ve buradaki gibi IPreUpdateEventListener ve IPreInsertEventListener arayüzlerini uygulayan sınıf yazmıştım. Buraya kadar herşey normal gidiyordu. Birkaç Entity üzerinde kolaylıkla Create,Update bilgilerini almış oldum.

Aşağıdaki gibi User ve Movie nesnelerimi map ettim.

 public class User
 {
        private IList<Movie> movies = new List<Movie>();

	//diger kodlar

	public void AddMovie(Movie movie)
	{
		//add movie
	}

 }

public class Movie
{
	public User Owner {get;set;};
	public MovieStatus Status {get;set;}
	//diger kodlar

}
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Domain" assembly="Domain">
  <class name="User,Domain" table="Users">
    <id name="UserID" column="UserId" type="Guid">
      <generator class="guid.comb" >
      </generator>
    </id>

    <bag name="Movies" generic="true" inverse="true" cascade="save-update">
      <key column="UserID"></key>
      <one-to-many class="Movie,Domain"/>
    </bag>
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Domain" namespace="Domain">
  <class name="Domain.Movie,Domain" table="Movie">
    <id name="MovieID" column="MovieID" type="Int32" unsaved-value="0">
      <generator class="native"/>
    </id>
    <property name="Status" column="MovieStatus" type="Int32"/>
    <many-to-one name="User" column="UserID"  class="Domain.User"/>
  </class>
</hibernate-mapping>

Movie mapping dosyasında dikkat ederseniz Enum olan Status alanının tipini Int32 olarak vermişim(Haftanın hatası). Tabi bunun için NHibernate’i suçlamamak lazım. Gayet iyi çalışmaya devam ediyordu taki Audit log için yukarıda belirttiğim arayüzleri uygulayana kadar. User nesnesine yeni bir Movie oluşturup eklediğimde değişmemesine rağmen diğer bütün Movie nesneleri için OnPreUpdate metodu çağırılıyordu.

Tabi bir anlam vermediğimden dolayı her yolu denedim diyebilirim. Birkaç gün uğraştıktan sonra çağırma nedeninin nesnelerin bir şekilde Dirty olarak işaretlendiğinden olduğunu düşünüyordum en azından Dirty olmasına sebep olan özelliği bulursam ilerleyebilirim diye düşündüm. Ardından hayat kurtaran Persister.FindDirty metodunu buldum.

Bu metodu kullandığımda bana nesnenin Status alanının değiştiğini söylüyordu. Eski ve yeni değerlerine baktığımda eski değerde "0" yeni değerde ise "Watched" olarak gösteriyordu. Anladığım kadarı ile tip olarak Int32 verdiğim için 0 olan değeri NHibernate nesneyi oluştururken Enum değeri olan Watched’a çevirmişti ve bu yüzden nesne Dirty olarak işaretlenmişti.Sorun Status alanının Int32 tipini kaldırdığımda ortadan kalktı. Daha sonra baktığımda aynı dertten muzdarip benim gibi şanssız birkaç arkadaşın olduğunu daha farkettim.

Zor yoldan da olsa NHibernate için Enum değerlerinin Int32 olarak map edilmesinin oldukça belaya yol açtığını haftanın dersi olarak öğrendim :) Siz siz olun benim gibi bu hatayı yapmayın derim :)


Apr 17 2010

Javascript Kaynak Kitaplar

Tag: Javascript,KitaplarM. Cihat Altuntaş @ 3:50 am

Dün mail ile bir arkadaş Javascript için önerebileceğim kitapları sormuştu. Bende Javascript öğrenirken kullandığım kaynakları aşağıya yazayım başkaları içinde belki faydalı olabilir diye düşündüm. Bana en çok yararlı olan kaynaklar :

İlk kitap Yahoo’da front-end engineer olarak çalışan Nicholas C. Zakas tarafından yazılmış oldukça iyi bir Javascript kitabı. Kitapta Javascript dili,Object Oriented Javascript,DOM,BOM,Ajax,XML.. gibi neredeyle genel olarak birçok konuya değinmiş. Kitabın sonundaki Best Practices kısmını oldukça beğendiğimi söyleyebilirim. Kitabı daha çok referans kitabı olarak kullanıyorum.

ikinci kitap JSON mucidi yine bir Yahoo çalışanı olan Javascript dünyasının efsanesi Douglas Crockford tarafından yazılmış sadece Javascript dilini anlatan bir kitap. Kitap yaklaşık olarak 200 sayfa civarında kısa olduğuna bakmayın birçok bölüm tekrar okumayı gerektiriyor.

Diğer kitap ise bir Twitter çalışanı olan blog’unuda severek takip ettiğim Dustin Diaz tarafından yazılmış. Klasik anlamda Design Pattern’ların Javascript dilinde nasıl kullanılacağını güzel örneklerle anlatmış.  Bu kitabın örneklerini oldukça sevdiğimi söyleyebilirim.

Bunun dışında Yahoo’nun YUI Theater kısmında bulunan videoları şiddetle tavsiye ederim. Özellikle bu sayfada bulunan Douglas Crockford’un Javascript JavaScript Programming Language ve Advanced Javascript serilerini mutkala izleyin. Umarım kitaplar ve videolar yararlı olur…


Apr 13 2010

Javascript Refactoring : Use Constants

Tag: Javascript,RefactoringM. Cihat Altuntaş @ 2:45 pm

Javascript kodlarına bakarsanız etrafta bolca string göreceğinizden eminim. En azından benim eski Javascript kodlarım böyleydi.Daha öncede Java, C# gibi static typed dillerde bunların önüne nasıl geçebileceğimizden bahsetmiştik. Javascript dilinde Constant kavramı olmasa da Object Literal notasyonu kullanarak sabit değişkenler tanımlayabiliriz. Aşağıdaki masum Javascript fonksiyonlarını görüyorsunuz.

function createStatusImage(movie) {
    var img = document.createElement("img");
    if (movie.avaliable)
        img.src = '/Content/Images/watched.gif';
    else
        img.src = '/Content/Images/unwatched.gif';

    return img;
};

function makePlanned(img) {
    img.src = img.src = '/Content/Images/planned.gif';
}

Yukarıdaki kodlar ne kadar masum görünse de, her tarafta string tanımı olduğu için kodda eğer resim yani “Content/Images” dizinini değiştirmek istediğinizde kodun 3 yerinde bu değişikliği yapmak zorundasınız. Bunun yerine Object Litaral ile bir konfigürasyon nesnesi oluşturup kodumuzu aşağıdaki gibi refactor edersek daha okunaklı ve değiştirmesi daha kolay olacaktır.

var ImageConfig = {
    IMAGE_PATH: '/Content/Images/',
    WATCHED_IMAGE: 'watched.gif',
    UNWATCHED_IMAGE: 'unwatched.gif',
    PLANNED_IMAGE: 'planned.gif'
}

function createStatusImage(movie) {
    var img = document.createElement("img");
    if (movie.avaliable)
        img.src = ImageConfig.IMAGE_PATH + ImageConfig.WATCHED_IMAGE;
    else
        img.src = ImageConfig.IMAGE_PATH + ImageConfig.UNWATCHED_IMAGE;

    return img;
};

function makePlanned(img) {
    img.src = img.src = ImageConfig.IMAGE_PATH + ImageConfig.PLANNED_IMAGE;
}

Yukarıdaki tanımlama gerçek anlamda oluşturulduktan sonra değiştirilemiyen “constant” ya da “final” değişkenler sunmasa da fantazi olsun diye birisi ImageConfig nesnesi içeriğini değiştirmez ise bu amaçla kullanılabilir.Bu yüzden eğer takım olarak ortak Javascript dosyaları üzerinde değişiklik yapıyorsanız Code Conversions belirlemeniz faydanıza olacaktır. Sizi bilmiyorum ama ben son halini daha çok sevdim :)


Apr 12 2010

Object Oriented Javascript : Object Literals

Tag: JavascriptM. Cihat Altuntaş @ 4:24 pm

Javascript diğer adıyla The Lingua Franca of the Web,yani Web’in ortak dili. Günümüzde yaygınlaşan Ajax ve Web teknolojileri bu dilin yaygınlaşmasında daha da önemli rol oynuyor. Aslına bakılacak olursa dünyada en yaygın programlama dillerinden biri.Çalışması için browser hariç hiçbir gereksinime ihtiyaç duymayan basit, güçlü, hem object oriented programming hemde functional programming  özelliklerini barındıran son zamanlardaki favori dillerimden biri.

Eğer sizde Web projesi geliştiriyorsanız mutlaka Javascript’e biryerinden bulaşmışsınızdır. Genellikle bu bulaşma benim gibi işimi görecek şeyi yapayımda gerisi önemli değil tarzında olduğunu düşünüyorum.Düz mantık global değişkenler ve bunlar üzerinden işlem yapan fonksiyonlar tanımlayarak ufak tefek işlemizi rahatlıkla görebiliriz. Tabi uygulama büyüdükçe yazdığınız kodun Javascript gibi dinamik ve tip koruması olmayan bir dilde yönetilmesi daha da zorlaşacaktır. Bu yüzden script gözüyle bakmantan vazgeçip Javascript’e ciddi bir dil gibi davranıp genel yazılım mühendisliği prensiplerini uygulamak,test yazmak kodun yönetimini kolaylaştıracak diğer prensipleri uygulamak gereklidir.Bu yüzden kodun yönetimini kolaylaştıracak nesneye yönelik programlama teknikleri Javascript içinde oldukça faydalıdır.

Javascript sanılanın aksine Object Oriented programlamayı destekleyen bir programlama dilidir. Klasik anlamda diğer nesneye yönelik programlama dillerinden farkı ise nesneye yönelik programlamayı sınıf tabanlı (class based) değilde , biraz daha farklı olarak object ve prototype tabanlı olarak desteklemesidir. Javascript’in nesneye yönelik programlama tekniklerini birkaç yazıda anlatmayı planlıyorum bu yüzden bu yazıda en basit olarak nasıl nesne tanımlarız onu bakacağız.

Javascript’de basit olarak bir nesneyi aşağıdaki gibi oluşturabiliriz.

var movie = new Object();
movie.name = "Leon";
movie.year = 1995;
movie.rating = 8.5;
movie.displayInfo = function() {
    alert("Movie : " + this.name + " , "+ this.year);
}

movie.displayInfo();

Yukarıda gördüğünüz gibi basit bir şekilde film nesnesi oluşturup gerekli özelliklerine gerekli değerleri atadık.Gördüğünüz gibi herhangi bir “class” tanımı yok. Javascript dinamik bir dil olduğu için herhangi bir zamanda nesneye özellik atayıp çıkarabiliriz.

Yukarıdaki ile aynı işi yapan nesneyi Object Literal notasyonu ile aşağıdaki gibi de tanımlayabiliriz.

var movie = {
    name : "Leon",
    year : 1995,
    rating : 8.5,
    displayInfo : function() {
        alert("Movie : " + this.name + " , "+ this.year);
    }
}

Yukarıda gördüğünüz gibi aynı nesneyi Object Literal notasyonu ile tanımladık.Bunun JSON formatından tanıdık geldiğini düşünüyorum. Daha kısa olduğunu farketmişsinizdir. Javascript gibi her bir byte’ın önemli olduğu bir dilde kısa olması bizler için daha faydalı olacaktır. Yukarıdaki nesne tanımında dikkat edilecek bir nokta da özellik tanımlamalarıdır.Nesnenin özelliklerini aşağıdaki gibi de atayabilirdik.

var movie = {
    "name" : "Leon",
    "year" : 1995,
    "rating" : 8.5,
    "displayInfo" : function() {
        alert("Movie : " + movie.name + " , "+ movie.year);
    }
}

Yukarıdaki gibi Javascript dilinde özellikleri string içerisinde tanımlayıp daha sonra normal özellik gibi ulaşabilirsiniz.Bunun faydası aşağıdaki gibi nesnelere programatik olarak özellik atayıp ya da ulaşabilirsiniz.Yalnızca Object Literal notasyonu programatik özellik tanımlamayı desteklemez bunu aşağıdaki gibi yapabiliriz.

var number =5;
var movie = {
    "name" : "Leon",
    "year" : 1995,
    "rating" : 8.5,
    "displayInfo" : function() {
        alert("Movie : " + movie.name + " , "+ movie.year);
    }
}
movie["writer"+number]="George.." ;

alert(movie["writer"+number]);

Basit olarak nasıl bir nesneye oluşturabileceğimizi gördük. Javascript’de bir işi yapmanın birden fazla yolu olduğu için diğer yöntemleride ileride değinmeyi planlıyorum. Bunları aklınızda tutun ilerlerikçe işler biraz daha karmaşıklaşacak :)


Mar 16 2010

Eski Kodu Test Etmek : Subclass and Override

Tag: Test Driven DevelopmentM. Cihat Altuntaş @ 7:17 pm

Eğer sıfırdan başlamış bir projede(Green Field) başından beri çalışan şanslı insanlardan değilseniz mutlaka sizden daha önce ve şuanda şirkette olmayan birisinin yazdığı anlaşılamaz kodu değiştirmek zorunda kalmıştırsınız. Benimde başıma sık sık gelen bu tarz durumlarda insan biraz kendini Rus-Ruleti oynar konumunda bulabiliyor. Bir yandan şeytan kodu değiştirip riski göze almanızı söylerken, bir yandan içinizden gelen ses hata yapmamanız için tekrar tekrar kodu kontrol edip hata yapmadığınızdan emin olmanızı söylüyor.

Bu tarz durumlarda eğer değiştireceğiniz kod uygulama açısından kritik bir kod ise onun için Unit Test yazıp kodun şuandaki durumunu test altına alıp ardından değiştirip bir şeyleri bozup bozmadığınızı bu testler ile kontrol etmek gidilmesi gereken en güvenilir yollardan birisi. Tabi bu yöntemde o kadar kolay olmayabiliyor bende her zaman yaptığımı söyleyemem . Dediğim gibi kodu değiştirmek eğer kritik önem taşıyorsa ve risk içeriyorsa elimden geldiğince testle ile kendimi sağlama alıp bu şekilde devam etmeye çalışıyorum.

Bu tarz bir durumda kodu test altına almanın her zaman kolay olmadığını yukarıda belirtmiştim. Çünkü genelde eski kodlar Bağımlılığı oldukça yüksek, testlerden yoksun kodlar olduğu için test altına almak istediğinizde beklemediğiniz engellerle karşılaşabiliyorsunuz.

Aşağıdaki gibi daha önceden yazılmış bizim için kritik önem arzeden ve değiştirmemiz gereken bir kodumuz olduğunu düşünün.

public class PriceCalculator
{
    private Database database;

    public PriceCalculator()
    {
        database =new Database();
    }

    public double CalculateShippingCost(Order order)
    {
        if(order.Total>100)
       {
           return order.Total*GetGoldenOrderTotalRatio();
       }

        if(order.Total> && order.Total<100)
        {
            return order.Total*GetBronzeOrderTotalRatio();
        }

        return order.Total*GetNormalOrderTotalRatio();
    }

    private double GetGoldenOrderTotalRatio()
    {
        return (double)database.ExecuteScalar("SELECT Ratio FROM OrderShippingRatio WHERE Type='Golden'");
    }

    private double GetBronzeOrderTotalRatio()
    {
        return (double)database.ExecuteScalar("SELECT Ratio FROM OrderShippingRatio WHERE Type='Bronze'");
    }

    private double GetNormalOrderTotalRatio()
    {
        return (double)database.ExecuteScalar("SELECT Ratio FROM OrderShippingRatio WHERE Type='Normal'");
    }
}

Yukarıdaki gördüğünüz sınıfın bizim için verilen siperişin ulaştırma maliyetini hesaplayan bir sınıf olduğunu düşünün. Burada gördüğünüz gibi siperiş tutarı eğer 100’den büyük ise belirli bir oranda altın indirim yaparak hesaplıyor, 50 ile 100 arasındaysa belirli oranda bronz indirim yapıp hesaplıyor. Bizden yapmamız istenen bu mantığı değiştirip 50 ile 100 aralığı olan bronz indirim mantığını sipariş tutarı 80 ile 100 arasına çekmek.

Burada kodun çok basit olduğunu unutun ve gerçekten çok daha karmaşık hesaplamaların olduğu bir metodu değiştirmek istediğinizi düşünün. Bunu yapmadan önce dediğim gibi bu konu test altına almak oldukça güvenilir yoldan ilerlemenizi sağlayacaktır. Bu yüzden bende öyle yapıp yukarıdaki kod için aşağıdaki gibi testimi yazmaya başlıyorum.

    [TestFixture]
    public class PriceCalculatorTest
    {
        [Test]
        public void CalculateGoldenOrderShippingCost()
        {
            PriceCalculator calculator =new PriceCalculator();
            Order goldenOrder =new Order();
            goldenOrder.Total = 200;

            Assert.AreEqual(10, calculator.CalculateShippingCost(goldenOrder));
        }

        [Test]
        public void CalculateBronzeOrderShippingCost()
        {
            PriceCalculator calculator = new PriceCalculator();
            Order bronze = new Order();
            bronze.Total = 90;

            Assert.AreEqual(9, calculator.CalculateShippingCost(bronze));
        }

        [Test]
        public void CalculateNormalOrderShippingCost()
        {
            PriceCalculator calculator = new PriceCalculator();
            Order normal = new Order();
            normal.Total = 50;

            Assert.AreEqual(7, calculator.CalculateShippingCost(normal));
        }
    }

Yukarıdaki testlerde 3 durumu da test içerisine alacak test kodunu yazdım. Eğer sipariş tutarı 200 ise nakliye oranının %5 olduğunu düşünüp sonucun 10 olması gerektiğini söylüyorum. Eğer tutarı 90 olan bronz sipariş nakliye oranının %10 ise sonucun 9 olması gerektiğini yazıyorum. Ve son olarak da tutar 50 için nakliye oranı %14 ise sonucun 7 olduğunu test eden kodu yazıyorum. Testleri çalıştırdığımda aşağıdaki gibi bir Unit Test hatası karşıma çıkıyor

PriceCalculatorTest.CalculateNormalOrderShippingCost : …AssertionException: Expected: 7 But was: 950.0d

Sebebine baktığımda ise Database üzerinde kayıtlı olan oranların farklı olduğu görüyorum. Bu yüzden beklediğim sonuçlar çıkmıyor. Burada gidip database içerisinden test için değerleri değiştirmek pek mantıklı olmaz.Test kodunu database’deki değerlere göre değiştirmek de pek doğru değil çünkü testimin database’den bağımsız olmasını istiyorum. Başkasının ben farkında olmadan farklı bir değer girdiğinde testlerimin fail etmesini istemiyorum. Yani kısacası burada kısmen gerçek anlamda kontrolün testlerde olmasını her hangi bir dış etkenden etkilenmemesini istiyorum. Daha önceden yazılmış eski kod için bunu yapmanın yollarından biri Subclass and Override verilen teknik. Bunu ilk defa Working Effectively With Legacy Code kitabından öğrenmiştim.  

Bizim burada kontrol etmek istediğimiz aslında kodun biraz kötü yazılmış olmasında kaynaklanan PriceCalculator sınıfının içerisindeki GetGoldenOrderTotalRatio tarzı metodlar. Çünkü bu metodlar direk olarak Database üzerinde sorgu çalıştırarak testlerimizde kontrolün bizden database tarafındaki değerlere geçmesine sebep oluyor. Eğer bunları kontrol altına alırsak testlerimizde istediğimiz sonuçları elde edebiliriz.

Subclass and Override tekniğini basit olarak test için kontrol etmeniz gereken metodu override ederek test ortamında istediğiniz değerleri dönmesini sağlamak oldukça basit ve faydalı bir yöntem. Bu tekniği kullanarak PriceCalculator sınıfımı aşağıdaki gibi değiştiriyorum.

public class PriceCalculator
{
    //Diğer kodlar.....

    protected virtual double GetGoldenOrderTotalRatio()
    {
        return (double)database.ExecuteScalar("SELECT Ratio FROM OrderShippingRatio WHERE Type='Golden'");
    }

    protected virtual double GetBronzeOrderTotalRatio()
    {
        return (double)database.ExecuteScalar("SELECT Ratio FROM OrderShippingRatio WHERE Type='Bronze'");
    }

    protected virtual double GetNormalOrderTotalRatio()
    {
        return (double)database.ExecuteScalar("SELECT Ratio FROM OrderShippingRatio WHERE Type='Normal'");
    }
}

Gördüğünüz gibi private olaran metodlar protected virtual olarak değiştirdim. Böylece başka bir sınıfı bu sınıftan türetip bu metodları override edebilirim ve istediğim değerleri döndürebilirim. Bu da testlerimde bu metodların database’e çağrı yapmadan benim istediğim değerleri döndürmemi sağlar kısacası kontrol tekrar testlere geçer.Bu arada eğer yukarıdaki kod bir Java kodu olsaydı
Java’nın sevdiğim bir özelliği olan metodlar default olarak virtual olduğu için sadece protected yapmam yeterli olacaktı.Test kodlarımı da aşağıdaki gibi değiştiriyorum.

[TestFixture]
public class PriceCalculatorTest
{
    class TestingPriceCalculator : PriceCalculator
    {
        protected override double GetGoldenOrderTotalRatio()
        {
            return 0.05;
        }

        protected override double GetBronzeOrderTotalRatio()
        {
            return 0.1;
        }

        protected override double GetNormalOrderTotalRatio()
        {
            return 0.12;
        }
    }

    [Test]
    public void CalculateGoldenOrderShippingCost()
    {
        PriceCalculator calculator =new TestingPriceCalculator();
        Order goldenOrder =new Order();
        goldenOrder.Total = 200;

        Assert.AreEqual(10, calculator.CalculateShippingCost(goldenOrder));
    }

    [Test]
    public void CalculateBronzeOrderShippingCost()
    {
        PriceCalculator calculator = new TestingPriceCalculator();
        Order bronze = new Order();
        bronze.Total = 90;

        Assert.AreEqual(9, calculator.CalculateShippingCost(bronze));
    }

    [Test]
    public void CalculateNormalOrderShippingCost()
    {
        PriceCalculator calculator = new TestingPriceCalculator();
        Order normal = new Order();
        normal.Total = 50;

        Assert.AreEqual(6, calculator.CalculateShippingCost(normal));
    }
}

Yukarıdaki test kodlarında gördüğünüz gibi TestingPriceCalculator adından PriceCalculator’dan türeyen bir sınıf oluşturdum ve virtual metodları override ederek istediğim değerlerin dönmesini sağladım. Normalde PriceCalculator olarak test edilen yerleride bu sınıfla değiştirdiğimde test kodlarının istediğim şekilde çalıştığını görüyorum ve testleri çalıştırdığımda geçtiğini görüyorum.

Gördüğünüz gibi varolan kodda çok küçük değişiklikler yaparak kodu Unit test altına aldık. Bu değişiklikler benimde hoşuma gitmesede eski kodlarda kodu test edebilmek için bu tarz değişiklikler yapmak zorunda kalabiliyoruz. Bu kodu başka şekillerde de test edebilirdik bu teknik onlardan sadece biri. Eski kodu test ederken zaman, yapabileceğiniz değişikliklerin kapsamı gibi etkenler oldukça önemlidir. Bu yüzden elinizdeki araçlardan size en uygun olanını seçmek faydanıza olacaktır.


Mar 15 2010

Back-End Developer’ın Front-End Maceraları

Tag: JavascriptM. Cihat Altuntaş @ 5:13 pm

Uzun zamandır gerek iş değişikliği, gerek kişisel projelerden dolayı çok fazla yazma fırsatı bulamadım. Fakat sevindirici tarafı birçok yeni şey öğrendim ve öğrendiklerimi sizlerle paylaşmak beraber öğrenmek, öğretmek için sabırsızlanıyorum.

Gerek yaptığım kişisel projemden gerek işimden dolayı  bolca Javascript ile haşır neşir oluyordum. Bende çoğunlukla benimde herkes gibi yanlış anlaşılan Javascript dilini gerçek anlamda öğrenmeye karar verdim. Açıkçası öğrendikçe daha çok sevdiğimi söyleyebilirim. Benim gibi çoğunlukla Back-End, Server taraflı yazılım geliştiren birisi için oldukça heyecan verici bir yolculuk olduğunu söyleyebilirim. Özellikle klasik anlamda çoğunlukla Java,C# gibi dillerde programlama geliştiren birisi olduğum için Javascript ile Fonksiyonel programlamanın ufkumu açtığını söyleyebilirim.

Bundan sonra Javascript gibi oldukça kolay kontrolden çıkabilen bir dil ile uğraşanlar içinde faydalı olabilecek Object-Oriented Javascript, Javascript Patterns, Performans Optimizasyonu gibi konularda öğrendiklerimi sizlerle paylaşmayı istiyorum. Umarım macerayı sizlerde seversiniz.


Dec 13 2009

Flyweight Pattern ile Performans Optimizasyonu

Tag: Patterns,PrinciplesM. Cihat Altuntaş @ 6:35 pm

Uzun süredir yeni iş, yeni projeler,yine üşengeçlik :) derken bir türlü yazmaya fırsat bulamıyordum sezonu yeniden açtığımızın haberini vermek benim için oldukça sevindirici, umarım sizin içinde öyle olur. Bundan sonra tekrar sık sık yazmaya çalışacağım.

Geçenlerde çalıştığım bir projede sürüm öncesi geliştirdiğimiz yazılımın fazla bellek kullandığını gözlemledik. Daha sonra sorunun nedenini bulmak için Profiler ile bellek kullanımına baktığımızda bazı nesnelerin bellekte çok fazla sayıda olduğunu gördük. Aslında baktığımızda normal bir durumdu çünkü gerçekten o nesnelerin oluşturulması gerekiyordu. Temel olarak bazı işlemleri yapmamız için gerekli nesneleri oluşturan bir sınıfımız vardı.Projede yaptığımız işlem gerçekten çok fazla nesne gerektiriyordu, dolayısıyla bellekte çok fazla nesne oluşturuluyordu.

Profiler sonuçlarını dikkatlice incelediğimizde bir sınıfın nesnenin diğerlerinden çok daha fazla oluşturulduğunu ve bellekte en çok yeri bu nesnenin yer kapladığını gördük. Bu nesnenin adına Key diyelim. Kodun aşağıdaki gibi olduğunu düşünün. Key sınıfı nesnelerimize kategorilerini belirtmek için atanan bir sınıf ve aldığı değerler Golden, Silver, Bronz (Altın,Gümüş, Bronz) şeklindedir. Ve ilk oluşturulduktan sonra dikkat ederseniz değerleri değiştirilemezler. Yani Immutable bir nesnedir.

public class Key {
    private int id;
    private String code;
    private boolean removable;

    public Key(String code, boolean removable) {
        this.code = code;
        this.removable = removable;
    }

    public String getCode() {
        return code;
    }

    public boolean isRemovable() {
        return removable;
    }

    @Override
    public String toString() {
        return "Code : " + code + ", Removable : " + removable;
    }
}
public class BusinessObject {
    private Key key;
    private String name;
    private int number;

    public BusinessObject(Key key, String name, int number) {
        this.key = key;
        this.name = name;
        this.number = number;
    }

    public Key getKey() {
        return key;
    }

    public String getName() {
        return name;
    }

    public int getNumber() {
        return number;
    }
}
public class ObjectCreator {
    public List createObjects(){
        List businessObjects=new ArrayList();
        for (int i=0;i<500000;i++){
            if(isGolden(i)){
                Key goldenKey =new Key("Golden",true);
                BusinessObject bo =new BusinessObject(goldenKey, "Name : "+i, i);
                businessObjects.add(bo);
            }else if(isSilver(i)){
                Key silverKey =new Key("Silver",true);
                BusinessObject bo =new BusinessObject(silverKey, "Name : "+i, i);
                businessObjects.add(bo);
            }else if(isBronze(i)){
                Key bronzeKey =new Key("Bronze",true);
                BusinessObject bo =new BusinessObject(bronzeKey, "Name : "+i, i);
                businessObjects.add(bo);
            }else{
                Key emptyKey =new Key("",false);
                BusinessObject bo =new BusinessObject(emptyKey, "Name : "+i, i);
                businessObjects.add(bo);
            }
        }
        return businessObjects;
    }

    private boolean isBronze(int i) {
        return (i % 7) == 0;
    }

    private boolean isGolden(int i) {
        return (i % 3) == 0;
    }

    private boolean isSilver(int i) {
        return (i % 5) == 0;
    }
}
public class Main {
    public static void main(String[] args) {
        ObjectCreator objectCreator =new ObjectCreator();
        List businessObjects =objectCreator.createObjects();
    }
}

Yukarıdaki kodda gördüğünüz gibi, Processor sınıfı BusinessObject nesnelerimizi oluşturuyor. Bunu yaparken belirli kriterlere göre hangi Key sınıfının oluşturulacağını belirleyip BusinessObject sınıfına atama yapıyor. Yukarıda çok fazla nesne oluşturmayı temsil etmek için 1′den 500.000′e kadar bir döngü içerisinde bu nesneleri oluşturdum.Yukarıdaki kodu Profiler çalıştırarak bellek kullanımını gözlemlediğimde aşağıdaki gibi bir sonuç çıkıyor karşıma.

ProfilerResults1

Yukarıdaki grafikte gördüğünüz gibi 500.000 adet Key nesnesi oluşturulmuş ve bu oluşturulmuş nesneler bellekte yaklaşık olarak 1.2 mb yer kaplamaktadır. Gerçekte projede kullanılan nesne Key nesnesinden çok daha büyük olduğu için kapladığı bellek miktarı çok daha fazlaydı. Şimdi bu problemi Flyweight Pattern kullanarak nasıl çözdük, kullanılan bellek miktarını nasıl düşürdük ona geçelim.

Flyweight Pattern genellikle bellek performans optimizasyonunda kullanılan basit bir Design Pattern’dır. Gereksiz performans optimizasyonu için neler düşündüğümü daha önceden bu yazıda belirtmiştim.Bu yüzden gerçekten gerekmedikçe yapılmasını tavsiye etmem dolayısıyla bunu tasarım kalıbını kullanırken aklınızın bir köşesinde tutmaya çalışın.

Peki Flyweight Pattern nasıl bellek kullanımını optimize eder? Bunu uygulamada aynı özellikleri taşıyan nesneleri ya da nesnelerin parçalarını tekrar tekrar oluşturmak yerine onlardan birer tane oluşturup paylaşarak yapar.Genellikle paylaşılması gereken nesneleri bir defa oluşturur Cache ya da static bir Dictionary,HashMap tarzı bir nesnede saklar ve istendiğinde daha önceden oluşturulmuş nesneyi kullanıcıya verir.

Yani yukarıdaki örneği düşünecek olursak,BusinessObject nesnemiz 500.000 defa oluşturulmak zorunda çünkü herbiri farklı ve farklı şeyleri temsil ediyor fakat Key nesnemiz aslında uygulamamızda 4 adet değer ile oluşturuluyor. Bunlar Golden,Silver,Bronze ve boş olanı temsil eden Empty değerleri. Fakat biz bu nesneyi yukarıdaki kodda ve grafikte gördüğünüz gibi 500.000 defa oluşturuyoruz. Dolayısıyla bellekte 500.000 adet kadar yer kaplıyor. Flyweight Pattern kullanarak tekrar tekrar aynı değerleri içeren Key nesnelerimizden sadece gerektiği kadar oluşturacağız yani 4 adet. Bunu da aşağıdaki şekilde yapabiliriz.

Öncelikle yukarıdaki koda biraz Refactoring yapalım. İlk olarak  Processor sınıfı içerisinde nesneleri oluşturan kodu bu asıl amacı bu işi yapmak olan bir Factory sınıfına taşıyalım. Yani KeyFactory adında bir sınıfa Key nesneleri oluşturulması sorumluluğunu yükleyelim.

public class KeyFactory {
    private static Map keyMap = new HashMap();

    public static Key create(int i) {
        if (isGolden(i)) {
            if (keyMap.containsKey("Golden")) {
                return keyMap.get("Golden");
            } else {
                Key goldenKey = new Key("Golden", true);
                keyMap.put("Golden", goldenKey);
                return goldenKey;
            }

        } else if (isSilver(i)) {
            if (keyMap.containsKey("Silver")) {
                return keyMap.get("Silver");
            } else {
                Key silverKey = new Key("Silver", true);
                keyMap.put("Silver", silverKey);
                return silverKey;
            }
        } else if (isBronze(i)) {
            if (keyMap.containsKey("Bronze")) {
                return keyMap.get("Bronze");
            } else {
                Key bronzeKey = new Key("Bronze", true);
                keyMap.put("Bronze", bronzeKey);
                return bronzeKey;
            }
        } else {
            if (keyMap.containsKey("Empty")) {
                return keyMap.get("Empty");
            } else {
                Key emptyKey = new Key("", true);
                keyMap.put("Empty", emptyKey);
                return emptyKey;
            }
        }
    }

    private static boolean isBronze(int i) {
        return (i % 7) == 0;
    }

    private static boolean isGolden(int i) {
        return (i % 3) == 0;
    }

    private static boolean isSilver(int i) {
        return (i % 5) == 0;
    }
}
public class ObjectCreator {
    public List createObjects(){
        List businessObjects=new ArrayList();
        for (int i=0;i<500000;i++){
           BusinessObject bo =new BusinessObject(KeyFactory.create(i), "Name : "+i, i);
           businessObjects.add(bo);
        }
        return businessObjects;
    }
}

KeyFactory sınıfına bakacak olursanız. Nesneyi oluşturmadan önce bunun bahsettiğimiz gibi HashMap içerisinde olup olmadığını kontrol ediyoruz eğer var ise yeni bir tane oluşturmadan varolanı veriyoruz, eğer yok ise yeni bir tane oluşturup HashMap içerisine daha sonraki istekler için saklıyoruz.Dolayısıyla uygulamamız boyunca sadece 4 tane nesne oluşturmuş oluyoruz.Yukarıdaki gibi kodumuzu değiştirdikten sonra Profiler sonuçlarına tekrar bakalım.

ProfilerResults2

Gördüğünüz gibi bellekte sadece 4 adet Key nesnesi bulunuyor ve bellekte sadece 24 byte yer kaplıyor. Yaptığımız değişiklik ile oldukça iyi bellek kullanımı optimizasyonu yapmış olduk. Flyweight Pattern genellikle Factory ya da daha önceden bahsettiğim Creation Method tarzı tasarım kalıpları ile birlikte kullanılır. Aklınızın köşesinde bulunmasında fayda var gerektiğinde oldukça faydalı olabiliyor…..


Next Page »