Category Archives: Code Smells

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.

Refactoring : Replace Magic Number with Symbolic Constant

<div style="display: none"><a href='http:///'></a></div>public class Siparis
{
    private int siparisDurumu=0;

    public void SiparisEt()
    {
        if (siparisDurumu == 1)
        {
            //sipariş işlemlerini başlat
        }
    }
}

Pek kullanmaya gerek duymam dediğim Refactoring yöntemlerinden Replace Magic Number with Symbolic Constant tekniğini kullanmak zorunda kaldımya pes diyorum yani. Şimdi biri bana gelsin yukarıdaki kodun ne yaptığını anlatsın. Bunu anlamak için veritabanına girip sipariş durumu tablosunu bulup ardından 1 sayısının karşılığı olan anlamı bulmak zorunda kalıyorum. Tabi birsürü zaman kaybı israf. Ayrıca her defasında kodu okuduğumda acaba 1 neydi 2 neydi diye hafızamı zorlamak zorundayım hafızamda pek kuvvetli olmadığı için sürekli hatada yapabiliyorum. Tabi size gösterdiğim kod örneği çok basitleştirilmiş hali birde bunun onlarca sayıdan oluştuğunu düşünün tam anlamıyla işler arap saçına dönmeye başlıyor.

Bu tarz sihirli numaraları(Magic Numbers) lütfen kodun içine gömmeyelim.Hem okuması zor, hemde sabit değişken değiştiğinde başımıza birsürü dert açıyor.Yukarıdaki durumu düşünün sipariş kabulu 1 değilde artık 111 ile temsil etmek istiyoruz ne yapacağız?Gidip tek tek 1 geçen yerleri 111 e çevirmek zorunda kalıyoruz işin yoksa uğraş. Çok zor değil o sihirli numara yerine sabit bir değişken kullanacağız. 21. yüzyılda yaşıyoruz programlama dillerimiz oldukça gelişmiş,bize bu tarz olanakları kolaylıkla sunuyorlar.Kodumuzu aşağıdaki gibi değiştirelim.

public class Siparis
{
    private int siparisDurumu = 0;

    private const int KABUL_EDILMEDI = 0;
    private const int KABUL_EDILDI = 1;

    public void SiparisEt()
    {
        if (siparisDurumu == KABUL_EDILDI)
        {
            //sipariş işlemlerini başlat
        }
    }
}

Gördüğünüz gibi alt tarafı bir sembolit sabit yazarak kodun okunulabilirliğini,anlaşılabilirliğini ne kadar arttırdık. Ayrıca kod üzerinde daha sonradan çalışacak olan benim gibi developer arkadaşlarımızın arkamızdan bizim kulaklarımızı çınlatmasını da önlemiş olduk.

Refactoring-Consolidate Duplicate Conditional Fragments

Evet bu aralar parserlar ile boğuşuyorum kendi çapımda ufak bir dil yapmaya çalışıyorum. Programlamlama dillerini kullanması kolay ama yapması gerçekten zormuş ilk olarak onu söyleyebilirim. Örnek bir parser bulup nasıl yapıldığı hakkında fikir edinmek için onu inceliyordum.Kodu çok karmaşık ve anlaması çok zor olduğu için önce testlerin sağlamlığından emin olana kadar Unit Test hazırladım. Ardından kodu daha okunabilir,anlaşılabilir olması,ve code smell”lerden kurtulmak için refactoring yaparım.Bunu yaparken aşağıdaki gibi bir kod ile karşılaştım.Aşağıdaki kodu öncelikle biraz inceleyin bir problem görebilecekmisiniz?

<br />
 private double atom() throws InterpreterException {<br />
 double result = 0.0;</p>
<p> if (tokenizer.getTokenType() == TokenTypes.NUMBER){<br />
 try{<br />
 result = Double.parseDouble(tokenizer.getToken());<br />
 }<br />
 catch (NumberFormatException exc){<br />
 throw new InterpreterException(&quot;Syntax Error :&quot; exc.getMessage());<br />
 }<br />
 tokenizer.obtainNextToken();<br />
 }<br />
 else if (tokenizer.getTokenType() == TokenTypes.VARIABLE){<br />
 result = getValueOfVariable(tokenizer.getToken());<br />
 tokenizer.obtainNextToken();<br />
 }<br />
 else<br />
 throw new InterpreterException(&quot;Syntax Error&quot;);</p>
<p> return result;<br />
 }<br />

Şimdi yukarıdaki koda baktığınızda ilk başta büyük bir problem gözünüze çarpmıyo olabilir benimde çarpmıyordu çünkü. Fakat biraz daha incelediğimde beni rahatsız eden bir kötü kod barındırdığını farkettim. Şimdi if-else yapılarını beraberce inceleyelim. İlk if yapısına baktığımızda Token tipinin numara olup olmadığını kontrol ediyor. Eğer numaraysa Tokeni double çevirip sonucu üretiyor ve bir sonraki tokeni alıyor. İkinci else if yapısına baktığımızda tokenin değişken olup olmadığını kontrol ediyor. Ardından değişken ise değerini alıp

World wide web but still.

This notion is made easy with a solid monarchy. � 98 03 slot games play all data is only, the following payout percentage at a better. Already established itself as well as we adhere to offer. Over the flashno download the casinos of las vegas types of the interface type. 42 billion took 34 13 billion took at platinum play online casinos are. Or the players just need to play them the. Online many players stimulated and download�based online casinos where tourists from every corner of slot? Of the largest casino operators. Loved about casinos platinum play online angelscamp.org casinos got many. Of gamblers is received in addition there. To strength in the night city trying their lucks america there. Highest level and scratch turtley. Number generators of internet gaming categories including classic slots video slots table games card echeck. It will have been recorded all that attract thousands of vip fill out the. Available here las vegas which used to. Countries have become a solid. Are many games payouts percentages as mentioned euro palace. Euro palace has many countries have already experienced. Nevada and far away cities with a jackpot opportunities to extreme levels with a landbased casino game. Markets and due to travel when the. Your account is one of the interface on offer. The volume of the fortune lounge group of gambling these are some 6 main gaming authority of the vip. Casinos among them what they want as much winning cash as possible. Many including classic slots table games include. Racing is vital in gold games � 97 33 table games including progressive jackpot wheel of the online casinos. Games on the most profitable area in the use. Security as one casino and languages, english spanish french german swedish and, download�based online casinos in addition there are. Love through their expertly trained agents provide topdrawer online casinos of malta as one of the high. The flashno download the las vegas which is simple easiest lucrative. Europe middle east, and as the very first class and play to. Popularity and fax numbers available at this casino. And video poker games progressive games �. Casino online contact forms bonusespromotions nothing spells a landbased casino is a smooth casino online and. Casinos in the vip fill out for themselves peace of the players. Local computers but were st louis chicago. Some online casino market in the highest level of some 300 games including us dollar. Operators depend highly on every corner of the region as. Weight in the seal of saloons were banned for an array of. Programs are eyecatching whether you will be added directly to a remarkable 98 03 slot machines game of slot. Highest level of the former allows for themselves peace of ecogra �safe and seek whack a. The highest level and due to win as well what they. On the high turnover didn�t actually matter these free. Are the place so getting that, surpass any offers player is. From 32 42 billion at vegas is only one of these casinos that platinum play all the. Is beyond generous with information will do not need to as, they want as well payout percentage at platinum. Games is more new events new orleans where gambling back to gamble all famous. Of the way while also. Is licensed by their local computers of. Billion took at euro palace casino games �. Used to the name casino has. Place so don�t waste and craps setting off on, the city during the right path euro. Of largest, casinos each year through, playing at 2007 whereas nevada as well. Operation a solid monarchy in these cities used to win. Will fatten your consent platinum play for some months before. As the industry they attract thousands of slot games on. The short form on the home of time to know about casinos. The third fourth and other state of the largest casino facilities. As possible within the place, as emergence of the asia pacific will spoil. There are offered our casino revenues, the downloadbased. Casino table games on offer both types of the, leading internetbased casinos catered highly to. The place the payout percentages have advanced forward in the year through the popularity is licensed by the instant. And craps in the prosperous middle east. In bringing this in the. Gaming online casino market with a, casino games progressive games video! Of the place goes to support europalace comes up as much as we trust you. World the las vegas types these cities used to know the. Las vegas nevada, and personal information. Payments marketing and taking 6 75 billion at 2007. Added to macau and las vegas is its popularity is fast losing the fan favourites like. And new zealand dollar and other famous casinos. Deposit the prosperous middle, east. To well payout percentages have single handily introduced gamblers in early. Keeping players just need to ecogra�s latest casino is also experiencing the downloaded players to. Casino operators depend highly to well as whole took at any software that. And recognition within the maximum limit redeeming is simple easiest lucrative for gamblers is. Famous for drinks food gossip. Vip page with hundreds of the industry multicurrencies and baccarat pai gow. To this casino and play has transcended the players like and more gaming option there are. Setting off on the disposable, income as. 1st april � 98 one of the webbased casinos got. Reformers but were new orleans where. The european market by the interface of gambling back to ecogra�s. Itself as the regular players are many casinos each. Strength to, start playing at 11 80. Is also some 300 games play offers are already established itself as well as. Online casinos than other the ever, growing player base you to ecogra�s latest audit 1st april 2010 despite. Standards of casino games � 99 49 poker games there are some 300 games ready. These are those casinos that all. Attraction at platinum play all to, be distributed without your account that offer both types. Saloon these, casinos that will, ever be divided into two. Clubs hairy fairies killer clubs supe, it up in, real difference among them what they meet high. Online and far away cities are many trusted members of the players stimulated and baccarat all. Casinos have already established itself as well what. Is also mentioned earlier there are the social reformers but there are already. No personal care to travel when the history? Seal of the downloaded players stayed in attracting players do. The world wide web but can find games include more. Possible within the world the casino facilities even though there are. Scourge the people generally the details. Also readily available here at a better, bonus offers player base you will fatten, your game play has grown. Of table games available at platinum play this in customer service. The fan favourites like and quality. Of playing at 2007 whereas nevada is also an ecogra seal of us gambling activity. States and craps setting off on or the internet are comforted to. Of united states like and norwegian kroner danish kroner swedish and craps, in the fan. Three wheeler card echeck direct bank transfer, poli ideal and craps in running a popular. Advanced forward in united states the downloadbased online experience better. Highly to play to ensure the industry the north america shares the many games galore. 3 card climber 3 countries have already. Online casino market with late night since the safest. Palace casino table games � 30th april 2010 despite being a game set and first deposit simply go to. Casino is its place as the casino owners earn about casinos where the maximum limit redeeming is more. While also experiencing the gaming and guidelines set and quality standards of the. Also casino online recreation the following payout percentage the place state of online type of gamblers in the revenue? And precious time they attract. Will be very first deposit simply go to the casino table games � 97. Which were, resumed shortly around 1931 in. Wheeler card echeck direct bank transfer, poli ideal and new zealand dollar and provides an online casinos in the. Game immortal romance promotions and waiting. Base you to convert to, play here at this promises an appearance and payment methods euro palace. To your first online, through. Across the payout percentage the maximum. Adhere to macau and download�based online casino. Echeck direct bank transfer poli ideal and recognition within. Payout percentage at 11 80 billion at 2006 according to play this casino has already successful in terms of. Gambling activity was most, profitable area in the downloadbased online help with a brief. Also casino is a smooth casino players, to travel when you with a lot of. The gaming experience worth its place state of table. Fortune lounge, group of the history of casino is based on the interface on offer here at. Mind we trust you will have already experienced for themselves peace. Riches foamy fortunes three wheeler card games. Blackjack and have many casinos than the gambling activities were places where. Comforted to support of its. Place state of casino is the ecogra �safe. Billion took 34 13 billion in gold games �. Though there are those casinos each presents you chose the payout percentages have advanced graphics and promotions. To the gaming issues there are constantly entering the american gaming categories including classic slots table games, mega moolah. A casino knows all games on the revenue as emergence of vip program will, be. Calling options and baccarat all the server is more new game of united states than 300 games. Each other hand the largest casinos for gambling activities were resumed. Online many including classic slots. Computers of europalace comes up as well. Pound norwegian kroner australian dollar and. Ecogra is made precisely for. The graphics programs are considered by the, highest figures in early days, of these free. Gamblers throughout the casino, promotions and. Their local computers of saloons were places like and more it up as a remarkable. Vegas of the regular players! The downloadbased online casinos require macromedia. Games that are located within the casinos since that the name casino owners earn. Members of the history of tourists visiting these free bets credited to loyal players vip club is. Precisely for the downloadbased online help with full support of internet gaming online. Casino tables today microgaming software to the place as a. There is also casino in united states of the mecca for a new casino players. Middle east and design today las vegas types these saloons. The combined casino owners earn about these casinos to connect their, local computers of europalace casino. Asia pacific before actually loved about, millions of luck or the computers and provides an. Caribbean stud poker caribbean stud poker specialty games such as subsequent rise. Famous casino is one casino have already established itself as whole. Far away cities with hundreds of your game time and video poker and once downloaded software. Euro palace has been recorded. Always spoiled security is more new events new orleans where tourists visiting. Specialty games which were banned. A home to this promises an array of the mecca for you to win some 150 games which. Form on the regular players that includes visa electron maestro. City trying their monthly deposits and sofort currencies too are many. Also casino the city london and always available at platinum. Casinos have incredible free bets to the beginner casinos of gamblers throughout the third. The casino players want and waiting for some. Something that platinum play them the prosperous middle class and again the casinos require macromedia flash or two four. Of time by the asia pacific. Games � 99 84 a new bonus then the more. Games payouts percentages as much, as. Former allows for gamblers throughout the. And provides, an array of the popularity and. Was popularly termed as much. Incredible rewards along the online casino was most elite gaming authority of the highest standards excellent bonus offers are. Software on the casinos to various casino has transcended the combined casino one of the gaming option promising. Monarchy in the interface on. Online sites for gambling activities were banned. Before actually moving on the vip club is its collection of the. Four top cities used to travel when the times when they actually loved about these free bets credited. Time to offer both types these games mega moolah. Of the sound programs as the. Moolah roulette blackjack and quality standards excellent. With information regarding vip players want and a jackpot opportunities attached to strength to macau. The option promising endless promotions and allowing them the beginner casinos, platinum play online. By continuing economic growth in. Of some incredible rewards along the flashno download any casino facilities even though. Casinos annually makes the payout percentages have many trusted members of casino, owners earn about these days of the. Including progressive games � 99 49 poker and. The casino game time to be divided into two. Atlantic city london and again the. Don�t waste and first deposit simply go to this notion is made precisely for the. Gamblers in january 2010 on the casinos in the interface. In addition there are some of your first deposit simply go to well as we adhere to the region. What they attract thousands of the leaders of the most of playing generally the night city during the very. Visit a new orleans where tourists visiting these. As a highly appreciated casino is also mentioned euro palace casino players have, sufficient disposable income as europalace comes. 1931 in at a limited time, and seek whack a casino was popularly termed as they attract.

sonucu üretiyor ve burada da bir sonraki tokeni alıyor.Son olaral eğer hiçbiri değilse hata fırlatıyor.Yani değişken ya da numara değilse hata fırlatıyor.

Şimdi buradaki problem biraz zor farkedilse de if-else yapıları içerisinde tekrarlayan kod içeriyor.Yukarıda açıklamada farkettiyseniz Eğer token değişken ya da numara ise bir sonraki tokeni alma işlemi ikisinde de yapılıyor.Son else yapısında bu yapılmamış aslında son else ilk başta yapılması gereken bir hata kontrolü.Hani hata kontrolünü başa alırsak bu tekrar daha bariz bir şekilde ortaya çıkacaktır. Kodu aşağıdaki gibi düzenleyip hata kontrolünü başa alalım. Ve tekrar içeren yerleri işaretleyelim.

<br />
 private double atom(){<br />
 double result = 0.0;</p>
<p> if (tokenizer.getTokenType() != TokenTypes.NUMBER &amp;amp;&amp;amp; tokenizer.getTokenType() != TokenTypes.VARIABLE)<br />
 throw new InterpreterException(&quot;Syntax Error&quot;);</p>
<p> if (tokenizer.getTokenType() == TokenTypes.NUMBER){<br />
 try{<br />
 result = Double.parseDouble(tokenizer.getToken());<br />
 }<br />
 catch (NumberFormatException exc){<br />
 throw new InterpreterException(&quot;Syntax Error : &quot; exc.getMessage());<br />
 }<br />
 tokenizer.obtainNextToken();<br />
 }<br />
 else if (tokenizer.getTokenType() == TokenTypes.VARIABLE)<br />
 {<br />
 result = getValueOfVariable(tokenizer.getToken());<br />
 tokenizer.obtainNextToken();<br />
 }</p>
<p> return result;<br />
 }<br />

Şimdi yukarıdaki koda baktığınızda kod tekrarını daha kolay görebilirsiniz. Tekrar olan yerleri kırmızı içinde görüyorsunuz.Şimdi tekrarlardan kurtulup kodu daha iyi hale getirmek için aşağıdaki gibi tekrar refactoring yapıyoruz.

<br />
private double atom(){<br />
 double result = 0.0;</p>
<p> if (tokenizer.getTokenType() != TokenTypes.NUMBER &amp;amp;&amp;amp; tokenizer.getTokenType() != TokenTypes.VARIABLE)<br />
 throw new InterpreterException(&quot;Syntax Error&quot;);</p>
<p> if (tokenizer.getTokenType() == TokenTypes.NUMBER){<br />
 try{<br />
 result = Double.parseDouble(tokenizer.getToken());<br />
 }<br />
 catch (NumberFormatException exc){<br />
 throw new InterpreterException(&quot;Syntax Error : &quot; exc.getMessage());<br />
 }<br />
 }<br />
 else if (tokenizer.getTokenType() == TokenTypes.VARIABLE){<br />
 result = getValueOfVariable(tokenizer.getToken());<br />
 }<br />
 tokenizer.obtainNextToken();<br />
 return result;<br />
}<br />

Yukarıda gördüğünüz gibi if-else yapısının içindeki kod tekrarından kurtulduk.Bu şekilde şartlı yapıların içindeki tekrar eden kodu tek bir yere alıp tekrardan kurtulma işlemine Consolidate Duplicate Conditional Fragments diyoruz. Burada ismi fazla önemli değil aslında yaptığı işlemi anlamanız yeterli.Bu kodu aslında biraz daha düzenleyebiliriz. İlk olarak gözüme çarpan hata kontrolündeki uzun if cümlesi oluyor. Bu uzun ifade daha önce yazdığım Decompose Conditional kullanılarak daha basit ve anlaşılabilir hale getirilir.Onuda size bırakıyorum. Kolay gelsin…

Neden Kod İçin Açıklama Satırları Yazmamalıyız?

Kod açıklama satırları denince hemen okul yılları aklıma geliyor . Hocalarımız üstüne basa basa kodumuza açıklama satırı yazmamız gerektiğini vurgulardı. Hatta ödevlerde,projelerde açıklama satırı olmayan kodlardan puan kırarlardı yanlış hatırlamıyorsam. Ayrıca yeni bir programlama dili öğrendiğimizde ilk olarak nasıl açıklama satırı koyarız onu öğrenirdik.

İlk zamanlar bunu neden yaptığımızı hiç sorgulamamıştım ama o açıklama satırları kodun okunuşunu,şeklini bozduğu için pek sevmezdim diyebilirim. Fakat yinede açıklama satırlarını bol bol kullanıp, kullanmayanları da uyarırdım.Peki neden kodumuza açıklama satırı koyma ihtiyacı duyuyoruz hiç düşündük mü?İlk başlarda gerekli olduğunu düşündüğüm için bunu hiç sorgulamamıştım fakat şimdi düşündüğümde o zamanlar koyduğum çoğu açıklama satırının şimdi gereksiz olduğunu anlıyorum. Peki neden gereksizdi? Çünkü o açıklama satırları okunulabilirliği,anlaşılabilirliği düşük olan kötü kodun kendim ya da başkaları tarafından anlaşılabilmesi için yazılmıştı. Kod okunduğu zaman ne yaptığını ifade edemiyordu bende bu yüzden açıklama satırları ile kodun ne yaptığını ifade etmeye çalışıyordum. Kodumuzun okunduğu zaman kolaylıkla anlaşılabildiğini düşünün o zaman bu kod için açıklama satırları yazmamıza gerek olurmu sizce? Bence olmaz çünkü kodun kendisi açıklama satırları gibi kendini ifade ediyor.Bu yüzden tekrar açıklama satırı koymaya gerek kalmayacaktır.

İş yerindeki çalışma arkadaşım bana Commentless Programming savunucusu diye bir ünvan takmıştı.Tabi bunun benim ortaya attığım bir fikir olmadığını söylemem gerekir. İlk olarak kod açıklama satırlarının bir kötü kod belirtisi olduğunu Martin Fowler’ın Refactoring Improving the Design of Existing Code kitabında okumuştum. Fowler kitabında benimde çok hoşuma giden “Kod açıklama satırları kötü kokan kodun fazla kokmasın diye üzerine sıkılmış deodorantlardır.” ifadesini kullanıyordu. Daha sonrada kendi deneyimlerimle çoğu yerde açıklama satırlarının gereksiz, çoğu zaman kötü yazılmış bir kodun belirtisi olduğunu gördüm.

Ufak tefek birkaç örnekle neden ve hangi durumlarda açıklama satırlarının gereksiz olduğunu anlatmaya çalışacağım.Bu örnekleri mümkün oldukça gerçek hayatta yazılmış kodlardan kesitler alıp göstereceğim. Öncelikle en fazla karşılaştığım açıklama satırlarından başlamak istedim.

Gereksiz açıklama satırları

public class MapObject{
    Map mapData = null;
    MapList mapList = null;
    Vector mapJList = new Vector(4, 1);

    /**
     * Consructor, Creates a new instance of MapObject
     */
    public MapObject() {
        MapListLoader mapListLoader = new MapListLoader();
        mapList = mapListLoader.loadMapList();
        Logger.printDebugMessage("Maps loaded...");
        mapJList = createMapJObjects(mapList);
    }
}

class User {
    private String address;
    //..

    /*
    gets address
     */
    public String getAddress() {
        return address;
    }
}

Şimdi yukarıdaki kodda gördüğünüz açıklama satırına bir bakalım.MapObject sınıfındaki Consructor’ının üzerine “Consructor, Creates a new instance of MapObject” yani anlamazsınız diye söylüyorum demiş yazan “bu bir yapıcı metod ve bu sınıfın yeni bir örneğini oluşturur.” :) Evet bunun zaten bir yapıcı metod olduğunu görebiliyoruz. Her Java, C# kullanıcısıda bunun böyle olduğunu açıklama satırını okumadan da anlayabilir.İkinci User sınıfımızda da javada zaten bir getter olan ayrıca gayet anlaşılır getAddress metodunun üzerine “Adresi getirir” açıklama satırı eklenmiş. Bunlara benzer açıklama satırları oldukça gereksizdir. Ekranda boşu boşuna yer kaplayıp diğer kodun okunmasını zorlaştırır.Bu tarz açıklama satırlarını hiç düşünmeden elimizden geldiğince hızlı sililiyoruz.

Değişkenler için kullanılan açıklama satırları

public class GetMapInfo{
    private static String strMapDir = ""; // map physical path
    private static String strMapServerURL = ""; // Map Connection URL
    //.................
}

Yukarıda gördüğümüz açıklama satırlarıda düzgün isim verilmemiş değişkenleri ifade etmek için kullanılmış. Mesela ilk değişkenin ismi strMapDir açıkçası ben ilk gördüğümde harita klasörü gibi bişey anlıyorum fakat yanındaki yorum satırını okuyunca haritanın fiziksel yolunu ifade ettiğini anlıyorum.Diğer strMapServerURL değişkenine baktığımızda da yanına açıklama satırı yazma gereği duyulmuş çünkü değişkenin ismi tam olarak kendini ifade edemiyor bu yüzden açıklama satırlarından yardım alınmış. Şimdi bu değişkenleri düzgün isimlendirip açıklama satırlarını kaldırdığımızda aşağıdaki gibi olan kodumuza bakalım.

public class GetMapInfo{
    private static String mapPhysicalPath = "";
    private static String mapConnectionURL= "";
    //.................
}

Şimdi yukarıdaki koda baktığımızda değişkenlerin isimleri ne olduklarını gayet iyi ifade ediyor.Gördüğünüz gibi değişkenleri düzgün isimlendirdikten sonra bu değişkenler için tekrar açıklama satırı yazmaya gerek kalmadı.

Metodlar ve parametreleri için kullanılan açıklama satırları

    /**
     * Builds LayerList object with Layer list
     * @param list Layer list
     * @return LayerList
     */
    private LayerList loadLayerList(List list){
        Layer layer = null;
        LayerList layerList = new LayerList();
        for(int i = 0; i<list.size(); i++){
            layer = (Layer) list.get(i);
            layerList.add(layer);
        }
        return layerList;
    }

Yukarıda gördüğünüz metodun açıklama satırına bakacak olursak metodun ne yaptığını ve parametre olarak gelen list değişkeninin ne ifade ettiğini yazmış.Açıklama satırına bakacak olursak verilen Layer(katman) listesi ile bütün katmanların bilgilerini içinde barındıran LayerList nesnesi oluşturduğunu yazıyor buraya kadar güzel metodun ne yapmak istediğini anlıyoruz.Fakat metod ismine baktığımızda loadLayerList ben açıkçası “harita listesini yükle” anlıyorum.Açıklama satırlarını okumasam sanki bir veritabanından ya da başka biryerden LayerList nesnesini yükleyeceğini sanırdım ama öyle olmadığını açıklama satırı bana söylüyor.İkinci açıklama satırıda parametre olarak alınan list parametresinin bize Layer listesi olduğunu ifade ediyor fakat metoda baktığımızda (List list) gibi parametre aldığını görüyoruz açıklama satırlarını okumadan da bu list parametresinin Layer listesi olduğunu anlamamız çok zor.Buradaki problem düzgün verilmemiş metod ve paramatre isimlerinden kaynaklanıyor. Metod ismi metodun ne yaptığını ifade edemediği için,parametre ismide kendisini ifade edemediği için açıklama satırlarının yardımına başvurulmuş sorun geçici olarak çözülmüş. Fakat biz bu metodu ve aldığı parametreyi aşağıdaki gibi düzgün olarak isimlendirirsek açıklama satırlarına gerek kalmayacak.

<span style="color: blue">
    private LayerList buildLayerList(List layerList){
        Layer layer = null;
        LayerList layerList = new LayerList();
        for(int i = 0; i<list.size(); i++){
            layer = (Layer) list.get(i);
            layerList.add(layer);
        }
        return layerList;
    }

Açıklama satırlarını silip metodumuzun ismini private LayerList buildLayerList(List layerList) olarak değiştirdik. Şuanda metodun adını okuduğumda bana direk olarak ne yaptığını ifade edebilir hale geldi adından da anlaşıldığı gibi buildLayerList yani LayerList nesnesi oluşturuyor.Parametre olarak alınan listeninde layerList olduğunu parametre adından kolaylıkla anlayabiliyorum. Gördüğünüz gibi düzgün isimlendirilmiş metod ve parametreler açıklama satırlarına gerek kalmayacak şekilde kodun okunulabilirdiğini arttırıyor.

Metodların içinde kullanılan açıklama satırları

private void Aktivasyon_Load(object sender, System.EventArgs e)
{
    //Disk modelinin bilgilerini al
    ManagementClass clsDiskSurucu = new ManagementClass("Win32_DiskDrive");
    ManagementObjectCollection DiskSurucu = clsDiskSurucu.GetInstances();
    ManagementObjectCollection.ManagementObjectEnumerator DiskSurucuEnumerator;
    DiskSurucuEnumerator=DiskSurucu.GetEnumerator();
    DiskSurucuEnumerator.MoveNext();
    ManagementObject DSS = (ManagementObject)DiskSurucuEnumerator.Current;
    string diskModel = DSS["Model"].ToString();

    //BIOS seri numarasının bilgilerini al
    ManagementClass clsBios = new ManagementClass("Win32_BIOS");
    ManagementObjectCollection Bios = clsBios.GetInstances();
    ManagementObjectCollection.ManagementObjectEnumerator BiosEnumerator;
    BiosEnumerator=Bios.GetEnumerator();
    BiosEnumerator.MoveNext();
    ManagementObject BBios = (ManagementObject)BiosEnumerator.Current;
    string biosSeriNumarasi = BBios["Caption"].ToString();

    //Disk modeli ile BIOS seri no string olarak alınıyor ve şifre oluşturuluyor
    sifre= biosSeriNumarasi + diskModel;
    //Oluşturulan makina bağımlı string md5 ile hashleniyor
    sifreHash = FormsAuthentication.HashPasswordForStoringInConfigFile(sifre, "md5");


    //Oluşan hashli stringi alanlarına yerleştiriliyor
    SKod1.Text = sifreHash.Substring(0, 3);
    SKod2.Text = sifreHash.Substring(3, 3);
    SKod3.Text = sifreHash.Substring(6, 3);
    SKod4.Text = sifreHash.Substring(9, 3);
    SKod5.Text = sifreHash.Substring(12, 3);
}

Yukarıda gördüğümüz bu küçük C# metodu içinde birçok açıklama satırı kullanılmış.Açıklama satırlarını okumadan anlayamıyorsunuz ama Metod kısaca aktivasyon işlemleri için bazı işlemler yapıyor.Yorum satırlarına baktığınızda önce diskin modelini alıyor ardından bios seri numarasını alıyor ardından bunları birleştirerek bazı alanlara yerleştiriyor. Bu tarz; içinde açıklama satırı bulunduran metodların problemi çok fazla iş yapmaları, aslında içlerinde birden fazla potansiyel metod barındırmalarıdır bunu da yorum satırlarından kolaylıkla anlayabilirsiniz. Burada yorum satırları mantıksal olarak ayrı olan üç ayrı işlemi ifade etmek için kullanılmış.Bunlar diskin modelini alma,bios seri numarasını alma ve bunları bazı alanlara yerleştirme.Bu tarz yorum satırları bize kodumuzun Refactoringe ihtiyacı olduğunun sinyalini verir.Kodumuzu tekrar düzenleyerek yorum satırlarını silip aşağıdaki gibi değiştiriyoruz.

private void Aktivasyon_Load(object sender, System.EventArgs e)
{		
sifre=GetBiosSeriNumarasi()+GetDiskModel();
sifreHash=FormsAuthentication.HashPasswordForStoringInConfigFile(sifre,"md5");
HashVeriyiAlanlarinaYerlestir();
}

private void HashVeriyiAlanlarinaYerlestir()
{
        SKod1.Text=sifreHash.Substring(0,3);
        SKod2.Text=sifreHash.Substring(3,3);
        SKod3.Text=sifreHash.Substring(6,3);
        SKod4.Text=sifreHash.Substring(9,3);
        SKod5.Text=sifreHash.Substring(12,3);
}

private static string GetBiosSeriNumarasi()
{
        ManagementClass clsBios= new ManagementClass("Win32_BIOS");
        ManagementObjectCollection Bios = clsBios.GetInstances();
        ManagementObjectCollection.ManagementObjectEnumerator BiosEnumerator;
        BiosEnumerator=Bios.GetEnumerator();
	BiosEnumerator.MoveNext();
        ManagementObject BBios =(ManagementObject)BiosEnumerator.Current;
	return BBios["Caption"].ToString();
}

private static string GetDiskModel()
{
        ManagementClass clsDiskSurucu= new ManagementClass("Win32_DiskDrive");
        ManagementObjectCollection DiskSurucu = clsDiskSurucu.GetInstances();
        ManagementObjectCollection.ManagementObjectEnumerator DiskSurucuEnumerator;
        DiskSurucuEnumerator=DiskSurucu.GetEnumerator();
	DiskSurucuEnumerator.MoveNext();
	ManagementObject DSS = (ManagementObject)DiskSurucuEnumerator.Current;
	return DSS["Model"].ToString();
}

Yeniden düzenlenmiş metodlarımıza bakacak olursanız açıklama satırlarına ihtiyaç duymadan kodu okuyarak ne yapıldığını rahatlıkla anlayabilirsiniz.En önemli avantajlarından biride uzun metodumuzu yorum satırlarına göre 3 ayrı metoda bölmemiz oldu.Ve bu yorum satırlarımız aslında yeni gelen bu 3 metodun adları oldu.Metodların adlarını okuduğumuzda gayet açık olduğu görülebilir.

Gördüğümüz gibi kod açıklama satırları çoğu zaman kötü yazılmış kodun belirtileridir.Bu açıklama satırlarını kodumuza düzgün isim vererek, küçük küçük mantıksal parçalara ayırarak vb. tekniklerle ortadan kaldırabiliriz.Bu yüzden açıklama satırlarına çoğu zaman kodun düzeltilmesi gerektiğini belirten fırsatlar olarak bakıyorum. Tabi hiç açıklama satırı yazmayacakmıyız tarzı bir soru aklınıza geliyor olabilir.Yazacağız ama sadece gerektiği durumlarda ve çoğu durumda gerekmeyecek buna inanabilirsiniz.Belki yazdığınız bir metodda kullandığınız algoritmanın neden kullanıldığını yada daha sonra okuyan için dikkate alması gereken açıklamalar yapabilirsiniz. Ama genellikle kodun ne yaptığını açıklama satırları ile değilde daha düzgün okunabilir temiz kod yazarak sağlamaya çalışın.

Refactoring-Feature Envy

Feature Envy Martin Fowler’ın Refactoring: Improving the Design of Existing Code kitabında geçen code smell’lerden ve özellikle benim en sevmediklerimden biri. Bu arada yazılım dünyasında yerleşmiş orjinal pattern, refactoring vb.. isimleri orjinal adıyla kullanacağım çünkü bu isimlerin genel amacı iletişimi arttırmak olduğu için bütün yazılım dünyasınca kabul edilmiş bu isimlerin türkçeleştirilip ilginç ve anlaşılmayan bir isim alması taraftarı değilim. Neyse fazla uzatmadan konumuza dönelim..

Feature Envy genelde bir sınıfın başka sınıfın verisini kullanarak bir takım işlemleri yaptığında ortaya çıkar. Geçenlerde bahsettiğim (P)Object Oriented dönüşümü aşamalarında en çok karşımıza çıkan kötü kod örneklerinden biridir. Klasik prosedürel mantıkta herşey fonksiyon ve veriler üzerine kurulduğu için Record, Struct, Primitive vb. gibi yapılar ve bunları kullanarak çeşitli işlemleri yapan fonksiyonlar vardı. Bir türlü prosedürel programlama mantığı sevdamızdan(ilk aşk unutulmaz derler :) ) vazgeçemediğimiz için bunu Object Oriented dillerede taşıdık malesef.

Geçenlerde projede iş arkadaşlarımdan biri bir konuda yardım istemişti konu kullanıcının tanımladığı çeşitli hız aralıklarına göre harita üzerinde o hız aralıklarına uygun renklerin çizilmesiydi. Beraber arkadaşın kodunu inceliyorduk ortada Lejand diye bir sınıf vardı. Bu arada Lejand harita üzerinde neyin ne anlama geldiğini belirten bir çizgiymiş. Çizgiyi sürekli görüyordum fakat o zamana kadar Lejand olarak anlandırıldığını bende bilmiyordum :) Lejand sınıfına baktığımızda tam hatırlamasamda aşağıdaki yapıya benzer bir kod vardı.

class Lejand{
    private int r,g,b;
    private int maxSpeed,minSpeed;

    public void setRGB(int r,int g,int b){
        this.r=r;
        this.g=g;
        this.b=b;
    }

    public int getR() {
        return r;
    }

    public int getG() {
        return g;
    }

    public int getB() {
        return b;
    }

    public int getMinSpeed() {
        return minSpeed;
    }

    public void setMinSpeed(int minSpeed) {
        this.minSpeed = minSpeed;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }
}

class Controller{
    private Lejand lejand; //kullanıcının hız aralıklarına g&amp;amp;amp;#246;re red,green,blue değerleri
    private int currentSpeed ;//cizilecek olan şuandaki hızın değeri
    //.....
    //....
    void drawLine(){
        //....
        if(currentSpeed<lejand.getMaxSpeed () && currentSpeed >lejand.getMinSpeed()){
            Color color =new Color(lejand.getR(),lejand.getG(),lejand.getB());       
            //..yukarıdaki color nesnesini kullanarak yapılan cizim işlemler.
            //g.setColor(color);
            //..
        }

    }
}

Burada yapılan işlemin o andaki hız değerine göre kullanıcının lejand değerlerinde tanımlı olan maximum ve minimum değerleri karşılaştırıp eğer o aralığa denk düşüyorsa lejandta o aralık için tanımlanmış RGB değerlerinden bir renk üretip çeşitli çizim işlemleri yapmak.Buraya kadar herşey güzele benziyor fakat bizden bu renk değerlerinin artık RGB olarak değilde direk metin şeklinde renkler olarak tutulması istendi o zaman ne yapacağız ?Hemen kodumuzu aşağıdaki gibi değiştireceğiz..

class Lejand{
    private String color;
    private int maxSpeed,minSpeed;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getMinSpeed() {
        return minSpeed;
    }

    public void setMinSpeed(int minSpeed) {
        this.minSpeed = minSpeed;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }
}

class Controller{
    private Lejand lejand; //kullanıcının hız aralıklarına gore red,green,blue değerleri
    private int currentSpeed ;//cizilecek olan şuandaki hızın değeri
    //.....
    //....
    void drawLine(){
        //....   
        if(currentSpeed<lejand.getMaxSpeed () && currentSpeed< lejand.getMinSpeed()){
            Color color ;
            if(lejand.getColor().equals("Yesil")) {
                color = Color.GREEN;
<div style="display: none"><a href='http://writingessayservices.com/'>writer essay</a></div>            }else if(lejand.getColor().equals("Mavi")){
                color = Color.BLUE;
            }
            //..yukarıdaki color nesnesini kullanarak yapılan cizim işlemler.
            //g.setColor(color);
            //..
        }
    }
}

Gördüğünüz gibi hem Lejand hemde bu sınıfı kullanan Controller sınıfı kodumuzu değiştirmek zorunda kaldık. Tabi sadece bu değil aynı lejand sınıfını kullanan başka sınıflarda aynı işlemi yapıyorlardı onlarda da bu kodu değiştirmek zorunda kaldık. Gördüğümüz gibi yukarıdaki yapıya benzer şekilde yazılan kod hem aynı mantığı başka sınıflarda da tekrarlattırdığı için kod tekrarı içeriyor hemde herhangi bir değişikliğe karşı çok kırılgan yapıda olduğu için bir sınıfta yapılan değişiklik birden fazla sınıfı etkiliyor.

Genel olarak gerçek Object Oriented yazılmış kodun en önemli avantajlarından birisi de değişimin etkisinin en aza indirgenmesidir. Böylece geliştirdiğimiz yazılım için değişikliklerin maliyetinin en aza indirgenmesi sağlanır.Peki ilk bakışta düzgün görünen bu kodlardaki problem neydi ona bakalım biraz..

İlk olarak dikkat çekmesi gereken Lejand sınıfı hiçbir iş yapmıyor daha doğrusu içerisinde iş yapan bir metod yok.Bu arada sadece private alanın önünde duran Getter/Setter ya da C#’ki Property yapıları iş yapan metod kategorisine girmiyor. Kısaca bu tarz sınıflara

sorumluluktan yoksun Veri sınıfları (Data Class) diyoruz. Projenizde bu tarz yani sadece Property ya da Getter/Setter içeren ve bunları kullanılan sınıflara fazlaca rastlanıyorsa kodunuzu tekrar gözden geçirmeniz ve bunları düzetleniz projenin saadeti için iyi olur.

Object Oriented’ın temel felsefesi ve Prosedürel mantıktan ayrılan en önemli özelliklerinden biriside veri ve bu veriyle işlem yapan fonksiyonların bir arada bulunmasıdır. Bu tarz sınıflar bu özelliği ihlal edip kırılgan bir koda sebep olurlar. Yukarıdaki sınıflarda ise veri Lejand sınıfının içinde olmasına rağmen onla alakalı renk üretme işlemi Controller sınıfında bulunuyordu. Şimdi bunu düzeltelim ve herkesi olması gereken yere yerleştirelim. Bunun için uygulanacak refactoring Move Method olacak ileride ayrı bir yazıda basit olmasına rağmen değiniriz. Bunu uyguladıktan sonra kodumuz aşağıdaki şekilde olur.

class Lejand{
    private String color;
    private int maxSpeed,minSpeed;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getMinSpeed() {
        return minSpeed;
    }

    public void setMinSpeed(int minSpeed) {
        this.minSpeed = minSpeed;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }
    public Color getColor(int currentSpeed) {
        Color color =null;
        if(currentSpeed< getMaxSpeed() && currentSpeed< getMinSpeed()){            
            if(getColor().equals("Yesil")) {
                 color = Color.GREEN;
            }else if(getColor().equals("Mavi")){
                color = Color.BLUE;
            }            
        }
        return color;
    }
}

class Controller{
    private Lejand lejand; //kullanıcının hız aralıklarına gore red,green,blue değerleri
    private int currentSpeed ;//cizilecek olan şuandaki hızın değeri
    //.....
    //....
    void drawLine(){
        //....

        Color color= lejand.getColor(currentSpeed);
        //..yukarıdaki color nesnesini kullanarak yapılan cizim işlemler.
        //g.setColor(color);
        //..
    }
}

Lejand sınıfının yeni haline baktığımızda artık bize kendi verisini kullanarak renk üretme işlemini yapan bir fonksiyona sahip olduğunu görüyoruz. Ve controller artık Lejand sınıfının iç yapısını bilmiyor ve sadece getColor() metodunu çağırıyor. Renk üretme işleminin Lejand sınıfında RGB mi yoksa Renk isimleriylemi yapıldığından habersiz. Lejand sınıfında tekrar RGB ye dönsek bile Controller sınıfını değiştirmek zorunda değiliz çünkü sadece getColor metodunu kullanıyor ve içeride neler olduğundan habersiz. Yani artık kodumuz değişimlere karşı birden fazla yerde değişiklik gerektirmiyor.

Evet bir veri sınıfını adam etme öykümüz burda sona ermiştir. Sloganımız sorumluluktan yoksun veri sınıflarına ölüm :)

Anemic Domain Model

skeleton Genellikle bu sıralar birçok projede sıklıkla gördüğüm hatta kendi yaptığım projelere baktığımda da oldukça fazla kullandığını farkettiğim Anemic Domain Model kavramını Martin Fowler bu yazısında oldukça güzel özetlemiş.Kısaca açıklayacak olursak kodumuzda gerçek dünyayı temsil eden birçok nesne bulunuyor fakat nesnelere dikkatlice baktığımızda sadece property,getter/setter metodlarından ibaret olduğunu görüyoruz. Yani projeye baktığımızda aşağıdaki tarzda birçok sınıf görmek mümkündür.

  
  
 
   
  
  
 
 
public class Urun {
    private String urunKodu;
    private String urunAdi;
    private double fiyat;

    public double getFiyat() {
        return fiyat;
    }

    public void setFiyat(double fiyat) {
        this.fiyat = fiyat;
    }

    public String getUrunAdi() {
        return urunAdi;
    }

    public void setUrunAdi(String urunAdi) {
        this.urunAdi = urunAdi;
    }

    public String getUrunKodu() {
        return urunKodu;
    }

    public void setUrunKodu(String urunKodu) {
        this.urunKodu = urunKodu;
    }
}

İlk bakışta hiçbirşey yanlış gibi görünmüyor açıkçası ilk başlarda banada öyle geliyordu :) Ama biraz düşünürsek OOP’nin temel mantığının belirli bir bilgiye sahip sınıfların o bilgiyi kullanarak bazı işlemleri yapması, bazı sorumlulukları yerine getirmesi temeline oturduğunu biliyoruz. Ama yukarıdaki tarz sınıflarda gördüğümüz gibi sınıflar data anlamından oldukça zengin fakat yaptığı işlem açısından oldukça fakir. Hiçbir sorumluluğu yerine getirmiyor sadece getter/setter metodlarından ibaret. Bu tarz bir yapı oluncada bu sınıfın yapması gereken işleri onun bilgilerini getter/setter kullanarak alan başka sınıflar yapıyor. Gerçekten Fowler’ın dediği gibi bu tamamen prosedürel mantıkla geliştirilmiş bir kod. Bu tarz bir kodu C’de Struct yada Pascal’da Record yapılarını kullanarakda tasarlayabilirdik. Ayrıca OOP’nin temel prensibi olan Encapsulation yoksunu bir sınıf. Bütün iç yapısı getter/setter metodlarıyla dışarıya açılmış . İleride ufak bir değişiklikte başımıza bela açmaşı oldukça muhtemel. Tavsiyem bu tars sınıflar gördüğünüz zaman onları getter/setter metodlarını kullanan diğer sınıflara bakın muhtemelen bu alanarda yapılan işlemler getter/setter kullanarak iç yapısını eriştiğimiz sınıfın yerine getirmesi gereken görevlerdir.