Yazılımcının Verimliliğini Artıran Eclipse Ayarları

Çoğu projede yazılım geliştirme ortamı olarak Eclipse’i kullanıyorum. Bu yazımda yazılım yaparken verimliliğimi artırdığını düşündüğüm Eclipse ayarlarını sizinle paylaşmak istiyorum. Kullandığım Eclipse sürümü 4.3.1 Kepler.

Hiç sevmediğim bir şey varsa, o da formatsız koddur. Bir Eclipse editöründeki bir kodu CTRL+SHIFT+F ile formatlamak mümkün. Ama bunu yazılımcı değil, Eclipse otomatik olarak yapmalı.

Bu ayarı Window –> Preferences –> Java –> Editor –> Save Actions bölümünde yapabiliriz.

Resim 1

Prefecences panelini açtıktan sonra üst kısımda yer alan arama alanına save kelimesini girmeniz, resim 1 de yer alan ekrana ulaşmanızı sağlayacaktır. Kodu otomatik formatlamak için Perform the selected actions on save kutusunun işaretli olması gerekiyor. Bu kutuyu işaretledikten sonra diğer opsiyonlar aktif hale gelir. Kodu formatlamak için Format source code kutusunu işaretlemek yeterli olacaktır.

Save Actions panelindeyken diğer gerekli gördüğüm ayarları da yapalım isterim.

Bu paneldeki Additional actions kutusunu işaretleyelim ve Configure butonuna tıklayalım. Karşımıza resim 2 de yer alan panel çıkacaktır.

Resim 2

Code Style tabındayız. Ben burada Use blocks in if/while/for/do statmens –> Always ayarını kullanıyorum. Şu şekilde bir if bloğu oluşturduğumda

[source language=”java”]
if(i>0)
doIt();
[/source]

bu Eclipse tarafından otomatik olarak şu şekilde formatlanır.

[source language=”java”]
if(i>0){
doIt();
}
[/source]

Buradaki maksat tek satırlık if/while/for/do yapılarını küme parantezi kullanarak bir blok haline getirmektir. İlk başlarda ben bu tür tek satırlık yapılarda küme parantezlerini kullanmazdım, çünkü bu bana koddan bir satır tasarruf etmemi sağlardı. Lakin sonraları çalıştığım birçok projede firma yazılım geliştirme politikası olarak küme parantezlerinin kullanılması koşulunu takip etme zorunluluğu doğduğundan ve Sonar gibi statik kod analizi araçlarının küme parantezi olmayan bloklardan hoşlanmadıklarından, ben de tek satırlık yapılarda küme parantezleri kullanmaya başladım. Bu bir alışkanlık meselesi. Çok kısa zamanda insan kullandığı yeni yapılara alışıyor ve bırakmak istemiyor. Bunu bir mezhep kavgasına dönüştürmenin bir anlamı yok anlayacağınız ;-)

Yazdığım kodda sınıfların, metotların, değişkenlerin, metot parametrelerinin ve metot gövdesinde kullanılan değişkenlerin mümkün mertebe final olmalarına dikkat ederim. Final olan yapılar genel olarak değiştirilemez olduklarından, istenmeden değiştirilmeleri mümkün değildir. Örneğin final olan bir değişkene yeniden bir değer atanamaz. Paralel çalışan (multi threaded) bir uygulamada final olan yapılar threadlar arasında sıkıntı olmadan paylaşılabilir.

Ben eğer şöyle bir metot yazdı isem

[source language=”java”]
public void doIt(int i) {
int y = i;
System.out.println(y);
}
[/source]

bu metodun Eclipse tarafından şu şekilde formatlanmasını arzularım:

[source language=”java”]
public void doIt(final int i) {
final int y = i;
System.out.println(y);
}
[/source]

Bunun Eclipse tarafından yapılması sağlamak için resim 2 de yer alan Use modifier final where possible kutusunun işaretlenmesi gerekmektedir. Burada üç seçenek bulunmaktadır. Eğer private olan değişkenlerin final olmasını istiyorsak Private fields, metot parametrelerinin final olmasını istiyorsak Parameter ve metot gövdesindeki değişkenlerin final olmasını istiyorsak Local variables seçeneğini aktif hale getiriyoruz.

Resim 3,4 ve 5 de Additional Save Actions panelindeki ayarlarım yer alıyor.

Resim 3

Resim 4

Resim 5

Resim 5 de yer alan Remove unused imports seçeneği koddan kullanılmayan import direktiflerinin silinmesini sağlamaktadır. Bir Java sınıfı bünyesinde zaman içinde import direktifleri ile birçok sınıf kullanılır. Bu sınıf yeniden yapılandırıldığında kullanımda olan bazı sınıflar ihtiyaç dışı kalabilir. Yazılımcılar genelde bu şekilde kullanım dışı kalan import direktiflerini görmediklerinden koddan uzaklaştırmazlar. Ben böyle bir sınıfı editörüme yüklediğimde yaptığım ilk kayıt işlemi (save) ile kullanım dışı olan tüm import direktifleri koddan silinir ve kod formatlanır.

Faydalı bulduğum diğer bir ayar ise, hangi küme parantezi bloğunda olduğumu doğrudan görebilmektir. Resim 6 da hangi blok içinde isem, o bloğun küme parantezleri öne çıkmış durumda. Bu ayarı yapmak için resim 7 de görülen Editor paneline gitmemiz ve orada Bracket highlighting seçeneklerinden Enclosing bracket seçeneğini seçmemiz gerekiyor. Bu bizim içinde bulunduğumuz kod bloğunu doğrudan görmemizi sağlayacaktır.

Resim 6

Resim 7

Java’da biliyorsunuz satır sonunda ; işaretini kullanma zorunluluğu var. Bunu da Eclipse bizim için yapabilir. Resim 8 de yer alan Automatically insert at correct position {} ve ; işaretlerinin doğru yerlerde Eclipse tarafından koda eklenmesini sağlamaktadır.

Resim 8

Eclipse altında CTRL+F11 tuşlarına bastığınızda bir uygulamayı koşturabilirsiniz. Genelde ben bir uygulamayı test ederken bu tuş kombinasyonunu şıkça kullanıyorum. Lakin kaynak kod üzerinde yaptığım değişiklikler CTRL+F11 tuşlarına bastığımda otomatik olarak kaydedilmiyor ve böylece yaptığım değişiklikler koşturduğum uygulamaya yansımıyor. Ayrıca CTRL+F11 her zaman en son koşturduğum uygulamayı koşturmayabilir. Uygulamayı koşturmadan önce değişiklikleri kaydetmek ve uygulamayı yeniden derlemek için resim 9 da yer alan ayarların yapılmasında fayda vardır.

Resim 9

Ne zaman iyi bir yazılımcı oluruz? Kullandığımız yazılım geliştirme ortamına sunduğu birçok kısa yol tuşlarıyla hakim olduğumuz zaman, çünkü bu bizim yazılımcı olarak verimliliğimizi artırır.


EOF (End Of Fun)
Özcan Acar

Spring Çatısının Yazılım Geliştirme Filozofisi

Özellikle nesneye yönelik programlama teknikleri kullanıldığında, nesneler arasında var alan bağımlılıklar çok karmaşık bir yapının oluşmasına neden olabilmektedir. Uygulama geliştirme esnasında bağımlılıkların kontrol altına alınmasına dair bir çalışma yapılmadığı taktirde, yazılımcının verimliliği ve uygulamanın kod kalitesi düşecektir. Kaliteyi artırmanın ve yazılımcının daha verimli olmasını sağlamanın bir yöntemi, tüm bağımlılıkların ve oluşan karmaşık yapının dış bir uygulama çatışı (framework) tarafından yönetilmesini sağlamak olabilir. Bu bağımlılıkların uygulama tarafından değil, kullanılan uygulama çatışı tarafından yönetilmesi anlamana gelmektir. Bu yazılım filozofisine kontrolün tersine çevrilmesi ya da Inversion of Control (IoC) ismi verilmektedir. Spring çatısının var oluşu ve çalışma prensipleri bu filozofiye dayanmaktadır.

Dependency Injection

Java gibi nesneye yönelik bir programlama dili ile geliştirilen uygulamalar ideal şartlarda kodun tekrar kullanıldığı modüler bir yapıdadır. Modüller birbirlerini kullanarak, yapmaları gereken işlemleri gerçekleştirirler. Bu modüller arası bağımlılıkların oluşmasını sağlar.

[source language=”java”]
class RentalController {
private RentalService service = new RentalServiceImpl();
}
[/source]

Yukarıda yer alan RentalController sınıfı/modülü bunun güzel bir örneğini teşkil etmektedir. RentalController sınıfı RentalService interface sınıfına bağımlıdır. Böyle bir bağımlılık modüler bir yapının oluşturulması ve kodun tekrar kullanımını sağlamak açısından zaruridir. Lakin RentalController bünyesinde somut bir implementasyon sınıfı olan RentalServiceImpl sınıfından new operatörü ile yeni bir nesne oluşturulması, mevcut bağımlılığın değiştirilemez ve tek bir tipte olması gerektiği anlamına gelmektedir. Bağımlılığı yeniden yapılandırabilmek için kodu değiştirmek ve yeniden derlemek gerekmektedir. Bağımlılıklarını kendisi yöneten bir uygulamada kod kalitesini düşüren bu tür bağımlılıkların oluşturulmasıdır. Oysaki bağımlılıkların tersine çevrilmesi prensibine (DIP; Dependendy Inversion Principle) göre bağımlığın yönü somut değil, soyut sınıflara doğru olmalıdır.

[source language=”java”]
class RentalController {
private RentalService service = rentalServiceFactory.instance();
}
[/source]

Somut bir sınıfa olan bağımlılığı yok etmek için rentalServiceFactory gibi bir fabrika (factory) sınıfından faydalanabiliriz. Fabrika tasarım şablonunu simgeleyen rentalServiceFactory bünyesinde hangi somut RentalService implementasyonunun kullanıldığını gizlemekte ve RentalController sınıfını bahsettiğim somut bağımlılıktan kurtarmaktadır. Lakin buradaki sorun rentalServiceFactory nesnesine olan bağımlılıktır. Bu nesnenin de bir şekilde new operatörü ile oluşturulması gerekmektedir.

[source language=”java”]
class RentalController {

private RentalService service;

public void setService(RentalService service){
this.service = service;
}
}
[/source]

Bağımlılıkları oluşturma işlemi ile hiç uğraşmasak, bunu başka birisi bizim için yapsa nasıl olurdu? Yukarıda yer alan kod örneğinde service değişkenine gerekli değer setService() metodu aracılığı atanmaktadır. Biran için setService() metodunun dış bir mekanizma tarafından koşturulduğunu düşünelim. Bu mekanizma setService() metodunu kullanarak herhangi bir RentalService implementasyonunu RentalController sınıfına enjekte edebilir. Bu işleme bağımlılıkların enjekte edilmesi yani dependency injection (DI) ismi verilmektedir. Bu işlemi yapan da Spring çatışıdır.

Aşağıda tipik bir Spring XML konfigürasyon örneği yer almaktadır. Yönetimi Spring’e devredilen bağımlılıklar için bu tarz konfigürasyon dosyaları oluşturulur. Spring bu konfigürayon dosyalarını kullanarak nesnelere arası gerekli bağımlılıkları oluşturur, yani bağımlılıkları enjekte eder.

[source language=”xml”]

Tek sorumluluk prensibi açışından bakıldığında da bu bir gerekliliktir.

Hollywood Prensibi

VIP (Very Important Person) olan şahıslara erişmek zordur. Onlar genelde “bizi aramayın, biz sizi ararız” şeklinde iletişimi tercih ederler. Holywood prensibi olarak bilinen bu prensibi IoC konseptini açıklamak için kullanabiliriz.

Bağımlılıkların enjekte edilmesi Hollywood prensibine göre çalışmaktadır. RentalController sınıfı kendi başına bir konstrüktör ya da fabrika metodu koşturarak bir service nesnesi edinmeye çalışmaz. Bunu yapsaydı eğer, o zaman bu VIP şahsı telefonda aramak ve benim service nesnesine ihtiyacım var demek gibi bir şey olurdu. Bunun yerine VIP şahıs, yani Spring RentalController sınıfında yer alan setService() metodunu kullanarak RentalController sınıfıyla iletişime geçmektedir. Spring RentalController sınıfına bir RentalService nesnesi enjekte edebilmek için setService() metodunu koşturmaktadır. Spring sınıfların set() metotlarını ya da konstrüktörlerini kullanarak gerek duyulan bağımlılıkları enjekte etmektedir. Bağımlılığı enjekte edebilmek için bu metotları koşturması, yani sınıfı araması gerekmektedir.

Spring koşturulacak metodun seçiminde konstrüktör ya da set() metoduyla sınırlı değildir. Hollywood prensibi sınıf bünyesinde yer alan sınıf metotları üzerinde de kullanılabilir. Bu Spring’in konfigürasyon dosyasında belirlenen herhangi bir sınıf metodunu koşturulabileceği anlamına gelmektedir. Kitabın on yedinci bölümünde inceleyeceğimiz Spring Task ve Scheduling modülünde herhangi bir POJO (Plain Old Java Object) sınıfın herhangi bir metodunu şu şekilde koşturmak mümkündür:

[source language=”xml”]

[/source]

Spring tarafından koşturulması gereken metodun ismi method element özelliğinde yer almaktadır. Görüldüğü gibi rentalDownloader nesnesi görevini yerine getirmek için hangi metodun koşturulması gerektiğini bilme sorumluluğundan arındırılmaktadır. Sadece konfigürasyon dosyası üzerinde değişiklik yaparak, POJO sınıfın çalışma tarzı adapte edilebilmektedir. Spring birçok modülünde bu mekanizmadan faydalanmaktadır.


EOF (End Of Fun)
Özcan Acar

Pratik Spring isimli kitabımdan alıntıdır.

Yeni Kitabım Pratik Spring

Bir sene süren çalışmalarım ardından Pratik Spring isimli yeni kitabımı tamamladım. Yeni kitabım Pratik Programcı Yayınları tarafından e-kitap olarak PDF formatında satışa sunuldu.

Kitap 18 bölümden oluşuyor. Ana bölüm başlıkları şunlar:

  • 1.Bölüm – Spring Nedir?
  • 2.Bölüm – Spring İle Tanışalım
  • 3.Bölüm – Spring İle Nesne Yaşam Döngüsü Yönetimi
  • 4.Bölüm – Konfigürasyon Yönetimi
  • 5.Bölüm – Spring İle Veri Tabanı İşlemleri
  • 6.Bölüm – Spring İle Transaksiyon Yönetimi
  • 7.Bölüm – Spring İle Hibernate Kullanımı
  • 8.Bölüm – Spring İle JPA Kullanımı
  • 9.Bölüm – Spring İle Aspect Oriented Programming
  • 10.Bölüm – Spring MVC
  • 11.Bölüm – Spring Security
  • 12.Bölüm – Spring REST
  • 13.Bölüm – Spring Remoting
  • 14.Bölüm – Spring Web Service
  • 15.Bölüm – Spring Testing
  • 16.Bölüm – Spring JMX
  • 17.Bölüm – Spring Task ve Scheduling
  • 18.Bölüm – Spring E-Mail

Tüm içerik başlıklarını görmek için aşağıda yer alan linke tıklayınız.

Kitabın birinci ve ikinci bölümlerini aşağıdaki linklerden edinebilirsiniz.

  Pratik Spring 1. Bölüm (282,3 KiB, 10.701 yükleme)

  Pratik Spring 2. Bölüm (452,8 KiB, 7.631 yükleme)

Kitap Okumanın Önemi

Şimdi size sorsam, en çok sevdiğiniz üç yazılım kitabını yazarları ile sayabilir misiniz? Sayabilmeniz lehinize olurdu, çünkü bir sonraki iş görüşmenizde bu soruyla karşılaşma şansınız yüksek. Başıma geldiği için söylüyorum :)

Bana son on beş yıllık yazılımcı iş hayatımda sorulan en ilginç soru buydu. Cevabım şu şekilde olabilir.

Bu sorunun altında yatan mentalite çok başka türden. Beni şaşırttı açıkçası. Artık eskisi gibi anlatın bakalım, şimdiye kadar neler yaptınız demiyorlar. Size belli bir zamanda çözmeniz gereken bir problem de sunmuyorlar. Bilginizin hangi temellere dayandığını anlamak için derin sondaj çekiyorlar. Bu soru benim için neden bu kadar ilginç, açıklamaya çalışayım.

Google, Stackoverflow ya da BTSoru.com gibi sistemlerin var olduğu bir dünyada yazılımcılar belli bir sorunun çözümüne birkaç tık sonra ulaşabiliyorlar. Copy/Paste Programcı başlıklı yazımda bunu dile getirmeye çalışmıştım. Çoğu zaman copy/paste yaparak bir takım sorunları çözüp, işi geçiştiriyoruz. Çoğu zaman ne yazık ki çözümün temelinde yatan konseptleri anlamadan…

Eğri oturalım, doğru konuşalım. Programcılık bilim ve mühendislikle alakalı bir meslek. Bu işin temelindeki bilimi kavrayabilmek için bu işin eğitimini almak gerekiyor. Ben üniversitedeki eğitimden bahsetmiyorum. O da önemli, lakin üniversiteden sonra bu bilim dalında kendimizi ne kadar ve nasıl geliştirdiğimiz çok daha önemli.

Programcılık bir ömür boyu öğrenim görmeyi gerektiren bir meslek. Bu eğitimi bize başkaları veremez. Kendi, kendimizi eğitmemiz gerekiyor. Bunun en başlıca yolu da bol, bol kitap okumaktan geçer.

Günümüzde programcı olarak bizim eğitimimize en büyük sekteyi yazılım çatıları (framework) vuruyorlar, çünkü sundukları imkanlarla çalışma sahalarındaki zorlukları ve bilgileri maskeliyorlar. Bu çatıları kullanmak programcı olarak bizim işimizi kolaylaştırmakla birlikte, temelde ne olup, bittiğini tam olarak anlamadığımız sürece yeni bilgi edinmek güçleşiyor. Bizim ana sorumluluğumuz sorun çözmek değil, sorunları çözebilmek için bilgi ve bilim taşıyıcısı olmaktır. İnternetten birkaç satırlık kodu alıp, sorun çözmek matah değildir. Asıl önemli olan kısa yolu değil, uzun ve acılı yolu seçip, belli bir öğrenim sürecinden sonra gerekli temel prensipleri kavramaktır.

Kendimizi ciddi anlamda geliştirmek istiyorsak, ilgi duyduğumuz alanlarda elimize geçen her türlü yazılı kaynağı sistematik bir şekilde tüketmeliyiz. İçimizde işin temellerine indiğimiz hissi uyanmadıysa, yılmadan daha çok kaynak kitap tükerek, bu hisse sahip olana kadar devam etmeliyiz.

Yılmamalıyız! İlim ve bilim, ilim ve bilim peşinde koşturanındır.

En son okuduğunuz üç kitabı yorumlarda görmek ümidiyle…


EOF (End Of Fun)
Özcan Acar

Spring Core Sertifika Sınavı Ardından

Geçen sene katıldığım Spring Integration ve Spring Core kurslarının ardından bu senenin mayıs ayında Spring Integration sertifikasını  almıştım. Katıldığım kurslardan sonra aklımda Pratik Spring Core kitabını yazma fikri oluştu. Kitabı tamamladım ve yakında pragmatikprogramci.com adresi üzerinden pdf formatında e-kitap olarak satışa sunulacak. Bu arada iki gün önce Spring Core 3.2 sertifika sınavına katıldım ve sınavı kazanarak bu sertifikayı almayı hak ettim.

Sınava hazırlık olması amacıyla bu ve bu mock sınav sorularını inceledim. Burada sınavın içeriği hakkında bilgiler yer alıyor. Burada da sınava hazırlanış hakkında detaylı bilgi bulmak mevcut.

Sınavda Spring sunucusu (container) ve Spring bean konfigürasyonu hakkındaki sorular çoğunlutaydı. JMX hakkında iki soru hatırlıyorum. Bunun yanı sıra sınavda Spring MVC, JMS, AOP, Spring Remoting ve Spring Security konularında sorularlar yer aldı.

Sertifika sınavına girebilmek için SpringSource tarafından sunulan 5 günlük kursa katılmak gerekiyor. Bu hem Spring Integration, hem de Spring Core 3.2 sertifikası için geçerli.


EOF (End Of Fun)
Özcan Acar

Yazılımcı Anketi 2013

Bu anketi hazırlayarak, yazılım ve yazılımcılık hakkındaki düşüncelerinizi öğrenmek istedim. Yeterli veri elde ettikten sonra Yazılımcı 2013 Raporu’nu sizinle paylaşacağım. Türkiye Yazılımcı Raporu 2012’ye buradan ulaşabilirsiniz.

Bu anket son bulmuştur. Türkiye Yazılımcı Raporu 2013’e buradan ulaşabilirsiniz.

JVM Nasıl Çalışır Yazı Serisi – Java Hotspot, Assembly Kod, Hafıza Bariyerleri ve Volatile Analizi

Java siniflari java derleyicisi javac (compiler) tarafından bytekoduna dönüştürülür.

[source language=”java”]
public class HelloWorld {

public static void main(String[] args) {
System.out.println("Hello World");
}
}
[/source]

Yukarida yer alan HelloWorld sinifinin bytekod olarak derlenmis seklini asagida görmekteyiz:

[source language=”java”]
public class HelloWorld extends java.lang.Object{
public HelloWorld();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return

public static void main(java.lang.String[]);
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String Hello World
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
[/source]

Derlenmis bir java sinifinin bytekod ciktisini su sekilde alabiliriz:

[source language=”java”]
javap -classpath . -c HelloWorld
[/source]

Oluşan bytekod dogrudan işlemci (CPU) üzerinde koşturulamaz, cünkü bytekod islemcinin anlayacagi bir yapida degildir. Bytekodu yorumlayan birimin adi java sanal makinedir (jvm – java virtual machine). Kosturmak istedigimiz derlenmis bir java sinifi classloader olarak tanimlanan sinif yükleyicileri tarafindan hafizaya yüklenir. Bu islemi örnegin su sekilde baslatabiliriz:

[source language=”java”]
java -classpath . HelloWorld
[/source]

Java komutu sanal makineyi baslatir ve sanal makinenin bünyesindeki sinif yükleyicileri devreye girerek, derlenmis ve bir class dosyasi halindeki HelloWorld sinifini hafizaya yükler. HelloWorld sinifi bünyesindeki kodlarin sanal makine tarafindan kosturulabilmeleri icin bu sinif bünyesinde main() isminde bir metodun bulunmasi gerekmektedir. Bu metod uygulamanin giris noktasidir ve sanal makina bu metodun basindan itibaren komutlari kosturmaya baslar.

Sanal makine bytekodlari iki sekilde kosturur. Bunlardan ilkinde bytekod yorumlanir. Ikincisinde ise bytekod mikroislemcinin anlayacagi sekilde derlenir. Bytekodun yorumlanmasi durumunda sanal makine bytekodun karsiligi olan islemci kodunu (microcode) tespit eder ve bu islemci kodunun kendi bünyesindeki derlenmis halini islemci üzerinde kosturur. Bytekodun yorumlanmasi java uygulamalarinin daha yavas calisir durumda olmalari dejavantajini beraberinde getirmektedir. Uygulamanin performansini artirmak icin bytekodun islemci koduna derlenmesi gerekmektedir. Bytekod derleme görevini sanal makine bünyesinde JIT (just in time) Hotspot derleyicisi (compiler) üstlenmektedir. Sikca ihtiyac duyulan kod birimleri JIT tarafindan derlenir ve dogrudan islemci üzerinde kosturulur. JIT olmadan sanal makine sadece bir bytekod yorumlayıcısıdır (interpreter). Hotspot çok sık kullanılan kod bölümlerini, mikroişlemci üzerinde daha hızlı koşturulabilmeleri için doğrudan mikroislemci koduna dönüştürür. Bu işlemi yapabilmesi için belli bir süre kodu analiz etmesi (profiling) gerekmektedir. Bu sebepten dolayı Java uygulamaları belli bir ısınma aşamasından sonra daha hızlı çalışmaya başlarlar, çünkü bytekodun belli bir kısmı ya da hepsi JIT tarafından Assembly oradan da islemi koduna dönüştürülmüştür.

JIT tarafından oluşturulan Assembly kodunun çıktısını alabilmek için bir Hotspot Disassembler plugin kullanmamız gerekmektedir. Kenai base-hsdis projesi bünyesinde böyle bir plugin yer almaktaktadır. Ben bu yazımdaki örnekler için Linux altında 64 bit JDK7 (jdk1.7.0_45) kullandım. Kullandığım disassembler plugin linux-hsdis-amd64.so ismini taşıyor. Bu dosyanın libhsdis-amd64.so ismini taşıyacak şekilde jdk1.7.0_45/jre/lib/amd64/server dizinine kopyalanması gerekiyor. Bu işlem ardından çalışan bir Java uygulamasının makine kodu çıktısını alabiliriz.

Önce koşturmak istediğimiz Java koduna bir göz atalım. Main sınıfı bünyesinde volatile olan volatileCounter ve counter değişkenleri yer almaktadır. count() metodu bünyesinde bir for döngüsünde bu değişkenlerin değerleri artırılmaktadır. For döngüsü volatileCounter değişkeni 100000 değerine ulaştığında son bulmaktadır. Hotspot JIT kod 100000 sefer koşturulduğundan dolayı islemci makine koduna dönüştürmektedir. Bu uygulamanın çok sıkca kullanılan alanlarının (hotspot; sıcak alan anlamında) makine koduna dönüştürülerek, daha da hızlı koşturulabilmeleri için gerekli bir işlemdir. Hotspot sadece sıkca koşturulan kodları makine koduna dönüştürür. Sıkça kullanılmayan kod bloklarının JVM tarafından yorumlanma hızı yeterlidir. Bu tür kodlar için makine kodunun oluşturulması çok maliyetli bir işlemdir. Elde edilecek kazanç çok az olacağından, sıkça kullanılmayan kod blokları makine koduna dönüştürülmez.

Eğer count() metodunda bir for döngüsü kullanılmasaydı, JIT tarafından daha sonra inceleyecegimiz assembly kodu oluşturulmazdı. Bunu sağlayan döngünün 100000 adet olmasıdır. JIT hangi kod bloğunun ne kadar koşturulduğunu takip ettiği için hangi kod birimi için makine kodu oluşturacağına karar verebilmektedir.

[source language=”java”]
public class Main {

private volatile int volatileCounter;
private int counter;

public static void main(final String[] args) {

new Main().count();
}

private void count() {

for (; this.volatileCounter < 100000;) {
this.volatileCounter++;

synchronized (this) {
this.counter++;
}
}
}
}
[/source]

Java derleyicisi (javac) tarafından oluşturulan bytekodunu aşağıdaki resimde görmekteyiz.

Şimdi gelelim Hotspot JIT tarafından oluşturulan assembly koduna. Assembly kodunu görebilmek için java sanal makineyi aşağıdaki şekilde çalıştırmamız gerekiyor:

[source language=”java”]
java -cp . -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly Main
[/source]

Aşağıda oluşan Assembly kodu yer almaktadır:

[source language=”java”]
1 0x00007f206906015c: jne 0x00007f2069060202 ;*monitorenter
; – Main::count@16 (line 16)
2 0x00007f2069060162: incl 0x10(%r13)
3 0x00007f2069060166: mov $0x7,%r10d
4 0x00007f206906016c: and 0x0(%r13),%r10
5 0x00007f2069060170: cmp $0x5,%r10
6 0x00007f2069060174: jne 0x00007f2069060226 ;*monitorexit
; – Main::count@28 (line 16)
7 0x00007f206906017a: mov 0xc(%r13),%r11d ; OopMap{rbp=NarrowOop r13=Oop r14=Oop off=222}
;*if_icmplt
; – Main::count@41 (line 13)
8 0x00007f206906017e: test %eax,0xa91ee7c(%rip) # 0x00007f207397f000
; {poll}
9 0x00007f2069060184: cmp $0x186a0,%r11d
10 0x00007f206906018b: jge 0x00007f20690602ef ;*aload_0
; – Main::count@3 (line 14)
11 0x00007f2069060191: mov 0xc(%r13),%r11d
12 0x00007f2069060195: inc %r11d
13 0x00007f2069060198: mov %r11d,0xc(%r13)
14 0x00007f206906019c: lock addl $0x0,(%rsp) ;*putfield volatileCounter
; – Main::count@10 (line 14)
15 0x00007f20690601a1: mov 0x0(%r13),%rax
16 0x00007f20690601a5: mov %rax,%r10
17 0x00007f20690601a8: and $0x7,%r10
18 0x00007f20690601ac: cmp $0x5,%r10
19 0x00007f20690601b0: jne 0x00007f2069060106
20 0x00007f20690601b6: mov 0xb0(%r12,%rbp,8),%r10
21 0x00007f20690601be: mov %r10,%r11
22 0x00007f20690601c1: or %r15,%r11
23 0x00007f20690601c4: mov %r11,%r8
24 0x00007f20690601c7: xor %rax,%r8
25 0x00007f20690601ca: test $0xffffffffffffff87,%r8
26 0x00007f20690601d1: je 0x00007f2069060162
27 0x00007f20690601d3: test $0x7,%r8
28 0x00007f20690601da: jne 0x00007f2069060100
29 0x00007f20690601e0: test $0x300,%r8
30 0x00007f20690601e7: jne 0x00007f20690601f6
31 0x00007f20690601e9: and $0x37f,%rax
32 0x00007f20690601f0: mov %rax,%r11
33 0x00007f20690601f3: or %r15,%r11
34 0x00007f20690601f6: lock cmpxchg %r11,0x0(%r13)
35 0x00007f20690601fc: je 0x00007f2069060162
36 0x00007f2069060202: mov %r14,0x8(%rsp)
37 0x00007f2069060207: mov %r13,(%rsp)
38 0x00007f206906020b: mov %r14,%rsi
39 0x00007f206906020e: lea 0x10(%rsp),%rdx
40 0x00007f2069060213: callq 0x00007f206905e320 ; OopMap{rbp=NarrowOop [0]=Oop [8]=Oop off=376}
;*monitorenter
; – Main::count@16 (line 16)
; {runtime_call}

[/source]

Java kodu sequentially consistent değildir yani Java bytekodun sahip olduğu sıraya göre satır satır koşturulma mecburiyeti yoktur. Hem Java derleyicisi (JIT) hem de mikroişlemci performansı artırmak için birbirine bağımlı olmayan kod satırlarının yerlerini değiştirerek işlem yapabilirler. Bu aslında oluşan java kodunun programcının yazdığı şekilde koşturulmadığı anlamına gelmektedir. Paralel çalışan programlarda bunun çok ilginç bir yan etkisi mevcut: bir threadin bir değişken üzerinde yaptığı değişikliği başka bir çekirdek üzerinde koşan başka bir thread göremeyebilir. Örneğin t1 (thread 1) a isimli değişkenin değerini bir artırdı ise ve t2 a belli bir değere sahip iken bir for döngüsünü terk etmek istiyorsa, t2 belki bu for döngüsünden hiçbir zaman çıkamayabilir, çünkü a üzerinde t1 tarafından yapılan değişiklikleri göremeyebilir. Bunun sebebi t1 in üzerinde çalıştığı çekirdeğin (core) a üzerinde yaptığı değişiklikleri kendi ön belleginde (L1/L2 cache) tutmasıdır. Mikroişlemciler yüksek performansta çalışabilmek için hazıfa alanları üzerinde yaptıkları değişiklikleri ilk etapta kendi ön belleklerinde tutarlar. Gerek duymadıkça da bu değişiklikleri diğer çekirdeklerle paylaşmazlar. Her çekirdek sahip olduğu önbelliği tüm hafiza alanıymış (RAM) gibi gördüğü için kendi performansını artırmak adına kod sırasını değiştirebilir. Bu belli bir sıraya bağımlı olan diğer threadlerin düşünüldükleri şekilde çalışmalarını engelleyebilir. Bu genelde paralel programlarda program hatası olarak dışarıya yansır.

Bu tür sorunları aşmanın bir yolu volatile tipinde değişkenler kullanmaktır. Volatile tipinde olan değişkenler üzerinde işlem yapıldığında mikroişlemci kodu programcının yazdığı sırada koşturmaya zorlanır. Bunu gerçekleştirmek için hafıza bariyerleri (memory barrier) kullanılır. Mikroişlemci bir hazıfa bariyeri ile karşılaştığında bir çekirdeğin sahip olduğu önbellekteki değişiklikleri doğrudan hafızaya geri yazar (write back) ve bu hazıfa alanını (cache line) kendi önbelleklerinde tutan diğer çekirdeklere mesaj göndererek bu hafıza alanını silmelerini (cache invalidate) talep eder. Böylece herhangi bir çekirdek üzerinde koşan bir threadin yaptığı değişiklik hemen hafızaya, oradan da diğer çekirdeklerin önbelleklerine yansır. Bu t1 tarafından a üzerinde yapılan bir değişikliğin t2 tarafından anında görülmesi anlamına gelmektedir. Bunun gerçekleşmesi için a isimli değişkenin volatile olması gerekmektedir.

Main sınıfında yer alan this.volatileCounter++; satırı ile bahsettiğim hafıza bariyerinin kullanımı gerekmektedir. JVM bunu sağlamak için Assemby kodunun 14. satırında mikroişlemci için lock addl komutunu kullanmaktadır. 13. satırda yer alan mov komutuyla %r11d registerinde yer alan volatileCounter isimli değişkenin değeri doğrudan hafızaya (RAM) aktarılır. Hafiza alanının adresi %r13 registerinde yer almaktadır. 14. satırda yer alan lock addl ile tüm mikroişlemci bünyesinde global bir hafıza transaksiyonu gerçekleştirilir. Atomik olan bu işlem ile tüm çekirdeklerin üzerinde değişiklik yapılan hafiza alanını önbelleklerinden silmeleri ve yeniden yüklemelerini sağlanır. Böylece diğer threadler yapılan değişiklikleri anında görmüş olurlar.

Java kodunu sequentially consistent yapmanın diğer bir yolu synchronized kelimesinin kullanımıdır. Synchronized kullanılması durumunda mikroişlemci değişikliğe uğrayan değeri önbellekten alıp hafızaya geri aktararak, diğer çekirdeklerin kendi önbelleklerini tazelemelerini sağlar.

Main sınıfında yer alan counter isimli değişken volatile olmadığı için üzerinde yapılan değişiklikler diğer çekirdeklere yansımaz. Bunu sağlamak için count() metodunda değer atamasını synchronized bloğunda yaptım. Bu JVM tarafından tekrar bir hafıza bariyeri kullanımı gerektiren bir işlemdir. JIT makina kodunun 34. satırında lock cmpxchg ile gerekli hafıza bariyerini oluşturmaktadır. Bu üzerinde işlem yapılan çekirdeğin counter isimli değişkenin değerini tekrar hafızaya geri aktarmasını ve diğer çekirdeklerin bu değeri tekrar hafızadan kendi önbelleklerine çekmelerini sağlamaktadır.


EOF (End Of Fun)
Özcan Acar

Koddan Korkan Programcı

Bir senior ve bir junior arasında yapılan konuşmaya kulak misafiri olalım:

Senior: Sakın başkasının kodunu değiştirme! Ufak bir değişiklik ummadığın hataların oluşmasına sebep olabilir. Yaptığın değişiklik sonucu bir hata oluşmadı ise, kimse seni övmez. Ama hata olursa, herkes başına üşüşür. Bunu istediğini zannetmiyorum.
Junior: Ama agile diye bir şey var, öyle kodu yeniden yapılandırmadan olmazki! Kodu okunabilir hale getirmek lazım. Bu devamlı yapılmassa, bir zaman sonra kodun bakımı zorlaşacaktır.
Senior: Sen bilirsin! Ben söyleyeceğimi söyledim, kodu değiştirdiğin zaman olacaklardan her zaman sen sorumlu olursun.

Bahsi geçen projenin kod tabanı çok geniş. Gerçekten de en ufak bir değişiklik beklenmeyen neticeler doğurabiliyor. Bu sebepten dolayı ekipte genelde “do not touch a running system (çalışan bir sistemi değiştirme)” mentalitesi oturmuş durumda. Hepsinin temelinde korku var: programcılar koddan korkuyor.

Tecrübeli bir kuaför saçtan korksa idi, saça form verebilir miydi? Usta bir fırıncı hamurdan korksaydı ekmek yapabilir miydi? İyi bir futbolcu toptan korksaydı gol atabilir miydi? Peki koddan korkan bir programcı iyi kod yazabilir mi?

Koddan korkan, kodun hakkını veremez! Koddan korkmanın tek nedeni, yapılan değişikliklerin meydana getirebileceği yan etkileri kestirememektir. Ama programcının yaptığı her türlü değişikliğin yan etkilerini ölçmek için bir aracı olsa korkusu azalır mıydı? Evet, azalırdı ya da tamamen yok olurdu. Böyle bir araç var mı? Evet, var. Peki bu aracın ismi nedir? Birim testi, entegrasyon testi, onay/kabul testi. Her türlü test makbuldür, yeterki değişikliklerin yan etkilerini tespit etmekte yardımcı olabilsiler.

Test yazılmayan projelerde er ya da geç kod korku oranı artar. Belki de projelerin gidişatını tahmin etmekte bu bahsettiğim korku oranı bir metrik olarak kullanılabilir. Bu metrik örneğin şu şekilde tespit edilebilir:

Yönetici: Bah, burada bir parça kod var. Bah baalım! Bakınca ne kadar korktun, süle bakim?
Programcı: Anaaammmm, göstermeyin bana böyle kodlar, öcü gibi, çok korktum!
Yönetici: Tüh la, proje yakında duvara toslar, biliyodum zateng!

Şu sunumumda çevikliğin temelinde sürekli değişim için cesaretin olduğundan bahsetmiştim. Test yazmak yazılımcının cesaretini ve koda karşı özgüvenini artırır. Test yazılmadığında bunun tersi olur. Veresiye satan yazılımcı olmak ya da olmamak yazılımcının kendi elinde.

EOF (End Of Fun)
Özcan Acar
@oezcanacar

Alışkanlıkların Gücü

Hiç diyet yaptınız mı? O zaman her diyetten sonra tekrar kiloları fazlasıyla geriye aldığınıza diyet sayınız adedince şahit olmuşsunuzdur. Yeme alışkanlıkları değiştirilmeden hiçbir diyetin başarılı olduğunu görmedim. Bu konuda epeyce bir tecrübeliyim diyebilirim. Tipik bir iş gününün yüzde %90 ından fazlasını masa başında geçiren birisi olarak, kilolarımı dengede tutmak için yapmadığım diyet ve spor türü kalmadı. Ama bu konuda Karatay diyeti ile tanışana kadar kesinlikle başarılı olamadım. Verdiğim kiloları her zaman faylasıyla geriye aldım. Kilo vermek değil, kiloyu tutabilmek marifetmiş, bunu yaptığım bunca diyetten sonra çok iyi anladım.

Bir diyetin kısa bir analizini yapıp, neden başarılı olmadığını inceleyelim isterseniz. Her diyetin başında niyet vardır: kilo verme niyeti. Bu niyet olmadan diyetin başarılı olma ihtimali %0 dır. Hadi niyet sahibiyiz diyelim. İkinci adım hangi diyetin yapılacağının tespitidir. Hadi Diyet A yı yapmaya karar verdiğimizi düsünelim. Diyet A müthiş bir diyet ve bir ay içinde 10 kilo verdirebiliyor. Vay canına deyip, bu diyet ile sağlığımızı ne kadar büyük bir rizikoya soktuğumuzu göz ardı ederek diyete başlıyoruz. 10 kilo muazzam bir rakam. Ne yapıp, edip bu kilolardan kurtulmamız gerekiyor. Bu yüzden vücudumuzu darp edecek bu diyete başlıyoruz….

Bir ay sonra gerçekten 10 kilo verdiğimizi düşünelim. Bu utopik rakamı seçtim, çünkü insanların diyetlerden olan uçuk beklentilerini ifade etmek istiyorum. On senede 10 kilo alıp, bu kiloları bir ayda vermeyi istemek biraz absürd bir düşünme tarzı degil mi? Diyet yapanların %99.9999 kısmı diyet sona erdikten sonra eski yeme alışkanlıklarına geri dönerler. Bu onların altı ay içinde 20 kilo geri almaları anlamına gelir. Eğer sağlıklı yeme alışkanlarına sahip olsalardı, zaten diyet yapmalarına gerek kalmazdı.

Kiloların geri alınmasının tek sebebi, diyet yapanın sahip olduğu yeme alışkanlıklarıdır. Yapılan diyet bireyin yeme alışkanlıklarını değiştirmez. Sadece kilo kaybına sebep olur. İnsanlar kolay kolay sahip oldukları alışkanlıkları terk edemezler, çünkü onlar beyinde yerleşmiş aksiyon şablonlarıdır ve beyin tanıdığı şablonların dışına çıkmayı sevmez. Bu sebepten dolayı hiçbir diyet başarılı olamaz, ta ki diyet sonrası yeme alışkanlarıkları gözden geçirilip, adapte edilene kadar.

İnsan yaradılışı gereği her zaman kendi alışkanlıklarına sadıktır. Yeni alışkanları farkına varmadan edinir, mevcut alışkanlıklarının üzerine titrer. İnsanı comfort zone da tutan ve ilerlemesini engelleyen mevcut alışkanlıklarıdır. Beyinde çalışan ve alışkanlık olarak ifade ettiğim bu subrutinler değişikliğe karşı çok dayanıklıdır. Modifikasyona izin vermezler. Tek amaçları bir döngü içinde görevlerini yerine getirmektir. Bunun böyle kalması için beyin onları devamlı korur ve onlara runtime hizmetleri sunar. Onlara ne kadar çok etki etmeye çalışsak bile bunda çogu zaman başarılı olamayız. Bu yüzden silinmeleri gerekir. Bu onları değiştirmeye çalışmaktan daha zor bir iştir. Ama bunu yapmadığımız taktirde alışkanlıklarımızın rehini olmaya devam ederiz.

Alışkanlıklar organizma için otomatik pilot vazifesi görürler. Beyin onların yardımı ile zor olan “düşün-karar ver-uygula” döngüsüne girmeden aksiyon alabilir. Bu günlük hayata adapte olmamızı kolaylaştırır. Bu şekilde hiç farkında bile olmadan debriyaja basıp, vites değiştirerek, şehrin bir ucundan diğer ucuna araba ile gidebiliriz. Her vites değiştirmek istediğimizde bu işlemi nasıl yapacağımızı uzun, uzun düşünmek zorunda kalsaydık, araba sürmenin ne kadar zahmetli bir iş olacağını düşünebilirsiniz. Bu açıdan bakıldığında alışkanlıkların olumlu tarafları da yok değil, çünkü günlük hayatımızı kolaylaştırabiliyorlar.

Yazılımcılar da gün içinde, sahip oldukları birçok alışkanlığa maruz kalırlar. Örneğin uzun metotlar yazmak, metot, değişken, sınıf isimlerini özenle seçmemek, birim testi yazmamak, mevcut kod birimlerini tekrar kullanılabilir hale getirmeden copy/paste yapmak gibi. Bu şekilde çalışanlar, devamlı bu şekilde çalışmaya devam ederler, çünkü bu şekilde çalışmaya alışmışlardır. Bu şablonun neden dışına çıkmaları gerektigini sorgulamazlar. Bunu sorgulayanlar belli bir zaman dilimi için bu kötü alışkanlarıklarindan vaz geçmeye çalışırlar. Kısa metotlar oluştururlar, kullandıkları isimlere özen gösterirler, belki birim testi bile yazmaya başlarlar, ta ki sürüm zamanı yaklaşıp, günü kurtarmak zorunda kalıncaya kadar. O zaman ne olur? Edinmeye çalıştıkları yeni alışkanları top yekün terk ederek, eski alışkanlıklarına hemen geri dönüverirler, çünkü en hızlı o modda çalışabilirler ya da çalıştıklarını düşünürler. Bu aslinda programcının verdiği bir karar değildir. Daha ziyada beyin otomatik olarak eski şablonları çekmeceden çıkartarak, uygulamaya başlar. Beyin için içinde bulunulan stresli durumdan çıkmanın en kolay yolu mevcut alışkanlıklardan faydalanmaktır, yani işleri otomatiğe bağlamaktır.

Aynı şey Organizasyonel Değişim başlıklı yazımda değindiğim gibi yazılım ekiplerine yeni davranış biçimleri kazandırmak için verilen ugraşılar için de geçerlidir. Yeni bir eğitimden geçmiş bir ekibin, eğitim sonrasında yeni öğrenilen yetilerle yola devam etmesi beklenemez, çünkü ilk fırsatta ekip çalışanları kendi alışkanlıklarına geri dönerler.

Sahip olduğumuz alışkanları bir torbanın içinde toplanmış olarak hayal edelim. Beynimiz herhangi bir işlem gerçekleştirmek istediğinde bu torbaya elini sokup doğru olduğunu düşündüğü alışkanlığımızı seçerek, işletmeye başlayacaktır. Şimdi bu torbayı boşaltıp, yerine yeni alışkanlılar koyduğumuzu farz edelim. Bu durumda yeni alışkanlıklar devreye girecektir, çünkü torbada eski alışkanlıklar bulunmamaktadır. Beyin aslında yeni ya da eski alışkanlıklar arasında ayrım yapmadan, uygun bulduğu ilk alışkanlığı koşturacaktır. Demek oluyor ki torbadaki alışkanlıkları boşaltıp, yerine yeni alışkanlıklar koymamız gerekiyor.

Bize faydası olmayan alışkanlıklardan nasıl kurtulabiliriz yani torbayı nasıl boşaltabiliriz? Yeni alışkanlıklar edinerek. Bilinçli olarak yeni alışkanlık nasıl edinebiliriz? Pratik yaparak. Kod Kata ve Pratik Yapmanın Önemi başlıklı yazımda bu konuyu açıklamaya çalıştım.

Bu arada yazımın başında bahsettiğim Karatay diyetini merak ediyor olabilirsiniz. Bu bir diyet değil, sayın Prof. Doktor Canan Efendigil Karatay hanımefendi tarafından geliştirilmiş bir sağlıklı beslenme metodudur. Diyet olarak da uygulanabilmektedir, lakin ana amacı uzun vadede sağlıklı beslemek ve sağlıklı beslenme alışkanlıkları edindirmektir. Sağlıklı beslenmek isteyenlere şiddetle tavdiye edilir.


EOF (End Of Fun)
Özcan Acar

Kim Senior Programcıdır?

İlk bakışta bir programcıyı senior yapan teknik bilgisidir. Yüksek seviyede teknik bilgiye sahip olmak için çok tecrübe sahibi olmak gerekir. Yüksek seviyede teknik bilgiye sahip bir şahsın senior olarak algılandığını düşünebiliriz. Lakin teknik bilgi senior olmanın sadece bir boyutudur. Senior mozaiğinin tamamlanması için birçok parçanın bir araya gelmesi gerekir.

Kendisini senior olarak tanımlayan birçok programcı gördüm. Benim açımdan bu programcıların çok büyük bir kısmı senior değil. Şu sebeplerden dolayı:

  • Üç ya da beş sene programcı olarak çalıştıktan sonra kıdem alma zorunluluğu varmış gibi kendine durup, dururken senior ünvanını uygun görürler. Böyle programcılar senior ünvanından en uzak olan programcı adaylarıdır.
  • Bir ya da birden fazla çatıyı (framework) iyi kullanabildiklerinden dolayı senior olduklarını düşünürler. Bu tip programcılar senior olma yolunda değil, daha ziyada uzman olma yolunda ilerlemektedirler.
  • Yıllarca programcı olarak çalışmış olmalarına rağmen ekibin parçası olmaktan acizdirler. Kendi dünyalarında yaşayıp, ekipten kopuk olarak çalışmaya devam ederler. İletişim kurmakta zorluk çekerler.
  • Çoğunun müşteriyle iletişimi yoktur ya da çok azdır. Müşterinin tam olarak ne istediğini bilmeden kod yazarlar. Müşterinin ne istediğini bilmediklerinden dolayı nerede durmaları gerektigini bilmezler. Onu da ekleyelim, bu da olsun derken gereksiz zaman ve para kaybına neden olan kod yazarlar.
  • Kitap okuyup, kendilerini devamlı geliştirmezler. Geçen yılların onları otomatik olarak senior yaptığını düşünürler. İlk sene bir şeyler öğrentikten sonra dokuz sene aynı şeyleri tekrar etmeyi on senelik tecrübe sahibi olmak olarak algılarlar. Bu onların açısından senior olmak için yeterlidir.
  • Test yazmayı zaman kaybı olarak görürler. Başlarını en çok ağrıtan durumun bu olduğunu anlamakta zorlanırlar.
  • Teknik olarak belki çok iyidirler ama detaylarda kaybolduklarından veya lüzumsuz şeylerle uğraşmayı sevdiklerinden gereğinden fazla kod yazarlar. Bu hem işverene zarar verir hem de müşteriyi daha çok memnun edecek bir netice ortaya koymaz.

Bu listeyi sayfalar dolduracak sekilde genişletmek zor değil. Benim senior olabilmek için iki kriterim var. Yukarıda saydığım durumları zaman içinde aşıp, senior olmak zor değil. Lakin aşağıda sıraladığım iki kriter olmadan senior olmak hemen hemen imkansız. Bu kriterler:

  • Programcının müşteri ile olan iletişimde ne kadar başarılı olduğu.
  • Programcının başarıyla kaç proje tamamladığı.

Program yazmak çok maliyetli bir iş. Yazılan her satır kod para demek. Eğer bu satır gereksiz bir satır ise, o zaman bu para pencereden dışarıya atılmış para demektir. Programcı yazdığı her satırın gerekli olup, olmadığını nasıl anlayabilir? Müşteriye ne istediğini sorarak. Müşterinin ne istediğini anlamadan yazdığı kodun gerekliliğini bilemez. Müşteri ne istediğini tam olarak ifade eder ya da etmek zorundadır. Ben şunu istiyorum dediği zaman, programcının müşterinin şu olarak ifade ettiği şeyi koda dökmesi gerekir. Bundan fazlası zarardır, maddi kayıptır. Ne yazık ki kendisini senior olarak gören birçok programcı müşterinin ne istediğini anlamadan oturup, günlerce, haftalarca ya da aylarca program yazabiliyor. Müşterinin ne istediğini tam olarak anlamadan kod yazan, senior programcı olamaz, çünkü kendisini işverenine karşı sorumlu olarak gören bir programcının gönlü kendi yaptığı hatanın ya da keyfi çalışmalarının parasal zarar olarak işverenine yansımasına razı gelmez. Senior programcı bu dengeleri hep kafasında kendisiyle birlikte taşıyan programcıdır.

Başarıyla birçok projeyi tamamlayarak sınır koymanın, sadece gerekeni yapmanın, müşteriyi memnun etmenin, işvereni mutlu etmenin ne demek olduğunu bilmeyen programcı senior ünvanını hak etmez. Başarıyla tamamlanan her proje programcıyı senior olma yolunda ilerlerken pekiştirir, tecrübelendirir. Başarıyla bir proje tamamlamak demek, müşterinin isteklerini tatmin eden bir ürün ortaya koymak demektir. Bu başarıyı birkaç kere tatmadan gerçek anlamda senior olmak çok güçtür ya da imkansızdır.

Senior olmayı bazıları sadece bilgi küpü olmak ve daha fazla maaş almak olarak tanımlıyor demiştim geçenlerde attığım bir tweetde. Senior olmayı sadece bilgili olmak ve fazla maaş almak gibi iki zayıf sıfat ile tanımlamaya kalkmak gerçek senior programcılarin hakkını yemek olur. Bu iki şey gerçek senior programcılar için çok öncelikli olmayan şeylerdir. Onlar müşteriyi dinlemeyi, onun isteklerini tatmin etmeyi yeğlerler.


EOF (End Of Fun)
Özcan Acar

Açık Kaynağa Destek

Şüphesiz açık kaynak (open source) filozofisi biz programcıların hayatını derinden etkiledi. Açık kaynağın bize sağladığı bariz iki avantaj var. Bunlar:

  • Başkalarının, bu başkaları çoğu zaman usta olarak tabir edebileceğimiz yetenekli programcılar, yazdığı kodlara bakarak kendimizi programcı olarak geliştirebiliriz.
  • Açık kaynaklı programları lisans bedeli ödemeden kullanabiliriz.

İkincisi çok bariz olarak karşılaştığımız bir durum. Hibernate, Spring, Eclipse.. bu meşhur açık kaynaklı programların kullanılmadığı proje sayısı çok az ya da yok gibi.

Birileri, bir yerlerde oturmuşlar, bizim hayatımızı kolaylaştırmak için gece, gündüz demeden açık kaynaklı programlar oluşturmak için çalışıyorlar. Neden bunu yapıyorlar acaba?

Bunun çeşitli sebepleri olabilir. Örneğin:

  • İdealistler ve dünyayı iyileştirmek istiyorlar.
  • Bu işten para kazanmak istiyorlar. Açık kaynaklı ürünleri satmak imkansız, ama destek sağlayarak para kazanmak mümkün.
  • Bir açık kaynaklı ürün oluşturarak piyasada tanınmak ve ün salmak isteyenler olabilir.
  • IBM gibi firmalar açık kaynaklı ürünlerin oluşturulmasına destek vererek Microsoft gibi firmaların oluşturdukları monopolleri kırmak isteyebilirler. Nitekim Eclipse IBM tarafından geliştirilmiş ve daha sonra açık kaynak olarak bizlerin kullanımına sunulmuştur. IBM’in amacı Java ekosistemini güçlendirmek ve Java’nın .NET platformuna alternatif oluşturmasını sağlamaktır.
  • Belli bir teknolojinin yayılmasını sağlamak için açık kaynaklı programlar oluşturulabilir. Örneğin Java’nın daha yaygın hale gelmesini sağlamak için sahip olduğu ekosistemi oluşturan hemen, hemen her parça açık kaynaklıdır.
  • Bir ürünün yayılmasını sağlamak için ürün açık kaynaklı yapılabilir. Örneğin JetBrains firmasının IntelliJ IDEA isminde açık kaynaklı kod geliştirme ortamı bulunuyor. Community Edition ismini taşıyan bu sürüm programcıların temel ihtiyaçlarını karşılarken, JetBrains bu ürünün profesyonel sürümlerini oluşturup, satarak para kazanıyor.

Bu listeye eklenti yapmak zor değil. Benim ilk düşündügümde aklıma gelen noktalar bunlar. Peki bize bu kadar muazzam getirisi olan bir akım için biz programcılar neler yapıyoruz ya da yapabiliriz? Sayalım:

  • Açık kaynaklı ürünleri kullanarak belli teknolojilerin öne çıkmasına destek verebiliriz. Linux örneğinde olduğu gibi bu monopollerin kırılmasını ya da dengede tutulmasını sağlayabilir.
  • Açık kaynaklı ürünlerin geliştirilmesine katkıda bulunabiliriz. Açık kaynaklı projelerin çoğu gönüllü olan programcılar sayesinde geliştirilebiliyor.
  • Açık kaynaklı ürünlerin kullanımında keşfettiğimiz hataları gerekli yerlere bildirerek, bu hataların giderilmesine katkıda bulunabiliriz. En ideal olanı bu hataları gidererek, projeye doğrudan destek saglamaktır.
  • Açık kaynaklı projelerin sürdürülebilmesi için parasal destekte bulunabiliriz, yani bağış yapabiliriz.

Eclipse benim yıllardan beri kullandığım açık kaynaklı bir araç. Bugün Eclipse Foundation için belli bir miktarda bağış yaptım. Ne kadar bağışladığım önemli değil. Önemli olan bağışın kendisi. Yıllardan beri freelancer olarak çalıştığım birçok projede Eclipse’i kullandım. Eclipse olmasaydı başka bir ürünü kullanırdım. Ama Eclipse vardı ve onu kullandım. Bunun karşılığında hiçbir bedel ödemedim. Eclipse bana programcı olarak çok şeyler kattı. Para kazanıp, hayatımı sürdürmeme destek oldu. Yaptığım bağış okyanusta bir damla bile olsa, damlaya, damlaya göl olur sözünü unutmamak lazım. Bağışı yaptıktan sonra Friend Of Eclipse ünvanina sahip oldum :) Ne güzel….

Çoğu programcı kullandıkları araçların açık kaynaklı olduklarına pek kafa yormadan hergün bu araçları kullanarak, işlerini yapıyorlar. Aynı şekilde çoğu programcının kullandıkları açık kaynaklı programların kodlarını inceleyip, daha iyi bir programcı olmak için çaba sarfettiklerini düşünmüyorum. Çoğu programcı bu ürünleri kullanırken keşfettikleri hataları bir yerlere bildirmiyorlar, çünkü birileri bunu yapar diye düşünüyorlar. Çoğu programcı commiter olarak açık kaynaklı projelere destek vermiyor, çünkü bunun için zamanları yok ya da zamanlarının olmadığını düşünüyorlar. Çoğu programcı lisans bedeli ödememek için bahsettiğim açık kaynaklı programları kullanıyorlar. Hepsini topladığımızda açık kaynaklı akımı desteklemeyen, egoistçe kullanan ve hiçbir şey geriye vermeyen bir programcı kitlesi oluşuyor. Ama üzülmesinler, yapabilecekleri bir şey var. Hiçbir şey yapamıyorlarsa, o zaman açık kaynaklı projelere bağış yapabilirler. Bu şekilde fayda sağladıkları projelerin devam etmelerini sağlayabilirler. Kullanıkları açık kaynaklı ürünler olmasaydı hayatlarının programcı olarak ne kadar daha zor olacağını düşünmeleri yeterli.

Her programcıyı kullandığı açık kaynaklı araçları desteklemek için bağış yapmaya davet ediyorum. Bağış bir Lira’da olsa damlaya damlaya göl olur.

Not: Bağış yapanlar bu yazıya yorum bırakarak, hangi açık kaynaklı projeyi desteklediklerini bildirebilirler.


EOF (End Of Fun)
Özcan Acar

SpringSource Certified Integration Specialist Sertifikası

Eylül 2012 de katıldığım SpringSource Certified Enterprise Integration Specialist kursunun ardından geçen hafta katıldığım imtihanı kazanarak SpringSource Certified Integration Specialist sertifikasını almaya hak kazandım.



Resim 1: Kursa katılım belgesi

Dört gün süren kursun içeriği aşağıdaki konulardan oluşuyor:

  • Spring Remoting
  • Spring Web Services
  • REST
  • JMS
  • Transactional JMS
  • XA Transactions
  • Spring Batch
  • Spring Integration

Spring bünyesinde Spring Integration ismini taşıyan ve EDA (Event Driven Architecture) ve SEDA (Staged EDA) mimarileri oluşturmak için kullanılabilecek bir modül yer alıyor. Certified Integration Specialist ifadesini duyanlar kursun ve imtihanın tamamen Spring Integration yapıları üzerine olduğunu düşünebilir. Ama ne yazık ki öyle değil. Certified Integration Specialist başlığı altında yukarıda saymış olduğum ve daha ziyada sistem entegrasyonu için kullanılabilecek konular yer alıyor.

SpringSource tarafından sunulan kursa katılmadan sertifika imtihanına katılmak mümkün değil. Bu diğer SpringSource sertikaları için de geçerli. Bu sertifiyı edinmenin önünde bulunan bir bariyer. Buradaki amaç belli: Kurslar aracılığı ile para kazanmak. Gönül isterdi ki ilgi duyan herkes engel olmadan bu sertifikayı edinebilsin.

Ne yazık ki internet ortamında imtihan ile ilgili kaynak bulmak kolay değil. Bu serfikanın çok yaygın olmadığının bir göstergesi. Ben bu örnek soruları keşfettim. İmtihan hakkında fikir sahibi olmak için faydalı bir kaynak. İmtihanda başarı sağlamak için SpringSource tarafından hazırlanan Spring Integration Certification Guide‘da yer alan konulara çalışmak yeterli.


Resim 2: Sertifikanın kendisi

Bu sertifika sahibi olanlar aşağıda yer alan logoyu kullanabiliyorlar.


EOF (End Of Fun)
Özcan Acar

TeletAPI’nin API’si

Yazılımcılar detaylara olan sevdaları ile tanınırlar. Bir yazılımcı kullanılmak üzere yeni bir API (Application Programming Interface) geliştirdi ise ve kendisinden bu yeni API’nin nasıl kullanıldığının açıklanması istenirse, size detaylar içinde kaybolmanız ve oturum sonunda API’nin nasıl kullanıldığını anlamamanız garantisini veririm.

Bir API’yi kullanmak nedir, önce bunun tanımlamasını yaparak başlamak istiyorum. Bir API ideal bir dünyada bir yazılım modülünün, kendisinin dış dünyadan kullamını mümkün kılmak için dış dünyaya açtığı pencere ya da pencerelerdir. Biliçli olarak bu tanımlamada kapı kelimesini kullanmadım, çünkü pencereyi kullanarak modülün iç dünyasında olup, bitenleri anlamak mümkün değildir. Ama kapı metaforunda kapıyı kullanarak içeri girmek ve olup bitenleri görmek ve anlamak mümkündür. Bu demek oluyor ki bir API kesinlikle modül içinde olup bitenlerin dış dünyaya sızmasına izin vermez ya da vermemelidir. Modülün nasıl çalıştığını API’ye bakarak anlamak mümkün değildir. API sadece modül ile bir kara kutuymuşcasına interaksiyona girmek için kullanılır. Bu API aracılığı ile sadece modülün sunmak istediği servislerin, izin verdiği ve kendisinin tanımladığı şekilde kullanılabilmesi anlamına gelmektedir. Modülün bu servis ya da servisleri kendi iç dünyasında nasıl hazırladığını anlamak, görmek ya da değiştirmeye kalkmak API aracılığı ile mümkün değildir. Tabi modül buna yine API’si aracılığıyla izin veriyorsa, durum değişik olacaktır.

Bu tanımlamaya göre bir API kullanıcısı API’nin arkasındaki gizli dünyayı bir kara kutu olarak görür. Bu kara kutuyu programlamış programcı için ise durum farklıdır. Programcı tüm detayları bilir ve API’nin nasıl kullanıldığını tanıttığı bir oturumda bu detaylarda kaybolur gider.

Bunun başlıca sebebi yazılımcının kendi geliştirdiği modüle kullanıcı gözlüğünü takarak bakamamasıdır. O her zaman modülü bir beyaz kutu (white box) olarak görür. Bu gözlüğü takarak modülü geliştirir. Bu aslında bir noktaya kadar yapması gereken bir seydir, lakin belli zamanlarda kullanıcı gözlüğünü takabilmelidir. Takamadığı taktirde kullanıcının anlamakta ve kullanmakta güçlük çektiği API’ler oluşabilir.

Yazılımcı modül API’sini mutlaka kullanıcı gözlüğü ile tasarlamalıdır. Bunun için en ideal zaman modül için kod geliştirmeye başlamadan öncesidir. Ortada herhangi bir modül yokken, API’si vardır. Bu şekilde düşünmek bile birçok yazılımcıyı zorlar. Yazılımcı hemen oturur ve hayal ettiği şekilde modülü geliştirmeye başlar. Bu esnada kullanılmayan ya da gereksiz birçok metot ve sınıf oluşur. Bunun sebebi yazılımcının modülün nasıl kullanılacağını bilmemesinde yatmaktadır. En kötü ihtimalle yazılımcı modülün işleyiş tarzını kodladıktan sonra API’si hakkında kafa yormaya başlar. Bu API yırtık yamadan farksızdır ve modülün verimli bir şekilde kullanılmasının önünde engeldir. Bunun bir örneği aşağıda yer alan kodda yer almaktadır.

[source language=’java’]
File metaFile = new File(“abc”);
Storage storage = StorageHelper.createStorage(StorageLoader.load(MetaHelper.createMetaFile(metaFile)));
Reader reader = storage.getReader();
Object obj = reader.getObjectById(1);
[/source]

Bu kod parçasına ilk bakıldığında ne yaptığını anlamak zor olmamakla birlikte, kullanılması zor olan bir API’yi ihtiva etmektedir. Bu kod örneğinde Storage isminde bir modül mevcuttur. Kullanıcı bu modülü kullanabilmek için Storage, StorageHelper, StorageLoader, MetaHelper gibi aslında pek varlıklarından bile haberdar olmaması gereken sınıflarla boğuşmaktadır. Bunun sebebi bu modülün bir API’sinin olmaması ve geliştiricisinin geliştirme sürecinde bu modül nasıl en kolay bir şekilde kullanılır sorusuna cevap aramamış ya da bu soruya cevap bulamamış olmasıdır. Yazılımcı API zannettiği birçok sınıfı ortaya atmış, hem modülün basit bir API üzerinden kullanılmasını engellemiş, hem de modül icinde olup bitenleri herkesin göreceği şekilde açığa vurmuştur. Bu tarz bir modül ve API oluşturulması gereksiz bağımlılıkları beraberinde getireceğinden, kodun bakımını uzun vadede çıkmaza sokacaktır. Şöyle bir API işi çok daha kolay yapmaz mıydı?

[source language=’java’]
Storage storage = Storage.create(“abc”);
Object obj = Storage.getObjectById(1);
[/source]

ya da;

[source language=’java’]
Object obj = Storage.instance(“abc”).getObjectById(1);
[/source]

Yukarıda yer alan örneklerde veri tabanından belli bir nesneyi edinmek için önce bir Storage nesnesinin oluşturulması ve akabinde getObjectById() metodun kullanılması yeterli olmaktadır. Modülün API’si sadece bu ya da buna benzer metotlardan oluşmaktadır. Kullanıcının diğer örnekte görüldüğü gibi modül içinde kullanılan StorageLoader ya da MetaHelper gibi sınıfları tanıması ve kullanması şart değildir. Bu modülün kullanımını kolaylaştıran ve API’yi sadeleştiren bir durumdur. Böyle bir API’de kullanıcı sadece Storage sınıfına bağımlı olduğundan, modülün içinde yer alan sınıflar bünyesideki herhangi bir değişiklik kullanıcıyı etkilemeyecektir. Verdiğim ilk örnekte modülün sahip olduğu iç sınıflara bağımlılık doğrudan olduğu için, modülü kullanan kodun kırılganlığı modül üzerinde yapılan her değişiklik ile doğru orantıda artacaktır.

API tasarımı modül için gerekli kodun yazılmasından sonrasına bırakılamayacak kadar ciddi bir konudur. Öyle ise API tasarımını kod yazmadan destekleyecek bir yöntemin kullanılmasında fayda vardır. Bu yöntemin ismi test güdümlü yazılımdır (TDD – Test Driven Development).

Test güdümlü yazılımın en büyük avantajlarından birisi kod yazmadan, geliştirilmek istenen kod biriminin kullanıcı gözünden görülmesini sağlamasıdır, çünkü yazılan tesler oluşturulan kod birimleri için kullanıcı olma niteliğindedir. Yani aslında test sınıfları API’lere yönlendirilmiş kullanıcılardır. Bu sebepten dolayı testler bir kullanıcının ihtiyaçları doğrultusunda kod birimlerini test ederler. Durum böyle olunca test güdümlü yazılım yaparken oluşturlan testlerde akla gelen ilk soru “ihtiyacım nedir ve API bu ihtiyacımı nasıl giderir” şeklinde olmaktadır. API yoksa oluşturulur, varsa doğrudan kullanılır.

Şimdi modül için gerekli kodu yazmadan testler aracılığı ile ihtiyaç duyduğumuz Storage API’sini nasıl oluşturabileceğimizi bir örnek üzerinde inceleyelim. Testler ile birlikte API ve akabinde modül için gerekli kod yavaş yavaş oluşmaya başlayacaktır. İhtiyaç duyduğumuz API’yi aşağıdaki şekilde test ederek başladığımızı farz edelim. Ortada henüz Storage isminde bir sınıf yok, dolayısıyla bu sınıfın getObjectById() isminde bir metodu da bulunmuyor. Ama biz ihtiyaç duyduğumuz API’yi hayal ederek, yani kullanıcı olarak yola çıkarak böyle bir sınıf ve böyle bir metot olsaydı, istediğimiz veriyi veri tabanından böyle edinebilirdik şeklinde hayal ettik ve bunu da test olarak ifade ettik.

[source language=’java’]
@Test
public void
storage_should_deliver_the_value_1(){
Storage storage = new Storage(“abc”);
Object obj = storage.getObjectById(1);
assertThat(obj.getValue(), equalTo(1));
}
[/source]

Oluşturduğumuz test bizi ister, istemez sade bir API oluşturmaya itmektedir. Bu tarz bir test yazmak bizi kesinlikle önce bir MetaHelper sınıfı, akabinde bir StorageLoader ve daha sonra veri tabanını kullanıma hazırlamak için kullanılan StorageHelper sınıfını oluşturmaya yönlendirmemektedir, çünkü kullanıcı olarak bunlar bizi ilgilendirmeyen, modülün kendi sorumluluğunda olan konulardır. Bizim kullanıcı olarak tek bir beklentimiz vardır, o da API üzerinden belli bir verinin veri tabanından en kolay şekilde nasıl edilenilebileceği konusudur.

Testi oluştururken taktığımız kullanıcı gözlüğü bizi her zaman kullanıcının gereksinimlerini doğrudan tatmin eden bir API’yi oluşturmaya yönlendirmektedir. Kullanıcı gözlüğü modül içinde olup, bitenler ile ilgilenmemektedir, çünkü detayları bilmesi verdiğim ilk örnekteki gibi kafa karıştırıcı tarzda olacaktır. Bu yüzden kullanıcı her zaman en sade API’yi tercih etme iç güdüsüne sahiptir.

Yazmış olduğum testin başarılı olması için Storage isminde bir sınıfın oluşturulması ve bu sınıfın getObjectById() isminde bir metodunun olması gerekmektedir. Bu noktadan itibaren detayları bilen yazılımcı gözlüğünü takarak modülü ve içeriğini düşündügüm şekilde geliştirebilirim. Böyle bir API oluştuktan sonra yazılımcı iç güdüsel olarak Storage modülünün tüm işleyiş tarzını kullanıcıdan saklamaya özen gösterecektir, çünkü kullanıcının getObjectById() metodu haricinde başka bir şeye ihtiyacı olmadığını bilmektedir. Bunu kendisine söyleyen yazdığı birim testidir. Birim testi modülün kullanılma şekillerinden birisini yazılımcıya göstermiştir. Storage modülü için yapılabilecek implementasyonlardan birisi şu şekilde olabilirdi.

[source language=’java’]

public class Storage{

private static Storage storage;

private Reader reader;

public static Storage create(String dir){
if(storage == null){
storage = new Storage(dir);
}
return storage;
}

private Storage(String dir){
initStorage(dir);
}

private void initStorage(String dir){
File metaFile = new File(dir);
reader = StorageHelper.createStorage(StorageLoader.load(MetaHelper.createMetaFile(metaFile))).getReader();
}

public Object getObjectById(int i){
return reader.getObjectById(i);
}

class Reader{
…
}

class StorageHelper{
…
}

class StorageLoader{
…
}

class MetaHelper{
…
}

[/source]

Storage modülünü bir singleton olarak implemente ettim. Görüldüğü gibi Storage.create() statik metodu ile singleton olan bir storage nesnesi edinmek mümkündür. Akabinde bu nesneyi kullanarak getObjectById() metodu aracılığı ile veri tabanından istediğim türde bir veriyi çekebilmekteyim. Bunun yanısıra modül bünyesinde kullanılan tüm sınıfları iç sınıf olarak tanımladım. Bu şekilde dış dünyadan hiç kimse bir Reader ya da StorageHelper nesnesi oluşturamaz ya da kullanamaz. Storage modülü bu şekilde iç dünyasında olup bitenleri tamamen dış dünyadan gizlemekte ve tanımladığı iki metot aracılığı ile kullanımını mümkün kılmaktadır. Bu iki metot Storage modülünün API’sidir. Storage modülünün kara bir kutu gibi işlev görmesi, kullanıcıları etkilemeden modül bünyesinde değişiklik yapılabilmesini mümkün kılmaktadır.

Yapmış olduğumuz API tanımlamasına “API kullanıcı ve sunucu arasında bir kullanım sözleşmesidir” ibaresini ekleyebiliriz. Nitekim bir modül sahip olduğu API’si aracılığıyla dış dünyaya nasıl kullanılabileceğinin mesajını verir. Kullanıcılar istedikleri API metotlarını seçerek modülü kullanmaya başlarlar. Bu kullanıcı ve modül arasında bir bağ oluşturur. Kullanıcı her zaman oluşan bu bağın sağlam olmasını arzular. Değişikliğe uğrayan API kullanıcılarını kırılgan hale getirir. Bunu engellemek için API’nin sıkça değişmemesi şarttır. Durum böyle olunca bir defa kullanıma sunulan bir API’nin değiştirilmesi artık kolay değildir, çünkü sayısı bilinmeyen birçok kullanıcısı vardır. Bunu göz önünde bulundurduğumuzda API tasarımcısı olarak her zaman tutucu (konservatif) bir pozisyonda durarak oluşturduğumuz sınıfları öncelikle iç sınıf ya da package private olarak tanımlamamız gerekir. Sadece bu durumda hemen keşfedilerek kullanılmalarını engelleyebiliriz. Kullanımını engelleyemediğimiz sınıflardan her zaman sorumluyuzdur. Bir API kullanıma açıldığında o API’de ne kadar sınıf ve metot mevcutsa, modülün ömrü boyunca bu sınıflara ve metotlara destek vermek zorunda kalırız, çünkü kullanıcılarını API’yi değiştirerek sinirlendirmemiz gerekir. Bu yüzden API’nin çapı ne kadar küçükse, sorumluluk ve verdiğimiz desteğin oranı o oranda küçük olacaktır.

API’lerin kullanıcılara hitap edecek ve onların gereksinimleri doğrudan ve kolay bir şekilde tatmin edecek şekilde tasarlanmaları şarttır. Windows ortamında C/C++ ile Windows API’sini kullanarak uygulama geliştirenler çok iyi bilirler. Bu API en zor API’lerden bir tanesidir. API sadece birkaç sınıf ya da metot birleşimi bir sey değildir. Aynı zamanda API’nin ihtiva ettiği sınıf ve metot isimlerinin ifade gücünün yüksek olması gerekir. Her sınıf ya da metot için seçilen isim bu API’nin arkasındaki gizli servisin nasıl kullanılabileceğini ifade edebilmelidir. Unutmayalım programlar bilgisayarlar için yazılıyor, lakin kodu okuyan insanlar. Bu yüzden ifade gücü yüksek olan isimlerin seçilmesi API’nin doğru kullanımı kolaylaştıracaktır.

Bol TeletAPI’li günler diliyorum.


EOF (End Of Fun)
Özcan Acar

Bir Java’cının Gözünden Ruby

Son zamanlarda en çok merak edip, öğrenmek istediğim diller arasında geliyor Ruby. Ruby herkesin dilinden düşürmediği, dinamik veri tipli ve her şeyin istisnasız nesne olduğu bir programlama dili. 1993 yılında Yukihiro Matsumoto tarafından geliştirilmiş. 2006 senesinde Ruby on Rails çatısının oluşturulmasıyla popüler bir web programcılığı dili olmuş.

Bu yazımda bir Java programcısının, yani benim Ruby dilini nasıl algıladığını, bu dilin kendisini nasıl hissettirdiğini sizlere aktarmak istiyorum.

Java’da her zaman şöyle bir şey yapmak istemişimdir:

[source language=’java’]
throw new Exception() if(abc….);
[/source]

Böyle bir yapı Java’da mümkün değil. Onun yerine her zaman şöyle bir şey yazmak zorundasınız:

[source language=’java’]
if(abc…)
{
throw new Exception();
}
[/source]

Tek bir satır ile ifade etmek istediğim bir düşünce için Java’da dört satır kod yazmam gerekiyor. Java’nın en büyük sorunlarından birisi bu. Bu zamanla Java’da yazılan programların okunamaz hale gelmesine sebep oluyor. İşin içine birde hata yönetimi (Exception Handling) girdi mi, kodu anlayana aşk olsun. Ruby’de dikkatimi çeken ve Java’da hasretini çektiğim if ve unless yapıları oldu. Ruby’de şöyle bir şey mümkün:

[source language=’ruby’]
puts ‘hello world’ if x==4
puts ‘hello world’ unless x==4
[/source]

[source language=’ruby’]
unless x == 4
puts ‘hello world’
end
[/source]

[source language=’ruby’]
order.calculate_tax unless order.nil?
[/source]

Belli bir düşünceyi Ruby’de olduğu gibi tek bir satır olarak ifade etmenin kodun okunabilirliği açısından çok büyük getirisi var. Bu satırı bir blok halinde yazmak elbette mümkün. Lakin bu ifade edilmek istenen düsüncenin kod arasında kaybolma rizikosunu artırıyor. Burada Ruby’nin takip ettigi filozofinin “ne kadar az kod, o kadar çok ifade edilmek istenen düsüncenin ön plana çıkması” olduğu belli oluyor.

Aynı sadelik Ruby’nin while ve until döngüleri için de geçerli:

[source language=’ruby’]
x = x+1 while x < 10 [/source] [source language='ruby'] x = x-1 until x == 10 [/source] Ruby'de her şey nesne: [source language='ruby'] >> 4.class
==> Fixnum
>> 4+4
==> 8
>> 4.methods
==> [“inspect”, “%”, “<<", "singleton_method_added", "numerator","*","+","to_i"......] >> true.class
==> TrueClass
>> false.class
==> FalseClass
[/source]

Java’da 4 rakamı int primitif tipine sahip iken, Ruby’de Fixnum tipinde bir nesne. 4.methods bu nesnenin sahip olduğu metotları sıralıyor. Ruby safkan bir nesneye yönelik programlama dili.

Ruby’de duck typing ismi verilen ilginç bir konsept uygulanmış. Bunun ne olduğunu açıklamadan önce bir Java örneği sunmak istiyorum.

[source language=’java’]
public void printFileName(File file)
{
if(file.exists())…
}
[/source]

printFileName() ismini taşıyan metodun file isminde bir parametresi bulunuyor. Metot gövdesinde bu parametrenin sahip olduğu sınıf tipine göre değişik metotlar koşturabilirim. Bunlardan bir tanesi exists() metodu. Bu metodu kullanabilmem için file ismindeki metot parametresinin File sınıfından türetilmiş olması gerekiyor, aksi taktirde exists() metodunu kullanamam. Java’da bir nesnenin sahip olduğu tip o nesnenin sınıfı tarafından belirleniyor. File tipinde olan bir değişken sadece File sınıfının metotlarını kullanabilir. Ruby’de durum farklı. Aradaki farkı görmek için bir Ruby örneğini inceleyelim:

[source language=’ruby’]
def copy_file(obj, dest_path)
src_path = obj.get_path
puts “Copying file \”#{src_path}\” to \”#{dest_path}\”.”
end
[/source]

copy_file() metodunun obj ve dest_path isminde iki tane parametresi bulunuyor. Bu iki parametrenin hangi tipte olduğu belli değil. Tipini, yani sınıfını tanımadığım bir nesnenin nasıl olurda obj.get_path() şeklinde bir metodunu koşturubilirim? obj nesnesinin ait olduğu sınıfta get_path() isminde bir metod olduğunu nereden biliyorum? Bilmiyorum, bilmek te zorunda değilim.

Ruby’de her şey nesne. Durum böyle olunca Ruby’nin kontrol etmesi gereken tek şey, kullanmak istediğim metodun nesnede var olup, olmadığı. Eğer kullandığım metodu Ruby nesnede bulamassa NoMethodError hatası oluşturur. Bunu da yakalayıp, gerekli işlemi yapmak zor değil. Buradan çıkardığımız sonuç şu: Ruby nesneleri üzerinde istediğim herhangi bir metodu koşturabilirim. Eğer nesnenin böyle bir metodu varsa, nesne istediğim şekilde davranış sergileyecektir. Aksi taktirde NoMethodError hatası oluşacaktır. Bu Ruby’de nesne tipinin sahip olunan sınıfa göre değil, nesnenin ihtiva ettiği metotlara göre belirlendiği anlamına geliyor.

Ruby’de Java ya da C# da olduğu gibi bir sınıf tanımlamak zorunda kalmadan şu şekilde bir metot tanımlanabiliyor:

[source language=’ruby’]
def bugunHavaSicakMi
true
end
[/source]

Ruby’de her fonksiyon bir değer geri veriyor. Eğer metodun son satırında return komutu kullanılmadı ise, o zaman son satırda yer alan değer geri veriliyor. Yukarıda yer alan örnekte geri verilen deger true olacaktır.

Bir array şu şekilde tanımlanabiliyor:

[source language=’ruby’]
>> hayvanlar = [‘Kedi’, ‘Fare’, ‘Yilan’]
==> [“Kedi”, “Fare”, “Yilan”]
>> puts hayvanlar
Kedi
Fare
Yilan
>> hayvanlar[0]
==> Kedi
>> hayvanlar[10]
==> nil
>> hayvanlar[-1]
==> “Yilan”
>> hayvanlar[0..1]
==> [“Kedi”, “Fare”]
[/source]

Var olmayan bir array elementine erişmek istediğimizde Ruby nil değerini geri veriyor. Java’da bu IndexOutOfBoundException hatası olurdu. Index olarak eksi değerler kullanıldığında Ruby arrayi sondan başa doğru görmeye başlıyor. Örneğin hayvanlar[-1] “Yilan”, hayvanlar[-2] “Fare” değerini geri verir.

Ruby ile ismi olmayan anonim fonksiyonlar tanımlanabiliyor. Bu anonim fonksiyon başka metotlara parametre olarak ta vermek mümkün. Aşağıdaki örnekte hello world ekranda üç sefer görüntülenir. Küme parantezi içinde yer alan kod aninim fonksiyondur.

[source language=’ruby’]
3.times {puts ‘hello world’}
[/source]

Anonim fonksiyonları parametrelendirmek mümkündür. Aşağıdaki örnekte each bir for döngüsü oluşturup, hayvanlar isimli listenin her elementini döngü içinde anonim fonksiyona parametre olarak vermektedir. Tek satırlık kod ile tüm listenin içeriğini ekranda görüntülemek münkündür.

[source language=’ruby’]
hayvanlar = [‘Kedi’, ‘Fare’, ‘Yilan’]
hayvanlar.each { |a| puts a}
[/source]

Java’da anonim fonksiyon tanımlamak için bir anonim class implementasyonu oluşturmak gerekiyor. Bir listedeki değerleri anonim bir fonksiyon tarafından ekranda görüntülemek için aşağıdaki şekilde Java kodu yazardık:

[source language=’java’]
package xxx;

import java.util.ArrayList;
import java.util.List;

public class Test {

final static List animals = new ArrayList() {
{
add(“dog”);
add(“cat”);
}
};

private static abstract class AnimalLister {
abstract void show(String animal);
}

public static void main(String[] args) {

each(new AnimalLister() {
@Override
void show(String animal) {
System.out.println(animal);
}
});
}

private static void each(AnimalLister animalLister) {

for (String animal : animals) {
animalLister.show(animal);
}
}
}
[/source]

Java’da bir sınıfa yeni bir metot eklemek için ya o sınıfı yeniden derlemek, ya AOP kullanmak ya da sınıfı bytecode seviyesinde manipüle etmek gerekiyor. Ruby’de mevcut bir sınıfa yeni bir metot eklemek çocuk oyuncağı:

[source language=’ruby’]
class Fixnum
def my_times
i=self
while i > 0
i = i-1
yield
end
end
end

3.my_times {puts ‘hello world’}
[/source]

Yukarıda yer alan Ruby örneğinde Fixnum isimli sınıfa my_times isminde yeni bir metot ekledik. Oluşturduğumuz bu yeni metodu 3.my_times şeklinde kullanabiliriz. JDK içindeki bir sınıfa doğrudan yeni bir metot eklemek istediginizi düşünün. Ruby’de mevcut her sınıfa yeni bir metot eklemek mümkün.

Java gibi nesneye yönelik programlama yapılan dillerde ortak kullanılan metot ve değişkenler kalıtım yolu ile altsınıflara verilir. Ruby’de bu mekanizma modüller aracılığı ile işlemektedir. Bir modül içinde fonksiyonlar ve değişkenler yer alır. Herhangi bir Ruby sınıfı tanımlı bir modülü kendi bünyesine kattığında, modül içinde yer alan tüm metot ve değişkenler sınıf tarafından kullanılabilir.

Aşağıda yer alan Ruby örneğinde ToFile isminde bir modül yer alıyor. to_f metodu to_s metodundan gelen değeri bir dosyaya ekliyor. to_s metodu modül bünyesinde tanımlı değil. Bu metodun modülü bünyesine katan sınıf tarafından implemente edilmiş olması gerekiyor. Ruby daha önce bahsettiğim duck typing yönetimi ile nesnenin to_s metoduna sahip olup, olmadığını kontrol ediyor.

Person sınıfı include ToFile ile modülü bünyesine katıyor ve to_f metodunu kendi bünyesinde tanımlıymış gibi kullanabilir hale geliyor.

[source language=’ruby’]
module ToFile
def filename
“object_#(self.object_id).txt”
end

def to_f
File.open(filename, ‘w’) {|f| f.write(to_s)}
end
end

class Person
include ToFile
attr_accessor :name

def initialize(name)
@name = name
end

def to_s
name
end
end

Person.new(‘özcan acar’).to_f
[/source]

Bu örneği Java’da aşağıdaki şekilde yazabilirdik. Java’da sadece tanımlı olan metotlar kullanılabilir. Ruby ToFile modülü örneğinde yer alan to_s metodunu kullanabilmek için bu metodun bir sınıf bünyesinde tanımlı olması gerekir. Aşağıda yer alan örnekte To_S isminde bir interface sınıf tanımlayarak, to_s metodunu bu sınıfa ekliyoruz. Soyut olan ToFile sınıfı bu interface sınıfı implemente ettiği için to_s metodunu tanır hale geliyor. Person sınıfı ToFile sınıfını genişlettiği için to_s metodunu implemente etmek zorunda. Person sınıfı ToFile sınıfını genişlettiği için to_f metoduna sahip oluyor. Person nesnesi tarafından to_f metodu koşturulduğunda, to_f metodu person nesnesi bünyesinde yer alan to_s implementasyona erişip, gerekli değeri edinebiliyor.

Ruby ile Java arasındaki en büyük fark, Java’nın kullanılan metotların hangi sınıflara ait olduklarından haberdar olması zorunluluğu. Ruby duck typing mekanizması ile bu zorunluluğu ortadan kaldırıyor.

[source language=’java’]
public interface To_S {

String to_s();
}
public abstract class ToFile implements To_S {

public String filename() {
return this.getClass().getSimpleName();
}

public void to_f() {
FileUtils.writeStringToFile(new File(“xxx”), to_s());
}
}
public class Person extends ToFile{

private String name;

public Person(String name) {
this.name = name;
}

@Override
public String to_s() {
return this.name;
}

public static void main(String[] args) {
new Person(“özcan acar”).to_f();
}
}
[/source]

Bu kısa tanıtım umarım Ruby diline ilginizi çekebilmiştir. Ruby dilinin ifade edilmek istenen düşüncenin çok az satır ile, düşüncenin kod kargaşası arasında kaybolmadan implemente edilmesini mümkün kılması beni etkileyen en önemli özelliği oldu. Benim için ön planda olan kodun nasıl yazıldığı değil, düşüncenin kod olarak nasıl ifade edildiğidir. Programcılıkta zamanla ilgi alanı problem çözme, algoritma kullanımı vs. gibi konulardan, düşüncelerin sade ve çok kısa kod parçası olarak kodlanabilmesi yönüne kaymaktadır. Bu en azından benim için geçerli olan bir durumdur. Bu sebepten dolayı Ruby gibi düşüncelerin sade ve yüksek bir soyutluk seviyesinde ifade edilmesine izin veren dilleri tercih ederim.


EOF (End Of Fun)
Özcan Acar

Alet İşler, El Övünür

Birçok meslekte araç ve gereç sahibi olmadan iş yapmak mümkün değildir. Günlük hayatımızda da birçok araç ve gereci kullanırız. Örneğin bir resmi duvara asabilmek için bir çivi ve bir çekic kullanırız. Çoğu zaman işimizi gördükten sonra başarımız ile övünür, bir sonraki ihtiyacımıza kadar kullandığımız araçları hatırlamayız.

Araçlar zamandan tasarruf etmek ve işimizi kolaylaştırmak için vardır. Bazı araçlar olmasaydı, isteğimiz işi yapmamız bile mümkün olmazdı. Çekiç sahibi olmadan duvara çivi çakmak mümkün değildir. Bunun için bir taş parçası bile kullansak, kullandığımız bu taş parçası bir araç haline dönüşür.

Yazılımcı olarak ta günlük hayatımızda birçok araç kullanırız. Bunların başında kod yazmak için kullandığımız IDE (Integrated Development Environment) araçları gelir. Ben günlük işlerimde genellikle Eclipse IDE’yi tercih ediyorum.

Araçlar işimizi kolaylaştırmak ve zamandan tasarruf etmek için var demiştim. Ne yazık ki bazı yazılımcılar bunun bilincinde değiller. Gerekli araç ve gereçleri kullanmalarına rağmen, zamandan tasarruf ettikleri söylenemez, çünkü kullandıkları araçların hakkını veremiyorlar.

Kod yazmak için kullanılan bir aracın en verimli kullanım şekli, bazı aksiyonlar (örneğin yeni bir sınıf oluşturma, yeni bir metot oluşturma) için kısa yol tuşlarını tanımak ve uygulamaktır. Örneğin bir interface sınıfını implemente etmek istediğimizde, implementasyon sınıfında tek tek metot gövdelerini oluşturmak yerine Eclipse altında STRG+1 tuşlarına baştıktan sonra Add unimplemented methods seçimini yapmak yeterlidir. IDE otomatik olarak interface sınıfı bünyesinde yer alan her metot için implementasyon sınıfında gerekli metot gövdesini oluşturacaktır. Bu işlemi elden yapmak çok büyük bir zaman kaybıdır. Bu aracı kullanıp, hakkını verememektir.

Bir yazılımcının en önemli araçlarından birisi kullandığı IDE olduğuna göre, IDE’nin sundugu imkanlar doğrultusunda yaptığı işlemlerin sürelerini kısaltmanın yollarını aramalıdır. Bunun yolu kısa yol tuşu hakimiyetinden geçmektedir. Bunun yanısıra fare kullanımından sakınmalıdır. Fareye uzanan el bir thread context switch gibidir. İş akışını bir an için bile olsa böler. Programcının en önemli aracı klavyesidir. Klavyeye ek olarak fareyi kullanması, klavyenin hakkını veremediği anlamına gelir. Aynı işi tek bir araç ile yapabilecekken, iki değişik araç kullanarak zaman kaybeder.

Bir başka zaman kaybı türü de yazılımcının on parmak kod yazamamasıdır. Yazılımcının kod kaynağına bakacağı yerde, x tuşu nerede diye klavyeye bakması context switch’dir. Devamlı bu şekilde çalışmak yazılımcıyı hem yorar, hem verimini düşürür hem de zaman kaybetmesine neden olur. Bu sebepten dolayı her yazılımcının on parmak kod yazabilme yetisini geliştirmek için çalışma yapması zaruridir.

Yazılım otomasyon demektir. Otomasyonun olmadığı yerde zaman kaybı var demektir. Ant ya da Maven ile otomatik sürüm oluşturmak yerine, bu işi her defasında elden yapmaya çalışmak çok büyük zaman kaybıdır. Yazılımcının bu noktada zamanının belli bir kısmını sürüm oluşturma araçlarının kullanımını öğrenmek için harcaması, bu yatırımın sürümlerin daha hızlı ve otomatik oluşturularak amortize olmasını sağlayacaktır.

Kullandığı araçlara hakim olmayan bir ustaya kim usta gözüyle bakar? Elimizin övünmesini istiyorsak, kullandığımız araçlara hakim olduğumuzu gösterelim.

Eklenti (17:51 . 22.02.2013):

Bir yazılımcı için kullandığı en önemli araç bilgisayarıdır. Klasik bir iş bilgisayarları okuma kafası dakikada 5000 ila 7000 arasında dönen sabit disklere sahiptir. Taş devrinden kalma bu teknoloji yüzünden yazılımcılar hergün dakikalar ya da saatlerle ölçülebilen zaman kaybına uğruyorlar. Windows gibi bir işletim sistemi ve yetersiz hazıfa (ram) kapasitesi buna eklendiğinde yazılımcıların mesaileri kabusa dönüşebiliyor. Bunun önüne geçmek için yazılımcını 64 bit genişliğinde, SSD sabit diskine ve en az 8 GB hazıfa alanına sahip bir bilgisayar kullanmalıdır. Bunun altindaki her konfigürasyon işletim sisteminin akışkanlığını bozarak, yazılımcının belli aktiviteler için bekleme süresini artıracaktır ve verimliliğini düşürecektir.


EOF (End Of Fun)
Özcan Acar

Cahilliğime Verin

BTSoru.com‘da bir soru sorulmuş. Tüm soruları kontrol ederek ihtiyaç durumunda başlığı, içeriği ve etiketleri düzenlemeye çalışıyorum. Bu soruyu incelerken verilen kod örneğini Struts kodu zannettim ve sorunun etiketini Struts olarak değiştirdim.

Kısa bir zaman sonra soruya bir yorum yapan bir arkadaşımızdan bir uyari e-postası aldım. Arkadaş iletisinde etiketin asp.net-mvc olmasının daha anlamlı olacağını bildiriyordu. İlgisi için kendisine teşekkür ettim ve etiketi asp.net olarak değiştirdim. Bilmediğim bir şey vardı: asp.net ve asp.net-mvc iki değişik şeydi.

Kısa bir zaman sonra aynı arkadaşımızdan tekrar bir uyarı iletisi aldım. Çok kibar bir şekilde asp.net ile asp.net-mvc’nin iki ayrı teknoloji olduğunu belirtiyordu. Özür dileyerek sorunun etiketini asp.net-mvc olarak değiştirdim.

Buradan çıkarabileceğimiz bazı dersler var. Bunlar:

  • Yanlış olanı düzeltmek için çaba sarfetmek her programcının asli görevlerinden birisidir.
  • Sesini yükseltip, yanlışlara işaret edebilmek cesaret ister. Bunu yapabilen yaptığı işin hakkını veriyordur.
  • Birilerinin bir şeyler hakkında daha fazla bilgiye sahip olma ihtimali yüksektir. Her şeyi bilirim edasıyla hayatın içinden geçip gitmek abesle iştigaldir.
  • Daha iyi bilenin yakasına yapışmak ve ondan öğrenmek farzdır. En kolay öğrenme yöntemi budur.
  • Bu konu hakkında bilgim yok, ama öğrenebilirim demek bir erdemdir. Bilgisi olmadığı halde bilgisi varmış gibi davranmak ahmaklıktır.
  • Tatlı dil yılanı deliğinden çıkarır. Bahsettiğim arkadaş kendi bilgisel üstünlüğünü ortaya koymak için kühtahça bir ileti de gönderebilirdi. Bunun yerine çok nazik ve kibar bir üslup ile yanlışa işaret etmeyi tercih etti. İki şekilde de kazanan o oldu: hem isteğinin yapılmasını sağladı, hem de efendi bir üsluba sahip oldugunu ispatladı.

Hz. Ali’nin güzel bir sözü var: Bana bir harf öğretenin kırk yıl kölesi olurum… Ditto!


EOF (End Of Fun)
Özcan Acar