Category Archives: Patterns,Principles

Yazılımda Basitliğin Önemi

Herhalde biz yazılımcılar işleri zorlaştırmayı sevdiğimizden olsa gerek yazılım geliştirmede problemlerin çözümlerini karmaşıklaştırmada zorlaştırmada üzerimize yok. Aklıma okul yıllarından, profosyonel iş hayatımdan üzerinde çalıştığım birçok proje geldi.Özellikle okulda arkadaşlara ne kadar karmaşık zor kod yazdığımıza dair övünürdük. İşte şöyle bir kod yazdım bilmem kaç satır , içinde bilmem kaç milisaniye kısa süren sıralama algoritması kullandım.. diye uzayıp giderdi muhabbet. Kısa ve basit çözümler bulanlara kötü gözle bakılırdı .Yazılımcı adam basit şeyler yapmaz zor işlerin adamıdır değil mi?:).Bu yüzden problemleride zor çözüm yollarıyla halletmek iyi gelirdi.Tabi bu alışkanlıklar iş hayatında da peşimizi bırakmadı aynı muhabbetler uzun süre devam etti.

Şimdi kendi yazdığım kodları gözden geçiriyorum ve aynı kompleksliği görebiliyorum.Çok basit bir şekilde halledebileceğim şeyleri ne kadar gereksiz zora sokup uzatmışım, ne kadar karmaşık şekilde çözmüşüm hayret ediyorum.Tabi yıllar sonra yazılımcının zor problemleri kolay ve basit bir şekilde çözmesi gerektiğini anladım.Sebebi adı gibi çok basit. Basit çözüm anlaması basit, değiştirmesi basit, yönetilmesi basit olduğundan her zaman kompleks çözümden daha avantajlıdır. O halde işleri zorlaştırmanın karmaşıklaştırmanın hiçbir gereği yok.

Extreme Programming’in temel prensiplerinden olan Basitlik(Simplicity) yazılım geliştirmede büyük bir öneme sahip.Basitliği bir problemin en basit çözümü olarak düşünebiliriz.Kod için düşündüğümüzde belirli bir işi yapması gereken kodun en basit şekilde sonucu üretmesi, ya da yazılımın şuandaki gereksinimleri karşılayan en basit halde olması diyebiliriz.Aksi takdirde anlaşılması zor ,yönetilmesi zor, değiştirmesi zor gereksiz birçok karmaşıklık içeren yazılıma sahip oluruz buda akıl,ruh sağlığı ve iş hayatımızdaki mutluluğumuz için pekde iyi değildir.

Aşağıda daha önceden yazdığım bir kod parçasından örnek verirsem demek istediğimi kod için daha rahat anlayabilirsiniz.Bu arada kızmayın, nasıl bu kadar karmaşık yazdığıma bende şaşırıyorum ama sebebi sanırım bir aralar Design Patterns hastalığına tutulmamdı:)

interface PanType {
    static final String LEFT  ="PanLeft";
    static final String RIGHT ="PanRight";
    static final String UP    ="PanUp";
    static final String DOWN  ="PanDown";
}

interface IPanPoint {
    Point2D.Double getCenterPoint(int screenWidth,int screenHeight);
}

abstract class AbstractPanPoint implements IPanPoint{
    public static IPanPoint createInstance(String panType){
        if(panType.equals(PanType.LEFT))
            return new PanLeftPoint();
        else if(panType.equals(PanType.RIGHT))
            return new PanRightPoint();
        else if(panType.equals(PanType.UP))
            return new PanUpPoint();
        else if(panType.equals(PanType.DOWN))
            return new PanDownPoint();
        else
            throw new IllegalArgumentException();
    }

    public Point2D.Double getCenterPoint(int width,int height) {
        return new Point2D.Double(calculateX(width),calculateY(height));
    }

    abstract int calculateX(int screenWidth);
    abstract int calculateY(int screenHeight);
}

class PanDownPoint extends AbstractPanPoint{
    int calculateX(int width) {
        return width/ 2;
    }

    int calculateY(int height) {
        return (height / 2 + height / 6);
    }
}

class PanLeftPoint extends AbstractPanPoint{
    int calculateX(int width){
        return  (width/ 2) - (width/ 6);
    }

    int calculateY(int height){
        return (height /2);
    }
}

class PanRightPoint extends AbstractPanPoint{
    int calculateX(int width) {
        return  (width/ 2) + (width/ 6);
    }

    int calculateY(int height) {
        return (height /2);
    }
}

class PanUpPoint extends AbstractPanPoint{
    int calculateX(int width) {
        return (width/ 2);
    }

    int calculateY(int height) {
        return (height / 2) - (height / 6);
    }
}

public class MapModel
{
   //diğer metodlar ve alanlar.....
   public void pan(String panType) {
        IPanPoint panPoint = AbstractPanPoint.createInstance(panType);

        Point2D.Double mapPoint = panPoint.getCenterPoint(width,height);
        //diğer işlemler....
<div style="display: none"><a href='http://buyessayonlinee.net/'>buy online essays</a></div>   }

}

Yukarıda gördüğünüz kod parçasının ne yaptığını fazla önemsemeyin.Yapılan şey kısaca sağ,sol,yukarı,aşağı yönlerine göre ekran büyüklüğü kullanılarak x,y değerlerini hesaplamak ve o değerlere göre bazı işlemler yapmak.Şimdi kodumuza şöyle bir bakalım.2 interface,1 abstract sınıf, 4 adet normal sınıf var. Ayrıca her sınıfta 2 metod,ayrıca 1 factory metodu var. Şimdi kullanılan Design Pattern’lara bakıyorum bol bol kullanmışız.1 adet Factory ,1 adet Template Method, 1 adet Strategy Pattern kullanmışız.(Ben neymişim be abi) Ama hemen kızmayın birde esneklik olarak baktığımızda baya iyi durumdayız. Kodumuz sonradan eklenebilecek durumlara karşı değişmeyecek. Tabi bu şekilde Design Pattern kullanmasak durum böyle olmazdı.Mesela ileride olabilecek kuzeybatı yönü hesaplaması için sadece AbstractPanPoint sınıfını extend edip ilgili metodu yazmamız birde Factory metoda eklememiz yeterli.MapModel sınıfı içinde hiçbir değişiklik yapmamıza gerek kalmadan yeni yönümüzü ekleyebiliriz.Fakat ileride böyle bir istek olacak mı?Büyük bir ihtimalle hayır.Olsa bile bugünden ileride gelebilecek istekleri aşırı kompleks düşünüp kodumuzu zorlaştırmanın anlamı yok.

Bu şekilde kodu yazmamızın hiçbir getirisi yok şuanda ilerisi için kodu daha esnek hale getirsekte karmaşıklığı sayesinde ileride değiştirmek daha zor olacak. Ayrıca 4 yönden başka durum olamayacak yani ilerisi içinde böyle bir değişiklik olacakmı onu bile bilmiyoruz. İleriyi düşünerek daha esnek yapalım derken gereksiz yere kodu karmaşıklaştırdığımızla kaldık.Ama bu arada süper iyi programcıyız bakın nasıl kompleks şekilde çözmüşüz problemi nasılda havalı Design Patternlar kullanmışız.:) Şimdi süper iyi programcı modundan çıkıp probleme daha basit gözle bakalım.Kodumuzu aşağıdaki gibi yeniden düzenleyelim.

public class MapModel{
//.........
    public static final String LEFT  ="PanLeft";
    public static final String RIGHT ="PanRight";
    public static final String UP    ="PanUp";
    public static final String DOWN  ="PanDown";

    public void pan(String panType) {
        Point2D.Double mapPoint ;

        if (panType.equals(LEFT)) {
            mapPoint = new Point2D.Double((width / 2) - (width / 6), (height / 2));
        } else if (panType.equals(RIGHT)) {
            mapPoint = new Point2D.Double((width / 2) + (width / 6), (height / 2));
        } else if (panType.equals(UP)) {
            mapPoint = new Point2D.Double((width / 2), (height / 2) - (height / 6));
        } else if (panType.equals(DOWN)) {
            mapPoint = new Point2D.Double(width / 2, (height / 2 + height / 6));
        }
        //nokta kullanılarak yapılan işlemler.......
    }

}

Gördüğünüz gibi eski karmaşık kodu aslında bu kadar basit birkaç if-else içeren kod ile halledebiliyoruz.Birçok sınıf,interface,gitti yerine birkaç satır kod kaldı. Ayrıca kullanılan Design Pattern’lar da kalktı.MapModel sınıfı belki geleceğe yönelik bir istekte değişecek fakat bugünün ihtiyaçlarını en basit şekilde karşılıyor. Anlaşılması öncekinden daha kolay ,yönetilmesi daha kolay vb…Gördüğünüz gibi basit şekilde problemi çözdük.

Basitlik sözde basit gibi gözüksede uygulamada kompleks problemler için basit çözümler üretmek gerçekten zordur.Özellikle yukarıdaki kod parçasında da gördüğünüz gibi Design Pattern gibi koda esneklik sağlayan ilerisi için yapılmış şeyler kodu oldukça zorlaştırmaktadır. Aynı şey bugünden karşımıza çıkmayan gereksiz performans optimizasyonu için de geçerli. Performans sıkıntısı çekmeden kod daha iyi çalışsın diye yapılan değişikliklerde kodu aynı şekilde karmaşıklaştırır.Bu yüzden kodu yazarken sadece bugünün isteklerini göze alıp geliştirmek önemli. Şahsen ben bazen bunu gelecek varsayımlara göre yukarıdaki gibi karmaşık kod geliştiriyordum ama hatalarımdan ders aldım diyebilirim.Özellikle Design Pattern gibi koda komplekslik katan kalıpları kullanırken dikkatli olmak önemli.Zaten Design Patterns kitabanın yazarlarından Eric Gamma’da bir sözünde Design Pattern’ların sadece Design acısı çekildiği zaman kullanılmasını öneriyor.O yüzden hepimizin asıl zor olan şeyi başarmak olan “zor problemlere basit çözümler bulmak” için çabalamasını tavsiye ediyorum.