22 Nisan 2012 Pazar

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 :) Devamı için : Güzel Kod Yazma Sanatı

21 Nisan 2012 Cumartesi

Manager of pid-file quit without updating[FAILED] hatasi

Eğer Starting MySQL....Manager of pid-file quit without updating[FAILED] hatası alıyorsanız, muhtemelen bir sebepten ötürü mysqlinizi durdurmuşsunuz, ama sonra bir daha başlatamamışsınız demektir. Benim de hata şöyle başıma geldi. Bazı sitelerimiz yaklaşık 2 dakikadır açılmıyordu. Server a Ssh'tan giriş yapabildim, ve kontrol edebildim. Makina'da load yoktu. (2-3 civarındaydı.) ben de serviceleri yeniden başlatarak bir rahatlama sağlayabileceğimi düşündüm. Servisleri durdurdum fakat, mysqli başlatamadım. Başlıkta belirttiğim hatayı verdi. Daha sonra diskte yer kalmadığını gördük. Pid dosyasını da güncelleyemiyordu haliyle.

Çözüm

Diskte bir miktar yer açtıktan sonra mysql sıkıntısız bir şekilde başladı. Ah bu loglar yok mu... Devamı için : Manager of pid-file quit without updating[FAILED] hatasi

17 Nisan 2012 Salı

Bu html taglarını biliyor muydunuz

Web öyle bir şey ki, en çok bildiğinizi iddia ettiğiniz şey hakkında bile bazen ne kadar az bildiğinizi görebiliyorsunuz. HTML de öyle bir şey. (hele hele de sektörümüzde internet explorer gibi bir "şey" varken.. ) Ben şu aşağıda bahsedeceğim tagleri ilk defa gördüm, bakalım siz biliyor musunuz? <em>Emphasized text</em> <dfn>Definition term</dfn> <code>A piece of computer code</code> <samp>Sample output from a computer program</samp> <kbd>Keyboard input</kbd> <var>Variable</var> <cite>Citation</cite> Devamı için : Bu html taglarını biliyor muydunuz

13 Nisan 2012 Cuma

dubluve.net guncel tarayici (browser) kullanim oranlari

Dubluve.net in 5 aylık istatistiklerine dayanarak insanların hangi browser'i kullandığını merak etmiştim, yanıtı da paylaşmak istedim.

Birinci Tarayıcı Google Chrome!

Google analytics'ten edindiğim verilere göre, dubluve.net'i ziyaret eden kullanıcıların en çoğu(yarısı) google chrome kullanmakta. Aşağıdaki tabloda en çok kullanılan 4 browser ve bunların yüzdelerini vermek istiyorum.  
Browser % Ziyaret
1. Chrome
49.42%
2. Firefox
30.71%
3. Internet Explorer
16.69%
4. Opera
1.27%
Dubluve.net in yazılım ve araştırma ağırlıklı içeriğinin hitap ettiği kesime benzer kesim için bilgiye ihtiyacınız olursa faydalanılabilir diye düşündüm. Devamı için : dubluve.net guncel tarayici (browser) kullanim oranlari

12 Nisan 2012 Perşembe

C dilinde yapılar ve kullanımları (structures in C)

Struct nedir?

Struct(yapılar), birbirleriyle ilişkili olan değişkenlerin bir arada tutulması, tek bir isim altında toplanmasıdır. Kabaca bir örnek vermek gerekirse; bir öğrenci struct'ımız olsun (ismine ogrenci diyelim). Bir öğrenciye ait hangi bilgileri tutabiliriz? Öğrenci ismi, okul numarası, cinsiyet, okul ismi, vs. Peki bu structı nasıl oluştururuz?
struct ogrenci{  	char *isim[30];  	char cinsiyet;  	int okulNumarasi;  	char *okul[30];  };
Struct tanımladıktan sonra noktalı virgülü unutmak hataya yol açar. Görüldüğü gibi, bir yapının içerisinde birden fazla türde değişken tanımlayabildik. Bu yapı içerisinde isim ve okul için karakter dizisi elemanı, okul numarası için int tipinde bir eleman, cinsiyet için de E ve ya K içerebilecek bir char tanımladık. Yaptığımız işlem sadece yeni bir değişken türü tanımlamak oldu, hafızada bu işlem için bir yer ayrılmadı! Yani int ya da char nasıl bir değişken türüyse, şu an ogrenci'de bizim için yeni bir değişken türü oldu. Dolayısıyla biz oluşturduğumuz yapı türünden istediğimiz sayıda değişken bildirebiliriz. Ama nasıl? 3 adet öğrenci olsun elimizde, bunlara gokhan, emre, ahmet diyelim. Biz bunların ne olmasını istiyoruz? struct ogrenci tipinde birer değişken olmalarını istiyoruz. Öyleyse bu değişkenleri bildirmeliyiz;
struct ogrenci gokhan, emre, ahmet;
Şimdi sıra geldi bunları kullanmaya. Tanımladığımız her değişken, yani gokhan, emre ve ahmet ayrı ayrı, birbirinden bağımsız olarak, her biri, struct ogrenci içinde tanımladığımız değişkenlere sahiptir. Biraz daha açık yazmak gerekirse, gokhan için kullanacağımız char okul[30] ile ahmet için kullanacağımız char okul[30] birbirinden bağımsızdır. Bunların içlerinde aynı şeyler olabilir, ama birbirleriyle bir alakaları yoktur. Öyleyse, struct ogrenci tipinde tanımladığımız değişkenlerimiz için değer atamaya başlayalım. Burada kullanacağımız 2 adet operatör var. Biri yapı elemanı operatörü olan nokta (.), diğeri de yapı gösterici operatörü olan ok (->)[arasında boşluk olmadan eksi işareti ve büyüktür işareti]. Mesela, gokhan değişkenine okul numarası atayalım her iki yolla da. Yapı elemanı operatörü'nü yani noktayı kullanırken işimiz çok kolay.
gokhan.okulNumarasi = 5210010;
Aslında yapı gösterici operatörü kullanmak da bir o kadar kolay. gokhan için bir adet gösterici bildirelim, gPtr olsun adı. Burda önemli olan, bu göstericimizin türünün de struct ogrenci olacağı.
struct ogrenci *gPtr;  gPtr = &gokhan;
Görüldüğü gibi gokhan'ın adresini gPtr'ye atadık. Şimdi de ok (->) nasıl kullanılır ona bakalım.
gPtr->okulNumarasi = 5210010;
Mesela emre'ye isim atayalım;
struct ogrenci emre;  struct ogrenci *ePtr;  ePtr = &emre;    ePtr->isim[30] = "Emre";  
Bunların printf içerisindeki kullanımları da aynı şekildedir.
printf("%s", ePtr->isim[30]);
diyebiliriz mesela.

typedef nedir?

typedef anahtar kelimesini kullandığımızda, yapımız için yeni değişken tanımlarken struct kullanmak zorunda kalmayız.
struct ogrenci{  	char *isim[30];  	char cinsiyet;  	int okulNumarasi;  	char *okul[30];  };    struct ogrenci gokhan;  
Bunu typedef kullarak şu şekilde yaparız;
typedef struct{  	char *isim[30];  	char cinsiyet;  	int okulNumarasi;  	char *okul[30];  }Ogrenci;    Ogrenci gokhan;  
Dikkat, ogrenci ve Ogrenci birbirinden farklıdır! Görüldüğü gibi değişken tanımlarken tekrar struct yazmıyoruz, typedef sayesinde bir bakıma takma isim kullanmış oluyoruz. Ayrıca gokhan, emre, ahmet gibi struct ogrenci tipinden değişken tanımlamasını şu şekil de yapabiliriz;
  struct ogrenci{  	char *isim[30];  	char cinsiyet;  	int okulNumarasi;  	char *okul[30];  };      typedef struct ogrenci Ogrenci;  Ogrenci gokhan, emre, ahmet;  
Yapılarla kullanılan geçerli işlemler, yapı değişkenlerini aynı tipte yapı değişkenlerine atamak, bir yapı değişkeninin adresini almak, yapı değişkenlerine erişmek, ve yapı değişkeninin boyutunu belirtmek için sizeof kullanmaktır. sizeof kullanımına örnek verecek olursak;
printf("%ld", (long) sizeof(struct ogrenci));
Bunun çıktısı bize, struct ogrenci tipinden bir değişkenin hafızada kaç byte tutacağını gösterir. Devamı için : C dilinde yapılar ve kullanımları (structures in C)

10 Nisan 2012 Salı

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.
Devamı için : Java Generics - Tipler Üzerinde Soyutlaşma

HTTP Code Response sitesi httpstat.us

Kendi yazmış olduğumuz kodlar, dış sitelerle bağplantıya geçiyorsa, hata kontrollerini yapmak kritik önem taşımaktadır. Bu site, farklı farklı HTTP kod yanıtları üreten süper basit bir site. Test ortamınızda dönen HTTP response kodlarına göre nasıl davranacağınızı ayarlayabilmeniz için size ortam sağlamış oluyor. Örneğin 200 OK yanıtı veren bir istek yapmak istiyorsam, httpstat.us/200 yazmam yeterli. Yanıtlar da şu kalıpta dönüyor ; HTTP/1.1 {status code} {status description} Content-Type: text/plain Content-Length: {something} {any custom response headers} {status code} {status description} {list of any custom response headers we added} sadece 100 ve 101 isteklerini veremeyeceğini belirten bu sistem, umarım ilgili konularda işinize yarayacaktır. Devamı için : HTTP Code Response sitesi httpstat.us