Author Archives: M. Cihat Altuntaş

Eski Kodu Test Etmek : Subclass and Override

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.

Back-End Developer&rsquo;ın Front-End Maceraları

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.

zp8497586rq

Flyweight Pattern ile Performans Optimizasyonu

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…..

zp8497586rq

Cargo Cult Programming (&Ccedil;akma Programlama)

Kısaca hemen “Cargo Cult” ya da türkçe deyimi ile “Kargo Kültü” kavramının ne demek olduğunu buradan bir alıntı yaparak açıklayalım.

Güney Pasifik’te daha önceleri Batı dünyasından kimsenin uğramadığı, unutulmuş birtakım adalar, II. Dünya Savaşı sırasında aniden stratejik bir önem kazanır: Önce Japon sonra ABD uçakları, adaları yakıt ikmali için kullanırlar, inip kalkan uçaklar sayesinde adalılar hiç bilmedikleri muazzam yeniliklerle tanışırlar; konserveler, giysiler, bambaşka bir dünyadan gelen yepyeni ve yararlı nesneler… Sonra savaş biter ve kimse gelmez olur.

Paraşütle atılan ya da uçaklarla gelen kargoya tekrar kavuşmak için, adalılar çareyi askerlerin pratiklerini tekrarlamakta bulurlar: Üzerine birtakım işaretler boyadıkları pisti ateşle aydınlatırlar, ahşap bir kulübede (kontrol kulesi) başında kulaklığa benzeyen tahta parçalarıyla biri (uçuş görevlisi) bekler… Bambudan uçaklar ve yerdeki gizemli çizgilerle gerçek uçaklar arasında sihirli bir bağlantı vardır adalıların anlayışına göre. Uçakların tekrar gelmesi için, her şey yapılmış, her önlem titizlikle alınmıştır. Gelen giden olmaz, o ayrı.

Kargo Kültü kısaca bir süreci ya da

The goes pretty buy online viagra quart: looking hand. And http://www.backrentals.com/shap/diabetes-and-ed.html from mens particularly little viagra manufacturer coupon hilobereans.com the annoying blonde not domain hilobereans.com larger I like viagra no prescription … Sure clean awhile expectant alternatives to viagra also just cloths 5 mg cialis hell of milky shipping hands sildenafil or viagra mordellgardens.com dry. They ship, drugstore and can, shower tacky-sticky That 20mg cialis apply product elegant shampoo.

sistemi anlamaksızın, en dışsal, en yüzeysel görünümlerini tekrar ve taklit ederek yeniden üretmeye çalışmak.


Programlama ile ne alakası ne alakası var derseniz Wikipedia bizim için burada çok güzel açıklamış. Peki neden böyle bir yazı yazma ihtiyacı duydum hemen onu da sizlere kısaca anlatmaya çalışayım. Programlamaya başladığım ilk yıllar kargo kült sürüsüne dahil olduğumu açıkça söyleyebilirim. Ne yapardık peki bu sürüde ? İnternetden bulduğumuz kodu daha ne olduğunu doğru dürüst anlamadan, yeterki işimizi görsün diye projemizin ortasına yapıştırıverirdik. Nede olsa tekrar kullanılabilir kod böyle birşey olsa gerekti. Lazım olduğu sürece kopyala yapıştır gitsin. Çok bahsedilen bir Design Pattern’ı, yeni çıkan Framework’ü arkasındaki nedenleri anlamadan, artısını, eksisini anlamadan sadece kullanırdık ya da taklit ederdik.

Peki bunun dezavantajı nedir? Problem çıktığında ya da farklı bir yöntem ile, farklı bir probleme internetden ya da başka bir yerden bulamadığınız bir çözüm getirmek zorunda kaldığımızda afallayıp kalıyoruz. Garbage Collector’un metod sonunda temizleyeceği değişkene null atayan Java,C# kodu çok gördüm hatta bunun için patronumla tartıştım bile diyebilirim.
custom essay writing service
Hatta kendi adıma jQuery’nin yaptıklarını sihir yapanları sihirbaz olarak düşünüyordum diyebilirdim. Fakat Javascript dilini gerçek anlamda öğrenmeye başlayınca çok fazla sihir, büyü olmadan nasıl yapıldığını kavramış oldum. Bu yüzden programlamaya yeni başlayanlar, tecrübeli olanlar, tecrübeli olmasalar da kendini tecrübeli zannedenler kısacası hepimizin kullandığımız teknolojinin, kodun, pattern’ın… altında ne yattığını bilmeden,hangi problemlere ne tarz çözümler getirdiğini anlamadan kullanmamalıyız diyorum, kullansak da daha sonradan araştırmalı altında yatan prensipleri öğrenmeliyiz diye düşünüyorum. Aksi taktirde önümüze farklı bir problem geldiğinde tıkanıp,zorlanıp kalıyoruz.

Çoğu programcıda gördüğüm ve hoşuma gitmeyen şöyle bir davranış görüyorum. Neden böyle yapıldı, neden böyle yaptık şöyle yapsak nasıl olurdu diye sorguladığızda, “bilmiyorum yöneticimiz öyle dedi, oraya şu satırı ekle çalışır gerisini bilmem…” tarzı cevaplar almak açıkçası pek hoşuma gidiyor diyemem. Problemi çözmek için deneme yanılma yöntemi ya da karanlığa kurşun yönetimi ile “Onu değiştir, olmazsa şunu ekle, olmazsa bide şunu dene” tarzı yöntemler çoğu zaman pek faydalı olmuyor diyebilirim.

Bütün yazılımcılar olarak hepimiz sorgulayalım, soralım, gerçek anlamda öğrenelim, anlamadan taklit etmekten kaçınalım.Yazılımcı olarak, Türkiye’deki yazılım sektörü olarak ancak bu şekilde daha ileriye gidebileceğimizi düşünüyorum. Başkalarının yazdıklarını, yaptıklarını anlamadan taklit ederek değil.

Kısaca sıralarsak

  • Kullandığınız kodun ne yaptığını ,
  • Kullandığınız framework, mimari .. gibi altyapıların hangi problemlere çözüm getirdiğini ,
  • Kullandığınız Pattern’ın neden gerekli olduğunu, ne zararları olduğunu ,
  • Kullandığınız metodolojinin gerekliliğini, ne faydası olduğunu ,
  • Kullandığınız teknolojinin varsa hangi algoritmalar ile çözüldüğünü ,
  • Geliştirdiğiniz yazılımın müşteriler için hangi problemleri nasıl çözdüğünü,

Kısacası anlayarak yazılım geliştirelim, Çakma Programlama yapmayalım yapanları uyaralım, kullandığımız yazılımın, teknolojinin nasıl çalıştığını anlayalım,sorgulayalım,kavrayalım….

765qwerty765

Object Creation Patterns, B&ouml;l&uuml;m 1 : Creation Method

Uzun süredir yazamamanın verdiği rahatsızlığı üzerimden atmak üzere yeni yazı serilerimize başladığımızı bildiririm.(Vatana millete hayırlı olsun :) ) Bu satırları yazarken bile kendimi biraz daha rahatlamış hissettim. Yaklaşık belki 1 sene önce arkadaşım Sadullah’ın Factory Pattern ile alakalı yazı yazmamı istediğini hatırlar gibiyim. Daha sonra başka arkadaşlarda yorumlarında bu yönde istek belirttiler. Bu yüzden bende hem daha önceki sözümü geç de olsa yerine getirmiş olayım, hemde diğer arkadaşlara faydalı birşeyler sunayım diye bu konuda bildiklerimi sizlere anlatayım dedim. Bu yazı serisinde nesneleri oluşturmada kullanılan işimize yarayabilecek , benim de sık sık kullandığım yöntemlerden, pattern’lardan bahsedeceğim.

Biliyorsunuz nesneye yönelik bir dilde yazılım geliştirirken en çok kullandığımız kalıp new ile nesne oluşturmaktır. Bazen bu şekilde nesneleri oluşturmak her zaman en iyi yöntem olmayabiliyor.Bu yüzden nesneleri oluştururken kullanılan çeşitli yöntemler mevcut, her birinin avantajı ve dezavantajları var. Bu yazıda bunlardan ilk olarak bahsetmek istediğim Creation Method yöntemi.

Çok basit ve bir o kadar da faydalı bulduğum Creation Method yönetime pattern demek doğru olmaz sanırım. İlk olarak Effective Java kitabında Static Factory Methods başlığı altında bu yöntemle karşılaşmıştım. Daha sonra da Refactoring To Patterns kitabında aynı yöntemi Creation Methods olarak anlatıyordu. Factory Pattern ile karışmaması için Creation Method ismini daha uygun bulduğumu söyleyebilirim bu yüzden yazının bundan sonraki bölümünde Creation Method olarak bahsedicem.

Creation Method yöntemini kullanarak basit olarak nesneleri oluştururken sık sık kullanılan ve tekrar eden kodu, nesnenin üzerinde static metodlar içinde toplayarak tekrar eden kodu önleyebilirsiniz.Örnek olarak bu durumu aşağıdaki kodlar üzerinde inceleyelim.

private Attachment UploadFile(string filePath)
{
//Diğer kodları kısa tutmak için yazmıyorum
//……..
string outputFileName = "Fax_" + DateTime.Now.ToString("dd.MM.yyyy_hh_mm_ssss") + "." + extension;
string outputFilePath = uploadFolder + "\\" + outputFileName;
outputFileStream = new FileStream(outputFilePath, FileMode.Create);

int byteRead;
do
{
byteRead = inputFileStream.ReadByte();
if (byteRead != -1) outputFileStream.WriteByte((byte) byteRead);
} while (byteRead != -1);

Attachment attachment = new Attachment();
attachment.AttachmentName = outputFileName;
attachment.AttachmentPath = outputFilePath;
attachment.AttachmentType = EnumAttachmentType.Image;
attachment.MimeTypeIcon = Icons.Image;

inputFileStream.Close();
outputFileStream.Close();

return attachment;
}

Projenin diğer bir kısmında ise aşağıdaki gibi kodlar bulunuyor

protected void OnFileUpload(RelatedFile relatedFile)
{
Attachment attachment = new Attachment();
attachment.AttachmentName = relatedFile.RelatedFileName;
attachment.AttachmentPath = relatedFile.RelatedFilePath;
attachment.AttachmentType = EnumAttachmentType.Word;
attachment.MimeTypeIcon = Icons.Word;

product.SaveAttachment(attachment);
}
//………
//…..
protected void AddProduct()
{
Attachment attachment = new Attachment();
attachment.AttachmentName = "";
attachment.AttachmentPath = "";
attachment.MimeIconType =Icons.Empty

product.Attachments.Add(attachment);
}

Yukarıda gördüğünüz kod parçaları projenin birçok yerinde bulunuyor.Dikkat ederseniz farklı işlemler için Attachment yani eklenti nesnesini oluşturup kullanıyoruz. Bu oluşturma sırasında AttachmentType, MimeTypeIcon (eklenti tipi,dosya tipi ikonu) gibi özellikleri yapılan işleme göre atıyoruz.Bu nesneyi oluşturma kodu uygulamanın birçok yerinde tekrar ediyor. Dolayısıyla oluşturma sırasında her nesneye yeni bir özellik atamak istersek ya da varolan özelliklerden birinin(örn. MimeTypeIcon) değişmesi istersek uygulamanın her yerine dağılmış olan bu kodu tek tek düzenlemek zorunda kalırız. Öncelikle bu tarz tekrarı önlemek için nesnemize aşağıdaki gibi uygun yapıcı metodları ekleyebiliriz ve tekrarı önleyebiliriz.
custom essay writing service

protected void Metod()
{
Attachment attachment = new Attachment(relatedFile.RelatedFileName,relatedFile.RelatedFilePath,EnumAttachmentType.Word,Icons.Word);

//……

Attachment attachment = new Attachment(outputFileName,outputFilePath,EnumAttachmentType.Image,Icons.Image);

//……..

Attachment attachment = new Attachment(Icons.Empty);

}

Yukarıdaki gibi nesneye gerekli constructor metodlarını ekleyerek tekrarı önlemiş olduk. Fakat burada da şöyle bir problem ortaya çıkıyor. Eğer nesnenizde bu şekilde birden fazla constructor varsa dışarıdan bu sınıfları kullanacak olan yazılımcıların ya da takım arkadaşlarımızın her yapıcı metoda baktığında hangisini kullanacağı hakkında pek bir fikri olmamasıdır. Düşünün elinizde oluşturmak istediğiniz nesneye ait 5 adet farklı yapıcı metodunuz var hangisini kullanarak nesneyi oluşturmalısınız? Bu yapıcıların arasındaki fark nedir? Direk olarak anlamak pek mümkün değil. Çünkü yapıcı metodların isimleri Java, C# gibi dillerde nesne ismi ile aynı olmak zorunda bu da bize o yapıcı metodların neyi yaptığı konusunda pek ipucu vermiyor.

Aynı kodu birde Creation Method kullanarak aşağıdaki gibi tekrar yazalım.

public class Attachment:BusinessBase
{
//Diger kodlar…….
private static Attachment createAttachment(string filePath,string fileName,EnumAttachmentType type,MimeTypeIcon icon)
{
Attachment attachment =new Attachment();
attachment.AttachmentName = fileName;
attachment.AttachmentPath = filePath;
attachment.AttachmentType = type;
attachment.MimeTypeIcon = icon;
return attachment;
}

public static Attachment createImage(string filePath,string fileName)
{
return createAttachment(filePath,fileName,EnumAttachmentType.Image,Icons.Image);
}

public static Attachment createWord(string filePath,string fileName)
{
return createAttachment(filePath,fileName,EnumAttachmentType.Word,Icons.Word);
}

public static Attachment createEmpty()
{
return createAttachment("","",null,Icons.Empty);
}

//……………
}

Yukarıdaki kodda gördüğünüz gibi nesnemiz üzerine aynı nesneyi oluşturan static metodlar ekledik. Dolayısıyla nesnemizi oluşturan yerler bundan sonra aşağıdaki gibi oluşturacaklar.

protected void Metod()
{
Attachment attachment = Attachment.createWord(relatedFile.RelatedFileName,relatedFile.RelatedFilePath);

//……

Attachment attachment = Attachment.createImage(outputFileName,outputFilePath);

//……..

Attachment attachment = Attachment.createEmpty();

}

Gördüğünüz gibi artık yukarıda gördüğünüz kod hem tekrardan arınmış oldu hemde çok daha anlaşılır duruma geldi. Artık heryerde tekrar eden gereksiz oluşturma kodları tek bir yerde toplandı.Dolayısıyla nesneyi oluşturma sırasında yeni bir özellik eklemek istersek ya da varolan bir özelliği değiştirmek istersek bu işlemi tek bir yerde yapacağız. Ayrıca birçok construstor olduğunda hangisinin nasıl bir nesne oluşturacağı durumu ortadan kalktı. Nesnenin üzerindeki createWord, createImage, createEmpty gibi metodlar çok daha anlaşılır ve ne yaptığını ifade eden metodlar.Bu yüzden sınıfın kullanımı daha da kolaylaştı.

Gördüğünüz gibi Creation Method basit ama tekrarı önleyen, kullanım kolaylığını ve okunulabilirliği arttıran oldukça etkili bir yöntem. Ben bu yöntemi genellikle bu tarz basit durumlarda daha çok kullanıyorum. Eğer oluşturma mantığı daha kompleks ve farklı nesneler işin içine giriyorsa ya da nesne üzerindeki bu tarz Creation Method’ların sayısı gitgide artıyorsa Factory, Abstract Factory Pattern’ları kullanabilirsiniz.Bunlarada serimizin diğer yazılarında değinmek üzere sizleri kod ile başbaşa bırakıyorum….

765qwerty765

Findstr komutu ile Text Arama İşlemleri

Windows işletim sistemi kullanıcısı olarak neden Unix tabanlı işletim sistemlerindeki Grep gibi bir aracın bulunmayışından şikayet etmişimdir.Sık sık geliştirdiğiniz bir projede herhangi bir kod satırını, herhangi bir nesnenin hangi sınıflarda, dosyalarda kullanıldığını görmek isteyebilirsiniz.Kısacası kod üzerinde arama yapmak yazılımcıların olmazsa olmaz günlük aktivitelerindendir.

Bu yüzden eğer benim gibi aynı anda .NET, Java gibi birkaç platformda geliştirme yapıyorsanız, bu kod arama işlemini IDE üzerinden yapmak bazen oldukça zahmetli olabiliyor. Hatta bazen geliştirdiğiniz eski kodunuzun IDE’si bile bilgisayarınızda bulunmayabiliyor. Tekrar IDE kurmakda benim gibi üşengeç biri için büyük eziyet.

Buna benzer Windows ortamında kullanabileceğim özellikle komut satırından çalışan bir araç ararken ilk olarak Cygwin aracına rastladım. Bu araç sayesinde Linux ortamını ve araçlarını neredeyse birebir Windows ortamında komut satırı üzerinden kullanabiliyorsunuz. Dolayısıyla Grep gibi faydalı birçok Linux aracı Windows ortamında kullanıma hazır hale geliyor. Cygwin kurulumu biraz uzun olsada getirdiklerine değecek bir araç.

Uzun süre önce bilgisayarımı formatladığım ve açıkcası tekrar Cygwin kurulumuna üşendiğim için başka bir araç arayışına gittim. Bulduklarımdan biri Windows ortamında zaten bulunan Findstr komutuydu.Bu komut ile basit olarak text arama işlemlerini kolaylıkla yapabiliyorsunuz.Grep gibi tamamen Regular Expressions gücünü kullanarak arama yapamasanız da basit olarak Regular Expressions, ve birçok faydalı seçeneği ile text dosyalar üzerinde arama  yapabilmenize izin veriyor.

Findstr ile bu aralar benimde en çok kullandığım aşağıdaki arama ifadesi gibi ifadeler yazabilirsiniz.

Findstr /s /i "import java.util.Date" *.java

Yukarıdaki komutda bulunan “/s” parametresi ile bulunduğunuz dizin ve bütün altdizinler dahil, “/i” parametresi ile büyük,küçük harf farklılığını önemsemeyerek bütün java dosyaları içinde java.util.Date sınıfının kullanıldığı dosyaları arıyoruz.Ardından bulduğu satırları herhangi bir dosyaya ya da ekrana yazdırabilirsiniz. Yazılımcı olarak işimizin büyük çoğunluğu Text üzerine olduğu için Text dosyalar ile oynamayı iyi bilmek işimizi oldukça hızlandırıyor. Bu tarz araçların bütün yazılım geliştiriciler için de faydalı olacağına inanıyorum.

Ant ile Versiyon Numaralandırması

Geliştirdiğiniz uygulamanın sık sık yeni sürümünü çıkarıyorsanız, çıkardığınız sürüme versiyon numarası vermek oldukça faydalı olabiliyor. Özellikle uygulamanız aynı anda birden fazla versiyonu bulunabilecek bir uygulama ise(Desktop uygulaması,….) kullanıcılardan farklı versiyonlara ait farklı hatalar gelebilmektedir. Bu yüzden kullanıcının gönderdiği hatanın hangi versiyonda olduğunu bilmek işinizi oldukça kolaylaştırır.

Java ile geliştiridiğiniz projelerde sürüm otomasyonunu Ant ile yapıyorsanız versiyon numaralarını el ile vermektense bu versiyonlama işleminide otomatikleştirebilirsiniz. Özellikle bunu merkezi bir CI,build server üzerinde bu işlemi yapmak oldukça işinizi kolaylaştırır.

Ant scriptiniz içine aşağıdaki gibi satırları ekleyip numaralandırma işlemizi ant’a devredebilirsiniz.

buildinfo.properties

build.user=Administrator
build.num=0098
build.date=22.06.2009 10\:23

default.properties

name.build.info          = buildinfo.properties
name.build.referer       = ProjectVersion.java
name.build.prefix        = PROJEADI-
        <loadproperties srcfile="${basedir}/default.properties"></loadproperties>
	<loadproperties srcfile="${basedir}/buildinfo.properties"></loadproperties>

	<propertyfile file="${name.build.info}"
	 comment="Build Information File - DO NOT CHANGE">
	    <entry key="build.num"
	     type="int" default="0000"
	     operation="+" pattern="0000"/>
	    <entry key="build.date"
	     type="date"
	     value="now"
	     pattern="dd.MM.yyyy HH:mm"/>
		<entry key="build.user"
			type="string" value="${user.name}"/>
		
	</propertyfile>
	
	<replaceregexp file="${name.build.referer}"
	 match="@\(#\).*@"
	 replace="@(#)${name.build.prefix}-${build.num} (on:
	${build.date}) Built by : ${build.user}@"/>

Yukarıda gördüğünüz propertyfile Ant komutu içerisinde name.build.info yani buildinfo.properties dosyasının içerisine her defasında versiyon numarasını arttırarak yazmaktadır. Ardından replaceregexp komutu içerisinde name.build.referer yani ProjectVersiyon.java dosyasının içeriğine yukarıda arttırılan versiyonu ve diğer faydalı bilgileri buildinfo.properties içerisinden alıp yazmaktadır.

Ardından sizde projenizde uygun bir yere ProjectVersiyon.java içerisindeki bilgileri yazdırarak kullanıcıya hangi versiyonu kullandığını gösterebilirsiniz.

Uzun zamandır neden yazamıyorum?

p>Merak eden varmıdır bilmiyorum fakat ben yinede iyimser düşünüp merak edenler için açıklama yapayım dedim. Uzun zamandır yazamıyorum sebeplerini kısaca şöyle sıralayabilirim.

Sanatımızı sürekli icra etmeden usta olamayacağımızı düşündüğüm için, çok okuyup, çok yazı yazmak yerine, az okuyup çok kod yazmak yönünde bu aralar tercihimi kullanıyorum.  Bu yüzden sürekli yakındığım politik ve diğer bazı nedenlerden dolayı iş ortamında uygulayamadığım yazılım pratiklerini kendim evde uygulamaya karar verdim ve kolları sıvadım diyebilirim.Yani  Hackers and Painters kitabında verilen tavsiyeye uydum karnımı doyuran bir gündüz işine sahibim, geceleri ise istediğim pratiği uygulayabildiğim, pratik yapabildiğim, sanatımı icra edebildiğim projelere sahibim. Lafı fazla uzatmadan bahsedeyim nelerle uğraşıyorum?

ASP.NET MVC,NHibernate,jQuery,DI,TDD kullanarak uzun soluklu bir proje geliştiriyorum.

Gerçek anlamda JavaScript öğrenmeye çalışıyorum.

Perl,Ruby on Rails’e göz kırpıyorum.

Sizlere, başkalarına birşeyler öğretmek için öncelikle kendim yaşamalıyım o yüzden bu projeler süresince öğrendiklerimi, uyguladığım pratikleri ve belkide kaynak kodlarını sizinle paylaşacağım. Hatta kalmaya devam edin çok yakında güzel projeler ve yazılarla tekrar birlikte olacağız.

Yazılım Mühendisi Maaş Anketi

GÜNCELLEME : Anketimiz kapatılmıştır.Yaklaşık 10000 oy kullanılmış ekran görüntüsünü alıp anketi kapattım katılan herkese teşekkür ediyorum.

Daha önceden yazdığım Yazılım Mühendisi Maaşı yazısından en çok okunan yazılardan biri oldu. Ayrıca birçok kişi tarafından yorum yapıldı ve kaç YTL maaş alındığı konusunda sorular soruldu. Bu yüzden daha önceden belirtmediğimiz rakam olarak maaş konusunu açıklığa kavuşturalım istedim. Hemde sektöre girenler, girecekler.. için bir klavuz olsun.

maasanket

Maaş ücretleri için yukarıda gördüğünüz anketi hazırladım. Fakat yazılım sektöründe maaş konusu tecrübe, uzmanlık, çalıştığınız il,okul.. gibi birçok parametreye göre değiştiği için anketten ziyade bu yazının sonuna yorum olarak isminizi vermeden

  • Mezun olduğunuz okul
  • Mezun olduğunuz bölüm
  • Çalıştığınız İl
  • Çalıştığınız uzmanlık alanınız
  • Sene olarak tecrübeniz
  • Aldığınız brüt ya da Net Maaşınız

Yazarsanız bu konuda oldukça meraklı olan arkadaşları oldukça sevindirirsiniz. Mühendis, programcı, başka alandan mezun olup yazılım alanında çalışan kısacası Yazılım Uzmanı olan herkesin anketi doldurmasını temenni ediyorum.  Yorumların arasına bende kendi maaşımı ekleyeceğim ama isimsiz tabi :)

Basit Bir Abstraction Örneği

Object Oriented tasarım ve programlamada soyutlamanın her zaman önemini vurgulamışımdır. Yazılım geliştirirken soyutlamalar sayesinde yazılımı daha yönetilebilir parçalara, modüllere ayırıp daha esnek yazılımlar geliştirebiliyoruz. Buna geliştirdiğim yazılımdan küçük bir örnek vermek istedim.

Geçenlerde Hibernate Log dosyalarını parse eden bir program yazdığımı burada belirtmiştim.  Program belirli bir dizideki .log uzantılı dosyaları parse edip içlerinden SQL cümlelerini çıkarıyordu. Ekranda bulunan bir butonun altında yazılan kodda seçilen log dizininin altındaki log dosyalarını alıp Parser sınıfına işlemesi için gönderiyordu. Kodun ilk yazılan şekli aşağıdaki gibiydi.

private void openFileActionPerformed(java.awt.event.ActionEvent evt) {
    try {        
       //log dosyalarını seçili dizinden alıyoruz

       File directory =fc.getSelectedFile();
       FilenameFilter filter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(".log");
            }
        };
        File[] files =directory.listFiles(filter);

        //*****************
 
        for (File file : files) {
            Parser parser = new Parser(file);   
            sqlLogs = parser.parse();
            for (SqlLog sqlLog : sqlLogs) {
                listModel.addElement(sqlLog);
            }
        }

    } catch (Exception ex) {
        showMessage(ex.getMessage());
    }
}

Yukarıdaki basit bir işlem fakat metodun iki işi bir arada yaptığını fark ettiniz umarım. Log dosyalarını listeleme ve bu dosyaları parse etme. Ayrıca uygulamamı düşündüğümde şöyle bir ihtiyacım olduğunu anlıyorum.Uygulamam “Log dizinindeki dosyaları parse etme” işlemini yapıyor. Bu yüzden basit ama kodu ve yönetimi arttıran yeni bir sınıf ekliyorum. Aslında kısacası soyutlama yapıyorum. Uygulamam da daha önceden geçen “Log Dizini” dediğim kavram için bir sınıf oluşturuyorum. Kodu aşağıdaki gibi değiştirdim.

public class LogDirectory {
    private File directory;

    public LogDirectory(File directory) {
        this.directory = directory;
    }

    public File[] getLogFiles() {
        FilenameFilter filter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(".log");
            }
        };
        return directory.listFiles(filter);
    }
}

Yukarıdaki kodda basit bir soyutlama yaptım. Log dizinindeki dosyaları getiren işi ayrı bir sınıf olarak uygulamaya ekledim.Metod aşağıdaki hale geldi.

private void openFileActionPerformed(java.awt.event.ActionEvent evt) {
    try {       
        LogDirectory logDirectory =new LogDirectory(fc.getSelectedFile());        
        File[] files = logDirectory.getLogFiles();

        for (File file : files) {
            Parser parser = new Parser(file);
            sqlLogs = parser.parse();
            for (SqlLog sqlLog : sqlLogs) {
                listModel.addElement(sqlLog);
            }
        }

    } catch (Exception ex) {
        showMessage(ex.getMessage());
    }
}

Küçükde olsa bu tarz soyutlamanın uygulama için oldukça önemli olduğunu düşünüyorum.