Saturday, November 17, 2012

Programcılık tavsiyelerim

Uzun bir süredir yazmak istediğim şeylerden birisi, şu ana kadar programcılıkla ilgili edindiğim tecrübelerim. Çook çok tecrübeli ve bilgili bir programcı değilim. Ama bu, temel meslekî tavsiyeler veremeyeceğim anlamına gelmiyor. Burada okuyacaklarınız da genellikle "Tekerleği yeniden icat etmeyin", "Kodunuzu okunaklı kılın" seviyesindeki basit, bilindik tavsiyelerin tekrarı olacak.

Yanlış bildiğim kavramlar, hatalı olduğumu düşündüğünüz konular olabilir. Bu yazıyı asıl zenginleştirecek olan, sizlerden gelen yorumlar. Mesela esnekliği sağlamak için tam olarak neler yapılması gerektiğini halen bilmiyorum, o benim listelediklerim dışında.

Yedeklerinizin isimlendirilmesi

Çalışmanızın yedeklerinin ismini MUTLAKA tarihe göre isimlendirin (veya versiyona, ama ben tarihi tercih ederim). Bir gün içerisinde birden fazla yedeği alınacaksa o tarihe saat bilgisini de ekleyin. Bilgisayarda görülen son değiştirilme tarihine sakın bu konuda güvenmeyin; çeşitli nedenlerden dolayı o gördüğünüz tarih, sizin gerçekten yedeği aldığınız tarihten sonrasını gösterebilir.

Yedeklerin isimlerinin tek bir formata göre ve Yıl-Ay-Gün formatına göre düzenlenmesi, yedeklerin listesini okumanızı kolaylaştırır. İsimlerin alfabetik sırası, kronolojik sırayı verir. (Tabi ki, ayların rakamla gösterilmesi ve 10'dan küçük sayıların yazımının 0'la başlaması düzgün bir alfanümerik karşılaştırma için önemli.)

Benim tarih formatını versiyon numarası formatına tercih etmemin nedeni, özellikle takım çalışmasındaysanız, "Biz geçen cuma neyi yapmıştık?" sorusunun "Biz v0.1256'te ne yapmıştık?" sorusuna göre daha kolay olması.

İngilizce

Tutorial okuyabilecek kadar İngilizce bilmek çok önemli. C++, Java gibi en temel konular için Türkçe kaynak bulabilirsiniz, ama daha spesifik konular için pek şansınız yok. Yabancı dil bilgisi sadece kitap ve tutoriallar için gerekli değil; ama karşılaştığınız bir sorunu Google'da arattığınızda bulacağınız çözümler büyük ihtimalle İngilizce çıkacak. Eh, üyesi olduğunuz yabancı forum, maillistlerde soru sorabilmek için de yine, ... 


İngilizce demişken, değişken ve fonksiyon isimlerini İngilizce yapmak bence Türkçe'den daha hoş bir görüntü sunuyor. maasArtisi, indirmeSikligi, carpim, vs.... Bunun nedeni malum, değişken ismi içinde Türkçe karakter verilememesi.

Dev-C++'tan uzak durun

İlla kullanmak zorunda değilseniz, Dev-C++'tan uzak durun. Belki zamanına göre kral bir ücretsiz IDE'ydi, bilmiyorum, ama günümüze göre demode. Windows 7, Vista gibi yeni (?!) işletim sistemlerinde Dev-C++'ı başlatmakta sorun yaşayabilirsiniz, bu karşılaşacağınız sorunların henüz başı.

Windows için ücretsiz bir IDE arıyorsanız, Code::Blocks'ı önerebilirim. Parantezlerin nerede açılıp kapandığını görmek bile yeterli benim Code::Blocks'ı tercih etmem için. Visual Studio kullanmaya başlamadan önce onu kullanıyordum. Burada not düşeyim; Visual Studio kullanmaya başlamamın nedeni, iş hayatına girdikten sonra VS gerektirecek projelere dahil olmam. Ve sonrasında da VS'ya alışmış olmam.

VS Express Edition, CodeBlocks veya başka ücretsiz IDE'leri birbirleriyle mukayese edecek kadar tecrübe ve bilgi sahibi değilim. Ama Dev-C++ hariç.

İki milisaniyede kapanan C programları

Programcılığa yeni başlamış, okuduğu kitaplardaki C++ kodlarını çalıştırmaya çalışan insanların karşılaştığı genel bir sorun var: Yazdığınız programın, birkaç milisaniyeliğine görünüp ortadan kaybolması. Bazen kitap, herhangi bir tuşa basılana kadar programın bekletilmesi için ne yapılması gerektiğini anlatmaz.

Yapılabilecek şeylerden birisini burada söyleyeyim (Windows için): "conio.h" isimli bir header'ı include etmek, programı nerede bekletmek istiyorsanız o satıra getch(); komutunu yazmak. Bunun örneğini şuradan okuyabilirsiniz.

Pekii, getch() gibi bir "Klavyeden tuş al" komutunu kullanmayan örnekler hatalı mı? Eğer o programa Command Prompt (Komut İstemi) içerisinde erişirseniz, programın düzgün çalıştığını (yani "Hello world" yazdırıp hemen kapanmadığını) göreceksiniz. Bana sorarsanız, tek işlevi ekrana yazı yazdırmak olan bir Windows programının ne yazdırdığını görmek için illa onu Command Prompt'ta filan açmak zorunda kalmamalıydık.

Tekerleği icat etmek

Eğer çok temel, sık kullanılan bir fonksiyona ihtiyacınız varsa, ilk önce sizin kullandığınız kütüphanede (veya oyun motorunda) o fonksiyonun olup olmadığını bir araştırın. Özellikle de kendisini ispat etmiş, oturmuş bir kütüphane/oyun motoru kullanıyorsanız. Mesela bir vektörün, belirli bir uzunluğu geçmemesi için kırpılması fonksiyonunu oturup kendiniz yazabilirsiniz. Ama oyun motorunun kendi VClamp fonksiyonu kadar optimize ve güvenilir çalışmayabilir. Bu araştırmayı yapmak zaman alır, doğru, ama size daha fazlasını geri kazandırır. İki gününüzün sırf o kendi yazdığınız fonksiyonun verdiği hatalı bir sonuç yüzünden heba olduğunu düşünsenize...

Bu araştırmayı yapmanın bir faydası da, mesela mutlak değer fonksiyonunu ararken arada diğer fonksiyonları da görüp "Vaaay, demek bunu da yapabiliyormuşuz? Bunu aklımda tutayım" diyebilmek.

Bu araştırmayı sadece şu an kullandığınız sistemin çapı içerisinde gerçekleştirmeyin. Mesela belirli bir tip collision detection'a ihtiyacınız varsa, bu konu hakkında daha önceden yapılmış çalışmaları incelemelisiniz. Tamam, belki bu tip fonksiyonları en baştan geliştirmekten keyif alıyor olabilirsiniz, ben de alırım. Araştırma işi pek keyifli değil, benim için en azından. Ama verimli bir çalışma için bazen bu şart. Bir örnek daha vereyim.

Ben üniversitedeyken, konsola Türkçe karakterleri bastırabilmek için kendi fonksiyonumu yazmıştım (printf("ĞÜŞİÖÇ"); problemi işte). Sizin girdiğiniz  bir metindeki Türkçe karakterlerin sayısal değerini, konsolda görülebilecek karşılıklarına çeviriyordu. Ama kullanışı zor bir sistemdi. Geçenlerde Zombie Chess'i yaparken yine o fonksiyona ihtiyaç duydum, ama harddiskimde bulamadım. Sonra "Acaba başkası yapmış mıdır?" diye internette araştırma yapmaya karar verdim, bu problemin aslında çok basit bir şekilde halledildiğini o zaman gördüm.

C/C++ ile MS-DOS konsolunda Türkçe karakter çıkarmak

Önceki paragrafta bahsettiğim problemin çözümünü burada  buldum (real_digital'e buradan ++rep). Belki o sayfa şu an siz bunu okurken servis dışıdır, bu yüzden oradan buraya copy+paste edeyim.
1. <locale .h> isimli dosyayı include edin
2. main'in içine setlocale(LC_ALL, "Turkish");  satırını ekleyin.


#include <stdio.h>
#include <locale .h> /* Bu başlık dosyası bizi kurtaracak... */

int main()
{

   setlocale(LC_ALL, "Turkish"); /* Türkçe karakter desteği sağlanıyor */

   printf("Bu yazı düzgün yazıldıysa\n");
   printf("programınız doğru çalışıyor demektir.\n");

   return 0;
}

Convention

"Kodunuzun bakımını yapacak kişi, sizin nerede yaşadığınızı bilen tehlikeli bir psikopatmış gibi kod yazın."

Okunabilirlik, sizin kod yazma alışkanlığınız olsun. Ekibinizdeki tek programcı siz olsanız bile, kodunuzun ileride kimler tarafından görüleceğini bilemezseniz. Bu tavsiye, sadece grup projeleri için geçerli değil. Sadece kendinizin göreceği bir kod yazıyor olsanız bile, o koda 4 ay sonra geri döndüğünüzde "ahmet", "s", "dgshgs" gibi değişkenlerin neyi ifade ettiğini hatırlamıyor olacaksanız.

Birbirlerine karşılık gelen kıvırcık parantezlerin aynı hizada olması, değişken ve fonksiyonların sistematik bir şekilde isimlendirilmesi (mesela tüm değişkenlerin buSekildeIfadeEdilmesi) kodun okunabilirliğini yükseltecektir. Bu sadece göz zevki için değil, ama kodu okuduğunuzda tek odaklanacağız şeyin sadece önünüzdeki algoritma olması için önemli.



Bir de private/protected değişkenlerin alt çizgi ("_") ile başlaması alışkanlığı var. Eğer değişkenlerin public veya private olup olmadığının gösterilmesi önemliyse, eh, alt çizgi kullanılması gerekir. Ama zaten bütün değişkenlerin private olduğu (veya daha komiği, public/private diye bir ayrımın zaten mümkün olmadığı) bir sistemde bütüün isimlerin _alt _çizgi _ile _başlaması, _okunduğunda _insanı _çok _mutlu _eden _bir _görüntü _sunmuyor. _Bunu _ciddi _ciddi _ yapmış _olan _insanlar _var, _bu _yüzden _bu _konuya _değinme _ihtiyacı _duydum.

Sadelik ve esneklik

En önemli prensibin sadelik olduğuna inanıyorum.

Benim programcılık metodolojileriyle ilgili okuduklarımda karşıma en sık çıkan tavsiyelerden birisi KISS prensibi. "Keep it simple, stupid", "Keep it simple, sir", "Keep it short & simple" gibi çeşitli açılımları var. Bir sistem ne kadar karmaşık olursa, çıkan hataları düzeltmek, sistemde değişiklik yapmak da o kadar zorlaşır. Şuna inanıyorum: Sade bir tasarım; esneklik, optimizasyon gibi diğer önemli kriterleri de beraberinde getirir.

Yaptığınız şeyin esnekliği de önemli bir kriter. Tamam, eğer hazırlaması 3-4 saatinizi alacak bir ödeviniz varsa, yazdığınız kodun ileride başka bir amaca hizmet edeceği ihtimali çok yüksek değil. Ben bu tip ödevleri bodoslama bir şekilde başarıyla yerine getiriyordum. Ama aylarca sürecek bir iş yapıyorsanız, başlangıçta size verilen "Bu ürün şunu şunu yapmalı" listesi zamanla değişecektir. Hatta belki ilk başta sizden bir Windows formu yaratmanız istenip, sonra onu sürekli arkaplanda çalışacak bir uygulamaya dönüştürmeniz bile istenebilir. Şu an üzerinde çalıştığınız şeyin ileride nasıl bir değişim geçirmek zorunda kalacağını önceden sezmek zor. Ama bunun önlemi alınabilir.

Esneklik nasıl sağlanır, size kesin bir tavsiye verecek kadar bilgili değilim. Benim yaptığım şey; programın yapacağı bütün işleri ayrı ayrı alt fonksiyonlara bölmek (mümkün olduğunca birbirlerinden bağımsız), verileri hard-code etmekten kaçınmak (mesela bir sürü kameranın bağlı olduğu simülasyon sistemindeki kameraları dolaşan bir döngü 8'e kadar değil, MAX_CAMERA_AMOUNT'a kadar ilerlemeli) (bazı verilerin de kullanıcı tarafından configure edilebilir olması da önemlidir).