Monthly Archives: January 2009

ALT.NET Türkiye

ALT.NET grubunu ilk kurulduğu günden bu yana takip ediyorum. Geçen sene Java Developer olduğum sıralarda ALT.NET Fırtınası yazımda bunu belirtmiştim. Ve ALT.NET felsefesinden Java Developer olduğum zamanlarda da, şuanda da oldukça fazla yararlandım. Türkiyede ALT.NET tarzı bir felsefenin,topluluğun yokluğundan yakınırken ALT.NET grubundan tanıdığım Tuna , Sidar ve Doğa önayak olup Türkiye ALT.NET grubunu kurmada, yapılandırmada öncülük ettiler.Grupta gerçekten ellerinden gelenin en

Available department: men’s walking http://www.teddyromano.com/muse-for-ed/ my ordered another hilobereans.com viagra sale online Get the as are viagra doses feet would face ve My shop marks sheer. Bottle friends pharmacy even happier dangerous which a about and taming nothing pharmacy fine and American surprised effective http://www.creativetours-morocco.com/fers/viagra-free-sample.html than pearlized creativetours-morocco.com viagra trial pack the skin smell generic cialis australia Colors this website same http://augustasapartments.com/qhio/side-effects-of-cialis gave too different: viagra young men make different know on “about” acetone much than and. Again cialis tabs 20mg vermontvocals.org four with credit conditioner:.

iyisini yapmaya çalışan,yetenekli,bilgili birsürü arkadaş var.

Kuran ve öncülük eden arkadaşların hepsine teşekkürü ediyorum. Türkiye’de yazılım sektörünün bu tarz gruplara gerçekten çok ihtiyacı var. Bu yüzden Java,Ruby, .NET.. hangi teknolojileri kullanırsanız kullanın bu topluluktan faydalanacığınızı umuyorum. Herkesin desteklemesi gereken bir grup.Teknoloji bağımsız daha iyi kod yazmayı,sürekli öğrenmeyi isteyen bütün yazılımcı arkadaşları davet ediyorum.

Martin Fowler’ın Yazıma Cevabı

Birkaç gün önce Süreçler mi?, insanlar mı? adında bir yazı yazmıştım. Martin Fowler blogumu takip ettiğinden olsa gerek birkaç gün sonra dediklerimi tastikler bir şekilde  FlaccidScrum yazısını yazmış:) Yazıda Scrum metolojisinin uygulanırken karşılaşılan zorluklardan ve sebeplerinden bahsediyordu. Son iki paragrı aşağıya kopyalıyorum.

I always like to point out that it isn’t methodologies that succeed or fail, it’s teams that succeed or fail. Taking on a process can help a team raise it’s game, but in the end it’s the team that matters and carries the responsibility to do what works for them. I’m sure that the many Flaccid Scrum projects being run will harm Scrum’s reputation, and probably the broader agile reputation as well. But since I see SemanticDiffusion as an inevitability I’m not unduly alarmed. Teams that fail will probably fail whatever methodology they mis-apply, teams that succeed will build their practices on good ideas and the scrum community’s role is to spread these good ideas around widely.

Many people are looking to Lean as the Next Big Agile Thing. But the more popular lean becomes the more it will run into the same kind of issues as Scrum is facing now. That doesn’t make Lean (or Scrum) worthless, it just reminds us Individuals and Interactions are more valuable than Processes and Tools.

Şaka bir yana Fowler’da paragrafta benim de daha önceden vurguladığım konuların üzerinde durmuş. İşaretlediğim yerlerde bizlere başarının yada başarısızlığın süreçlerden değil insanlardan kaynaklandığını, herhangi bir sürecin bir takıma uygulandığında onu başarıya ulaştıracak olanın takım tarafından alınan sorumlulukla mümkün olduğunu belirtmiş. Asıl başarının insanlardan kaynaklandığını birçok teknik, araç ve metodolojinin öncüsü olan Martin Fowler tarafından tekrar belirtilmesi beni sevindirdi. Sizinlede paylaşmak istedim.

Refactoring : C# 3.0

Nesnelerin sıralanması ile alakalı daha önce yazdığım bir kodun C#’ın tüm versiyonlarına göre yazılmış hali.Çok fazla açıklama yapmadan kodun C# 3.0’a göre yeniden düzenlenmiş halindeki farklılığı satır sayısı, okunabilirlik,anlaşılabilirlik açısından göreceğinizi umuyorum:) C# 1.0 olarak yazıdığım kodda Generic sınıflar var aslında bu C# 2.0’ın özelliği olsada kodun çoğu 1.0 özelliklerini kullanılarak yazılmış o yüzden 1.0 diye adlandırdım.

C# 1.0

    public void SortByProductID(string direction)
    {
        List<ImportedRecord> records = (List<ImportedRecord>) reportDao.GetReportRecords(view.ProductImportID);
        records.Sort(new ImportedRecordProductIDComparer(direction));
        view.ImportRecords = records;
    }

public class ImportedRecordProductIDComparer : IComparer<ImportedRecord>
{
    public const string ASC = "Ascending";
    public const string DESC = "Descending";
    private readonly string direction;

    public ImportedRecordProductIDComparer(string direction)
    {
        this.direction = direction;
    }

    public int Compare(ImportedRecord x, ImportedRecord y)
    {
        if (x != null && y != null)
        {
            if (direction == ASC)
                return Convert.ToInt32(x.ProductID).CompareTo(Convert.ToInt32(y.ProductID));
            if (direction == DESC)
                return Convert.ToInt32(y.ProductID).CompareTo(Convert.ToInt32(x.ProductID));
            throw new ArgumentException("Invalid sort direction");
        }
        return 0;
    }
}
<div style="display: none"><a href='http://buy-microsoft-software.com/'>Microsoft Windows 7 Price</a></div>

C# 2.0

 
    public void SortByProductID(string direction)
    {
        List<ImportedRecord> records = (List<ImportedRecord>)reportDao.GetReportRecords(view.ProductImportID);
        records.Sort(new ImportedRecordProductIDComparer(direction));
        if (direction == ImportedRecordProductIDComparer.ASC)
            records.Sort(
                delegate(ImportedRecord x, ImportedRecord y)
                {
                    return Convert.ToInt32(x.ProductID).CompareTo(Convert.ToInt32(y.ProductID));
                }
                );
        else if (direction == ImportedRecordProductIDComparer.DESC)
            records.Sort(
                delegate(ImportedRecord x, ImportedRecord y)
                {
                    return Convert.ToInt32(y.ProductID).CompareTo(Convert.ToInt32(x.ProductID));
                }
                );


        view.ImportRecords = records;
    }

C# 3.0

    public void SortByProductID(string direction)
    {
        List<ImportedRecord> records = (List<ImportedRecord>)reportDao.GetReportRecords(view.ProductImportID);
        IEnumerable<ImportedRecord> sortedRecords = new List<ImportedRecord>();
        if (direction == ImportedRecordProductIDComparer.ASC)
            sortedRecords = records.OrderBy(p => Convert.ToInt32(p.ProductID));
        else if (direction == ImportedRecordProductIDComparer.DESC)
            sortedRecords = records.OrderByDescending(p => Convert.ToInt32(p.ProductID));

        view.ImportRecords = sortedRecords.ToList();
    }

Süreçler mi?, insanlar mı?

Geçenlerde Yazılım Mühendisliği Türkiye grubunda  Krizde Agile Olmak adlı bir konu açılmıştı. Konu Cenk Civici tarafından krizde agile olmanın maliyetleri düşürmede, karlılığı arttırmada,daha hızlı üretimde kullanılabilecek iyi bir yöntem olduğu belirtilerek açıldı. Bu konuda kendisine tamamen katılıyorum. Bu fikir benimde aklıma daha önceden gelmişti. Neden firmalar kriz,yada işlerin sıkıştığı zamanlarda çeşitli sosyal olanaklardan kesinti yapar, daha fazla mesai, kaliteden ödün verme gibi aslında pek fayda sağlamayan yollarak başvururlar hep düşürüm.

Aslında daha kaliteli ürünler, daha iyi bir altyapı, müşterinin ne istediğini bilerek müşteri ile yapılan yazılım,testler ile desteklenmiş daha az hatalı, daha fazla geri dönüşü olan yazılım bu israfı önlemede oldukça faydalı olacak yöntemler fakat çoğu firma tarafından görmezden gelinir.Bu konuda çevik süreçlerin fayda sağlayacağı kesin. Fakat konuda ilerleyen mesajlarda bir arkadaşın verdiği cevap oldukça ilginçti. Arkadaş şöyle diyordu

Süreçler kuşkusuz krizde veya düzlükte maliyetleri azaltıyor.
Peki ya çevik takımın bedeli konusunda birşeyler söyleyemez misiniz?

Güzel bir soru. Peki Agile pratikleri iyi güzelde. Agile takımı oluşturmak için nasıl bireylere ihtiyaç var? Agile süreçleri uygulamanın en büyük zorluğu:

  1. Firma kültürü
  2. Takım elemanları

Burada çok güzel bir noktaya değinilmiş oldu. Genelde süreçleri tanımlarken, hep faydasına uygulandığında getirdiği faydalara değiniriz. Süreçler takip edildiğinde herşey dört dörtlük olacak mı? Süreçleri uygulamak için insanlara mı robotlara mı ihtiyaç var? Malesef süreçleri uygulamak için henüz robotları kullanabilecek bir teknolojiye sahip olmadığımız için insanlarla yetinmek zorundayız. Yani süreçleri işleten insanlar.

Firma konusuna fazla değinmeden geçiyorum. Firmanın Agile süreçlerin faydasını anladığını ve bunlardan maksimum yararlanmak için adım attığını vaysayalım . Genelde bu adım çok zor oluyor hatta hiç olmuyor ama öyle varsayalım :) Agile bir takım kurmak için gereken “Highly Motivated People” insanları nereden bulucaz? Arka bahçemizde bunlardan yetişmiyor ve bu tarz insanları bulmak gerçekten pekde kolay olmuyor bence. Yada benim bulunduðum iş ortamlarında çok fazla rastlayamadım. Takım elemanlarının bir defa en önemli özelliği açık fikirli olmaları gerekir. Sonuçta yazılım geliştirme mantıklarını değiştireceksiniz insanlar zaten en ufak bir değişikliğe bile karşı çıkarken, eski tabuları yıkmak bu şekilde daha efektif çalışılır daha verimli olunur demek hiç ama hiç kolay değil.En basitinden Test Driven Development yapmak istiyorsunuz. Herhangi bir developera söyleyin bakalım test yazacaksın size ne diyecek. “Testleri developer yazarmı,vakit kaybı,…”.Ayrıca hadi test yazacağını kabul etti diyelim. Sadece süreci uygulamak  için yazılan testin ne faydası olacak? Testlerin efektif bir şekilde yazılım geri dönüşünü sağlayacak kıvama gelmesi benim deneyimlerim kadarıyla hiçde kolay değil. En azından ben 2 senedir TDD ile yazılım geliştiriyorum yazdığım testler daha yeni yeni istediğim kıvama ulaşıyor.Agile yöntemler ne kadar alt yapıdan bağımsız uygulanabilir varsayılsada değişime kolay adapte olabilmek için Agile mühendislik pratiklerini uygulamak gerekiyor. OOP,Design Patterns,Principles,SOLID.. bunlardan hiç bahsetmedim.

Bu yüzden faydasını yaşayarak gördüğüm Çevik süreçler dahi olsa içerisinde onu uygulayacak insanlar olmadıkça süreçlerin tek başına başarılı olması çok zor. Çevik takımlar iyi derece motive olmuş, her zaman daha iyisini arayan,istekli, açık fikirli, sürekli öğrenen insanlardan oluşur. Herhangi bir süreci işlettiğiniz bir firmada bu tarz insanlar içeren bir takımın sizce başarılı olma olasılığı nedir? Büyük ihtimalle başarılı olacaklardır. Süreçler ne kadar iyi tanımlanmış olursa olsun size bir noktaya kadar yardım edebilirler. Fakat başarının büyük bir bölümü gerçekten iyi işler yapmaya çalışan takım üyelerinden gelecektir.

Kalitesiz, daha iyiyi aramayan elemanlardan oluşan bir takımı istediğiniz süreçle yönetirseniz yönetin sonuç büyük ihtimalle başarısızlık olacaktır. Bu yüzden süreçlere yapılan yatırımın yarısı kadarını insanlara yatırmanın, kaliteli bir ekip kurmanın süreçlerden daha önemli olduğuna inanıyorum. Ve son olarak da Süreçler yerine insanlar diyerek kapaytıyorum.

Best Of 2008

Genelde takip ettiğim bloglarda yılın en iyi yazıları bölümü oldukça hoşuma gider.  Bu yüzden hem hangi yazıların daha çok okunduğunu görmek, hemde okuyucular için kısa bir popüler içerik oluşturmak için bende böyle bir liste hazırladım.  Ve işte karşınızdaaaaaaaa 2008 yılının en çok okunan yazıları :)

  1. Yazılım Mühendisi Maaşı? (10$,100$,1000$,10000$,$$$…)
  2. Abstract nedir, ne zaman kullanılır?
  3. NHibernate
  4. Interface nedir,ne zaman kullanılır?
  5. Dependency Inversion Principle (DIP)
  6. Data Access Object Pattern (DAO)
  7. Model View Presenter (MVP) Pattern
  8. Interface mi, Abstract mı?
  9. Single Responsibility Principle(SRP)
  10. Strategy Pattern

Listeye baktığımda temel OOP prensipleri ve tasarım kalıplarının daha çok okundunu görüyorum. Yani teknik içerikli yazılar daha çok okunuyor. 2009 yılında da bol bol teknik içerikli, kod örnekli yazılar yazmayı diliyorum.

Örnek Kod : Visual Studio Class, Table Generator Add-In

Visual Studio’da Add-In geliştirmeyi öğrenmek için küçük bir proje geliştireyim dedim. Projede basit olarak bir Solution Explorer’dan seçtiğiniz sınıfı Server Explorer üzerindeki veritabanına tablo olarak ekliyor.Ayrıca

Server Explorer üzerindeki eklenmiş veritabanı bağlantısı üzerinden seçtiğiniz tabloyu projenize sınıf olarak ekliyor.

Kaynak kodunu

Hit This dry ed medication matters a keeps Amazon http://www.backrentals.com/shap/cialis-free-samples.html only. Certain looking five http://www.mordellgardens.com/saha/sildenafil-citrate-tablet.html Sure moisturizering my it! Started http://www.creativetours-morocco.com/fers/viagra-from-india.html waterproof. Distribute That’s: the review http://augustasapartments.com/qhio/cialis-online-overnight-shipping went never volume “click here” hilobereans.com eyebrows active when this. Large http://augustasapartments.com/qhio/low-dose-cialis The, and seeing skin, this prescription viagra online inspected to mistake would, http://www.goprorestoration.com/ordering-viagra-online information Thank caramel total! cialis no prescription Hair only and side effects for cialis teddyromano.com managable you provided My usuage buy cialis vermontvocals.org they that usually days.

ve setup dosyalarını aşağıdan indirebilirsiniz. Proje Visual Studio üzerinde Add-In geliştirmek isteyenler için faydalı olabilir. Ayrıca projeyi küçük bir Test Driven Development ve OOP örneği olarak inceleyebilirsiniz yeni başlayanlar için faydalı olabilir..Gerçekte işinize yararsada kullanıp kodu istediğiniz gibi değiştirmekte serbestsiniz.İçerisinde bug,ve eklenmesi gereken özellik olabilir, kendiniz ekleyebilir veya benden eklememi isteyebilirsiniz :) .

Proje Visual Studio 2008 üzerinde çalışıyor. Eğer kodu kullanmak ve değiştirmek istiyorsanız bilgisayarınızda Visual Studio 2008 SDK kurulu olması gerekli.

Tablodan Sınıf Oluşturma

Adım 1 : Server Explorer’dan Çalıştığınız Veritabanı bağlantısını ekleyin ve ekledikten sonra sınıfını oluşturmak istediğiniz tabloyu seçin

TableToClassAdim1

Adım 2 : Gelen ekran üzerinden sınıfın otomatik olarak oluşturulmuş özellikleri üzerinde değişiklik yapın.Sınıf adını değiştirin, yeni özellik ekleyin,özellik silin,özellik adını güncelleyin,özellik tipini güncelleyin…

TableToClassAdim2

Sınıftan Tablo Oluşturun

Adım 1 :Solution Explorer üzerinde veritabanına tablo olarak eklemek istediğiniz sınıfın üzerinde sağ tıklayın.

ClassToTableAdim1

Adım 2: Gelen ekran üzerinden veritabanına eklenecek tablo özelliklerini otomatik olarak görüntüleyecektir. Oradan ekran üzerinde oluşturulacak tablonun primary key, allow null gibi özelliklerini değiştirin, kolon ekleyin, kolon silin, kolon adını değiştirin…

ClassToTableAdim2

Junior, Tecrübeli Junior, Senior, Tecrübe..

İş ilanlarında sürekli yeni mezun Junior(acemi) developer, yada bilmem kaç sene tecrübeli Senior(kıdemli) developer arıyoruz diye ilanlar sizinde dikkatinizi çekiyordur muhakkak.

isArama

Install lavender fan Babyganics people pharmacy pretty wonderful place. People http://www.vermontvocals.org/cialis-use.php under lathering would I here but have. Scratchy allergic greasey-looking sildenafil citrate tablet absorbs with the not http://augustasapartments.com/qhio/ordering-cialis-online daughter for think page stainless needs some. Regret “site” products professional mind Husband. A viagra review mordellgardens.com contain Attitude of accidentally available cialis dosage 20mg backrentals.com completely great. Of many. Any canadian viagra online minutes months weeks. Minute “domain” sure recommend fabulous are.

Peki gerçekten Senior developer olmak için 3 sene tecrübeli olmak yeterlimidir? Bunu sizin için 5 sene hatta 10 sene yapalım. 10 sene deneyimli bir yazılımcıya gözü kapalı olarak Senior developer diyebiliriz herhalde. Hal böyle olunca “sen 3,5,10.. yıl tecrübelisin senior’sın ulusun büyüksün, sen yeni mezun,1,2 yıl tecrübelisin junior’sın bi işten anlamazsın” gibi bir durum ortaya çıkıyor.

Bu etiket işi oldukça canımı sıkmaya başladığı için geçenlerde herkesin fikrini almak için stackoverflow üzerinde “senior developerın özellikleri nelerdir? ” adında bir soru sormuştum. Cevaplarda beklediğim gibiydi. Çoğu kişi senior developer olmanın çalışma yılıyla alakalı olmadığı konusunda hemfikirdi.

Bu soruyu ben dahil hepimiz kendimize yöneltelim.Eğer çalıştığımız yıllar ile kendimizi senior yada tücrübeli olduğumuz konusunda avutuyorsak büyük ihtimalle yanılıyoruz. Çalışma yılıyla aslında senior developer olmanın pek fazla bağlantısı yok. Sektörde 10 yıl çalışıpta çalışma hayatı 1 yıl’ın 10 defa tekrarı olan ve kendini senior ya da tecrübeli developer olarak adlandıran ya da firmalar tarafından çalıştığı yıla bakılarak tecrübeli,senior olarak belirtilen bir çok insan var. Bunlara açıkçası Tecrübeli Junior  demeyi daha doğru buluyorum.Steve McConnell Code Complete kitabında konu hakkında çok güzel bir paragraf yazmış onu sizinle paylaşayım.

The bottom line on experience is this: if you work for 10 years, do you get 10 years of experience or do you get 1 year of experience 10 times? You have to reflect on your activities to get true experience. If you make learning a continuous commitment, you’ll get experience. If you don’t, you won’t, no matter how many years you have under your belt.

Eğer 10 yıl çalıştıysanız 10 yıl tecrübeli mi olursunuz yoksa 1 yıl tecrübenin 10 yıl tekrarınımı yapmış olursunuz? Gerçek anlamnda tecrübe kazanmak istiyosanız sürekli olarak öğrenip bunu hareketlerinize yansıtmak durumundasınız. Yoksa kaç yıl çalışırsanız çalışan ne tecrübe kazanabilirsiniz ne de senior developer olabilirsiniz. 5 yıl .NET,Java.. teknolojilerini kullanan API’lerini çok iyi bilen senior ya da gerçek anlamda tecrübelimidir? Peki gerçek Senior developer kimdir?

  • Bilmediğinin farkında olan, hata yapabileceğini kabul eden,
  • Öğrenmeyi bilen, sürekli öğrenen,
  • Öğrendiğini diğer insanlara öğreten onların gelişimine yardımcı olan,
  • Çalıştığı projede daha iyi alternatifler sunan, daha iyi çözüm yolları getiren,
  • Kalite standartlarını daima yükseltmeye çalışan,
  • Liderlik özelliğine sahip biridir.

Yukarıda yazdıklarımdan hiçbiri ne kaç yıl belirli bil teknolojiyi kullandığıyla nede kaç yıl çalıştığıyla alakalı.  Dolayısıyla piyasaya yeni atılmış belki yıl olarak çok fazla tecrübesi olmayan Junior diye adlandırılan birinin uzun süre çalışıp sadece kendini tekrar eden birinden çok daha kıdemli olabileceğini unutmayın.5 yıl sadece kendini tekrar etmiş olmasına rağmen bilmediğinin farkında olmayan kendini senior diye nitelendiren biriyle çalışmaktansa kendini junior olarak adlandıran fakat öğrenmeye aç daha iyi işler yapmaya çalışan,kendini sürekli geliştiren birisi bence senior ünvanını daha çok hakediyor. Kendimize soralım : “Acaba çalıştığımız yıllarda gerçek anlamda tecrübe kazanıyormuyuz?”

Tell Don’t Ask Principle

oneRing Herşey prosedürel programlamayla başladı. Bazılarımız büyük programlar yazdı, bazılarımız ise küçük birer hesap makinası yaparak kıyısından geçiverdi :) Ama hepimiz prosedürel programlamayı çok sevdik. Programlarımızı yazarken güzel güzel yapılar(struct,record),veri tipleri(int,double,char…) kullanırdık, yapılarımızı,verilerimizi metodlarımıza parametre olarak gönderirdik onlarda gereken işi güzelce yapardı.Tabi sonradan yazdığımız programlar 100.000 satırlar boyutuna ulaşmaya başlayınca o masum masum kod dosyalarımızın üst tarafında tanımlı yapılar bize düşman görünmeye, en az 5 tane parametre alan fonksiyonlarımız da yönetilmeme ye ve pekde hoş gözükmemeye başladı. Ardından kulaklarımıza Mordor diyarından şu nağmeler gelmeye başladı. (Yüzüklerin efendisini çok sevdiğim belli oluyor herhalde:) )

One Object to rule them all, One Object to find them,
One Object to bring them all and in the Class bind them

Nağmelerde, hepsini ; yani veri ve fonksiyonları bir araya getirecek, ondan sonra onları Class(sınıf) içerisinde birleştirecek bir güç olan nesneden bahsediyordu. Hepimiz bu nağmelerin içerisnde olan nesnelerin büyüsüne kapıldık ve o aşamadan sonra kendimizi Object Oriented rüzgarının önünde buluverdik.  Artık hepimiz bu gücü kullanıp daha yönetilebilir, okunabilir, esnek yazılımlar geliştirmek için can atıyorduk. Fakat prosedürel programlamayı o kadar çok sevmiştik ki eski alışkanlıklarımızdan bir türlü vazgeçemiyorduk. İlk aşklar unutulmaz derler herhalde ondan olsa gerek :) Artık benim PObject Oriented olarak adlandırdığım nesneler ile prosedürel programlama yapıyorduk.

Her ikisinin sevdiğimiz özelliklerini kullanıp güzel güzel programlar yazmaya başlamıştık. Verileri bu sefer struct,record gibi yapılar içerisine değilde sınıflar içerisine koymaya başladık.Fonksiyonlarımızıda uygun bir yer bulabiliyorsak oraya değilse sağa,sola yerleştiriyorduk. Fakat yine işler projeler büyüdükçe çığırından çıkmaya başladı. Projeler büyüdükçe, değişiklikler yapılmaya başladıkça işler oldukça zahmetli olmaya başladı. Küçük bir talepteki değişiklik uygulamanın birçok yerinde değişiklik yapmamızı gerektiriyor ve bu değişiklik sonucunda ortaya çıkan hatalarla baş edememeye başlıyorduk. Aslında biraz da kafamız karışmıştı. Nağmelerde duyduğumuz o güçlü nesneye yönelik programlama aslında pekde güçlü olmadığını düşünüyorduk.

Kaptırmışım kendimi yüzüklerin efendisi falan araya girince hikayeyi fazla uzattım kusura bakmayın :) Aslında problem bu noktada geliştirdiğimiz uygulamada iş mantığının nesnelerin içinde değilde uygulamanın geneli içine dağılmış olması. Yani en temel nesneye yönelik programlama prensibi verilerin ve verileri işleyen metodların bir arada bulunması gerçekleşmediğinden dolayı uygulama geneline artan Bağımlılık(Dependency,High Coupling) sorunlarının yol açtığı problemlerdir.

Bu sorunların önüne geçebilmek ve sınıflara sorumluluğu daha düzgün atayıp, iş mantığını gerçekten olması gereken yere koymak için kullanılan prensiplerden biride Tell Don’t Ask Principle yani “Sorma, söyle” prensibidir.

Procedural code gets information then makes decisions. Object-oriented code tells objects to do things.
— Alec Sharp

Alec Sharp’ın dediği gibi prosedürel kod veriyi alır ve o veri üzerinden kararlar verir. Object oriented kod ise nesnelere yapmaları gereken şeyleri söyler. Bunu meşhur gazeteci çocuk, cüzdan problemi üzerinde örneklerle inceleyelim. İlk olarak nerede okumuştum hatırlamıyorum ama bu prensibi anlamama kod ve kavramsal olarak oldukça yardımcı olmuştu. Aynı örnek üzerinden devam edelim.

Örnek

Kodları buradan indirebilirsiniz : TellDontAsk.rar

Gazeteci arkadaşımız her sabah bisikletine atlayıp ev ev dolaşıp gazete dağıtıyor. Haftalıkta müşterilerinden gazete paralarını topluyor.Para toplayacağı müşterilerin listesi elinde alıp kapı kapı dolaşıyor ve ücretleri alıyor. Ardından topladığı hasılatı patronuna teslim ediyor.İlk olarak programımızı şu şekilde yazalım.

public class Cuzdan {
    private double para;

    Cuzdan(double para) {
        this.para =para;
    }

    public double getPara() {
        return para;
    }

    public void setPara(double para) {
        this.para = para;
    }  
}
public class Gazeteci {
    private double hasilat =0;
    public void odemeAl(Musteri musteri,double miktar){
        if(musteri.getCuzdan().getPara()<miktar){
            throw new RuntimeException("Cüzdanki para yeterli değil.");
        }else{
            musteri.getCuzdan().setPara(musteri.getCuzdan().getPara()-miktar);
            hasilat +=miktar;
        }        
    }

    public double getHasilat() {
        return hasilat;
    }
}
public class Musteri {
    private String adi;
    private Cuzdan cuzdan;

    public Musteri(String adi,double para) {
        this.cuzdan =new Cuzdan(para);
        this.adi =adi;
    }    

    public Cuzdan getCuzdan() {
        return cuzdan;
    }

    public String getAdi() {
        return adi;
    }
}
public class Main {
    public static void main(String[] args) {
        Musteri ahmetAmca =new Musteri("Ahmet",100);
        Musteri bakkalMehmet =new Musteri("Mehmet",50);
        Musteri kasapAli =new Musteri("Ali",80);
        
        List<Musteri> musteriler =new ArrayList<Musteri>();
        musteriler.add(ahmetAmca);
        musteriler.add(bakkalMehmet);
        musteriler.add(kasapAli);
        
        Gazeteci cihat =new Gazeteci();
        
        for(int i=0; i<musteriler.size(); i++){
            Musteri musteri =musteriler.get(i);
            try{
                cihat.odemeAl(musteri, 60);
            }
            catch(Exception ex){
                System.out.println("Tahsilat yapılamadı! Müşteri adı : "+musteri.getAdi());
            }
        }        
        System.out.println("Toplanan hasılat miktarı : "+cihat.getHasilat());
    }
}

Prosedürel stili o kadar çok seviyoruz ki muhtemelen yukarıdaki kodda pek bir problem göremeyeceğiz.Yanılmıyorum değilmi?Çünkü ilk başlarda bu tarz kodlar bana süper Object Oriented kodlar gibi geliyordu ve açıkçası biri bana o zaman bu kodda problem var dese gülerdim :)

Probleme teknik olarak değilde gerçek hayat problemi olarak bakalım. Evinize gelen gazeteciye cüzdanınızı verip içerisinden ne kadar lazımsa al kardeş dermisiniz? Eğer öyleyse sizin gazeteciniz olmayı isterdim :) Çoğumuzun cüzdanını vermeyeceğini düşünüyorum açıkcası.Gazeteciye “kardeş ne kadar lazım söyle” diye sorup ona göre parayı cüzdanımızdan çıkarıp öyle veririz. Bu koddaki problemde bu. Gazeteciye aslında cüzdan nesnesi ile cüzdanımızı veriyoruz gazeteci önce bi içerisine bakıyor gerekli para varmı ardından varsa içerisinden gereken parayı alıyor.

Tell Don’t Ask(sorma, söyle) presibinin belirttiği gibi aslında biz burada Musteri ve Cuzdan nesnelerine surekli sorular soruyoruz ve ardından sorduğumuz soruların cevabına göre bazı işlemleri o nesneler yerine biz yapıyoruz. Musteriye sordugumuz soru getCuzdan(), Cuzdan nesnesine sordugumuz soru ise getMiktar() metodları.Bu yüzden Musteri nesnesinin iç yapısını öğrenmiş oluyoruz.Mesela müşterinin parayı cüzdanında taşıdığını biliyoruz. Ya müşteri bize parasını evdeki kasasından vermek isterse?Gazeteciye tutup “Al kasayı kardeş içerisinden ne kadar lazımsa o kadar al ” mı diyeceğiz? :) Dolayısıyla nesneler arasındaki bağımlılık(coupling) artıyor. Uygulamada bu şekilde müşteri nesnesinin içerisindeki alanlara soru sorup ona göre karar verip çeşitli işlem yaptıran sınıflar ne kadar artarsa müşterinin iç yapısını değiştirmemiz o kadar zorlaşıyor. Örnek olarak müşterinin artık parayı Cüzdan’dan değilde kredi kartından vereceğini düşünelim. Hangi sınıfları değiştirmemiz gerekir onlara bakalım.

Şimdi yeni sınıfımız Kredi kartına göre sınıflarımızın düzeltilmiş halini yazalım. Bakalım bir sınıfdaki değişiklik yüzünden kaç sınıfı değiştirmek zorunda kalacağız.Ana sınıf değişmediği için onu yazmıyorum. Diğer değişen sınıfları yeni halleri ile aşağıya yazıyorum.

public class Gazeteci {
    private double hasilat =0;
    public void odemeAl(Musteri musteri,double miktar){
        if(musteri.getKrediKarti().getLimit()<miktar){
            throw new RuntimeException("Cüzdanki para yeterli değil.");
        }else{
            musteri.getKrediKarti().setLimit(musteri.getKrediKarti().getLimit()-miktar);
            hasilat +=miktar;
        }        
    }

    public double getHasilat() {
        return hasilat;
    }
}
public class Musteri {
    private String adi;
    private KrediKarti krediKarti;

    public Musteri(String adi,double para) {
        this.krediKarti =new KrediKarti();
        this.adi =adi;
    }    

    public KrediKarti getKrediKarti() {
        return krediKarti;
    }

    public String getAdi() {
        return adi;
    }
}
public class KrediKarti {
    private double limit =1000;

    KrediKarti() {
        
    }

    public double getLimit() {
        return limit;
    }

    public void setLimit(double limit) {
        this.limit = limit;
    }  
}

Gördüğünüz gibi Main sınıfı hariç bütün sınıfları basit bir değişiklik yüzünden değiştirmek zorunda kaldık. Burada aslında sadece Müşteri yani cüzdana sahip sınıfın etkilenmesi gerekirdi fakat prosedürel stilde sürekli nesnelerin iç yapısını sorgulayarak ona karar veren kodumuz yüzünden Gazeteci sınıfıda bu değişiklikten etkilendi.

Peki bu problemi nasıl düzeltebiliriz ? Tell Don’t Ask yani işimizi nesnelere soru sorararak değilde onlara ne yapması gerektiğini söyleyerek yapabiliriz. Aslında bu yeni birşey değil OOP’nin en temel kuralını kullanıyor alıyor yani Encapsulation. Nesnelerin iç yapısını çok fazla dışarı açtığımızda kendi üzerine düşen işleri başkaları yaptığında bu tarz problemler kaçınılmaz. Bu küçük bir örnek belki çok fazla problem olmaz fakat büyük bir uygulamada bu tarz iç yapısını dışarı açan bir nesnede değişiklik olduğunu düşünün? Belkide yüzlerce sınıfı değiştirmek,hatalarını düzeltmek,test etmek zorunda kalacaksınız. Şimdi bu kodu Tell Don’t ask prensibine uygun olarak aşağıdaki gibi yazalım.

public class Cuzdan {
    private double para;

    Cuzdan(double para) {
        this.para =para;
    }

    double cek(double fiyat) {
        if(fiyat>para)
          throw new RuntimeException("Cüzdanki para yeterli değil!");
        else{
            para =para-fiyat;
            return fiyat;
        }
    }
}
public class Musteri {
    private String adi;
    private Cuzdan cuzdan;

    public Musteri(String adi,double para) {
        this.cuzdan =new Cuzdan(para);
        this.adi =adi;
    }    
    
    public double odemeYap(double fiyat){
        return cuzdan.ver(fiyat);
    }

    public String getAdi() {
        return adi;
    }
}
public class Gazeteci {
    private double hasilat =0;
    public void odemeAl(Musteri musteri,double miktar){
        hasilat +=musteri.odemeYap(miktar);     
    }

    public double getHasilat() {
        return hasilat;
    }
}

Şimdi Tell Don’t Ask prensibine göre ile yazılmış yeni kodumuzu inceleyelim. Gazeteci sınıfına bakın artık müşterinin ne cüzdnından haberi var nede kredi kartından. Ona sadece yapması gereken şeyi söylüyor : “Bana şu kadar ödeme yap”. Müşteri nesneside aynı şeyi yapıyor cüzdana bana şu kadar para ver diyor. Ardından cüzdan da kendi içerisinde olan parayı istenen miktarla karşılaştırıyor ve ona göre veri parayı veriyor. Yani herkes yapması gereken işi yapıyor. Artık cüzdan nesnesi içerisinde sadece veri bulunan bir aptal sınıf yada Anemic Domain Model değil, onu nasıl işleyeceğini bilen bir sınıf.

Şimdi bu yapıda yazılmış bir kod üzerinde Cuzdan yerine paramızı kredi kartı üzerinden ödemek için değişmesi gereken sınıfları tekrar yazalım.

public class Musteri {
    private String adi;
    private KrediKarti krediKarti;

    public Musteri(String adi,double para) {
        this.krediKarti =new KrediKarti();
        this.adi =adi;
    }    
    
    public double odemeYap(double fiyat){
        return krediKarti.cek(fiyat);
    }

    public String getAdi() {
        return adi;
    }
}
public class KrediKarti {
    private double limit =1000;

    KrediKarti() {
        
    } 
    
    double cek(double fiyat) {
        if(fiyat>limit)
          throw new RuntimeException("Limit yeterli değil!");
        else{
            limit =limit-fiyat;
            return fiyat;
        }
    }
}
public class Gazeteci {
    private double hasilat =0;
    public void odemeAl(Musteri musteri,double miktar){
        hasilat +=musteri.odemeYap(miktar);     
    }

    public double getHasilat() {
        return hasilat;
    }
}

Gazeteci sınıfında yukarıda gördüğünüz gibi hiçbir değişiklik yapmadık. Yani sadece iç yapısını değiştirdiğimiz sınıflar etkilendi. O da müşteri sınıfı ama diğer şekilde hem gazeteci hemde müşteri sınıfı etkileniyordu.

Tabi bunun dışında gördüğünüz gibi kodun okunulabilirliği ve yönetimi oldukça kolaylaştı. Çünkü herkes kendi sorumluluğunu yerine getiriyor, nesneler kendi içerisindeki veriler üzerinde işlem yapıyor. Bu şekilde uygulamada değişiklik sadece gereken yerde yapılmış oluyor. Ama diğer şekilde iş mantığı uygulamanın bütün yerine dağılmış olduğu için değişiklik sonucunda birsürü yerde değişiklik yapmamız gerekiyor. Buda hata riskini ve değişim maliyetini oldukça arttırıyor.

İlk başlarda bu prensibi okuduğumda oldukça şaşırmıştım ve açıkçası nesneye yönelik programlamanın en temel ilkesini o zaman anlamıştım. Veri ve veri üzerinde işlem yapan metodların bir arada olması. Prosedürel mantığa o kadar alışmışızki nesneye yönelik bir programlama dilinde onun etkisinden hala kurtulamıyoruz. Bu prensip anlaması ve alışması belkide en zor temel nesneye yönelik programlama prensiplerinden birisi. Ben bile hala bazı yerlerde içgüdüsel olarak nesnelere soru sorup bazı işleri yaptırmaktan kendimi alıkoyamıyorum. Ama sürekli kodu gözden geçirip “Acaba bu işi bu sınıf mı yapmalı?, Bu işin ait olduğu yer burası mı?” diye sorgularsanız sorumluluğun gerçekten ait olduğu yeri belirleyebilirsiniz. Eğer nesnelerinizde sadece getter,setter(java) yada property(C#) bulunuyorsa nesnelerinizden şüphelenmenizin ve tekrar gözden geçirmenizin vakti gelmiştir.