Ahmet Orsorlu
ABOUT THE AUTHOR

Ahmet Orsorlu

Matematik Mühendisliği lisans, Bilgisayar Mühendisliği yüksek lisans mezunu. Halen Logo Business Solutions'ta Yazılım Uzmanı olarak görev yapmakta. Basit ve temiz olan herşeyi seviyor. Galatasaraylı. Stephen King ve Metallica aşığı.

Java Immutable (Değişmez) Sınıflar

Immutable (değişmez) sınıflar, nesneleri bir kez oluşturulduktan sonra nesne içeriği değiştirilemeyen sınıflardır. Bir nevi sabit sınıflardır diyebiliriz. Örneğin, Java’da String sınıfı değişmez sınıflardan bir tanesidir. Diğer bilinen değişmez sınıflardan bazıları, Integer, Double, Boolean, BigDecimal sınıflarıdır.

Gelin şimdi hem değişmez sınıfların özelliklerini görmek adına hem de değişmez bir sınıf nasıl yaratılır onu görmek adına bir sınıf yazalım.

public final class ImmutableMutant {
    
    private final String name;
    private final int numberOfArms;
    private final int numberOfLegs;
    
    public ImmutableMutant(final String name, final int numberOfArms,
                            final int numberOfLegs) {
        this.name = name;
        this.numberOfArms = numberOfArms;
        this.numberOfLegs = numberOfLegs;        
    }
    
    public String getName() {
        return name;
    }
    
    public int getNumberOfArms() {
        return numberOfArms;
    }
    
    public int getNumberOfLegs() {
        return numberOfLegs;
    }
}

Kodu incelediğimizde sınıfın final bir sınıf olduğunu görüyoruz. Sınıfı final olarak tanımlamanın amacı, sınıfın başka sınıflar tarafından extend edilmesini (türetilmesini) engellemek. Yani, final sınıfların alt sınıfları olmaz. Dolayısıyla değişmez sınıflardan herhangi bir şekilde başka sınıflar türetilemez.

İkinci olarak, sınıfın tüm elemanları private ve final‘dır. Yani, sınıf içinden veya dışından herhangi bir şekilde değiştirilemez.

Üçüncü olarak, sınıfın tüm elemanları sadece constructor vasıtasıyla ilklendirilebilir.

Ve son olarak, sınıf elemanlarını dışardan değiştirebilecek metodlar (setter metodları) yoktur.

Şimdi de değişmez sınıfların özellikleri ve avantajlarından bahsedelim. Değişmez sınıf nesneleri kesinlikle thread korumalıdır (thread-safe). Çünkü, bir kez oluşturulduktan sonra içeriği değiştirilemez bu da threadlerde kullanımda ortaya çıkabilecek senkronizasyon sorunlarını ortadan kaldırır. Değişmez sınıf nesnelerinin içerikleri değişmeyeceği için program akışı içerisinde içerikte istenmeyen değişikliklerin olmasının önüne geçilebilecektir. Değişmez sınıf nesnelerini gönül rahatlığıyla başka referanslara atayabilirsiniz. Örneğin, bir metoda yolladığınızda o metod içerisinde nesnenin değişmeyeceğini garanti etmiş olursunuz.

Güzel Kod Yazma Sanatı

Öncelikle belirteyim, bu alanda guru falan değilim. Ancak, şu ana kadar okuduklarım, tecrübe edindiklerim ışığında kendi “güzel kod yazma” fikirlerime sahibim. Yazıda belirteceğim konular da bunların sentezi şeklinde olacak. Ve son söyleyeceğimi baştan söyleyeyim; Robert C. Martin‘in Clean Code isimli kitabını edinin ve birkaç kez okuyun. Şu ana kadar okuduğum en iyi teknik kitaplardan birisi diyebilirim.

Güzel Kod

“Güzel Kod” kavramı kişiden kişiye değişebilir, ancak sanıyorum üç aşağı beş yukarı genel olarak benzer fikirler mevcuttur. Aslında, tek başınıza kod yazıyorsanız ve yazdığınız kod sadece sizin tarafınızdan okunacaksa, sizin için anlaşılır olanı, gözünüze hoş geleni yapmak yeterli olacaktır. Ancak, aynı kod üzerinde uğraşan kişi sayısı artmaya başladıkça, yazdıklarınızın anlaşılabilirliği üzerine sürekli düşünmeniz gerekecektir. Yazdığınız kod parçası başkası tarafından okunurken anlaşılması için 10 kere okunması gerekmesin.  Ayrıca kötü yazılmış kodun hatalardan arındırılması da zorlaşabilecektir.

Şimdi birkaç başlık halinde “Güzel Kod” örneklerine bakalım. Tekrar belirteyim, tüm yazdıklarım okuduğum kitapların (özellikle de Clean Code‘un) ve kendi tecrübelerimin sentezi sonucu ortaya çıkan kendi düşüncelerimdir.

İsimlendirme

Kod içerisindeki herşeyin isimlendirmesi. Değişkenlerin, fonksiyon/metodların, sınıfların… İlk vereceğim tavsiye, değişken, metod, sınıf neyi temsil ediyorsa açık açık o şekilde isimlendirin.

String var1; // isim
int var2; // yaş
//...
var1 = "ali"; // 156. satır
var2 = 15;

Kodunuzu okuyan ikinci bir kişi kod parçasının 156. satırında var1 değişkenine bir string atadığınızı gördüğünde bu değişkenin ne işe yaradığını çözmesi için kafasında bir çözümleme yapması gerekir. “ali”, değişkenin bir isim olduğunu az çok gösteriyor ama bu kimin ismi, kendisinin mi, babasının mı, ilkokul arkadaşının mı? Çok da belli değil.

String ownName;
int ownAge;
//...
ownName = "ali";
ownAge = 15;

Sanırım artık durum daha anlaşılır oldu. Bir değişken neyi temsil ediyorsa basit, anlaşılır şekilde onu ifade edin. Mümkün olduğunca kısa tutmaya çalışın ama kısa olması için de kısaltmalar yapmayın. Örneğin;

String doorHandCol; // çok anlaşılır değil
String doorHandleColor; // açık ve anlaşılır

Fonksiyon/Metod isimleri için de benzer kural geçerli. Açık, anlaşılır, ne yaptığını (ne azını ne çoğunu) anlatan.

public void function1(); // anlamsız isimlendirme
public void createFormVariables(); // anlamlı, örneğin, bu metodun form değişkenlerini yarattığı açıkça anlaşılıyor.

Metod içerisinde ne yapılıyorsa ismini o şekilde verin demiştim. Ya da tam tersi, metod isminde neyi berlittiyseniz metod onu yapsın.

public void createFormVariables() {
    // form değişkenlerine ilk değerlerini ver
    // ...
    showForm(); // metod ismiyle uyumsuz fonksiyonellik
}

Eğer, metod içinde gerçekten showForm metodunu çağırmanız gerekiyorsa metodun ismini değiştirin. Örneğin;

public void createFormVariablesAndShowForm() {
    // form değişkenlerine ilk değerlerini ver
    // ...
    showForm(); // metod ismiyle uyumsuz fonksiyonellik
}

Artık metod isminin belirttiği işi yapıyor ancak şimdi de alakasız iki işi birden yapmaya başladı (bu konuya fonksiyonlar/metodlar başlığında değineceğim).

Sınıf isimleri olabildiğince somut isimlerden oluşmalı ve olabildiğince kapsamlı isimler olmalı. Örneğin; Man, Woman gibi isimlendirmeler yerine Person sınıfı yapılıp, Person sınıfına cinsiyet değişkeni verilmeli.

Fonksiyonlar/Metodlar

Bu başlıkta tek bir konudan bahsetmek istiyorum. Yazdığınız metodlar/fonksiyonlar mümkün olduğunca minimal basit işler yapmalı. Metodlar içerisinde yapılan işlerin birbiriyle ilişkili işler olmasına dikkat edin. Son verdiğim örnekteki (createFormVariablesAndShowForm) metodlardan mümkün olduğunca kaçının. createFormVariables ve showForm metodlarını ayırın ve ikisini daha genel bir metottan çağırın.

Gösterim Biçimi (Notations)

Burada en çok bilinen iki gösterim biçiminden bahsedeceğim. hungarian_notation ve CamelCase.

Hungarian notation örneği;

int button_width = 200;

CamelCase örneği;

int buttonWidth = 200;

Ben CamelCase gösterimi kullanıyorum. Gözüme daha hoş ve anlaşılır geliyor. Üstelik sürekli alt tire yapma dolayısıyla fazla karakter derdinden de kurtarıyor. Genelde de CamelCase gösterim kullanılıyor diye biliyorum.

Değişken ve metod/fonksiyon isimlerinde ilk harf küçük diğer her kelimenin ilk harfi büyük şekilde, sınıf isimlerinde ise tüm kelimelerin ilk harfi büyük şekilde yazmaya çalışın.

String submitButtonText;
// ...
public void onSubmitButtonClicked ();
// ...
public class SubmitForm {}

Bir de eskiden kalma bir alışkanlık var. Sınıfların elemanlarının başına m_ öneki koymak.

int m_submit_button_width;
int mSubmitButtonWidth;

Kocaman bir sınıfın içinde kullandığınız değişkenin sınıfın değişkeni olduğunu göstermek için. Ancak, günümüzdeki hemen tüm kod geliştirme araçları bu elemanları renklendirdiği için bu kullanıma da artık yok.

Açıklamalar (Comments)

Açıkçası Clean Code‘u okuyana kadar düşüncem, kodlara mümkün olduğunca açıklama yazmaktı. Ancak, kitap beni bu konuda farklı yönde ikna etti; mümkün olduğunca az açıklama yazın 🙂

Kitabın savı da şu; çok açıklama kodunuzun az anlaşılır olduğunu gösterir. Bir nevi ters orantılı yani. Açıklama yazmak kolay iş ancak bu sefer de açıklamalar arasında kod parçalarını bulmaya uğraşacaksınız 🙂 Peki açıklama yazmazsak kodumuz nasıl anlaşılacak? Yazının başından beri anlatmaya çalıştığım şekilde. Güzel ve anlaşılır yazmaya çalışarak 🙂 Kısa ve net.

Giriş

Bu bölüm hem giriş hem sonuç olarak düşünülebileceği için giriş ismi vermeyi tercih ettim. Kod yazarken ilk başta en güzel kodu yazmaya zorlamayın kendinizi. Zaten ilk yazdığınız kod büyük ihtimalle yanlış ve az anlaşılır olacaktır. Üzerinden tekrar tekrar geçin, üzerinde tekrar tekrar düşünün. Gereksiz kısımları başka yere taşıyın. Alakasız metodları birbirinden ayırın. Değişkenlerinizi daha düzgün isimlendirmeye çalışın. Kodu sadece kendiniz geliştiriyor olsanız bile güzel, temiz, anlaşılır yazmaya çalışın.

Son olarak; mutlaka Clean Code‘u okuyun 🙂

Java Generics – Tipler Üzerinde Soyutlaşma

Generics?

Aslında konunun başlığı genel anlamda konuyu özetliyor (en azından sadece bir kısmını :)). Java 1.5 versiyonuyla gelen Generics özelliği, yazdığımız sınıfı tipler üzerinde soyutlaştırmamızı, türden bağımsız sınıflar yaratabilmemizi sağlıyor. Yani, sınıfı yazarken sınıfın metotlarının birden fazla tip için çalışabilirliğini sağlamış oluyoruz.

En güzel anlatım örnekle anlatımdır diyerek (tamamen kendi görüşüm :)) bir örnek üzerinde gösterelim. Örneğin, ArrayList sınıfı. Aslında 1.2 versiyonundan beri Generics özelliğinden mahrum olarak Java’da mevcut bir sınıf. İçerisinde tüm nesneleri tutabilen bir liste. İçerisinden istenilen tipi barındırabilmek ilk bakışta çok cazip gelse de aslında çok sakat(!) bir işlem. Bu konuya daha sonra değineceğim. Burada sadece örnek veriyorum.

Apple anApple = new Apple();
Pear aPear = new Pear();
       
ArrayList ourBag = new ArrayList();
ourBag.add(anApple);
ourBag.add(aPear);

Görüldüğü üzere elma ile armutu bir araya koyduk. ArrayList sınıfının eski halinde add metodu Object tipinde parametreye sahip olduğu için iki nesneyi de ekleyebildik.

add (Object o);

Şimdi de kendimizi biraz kısıtlayalım. Generics özelliğini kullanalım.

ArrayList<Apple> ourAppleBag = new ArrayList<Apple>();
ourAppleBag .add(anApple);
ourAppleBag .add(aPear); // Dikkat: derleyici izin vermez.

Oops. ArrayList‘in yanında Apple nesnesi var. Artık çantamıza sadece elma atabilir hale geldik (3. satıra derleyici izin vermeyecektir). Eğer, armutlarımızı tutmak istiyorsak yeni bir çanta almamız lazım.

ArrayList<Pear> ourPearBag = new ArrayList<Pear>();

Peki ne oldu? Neden birden kısıtladık kendimizi? Ayrıca türden bağımsızlık işin neresinde? Metodun parametresini Object türünde yaparsak tüm tipteki nesneleri alabilir değil mi artık?

Nimetler, Nimetler, Nimetler

Öncelikle elmayla armut aynı çantada olursa neler olur onu görelim. Parametre olarak bir ArrayList alan metodumuz olduğunu düşünelim.

getAppleJuice (ourBag);
// ...
public void getAppleJuice(ArrayList bag) {
        Apple anApple = bag.get(0);
}

Bu metodu derlemek istediğinizde derleyici hata vererek sizden cast işlemi yapmanızı isteyecektir. Çünkü;

Object get (int index);

get metodu Object tipinde bir nesne döndürüyor.

getAppleJuice (ourBag);
// ...
public void getAppleJuice(ArrayList bag) {
        Apple anApple = (Apple) bag.get(0);
}

Artık derleyici bize kızmıyor. Ama her zaman içinde elma olduğunu nereden bileceğiz. Şu durumu düşünelim;

getAppleJuice (ourBag);
// ...
public void getAppleJuice(ArrayList bag) {
        Apple anApple = (Apple) bag.get(1);
}

Derleyici için bir sorun yok. Programı çalıştırabilirsiniz. Hatta müşterinize satabilirsiniz. Bir süre sonra müşteriniz size elma suyu yerine armut suyu içtiğini, programın bozuk olduğunu söylerse şaşırmayın.

Gerçekte olan ise, programın çalışması anında Java bize kızar ve bir exception fırlatır. Buyrun size en güzelinden bir böcek.

E o zaman ArrayList sınıfına müdahele edelim ve Object olan yerleri Apple‘a çevirelim. Artık, getAppleJuice metodunun elma suyu döndürmesini garantilemiş olduk. Peki armutları tutmak için ne yapacağız? ArrayList sınıfını kopyalayacağız ve tüm Object olanları Pear yapacağız. Meyveler arttıkça kopya sınıflar da artmış oldu. Yeni her tip için sınıfı tekrar yazacağız.

Bu dertten kurtulmak gerekir. Bir kere yazalım hepsi için program anında bile düzgün çalışsın. Üstelik sadece 1 sınıfla!

Generics ile yazılmış ArrayList sınıfı ArrayList<E> şeklinde tanımlanıyor. Artık nesnesini oluştururken hangi sınıfı verirsek çantaya o nesneyi atabileceğiz. Yeni add metodu;

add (E e);

şeklinde. Artık parametre çanta yaratırken belirttiğimiz E tipinde.

ArrayList<Apple> ourAppleBag = new ArrayList<Apple>();
ourAppleBag.add(anApple);

Artık, çantamız bir elma çantası ve armut almıyor. Armut alan çanta için armut çantası yaratacağız.

Şimdi elma suyu metodumuza yeniden bakalım;

getAppleJuice (ourAppleBag);
// ...
public void getAppleJuice(ArrayList<Apple> bag) {
        Apple anApple = bag.get(1);
}

Biraz kısıtladık kendimizi değil mi? Ama program çalışırken ortaya çıkacak sürprizlerden kurtarmış olduk kendimizi. Artık metod aldığı çantanın bir elma çantası olduğunu biliyor. Cast işlemine de ihtiyaç duymuyor.

Sonuç?

Bu tarz her yazımda olduğu gibi yazının sonunda öneride bulunayım:

  • Halihazırdaki Java sınıflarını (özellikle ArrayList gibi Collection türündeki sınıfları) kullanırken Generics halini kullanın. Hatta diğer hali hiç kullanmayın 🙂
  • Eğer, kendi yazdığınız sınıf birden fazla tip için çalışacaksa tek ve doğru yolunuz Generics şeklinde yazmak.

Firefox Menü Çubuğunu Gösterme

Mozilla Firefox’un son sürümlerinde (sanırım 4 sürümünden itibaren) eski usül menü çubuğunu gizleme (tamamen kaldırılmadı) yoluna gitti. Onun yerine pencerenin sol üstünde bulunan  biraz daha modern bir menü sistemi getirildi.

Eski menü çubuğundan daha derli toplu durmasına rağmen, ben eski menü çubuğunu kullanmak istiyorum diyenler için hemen bir çözüm sunalım. Eğer geçici olarak göstermek istiyorsanız halihazırda ekranda menü çubuğu gözükmüyor iken klavyeden Alt tuşuna basarak menü çubuğunu geçici olarak gösterebilirsiniz.

Yok kalıcı olarak açık bırakmak istiyorum diyorsanız; yeni menüden (ilk anlattığım menü) Seçenekler > Menü Çubuğu yoluyla veya eski usül menü çubuğundan (ikinci anlattığım menü) Görünüm > Araç Çubukları > Menü Çubuğu yoluyla menü çubuğunu kalıcı hale getirebilirsiniz.

Diablo III – 150512 – Yine Yeniden Diablo

Ve nihayet beklenen gerçekleşiyor. Tam 12 sene aranın ardından Diablo ile yeniden buluşabileceğiz. Tabii ki en son 12 sene önce oynamadık 🙂 Sayıyı büyük söyleyince daha bir etkili oluyor 🙂 Hatta gün hesabı yaparsak daha etkili olabilir …

Öhöm. Konudan çok fazla çıkmadan asıl haberi verelim. Diablo 3 çıkış tarihi resmi olarak duyuruldu. 15 Mayıs’ta muhteşem oyunun yeni versiyonuyla buluşuyoruz. Çok özledik kendisini.

Bir not; oyun ilk çıktığında PvP olmayacak. Sanırım ileride patch ile ekleyecekler oyuna.

Az kaldı. Sabır…