Monthly Archives: March 2009

Yazılım Mimarı Kod yazmalı mı?

Orjinal adıyla “Should architects write code?” olan meşhur soruya kendi kişisel cevabımı burada vereyim. Soru belki binlerce kez cevaplandı, herkes kendince fikirlerini belirtti fakat yinede birkaç ayda bir bu sorununun yazılım dünyasındakilere hatırlatılması gerektiğini düşünüyorum.Peki neden?

Yazılım mimarı ünvanı adı altında,ya da projede yazılımın tasarımında,mimarisinde rol alan insanların genelde şöyle bir eğilimi olduğunu sık sık görüyorum. Yazılım mimarı arkadaş gereksinimlere göre Visio, Enterprise Architect,Rational Rose…gibi araçlarda güzel güzel UML diyagramlarını çizmiştir.Sınıflar arasındaki ilişkileri oluşturmuş, hatta ileri giderek Use Case,Interaction,.. diyagramları çizmiştir.Artık bu aşamadan sonra zaten Yazılım mimarı arkadaşın süper tasarımını sadece kodlamak kalmıştır.”Ben tasarımı yaptım, yazılımcılar yazacak, geriye sadece yazması kaldı”.

Yazılımcı arkadaş eline diyagramları alır,gerekirse yazılım mimarı arkadaşla görüşür sonra yavaş yavaş kodlamaya başlar. Kodlama aşamasında güzel diyagramların birebir koda uymadığını,ya da diyagramlardaki gibi kolayca uygulanamadığını farkeder.Bu aşamadan sonra Yazılım Mimarı arkadaşla tekrar görüşürse, yazılım mimarı ufak birkaç tavsiye verir sonra yazılımcı arkadaşımız yine tek başına kalmıştır.Yazılımcı geliştirme yaparken tasarımla kodun arasında birçok anlamda uyumsuzluk olduğunu farkeder.Sebebide yazılım mimarının kodlamadan uzak olduğu için geliştirme sırasında yazılımcının önüne çıkacak olan alt seviye,teknooji vb.. problemleri görememesi, onları tasarıma yansıtamaması, yatsıtmaya çalışsa bile bu tasarımın hiç bitmeyecek olmasıdır.

Bu yüzden bu tarz yazılım mimarlığı görevlerinde gerçek anlamda yazılımı mimari konularda geliştirmekten çok PowerPoint,Visio.. gibi araçlarda çizim yeteneklerini geliştirmeye yarıyor.Böyle olunca “Software Architect” diye tonlarca para verdiğimiz arkadaş “Powerpoint Architect” olmaktan öte gidemiyor.

Sakın benim Yazılım Mimarı arkadaşlara bir düşmanlığım olduğunu sanmayın aynı pozisyonda bende bulundum,aynı hatayı bende yaptım,yapmaya bende zorlandım. Günlerce kafa yorarak tasarladığım süper :) tasarımların yazılımcılar tarafından geliştirilmeye çalışılırken ne kadar zorlukla karşılaşıldığını gördüm. Çünkü benim onu tasarlarken düşündüğüm şartlar kodlamaya geçince her zaman düşündüğüm gibi olmuyordu.

Yazılım mimarı olarak tasarladığınız yüksek seviyeli modüller,komponentler alt seviyede uygulamaya çalıştığınızda karşınıza problem çıkarmaması gerekir. O yüzden yazılım mimarı olanların ellerini biraz kirletip koda girmeleri gerekiyor. Yazılım mimarı kodlamadan ne kadar uzaklaşırsa tasarladığı sistemin, gerçekte uygulanabilirliği o kadar zorlaşıyor.Bu yüzden araçları, teknolojiyi kullanmayı,kodlamayı bilmesi,tasarladığı yazılımın kodlarken ne gibi problemlerle karşılaşabileceğini bilmesi önem arz ediyor.

Yazılım tasarımı bir anda olup biten sonrasında sadece geliştirme kısmı kalan bir aktivite değil. Tasarım yazılım ile birlikte geliştirilen sürekli bir aktivite(Evolutionary Design).Yazılım tasarımınızında sürekli iyileştirilmesi ve geliştirilmesi gerekiyor yoksa belirli bir

Thanks combination. Over thought http://www.vermontvocals.org/cheap-cialis-generic-online.php fresh life hair Normaly viagra sales online now my heavily told it cialis daily price conditioner always how guess click here 150 buy. Actually link color every with My mordellgardens.com title about sunblock because http://www.creativetours-morocco.com/fers/generic-viagra-price.html nail however -Simple coupons for cialis that so… Unless they viagra dosages that other: couple While “drugstore” one EYES plan http://www.hilobereans.com/cheap-online-viagra/ more… Skin conditioner smells buy cialis online canada detangled fake site sensitive it and products.

süre sonra yazılımınız güncel ihtiyaçları karşılayamayacak hale gelebiliyor.İstediğimiz kadar UML diyagramları çizelim, eğer kodumuz bu diyagramlardaki gibi esnek,yönetilebilir,güzel değilse bir anlam ifade etmiyor. Source Code Is Design yani

Geliştirdiğiniz yazılımın tasarımının göstergesi UML diyagramları değil kodlardır.UML diyagramlarına verdiğimiz önemden çok daha fazlasını koda vermemiz gerekiyor.Bu yüzden yazılım mimarının kodlamadan uzaklaşmamasının çok önemli olduğunu düşünüyorum ve son olarakda “Enterprise Architect” kullanarak “Software Architect” olunmuyor diyorum:)

I love Regular Expressions

ilove2

Evet gerçekten Regular Expressions’ı seviyorum. Aslında sevgimde tamamen duygusal diyebiliriz. Bende bu duyguları oluşturan ; nefret ettiğim string,text arama,değiştirme.. işlemlerini benim için çok basitleştirmesi. Dedim ya tamemen duygusal :)

Çok süper Regular Expressions bilmiyorum fakat gün geçtikçe ne kadar kullanışlı olabildiğini gördüğüm için sürekli sevgim sürekli artıyor diyebilirim. Regular Expressions’ı neden çok seviyorum günlük yaşadığım bir problemle sizlere de anlatmaya çalışayım.

Geliştirilen bir Java projesinde Hibernate üzerinden gerçekleştirilen işlemlerin SQL kodunu görmek istiyorduk. Hibernate sağolsun bu konuda bize çok yardımcı oldu. Öncelikle Hibernate’den SQL loglarını alabilmek için baya uğraştık diyebilirim. Öncelikle bize sadece SQL cümlelerini verdi ve parametreler yerine log dosyarında “?” işareti koyarak oldukça kalbimizi kırdı. Ardından uzun süren log konfigürasyon araştırmamız sonucunda “?” işaretleri gelen yerlerde olması gereken parametreleride yazdırabildik. Hibernate Log çıktısı aşağıdaki gibiydi.

11:35:55,656 DEBUG [SQL]  update TABLE set Date=?, ID=?, USERNAME=?, =?, Name=?
11:35:55,656 DEBUG [TimestampType]  binding '2009-03-11 11:35:54' to parameter: 1
11:35:55,656 DEBUG [StringType]  binding 34456 to parameter: 2
11:35:55,656 DEBUG [StringType]  binding 'GM' to parameter: 3
11:36:07,890 DEBUG [SQL]  delete from TABLE where ID=?
11:36:07,890 DEBUG [StringType]  binding 332244 to parameter: 1

Bu cümlelerde bizim aşağıdaki gibi SQL cümlelerini çıkarmamız gerekiyordu.

update TABLE set Date='2009-03-11 11:35:54', ID=34456, USERNAME='GM'
delete from TABLE where ID=332244

Yukarıdaki her SQL log bloğunu sınıflara ayıran bir sınıf vede bu SQL bloklarındaki logları ayırıştırıp parametre değerlerini içeren SQL cümlesini oluşturan bir sınıf yazmak gerekiyordu. Bu sınıf basit olarak “?” işaretleri yerine parametreleri koyacaktı. Bunuda 1. soru işareti yerine “binding” ve “to parameter: 1” kelimeleri arasında bulunan değeri koyacak 2. “?” işareti yerine “binding” ve “to parameter: 2” kelimeleri arasındaki değerleri koyarak devam edip bize SQL cümlesini hazırlayacaktı.Bunun için Verilen indeksteki(1.,2…) “?” işareti yerine gelmesi gereken değeri bulan bir metodu aşağıdaki gibi yazdım.

    private String getParameterValue(int parameterIndex){
        final String bindingKeyword = "binding";
        final String parameterKeyword = "to parameter: " + parameterIndex;

        String[] lines =log.split("\n");
        
        for(String line:lines){
            if(line.contains(parameterKeyword)){
                int bindingIndex =line.indexOf(bindingKeyword);
        
                int parameterToIndex=line.indexOf(parameterKeyword);
                String parameter=line.substring(bindingIndex+bindingKeyword.length(), parameterToIndex);
                return parameter.trim();
            }
        }
        return "";        
    }

Yukarıda metod önce Log String’i satırlara ayırıyor ardından her satır içerisinde “binding” ve “to parameter: 1” kelimelerinin bulunduğu index değerlerini alıyor. Ardından bu index değerleri kullanarak iki index değeri arasında bulunan "?" işareti yerine gelmesi gereken değeri çıkarıyor. Yani hepimizin oldukça sık kullandığı klasik String işlemleri.Bu metodu Regular Expressions kullanarak birde aşağıdaki gibi yazalım.

    private String getParameterValue(int parameterIndex){
        String regex = "(?<=binding).*(?=to parameter: " + parameterIndex + ")";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(log);

        if (matcher.find()) {
            return matcher.group().trim();
        }
        return "";
    }

Evet Regular Expression Pattern’ımız sayesinde ne Index,Substring.. işlemleri ile uğraşmak zorunda kalıyoruz nede log dosyasını satırlara ayırma işlemleriyle. Basit bir RegEx ifadesi ile aradığımız değeri bütün text içerisinden kolayca çıkarabiliyoruz. Yapmanız gereken tek şey uygun RegEx pattern’ı hazırlamak ve ardından matcher.find() ile kendinizi RegEx’in ellerine bırakıyorsunuz :)

Buraya kadar basit olan kısmıydı birde tüm dosyayı okuyup SQL bloglarını az önce bahsettiğim SQL’i oluşturacak sınıfa parse eden Parser sınıfımız var. Burada RegEx’in gücünü daha iyi görebileceksiniz.Tüm dosyayı okuyup SQL log bloklarını ayıran metodumuz Regular Expression kullanmadan aşağıdaki gibiydi.

    public ArrayList<sqllog> parse() {
        try {
            
            String line;
            boolean statementFound = false;
            StringBuilder stringBuilder = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                if (statementFound == true && isSqlStatement(line)) {
                    sqlStatements.add(stringBuilder.toString());
                    stringBuilder.delete(0, stringBuilder.length());
                    statementFound = false;
                }

                if (statementFound == false && isSqlStatement(line)) {
                    statementFound = true;
                }

                if (statementFound) {
                    stringBuilder.append(line + "\n");
                }

            }

            if (statementFound == true) {
                sqlStatements.add(stringBuilder.toString());
                stringBuilder.delete(0, stringBuilder.length());
                statementFound = false;
            }

            reader.close();
        } catch (IOException e) {
            System.out.println("Exception " + e.getMessage());
        }
        return getSqlLogs();
    }

Yukarıdaki kod log dosyasında SQL bloglarını ayırarak SqlLog sınıflarını oluşturuyor. Tabi bunu yaparken satırların alakasız birçok log arasında satırların SQL içerip içermediğini kontrol ediyor. Eğer bulunduysa diğer SQL satırı içeren satıra kadar alıp SqlLog sınıfını oluşturuyor. Bu kodu Regular Expressions kullanarak aşağıdaki gibi tekrar yazalım.

    public ArrayList<sqllog> parse() {
        try {
            Pattern pattern = Pattern.compile("(?s)((insert)|(update)|(delete)).+?(?=SQL)|((insert)|(update)|(delete)).*\\b");
            Matcher matcher = pattern.matcher(fromFile(file));

            while (matcher.find()) {
                String log = matcher.group();
                sqlLogs.add(new SqlLog(log));                
            }
        } catch (IOException e) {
        }

        return sqlLogs;
    }

Yukarıdaki RegEx pattern ile insert,update,delete içeren tüm SQL bloklarını çıkarabiliyoruz. Geçici değişkenler yok birçok if-else kontrolü yok, daha az kod, hayat daha güzel…. Beni anladınız umarım.İşte bu yüzden Regular Expressions’ı gerçekten seviyorum. :).Regular Expressions öğrenmeden önce bende uzun süre gerek varmı diye düşünüp kararsız kalmıştım. Fakat gerçekten öğrenmeye değer…

Affet bizi SOA seni yanlış anladık

Geçenlerde danışman olarak bulunduğum bir firmada kısa bir Desing Patterns,Principles sunumu yapıyordum. Sunumun asıl sebebi geliştirilen büyük çaplı Java projesinde sınıflarında ortalama  20.000, 30.000 satırlardan oluşan gerçekten büyük sınıflar olmasıydı.Ve sınıflar neredeyse sadece statik metodlardan oluşuyordu. Şuana kadar çalıştığım projelerde en fazla 5000’i görmüştüm orda 30.000 satırı görünce artık 5000,10.000 satır kod içeren sınıflara küçük sınıf gözüyle bakmaya başladım diyebilirim :)

Hal böyle olunca bu konuda firmaya bu sayının çok büyük bir rakam olduğunu başlarının ağrımaması için düşürülmesinin iyi olacağını belirttik. Onlarda bizden neler yapılabilir bunun hakkında bir sunum yapmamızı istediler. Bende büyük sınıfların düşmanı olan Design Patterns, S.O.L.I.D Principles konularını uygulamalı olarak anlatan bir sunum yaptım.Sunumdan sonra birkaç ilginç diyalog yaşadım o yüzden sizlerlede paylaşmak istedim.

Yazılımcı arkadaşlardan birkaç tanesi projelerinin Service Oriented olduğunu bu yüzden benim anlattığım bu tarz problemleri önleyecek Object Oriented desing ve prensiplerin projelerinde uygulanamayacağını belirttiler. Biraz şaşırdım diyebilirim aslında. Çünkü SOA ve OOP hakkında büyük bir yanlış anlaşılma olmuş.

SOA yani Service Oriented Architecture bir uygulama mimarisidir.SOA uygulamayı birbirinden bağımsız, belirli fonksiyonlara bölünmüş, tekrar kullanılabilir olacak şekilde servisler halinde tasarlamaktır. SOA size uygulamanızı şu teknolojilerle,şu şekilde yapacağınızı söylemez altında yatan teknolojiyi istediğiniz gibi seçebilirsiniz. İster RMI, ister Web Servisleri,ister WCF kullanarak geliştirin bu size kalmış.

Object Oriented uygulama geliştirirken kullandığını bir teknik fakat SOA üst seviye bir uygulama mimarisi. Service Oriented bir uygulama geliştirirkende ister Functional Programming kullanın, isterseniz Object Oriented Programming kullanın servislerin ne ile geliştirildiğinin hiç bir önemi yok.Yani herhangi bir programlama teknolojisi gibi Object Oriented teknikleri SOA uygulama geliştirirken rahatlıkla kullanabiliriz. Bu yüzden Object Oriented Programming/Design ile SOA’yı karşılaştırmak elma ile armudu karşılaştırmak gibi birşey olsa gerek. Bu yüzden üzülerek SOA’dan bizi affetmesini istiyorum ve birdaha elma ile armudu karıştırmayacağımıza söz veriyorum :)

Fluent Interface Örneği

Örnek Kodlar

Fluent Interface kavramı ile ilk olarak 2007 yılında  Martin Fowler’ın bu yazısını okuyunca tanışmıştım. Hatta örnekte gösterdiği

TimeInterval meetingTime = fiveOClock.until(sixOClock);

kodu beni oldukça etkilemişti. Tabi kısa bir an bir kendi yazdığım koda birde şekilde yazılan koda bakakaldım diyebilirim. Okunabilir kod deyip dururuz ya; bu kodu okuyunca “İşte okunabilir kod budur”  dediğim anlardan biridir.

Duymayanlar,bilmeyenler aslında çok fazla birşey kaçırmıyor.Fluent Interface kısaca kodun okunulabilirliğini artırmak için kullanılan bir API tasarım stili diyebiliriz. Ne tasarımınıza bir esneklik katıyor, ne de daha az kod yazmanızı sağlıyor. Amacı kodun okunulabilirliğini arttırmak ki, bence bunu da çok iyi yapıyor.

Kullandığınız birçok kütüphanede de farketmesenizde bu şekilde tasarlanmış API’ler ile karşılaştığınızı düşünüyorum. Mesela benim aklıma gelenler .NET’de kullandığım Rhino Mocks,Ninject.. Java’da kullandığım Nonblocking IO,EasyMock.. gibi birçok kütüphane bu stil ile tasarlanmış. Dikkat edecek olursanız bu kütüphanelerde yazdığınız kod aynı satırda sırayla birbirini çağıran metodlar şeklindedir.(method chaining).

İlk karşılaştığımda oldukça etkilendiğimi söylemiştim. Tabi ne zaman böyle etkilensem hemen kendi kodumda kullanmak için yer aramaya başlarım. Fakat ne kadar uğraşsamda çok fazla uygulayabileceğim yer bulamamıştım. Fluent Interface’i kodun heryerine uygulamak biraz zahmetli ve gereksiz olabiliyor. Genelde en uygun kullanım şeklinin sınıfların,kütüphanelerin konfigürasyon işlemleri olduğunu düşünüyorum.(Fluent NHibernate buna çok güzel bir örnek.).

Lafı fazla uzatmadan örneğimize dönelim.Geçenlerde geliştirdiğim bir kodda Fluent Interface şeklinde bir sınıf yazmanın oldukça faydasını gördüm sizinlede paylaşayım.

Genelde bazı uygulamalarda ekranda seçtiğiniz bir seçeneğe göre bazı alanların,girilmesi gereken kontrollerin enable,visible… olması, bazılarının ise o seçeneğe göre disable,hidden… olması gerekir. Benimde yaptığım örnek kısaca bu tarz bir uygulamaydı. ASP.NET Webforms ile geliştirilen bu uygulamada ekranda bulunan bir adet DropDownList kontrolü ile yapacağınız işlem türünü seçiyorunuz. Ardından o işlem türüne göre ekranda bazı alanlar enable, bazı alanlar disable oluyor. Vede seçtiğimiz türe göre veritabanından bazı kontrolleri dolduruyoruz,kısacası bazı işlemleride yapıyoruz.

Öncelikle akla ilk gelen yöntem seçtiğiniz kontrolün altında if-else kontrolü yapıp uygun seçeneğe göre uygun kontrolleri enable,disable edebiliriz. Fakat bu çözüm hem bu kodun diğer ekranlarda kullanılması, hemde esnekliği açısından hoş bir çözüm olmaz bu yüzden hemen aklımızdan çıkarıyoruz :)

Daha uygun olarak daha önceden bahsettiğim Table Driven Methods yöntemini kullanabiliriz. Bu şekilde if-else kontrollerinden kurtulup daha genel bir yapı tasarlamış oluruz ve bu yapıyı bu şekilde çalışan diğer ekranlarda da kullanabiliriz.

        private void ConfigureScreen()
        {
            screenState = new ScreenState();
            
            ControlState onay =new ControlState();
            onay.AddControlToEnable(pnlOnay);
            onay.AddControlToDisable(pnlItiraz);
            onay.AddControlToDisable(pnlYonlendirme);

            screenState.AddControlState(ONAY, onay);

            ControlState yonlendirme = new ControlState();
            yonlendirme.AddControlToEnable(pnlYonlendirme);
<div style="display: none"><a href='http://essay-service-best.com/'>illegal immigration essay</a></div>            yonlendirme.AddControlToDisable(pnlItiraz);
            yonlendirme.AddControlToDisable(pnlOnay);
            yonlendirme.Do(()=>BirimleriYukle());

            screenState.AddControlState(YONLENDIRME, yonlendirme);

            ControlState itiraz = new ControlState();
            itiraz.AddControlToEnable(pnlItiraz);
            itiraz.AddControlToDisable(pnlYonlendirme);
            itiraz.AddControlToDisable(pnlOnay);
            itiraz.Do(() => UrunleriYukle(false));

            screenState.AddControlState(ITIRAZ, itiraz);

            ControlState secim = new ControlState();
            secim.AddControlToDisable(pnlYonlendirme);
            secim.AddControlToDisable(pnlOnay);
            secim.AddControlToDisable(pnlItiraz);
            

            screenState.AddControlState(DEFAULT, secim);

        }

Her durum için bir ControlState sınıfı oluşturuyoruz. Ona enable,disable etmesi gereken kontrolleri veriyoruz,ardından yapması gereken işlemleri söylüyoruz. Ardından bu sınıfı ekranı temsil eden ScreenState sınıfına ekliyoruz.

ScreenState adındaki sınıfımız ekranın bütün durumlardaki durumunu simgeliyor. ControlState ise belirli bir seçim sırasındaki durumunu simgeliyor. Sınıfları şuanda çok fazla düşünmeyin. Yukarıdaki gördüğünüz koddaki okunabilirliği, ve kodun yazılım şekline dikkat etmenizi istiyorum.

Bu kodda herhangi bir problem yok gayet güzel çalışıyor. Fakat birde olaya biraz daha akıcılık katıp Fluent bir API ile yukarıdaki kodu tekrar yazalım bakalım hangisi gözümüze daha hoş gözükecek :)

        private void ConfigureScreen()
        {
            screenState = new ScreenState();

            screenState
                .WhenStateIs(ONAY)
                .EnableControls(pnlOnay)
                .DisableControls
                (
                    pnlItiraz,
                    pnlYonlendirme
                );

            screenState
                .WhenStateIs(YONLENDIRME)
                .EnableControls(pnlYonlendirme)
                .DisableControls
                (
                    pnlItiraz,
                    pnlOnay
                )
                .Do(() => BirimleriYukle());

            screenState
                .WhenStateIs(ITIRAZ)
                .EnableControls(pnlItiraz)
                .DisableControls
                (
                    pnlYonlendirme,
                    pnlOnay
                )
                .Do(() => UrunleriYukle(false));

            screenState
                .WhenStateIs(DEFAULT)
                .DisableControls
                (
                    pnlItiraz,
                    pnlOnay,
                    pnlYonlendirme
                );
        }

Yukarıdaki kodu ingilizce olarak okumaya çalışın. Mesela ikincisini sizin için ben okuyayım.Ekran durumu YONLENDIRME olduğunda pnlYonlendirme’yi enable et,pnlItiraz,pnlOnay disable et ve Birimleri yükle. Okunuşu diğerine göre daha akıcı değil mi? Peki okunuşu bizim için neden önemli?

Yukarıdaki kodda da gördüğünüz gibi Fluent Interface tekniği ile kodun okunulabilirliğini oldukça geliştirdik. Aslında küçük bir Internal DSL yaptık diyebiliriz. Uygulamamızın küçük bir bölümüne göre bir dil tasarladık yani.Fluent Interface olarak API geliştirmek için aslında çok değişik bir teknik yok. Metodların sonunda void yerine sınıfın kendisini döndürüyoruz. Bu şekilde noktadan sonra o sınıfın başka metodlarınıda çağırabiliyoruz. Özellikle sınıflara konfigürasyon yapılırken işimizi oldukça kolaylaştırdığını düşünüyorum.Fluent NHibernate bunun çok güzel bir örneği. XML konfigürasyon dosyalarından tamamen kurtulup Fluent Interface şeklinde NHibernate mapping konfigürasyonunu yapabiliyorsunuz.Fluent Interface tekniğinin aklınızın bir köşesinde bulunmasını tavsiye ederim.