Jul 252015
 

Oldukça uzun bir süredir neredeyse antik sayılabilecek kod konuşlandırma/yayınlama (deployment) yöntemlerimizi daha pratik ve kontrollü bir hale getirip modernize etmeyi düşünüyordum. Sonunda birkaç ay önce uygun bir boşluk bulup bir pilot proje üzerinde denemeler yaparak bir düzen oluşturdum ve o günden bu yana da yönettiğim hemen her projeyi yavaş yavaş bu yeni düzene taşıdım. Bugün de yaptıklarım üzerine bir kaç şey karalamak istedim.

Öncelikle eskiden kullanılan yöntem(ler)i anlatayım:

  1. Eskiden uygulanan konuşlandırma yöntemleri zaman içerisinde evrim geçirmişler. Yıllar önceden bugüne kullanılan farklı yöntemleri sıralayayım:
    Kod Subversion deposuna gönderildikten sonra geliştirme makinesinde test edilir. Test edilen kod kendi içinde rsync kullanan bir bash betiği ile canlı ortama alınır.
  2. Kod Subversion deposuna gönderildikten sonra yine geliştirme makinesinde test edilir. Testler sonrasında bir sorun yoksa kod Subversion’da canlı ortamdaki stabil kodun bulunduğu dal (branch) ile birleştirilir (svn merge). Bir bash betiği sayesinde önce yeni bir tag oluşturularak kod etiketlenir, sonra canlı ortam ile birebir aynı konfigürasyona sahip bir ‘stage’ sunucusunda test edilir. Her şey yolundaysa kod yine başka bir bash betiği ile rsync kullanılarak canlı ortam sunucularına gönderilir.
  3. Uygulamanın çalıştığı dizin aslında sembolik bağ ile en son stabil kodun bulunduğu Subversion etiketi dizinine bağldır. 2. yöntemin bir değişik hali olarak her tag ayrı ayrı canlı ortam sunucularına gönderilir. Fakat bash betiği her çalıştığında uygulamanın sembolik bağı yeni Subversion etiketine bağlanır. Olur da yeni kodda bir sorun olursa, sembolik link hemen bir önceki stabil olan tage bağlanıyor.

Bu yöntemlerin farklı varyasyonları zamanla denendi, her biri, bir önceki yöntemdeki boşlukları giderse ve yaşanan sorunları çözse de yeterli değildi.

Projeler yoğun olduğunda yıllardır süre gelen ve alışılmış ve kabul edilmiş bir konuşlandırma yöntemini geliştirip daha iyi bir hale getirmek de oldukça zor ve sıkıntılı oluyor. Bu nedenle de eski yöntemler ‘bozuk değilse tamir etme’ mantığıyla değişmeden kullanılıyor.

Yeni özellik/kod konuşlandırma sürecinde genel olarak şu sıkıntıları yaşıyorduk:

  1. Kod gözden geçirmesi (code review) tamamen yeni kodu yazan programcının ekip liderlerine ‘şu şu şu dosyaları değiştirdim, canlı ortama almak istiyorum, kontrol eder misin?’ şeklinde iletişime geçmesi, ekip liderinin son değişiklikleri öncekilerle (svn diff) karşılaştırıp, ‘tamamdır’ şeklinde cevap vermesinden ibaretti. Gözden geçirilmemiş kodun canlı ortama alınmasını engelleyen hiçbir mekanizma yoktu. Commit hooklar ile commit engelleme yapmak mümkün olsa da, bu test sürecini etkiliyordu. Eğer bir geliştirici Subversion deposuna commit yapamıyorsa, test sunucusuna kodu elle taşıması gerekir ki, bu daha beter. Post commit hook ile svn diff alınıp e-posta ile bildirmek uzun bir süre denendi. Ama gün içerisinde onlarca ve belki de yüzlerce commit yapıldığı durumlarda baş ağrısından başka bir işe yaramadı.
  2. Subversion ile branch kullanımının ne kadar sıkıntılı olduğu malum.
  3. Her ne kadar prosedür gereği her kodun bir testten geçmesi gerekiyor olsa da, birim testini zorlayan herhangi bir mekanizma yoktu.
  4. Değiştirilen kod dosyalarının canlı ortama tek tek alınması birçok kez bazı dosyaların unutulması nedeniyle canlı ortamda sorunlara neden oluyordu.

Daha şimdi aklıma gelmeyen bir sürü problem.

Çözüm ve iyileştirme ilk olarak herkesi Subversion’dan Git’e geçmeye ikna ederek başladı. Git’e geçişi yaparken hem Git depolarını rahatlıkla yönetebileceğim, hem de kod gözden geçirmeyi kolaylaştıracak bir araç arayışına girdim. Her ne kadar Atlassian’ın Stash adlı aracı oldukça işe yarar olsa da, yönetime ekstra maliyeti pek açıklayamayacağımdan ücretsiz ve açık kaynak kodlu bir araç olan Phabricator‘de karar kıldım.

Phabricator, Facebook tarafından geliştirilmiş dahili bir araçken (aslında araçlar topluluğu) kamu kullanımına da açılmış. Subversion, Mercurial ve Git depolarını yönetebiliyor ve kod gözden geçirme için web arayüzü sunuyor.

Subversion’da tutulan depoları önce yerel Git depolarına çevirdim. Daha sonra da yerel depoları, Phabricator altındaki Diffusion ile oluşturduğum merkezi Git depolarına aktardım.

Phabricator’da kod gözden geçirme işlemi için Differential adı verilen bir araç kullanılıyor. Geliştiriciler Differential üzerinden 2 şekilde kod gözden geçirmesi talebinde bulunabiliyor:

  1. Değişen kodu bir yama olarak kaydedip, web arayüzü üzerinden göndermek.
  2. Arcanist adı verilen araç ile komut satırından talepte bulunmak.

Web arayüzüyle yama göndermek oldukça kolay olsa da komut satırından Arcanist kullanımının aşağıdaki gibi birçok avantajı var:

  • Arcanist ile basit bir komut vererek yama otomatik olarak gönderilebiliyor ve gönderilen yama bilgisi daha detaylı olduğu için değişikliği inceleyecek olan kişi veya kişiler değişen dosyayı bir bütün olarak da görebiliyor. Fakat web arayüzüyle gönderildiğinde bu mümkün değil.
  • Arcanist’in birim testlerini çalıştırıp, sonuçları değişiklik talebiyle birlikte göndermesi gibi bir özelliği var. Böylelikle incelemeye gönderilen her kod mutlaka birim testinden geçmiş oluyor.
  • Kod değişikliği inceleyen kişi tarafından onaylandıktan sonra Arcanist değişikliğin yapıldığı branch’i asıl branch ile (Git’te master) birleştiriyor ve eski branch’i siliyor.

Phabricator’u ayarlayıp, kod depolarını aktardıktan sonra iş akışımız şu şekilde değişti:

  1. Geliştirici her özellik, hata giderme, değişiklik vs. için (basitçe JIRA’da açılan her iş için) bir branch oluşuturuyor.
  2. Geliştirici ilgili branch’te çalışıp, yerel deposuna kaydediyor.
  3. Kodu test ettikten sonra ‘arc diff’ komutunu vererek değişiklik inceleme talebini gönderiyor.
  4. Arcanist önce linter ile kod hatalarını inceliyor, sorun yoksa birim testlerini çalıştırıyor.
  5. Kod birim testlerinden geçtikten sonra geliştiriciye konsolda bir form sunup, değişiklik ile ilgili bilgi girmesini istiyor (ne değişti, neden değişti?). Aynı formda bir de kodu kimin inceleyeceği bilgisi de soruluyor. Eğer herhangi birisinin ismi girilmezse, Phabricator’de önceden tanımlanmış bir kişi inceleyecek kişi olarak atanmış oluyor.
  6. İnceleyecek kişi, kod değişikliği ile ilgili bir e-posta alıyor. Differential (web arayüzü) her bir değişikliği kendi içinde ayrı bir ‘revision’ olarak saklıyor. E-postadaki revision linkine tıklayıp Differential’dan değişiklikler incelenebiliyor.
  7. Kodu inceleyen kişi, dilerse Differential’da kod satırlarının arasına notlar alabilir, değişikliği kabul edebilir veya reddedebilir.
  8. Eğer değişiklik reddedildiyse, ilgili değişiklikleri yapması için geliştirici bir e-posta alıyor. Değişiklikler yapıldıktan sonra yine ‘arc diff’ komutuyla inceleyen kişiye gönderiliyor.
  9. Kod değişiklikleri kabul edildiyse, geliştirici yine bir e-posta alıyor. Bu durumda ilgili branch’te ‘arc land’ komutu verilip kodun master branch’i ile birleşimi ve eksi branch’in silinmesi sağlanıyor.
  10. Son olarak master branch’i merkezi depoya gönderiliyor ve iş bitmiş oluyor.

Buraya kadar her şey güzel, ama kodu canlı ortama gönderme sürecinde bir değişiklik olmadı. Başlarda post-receive hook ile kodun farklı bir branch veya depoya gönderilmesiyle canlı ortama konuşlandırma işlemini otomatik bir hale getirmeyi düşünmüştüm. Oldukça kolay bir şekilde incelenen ve onaylanan kod canlı ortama alınmış olacaktı. Fakat, canlı ortama alma işlemini hem takip etmek, hem de kaydını tutmak istiyordum. Daha bir çok şeyi otomatikleştirebileceğim Jenkins’i denemeye karar verdim.

Projelerimizin çoğu PHP ile geliştirildiği için Jenkins’i de ona göre ayarlamam gerekiyordu. Bunun için http://jenkins-php.org adresindeki yönergeleri izleyerek bir kurulum gerçekleştirdim. Her proje için bir Ant betiği hazırladım. Bu sayede kod canlı ortama alınmadan önce linter, birim testi, kopyala yapıştır kontrolleri, vs. gibi birçok kontrolden geçiyor ve her biri için ayrı rapor hazırlanıyor.

Her bir proje için 4 tane Jenkins işi oluşturdum:

  1. Beta ortamına konuşlandırma
  2. Stage ortamına konuşlandırma
  3. Canlı ortama konuşlandırma
  4. Geri alma (rollback)

Beta ortamına konuşlandırma işlemi tamamen otomatik. Jenkins’in Git deposundaki master branch’ini takip edip, gönderilen her değişiklik için yeni bir ‘build’ hazırlamasını sağladım. Her build işlemi Ant ile şunları yapıyor:

  1. Linter kontrolleri
  2. phploc ile kod satırı istatistikleri
  3. phpmd ile kötü kod istatistikleri
  4. phpcpd ile birbirinin aynısı olan kodları arama (kopyala yapıştır programcılığını engellemek için)
  5. phpunit ile birim testleri ve test kapsamı raporları
  6. phpdox ile kod referans dökümanı hazırlama

Eğer kod yukarıdaki kontrollerden geçerse beta ortamına aktarılmış oluyor.

Stage ortamına konuşlandırma işi ise elle çalıştırılıyor. Basit olarak master’daki son kod canlı ortamın bire bir aynısı olan ama kullanıcılara açık olmayan bir sunucuya gidiyor. Burada Ant çalıştırmaya gereksinim duymadım. Çünkü zaten ilgili kontroller beta’ya giderken otomatik olarak yapılıyor.

Canlı ortama konuşlandırma işi de elle çalıştırılıyor. Fakat sonunda aşağıda bahsedeceğim bazı ek işlemler yapılıyor.

Geri alma işini de, olur da canlı ortama alınmış bir kodda sorun çıkarsa ve önceki bir revizyona dönüş gerekirse diye oluşturdum. Bu iş parametre olarak Jenkins BUILD_NUMBER’ı alıyor ve o build’daki versiyonu canlı ortama tekrar gönderiyor. Böylelikle projenin büyüklüğüne göre birkaç saniye içerisinde eski stabil koda geri dönüş sağlanabiliyor.

Jenkins sayesinde Phabricator ile yapılan kod inceleme işleminden geçmiş kodun canlı ortama alınış süreci şöyle şekillenmiş oldu:

  1. Merkezi depodaki master branch’e gönderilen yeni kod Jenkins tarafından otomatik olarak alınıp birçok kontrole tabi tutulup, raporlar hazırlanarak beta ortamına gönderiliyor.
  2. Eğer kontrollerden herhangi birisinde sorun çıkarsa Jenkins otomatik olarak geliştirme ekibine bir e-posta göndererek durumu bildiriyor.
  3. Beta ortamına alma işleminin sonucu (başarılı veya başarısız), Jenkins tarafından ilgili JIRA işlerine yorum olarak ekleniyor. Böylelikle işi açan, hatayı bildiren, işi yapan, işi takip eden herkes Jenkins’in kodu beta ortamına aldığını veya bir sorun nedeniyle alamadığını öğrenebiliyor.
  4. Beta’da kullanıcı testinden geçtikten sonra stage ortamına alınıp gerçek canlı ortamda doğabilecek sorunları gidermek amacıyla bir QA testi yapılıyor.
  5. QA ekibi stage ortamındaki koda onay verdikten sonra kod Jenkins ile canlı ortama aktarılıyor.
  6. Jenkins kodu canlı ortama aktardıktan sonra yine ilgili JIRA işlerini güncelleyerek kodun canlı ortama alındığını bildiriyor.
  7. Jenkins build numarasını kullanarak canlı ortama alınmış kodu Git deposunda etiketliyor (örn: production-3125).
  8. Son olarak tüm Git commit mesajlarını bir değişiklik kaydı (Change log) şeklinde kaydediyor.

Doctrine kullanılan projelerde her kod değişikliğinde /tmp dizinindeki proxy dosyalarının yeniden oluşturulması gerekebilir. Bazı projelerde de arka planda çalışan süreçlerin (mesela RabbitMQ kullanan işçi – worker süreçleri) durdurulup tekrar çalıştırılması gerekebilir. Bu gibi işleri yapmak için bir bash betiği oluşturdum. Sonra da Jenkins’e kodu canlı ortama aldıktan sonra ilgili sunuculara SSH ile bağlanıp bu betikleri çalışmasını belirtim.

Son birkaç aydır hemen herşeyi Phabricator ve Jenkins’e yüklemiş  ve rahata ermiş durumdayım. Eğer fırsat bulur ve üşenmezsem de uzun bir how-to yazmayı düşünüyorum.

 

Feb 242013
 

Daha önce SoapUI’ dan kısaca bahsetmiş ve hali hazırda var olan bir web servisinin bir istemci uygulaması geliştirmeye gerek kalmaksızın nasıl test edilebileceğini anlatmıştım. Şimdi de tam tersine, hali hazırda geliştirilmiş bir SAOP web servisi istemcisini, gerçek sunucuya erişim olmaksızın nasıl test edebileceğimizden bahsedeceğim. Çünkü bazen, gerçek sunucuya erişime hemen sahip olmayabilir ya da uygulamanızı çeşitli veriler ile test etmek isteyebilir ancak gerçek sunucuya erişiminiz olsa da her durumu test etmeye çalışmanız, sunucu servisi sağlayanlar tarafından hoş karşılanmıyor olabilir.
Continue reading »

Feb 032013
 

Birçok yerde programlamaya başlamak isteyenlerin (genellikle lise öğrencileri), hangi programlama dili ile başlamanın daha iyi olacağını sorduklarını görüyorum. Tabi her kafadan bir ses çıkıyor (buraya yazdıklarım da benim kafamdan çıkan sesler) ve soruyu soran da ayrı bir pişman oluyor. Soruyu soranların bir kısmı, sadece merak ettikleri için programlama öğrenmek isterken, bir kısmı da ileride kariyer olarak programcılığı seçmek istiyor. Bazıları da oradan buradan “abi, programcılıkta çok para var, süper bir proğram/site yapsan deli gibi para kazanırsın. Programcılara hem şirketler de manyak gibi para veriyor.”, “olm var ya, Java diye bir şey varmış, öğrenince şirketler havada kapıyormuş” vs. gibi şeyler duyup merak ediyor, “acaba ben de öğrenebilir miyim?” diye heves ediyor. Uzun sayılabilecek bir süredir programcılık yapan birisi olarak o manyak gibi para veren şirketlerle bir türlü karşılaşmış değilim, ama neyse 🙂

Büyük hevesle “ben programlama öğrenmek istiyorum, ne yapmam lazım?” veya “çeşitli programlama dilleri var, hangisini öğrenmeliyim?” diye sorun bir çocuğa, “hoop, biz senelerimizi bu işe verdik, sen bacak kadar boyunla nasıl hemen öyle programlama öğreneceksin? Önce git bakalım üniversiteye, oku adam gibi X’i, Y’yi, zartı zurtu, ondan sonra program yazarsın” diye cevap verip, çocuğun tüm hevesini kıran ruh hastalarını saymazsak, (bana göre) aklı başında cevap veren kişi sayısı çok az oluyor. Çünkü, verilen cevaplar genellikle ya “Java’ da çok para varmış” gibi sadece paraya dayalı ya da herşeyi abartarak “bu işi sonuna kadar öğreneceksen C öğren” tarzı saçmalıklar oluyor. Farklı programlama dillerinin fanatiklerinin de birbirlerine laf atıp, iyice kafa karıştırması da cabası.
Continue reading »

Dec 282012
 

Kısa bir hikaye bu. Mutlu sonla da bitmiyor. Belki limoni, ekşi bir son diyebiliriz.

Hikayemizin kahramanı Yaşar PHP ile yazılmış bir kodun, yapması gereken işi neden tam olarak yapmadığını anlamaya çalışmaktadır. Kapkaranlık terminal penceresinden akıp giden logları satır satır okumakta, her log satırını kod ile karşılaştırıp, programın akışını takip etmektedir. Yaptığı her testte, çalışması gereken kod satırı bir türlü çalışmamakta, PHP inatla o kod satırını es geçmektedir.

Söz konusu kod şuna benziyordu:

....
....
....
// 3. Parti API'den gelen cevabı loga yaz
// 3. Parti API'den gelen cevabı parse et, bu cevaptaki X değerini $x değişkenine Ata
....
....
....
if ($x > 0)
{
    BirSeyYap();
}
else
{
    BaskaBirSeyYap();
}

Logda 3. Partiden gelen cevap yazılıdır ve o logda X’in değeri 2’dir. Ama sanki $x değişkeni hiç bu değeri almıyormuş gibi kod sürekli BaskaBirSeyYap() fonksiyonunu çağırmaktadır. Yaşar en az 10 test yapmıştır, artık gözleri kararmaktadır. En sonunda değiştirmek istemediği kodda, if deyiminin hemen bir satır üstüne Log::writeLog(“X’in değeri bu: $x”); satırını ekler ki logda $x değişkeninin değeri görünsün. Bunun dışında hiçbir değişiklik yapmaz, “yemişim commiti” deyip, kodu Subversion deposuna göndermeden doğrudan production’a alır.

Aynı testi tekrarlar.

3. Parti API daha önceki 10 testte verdiği cevap ile aynı cevabı verir. X değeri 2’dir. Yaşar logları okumaya devam eder ve yeni eklediği log satırını görür. Şöyle yazmaktadır:
X’in değeri bu: 2

ve hemen altında BirSeyYap() fonksiyonun çağrıldığını gösteren log satırını görür. Kod doğru çalışmıştır. Halbuki $x değişkenini loga yazmak haricinde hiçbir değişiklik yapmamıştır. Gözlerini oluşturur. Testi yineler. Sonuç aynıdır. $x 2 değerini alıyordur ve kod doğru çalışıyordur.

Yaşar, “hayır, bu kadar aptalca bir şey olamaz” der ve 3. Parti API’den aldığı önceki cevaplarla, $x’ i loglara yazmasından sonraki cevapları karakter karakter karşılaştırır. Birebir aynıdırlar. Hatta bir Hex editörü ile log dosyasını açıp karşılaştırma yapacak kadar ileri gider. API’ nin döndürdüğü sonuç her durumda aynıdır ve koddaki tek değişiklik $x değişkeninin değerinin loga yazılmasıdır.

Hemen son yaptığı değişikliği geri alır ve kodu production’ a alp tekrar test eder. API aynı cevabı döndürür, $x artık logda görünmemektedir, fakat BirSeyYap() fonksiyonu çalışmaya devam etmektedir. Yaşar ne yaparsa yapsın, aynı durumu tekrar edemez. Halbuki o log satırını yazmadan önce en az 10 kez test etmiş, hepsinde de BaskaBirSeyYap() fonksiyonu çalışmıştır. Log satırını yazınca herşey düzelmiştir. Olayı etrafındakilere anlatır, ama tekrar edemediği için logları göstermesine rağmen kimseyi inandıramaz.

Sonuçta PHP’ ye bol miktarda güzel iltifatlar ederek işine devam eder.

Dec 272012
 

Kod taşımaya devam 🙂 Bu sefer bir Subversion deposunu başka bir dizine veya sunucuya taşıyoruz.

Önce eski depoyu bir dosyaya yedekleyelim:

$ svnadmin dump /eski/deponun/yolu > depoyedek
* Dumped revision 0.
* Dumped revision 1.
* Dumped revision 2.
* Dumped revision 3.
* Dumped revision 4.

Şimdi yeni depoyu oluşturalım:

$ svnadmin create /yeni/deponun/yolu

Eğer depoyu yeni bir sunucuya taşıyacaksanız “depoyedek” dosyasını kopyalayın.

Şimdi eski depoyu yeni depo olarak yüklemek için şu komutu verin:

$ svnadmin load /yeni/deponun/yolu < depoyedek
<<< Started new transaction, based on original revision 1
     * adding path : branches ... done.
     * adding path : tags ... done.
     * adding path : trunk ... done.
 
------- Committed revision 1 >>>
 
<<< Started new transaction, based on original revision 2
     * adding path : trunk/index.php ... done.
 
------- Committed revision 2 >>>
 
<<< Started new transaction, based on original revision 3
     * editing path : trunk/index.php ... done.
 
------- Committed revision 3 >>>
 
<<< Started new transaction, based on original revision 4
     * adding path : trunk/a.class.php ... done.
 
------- Committed revision 4 >>>

Depo aktarıldı. Artık svn checkout ile yeni depo URL’ ini kullanarak çalışma dizinleri oluşturabilirsiniz.

Eski çalışma dizinlerini yeni URL’ e geçirmek isterseniz “svn switch” kullanmanız gerek:

Eğer depolar çalışma dizinleriyle aynı sunucudaysa;

$ svn switch --relocate file:///eski/deponun/yolu file:///yeni/deponun/yolu

Eğer depolara SSH tüneli ile ulaşacaksanız;

$ svn switch --relocate svn+ssh://eskidepoadresi.com/eski/deponun/yolu svn+ssh://yenidepoadresi.com/yeni/deponun/yolu
Oct 182009
 

Evet, lutfen, cik hayatimdan. Seninle uzun zamandir suren bir birlikteligimiz vardi. Seni hep sevdim ve ozellikle web programciliginda hep tercih ettim, hep savundum. Hala daha seni web programciliginda savunabilirim. Ama sen de cok iyi biliyorsun ki 4 yildir web programciligi yerine, “back-end” diye tabir edilen tarafta calisiyorum ve mecburen seni kullaniyorum. Ve sen, back-end’de ayni sabahlari daha ayilamamis kaprisli bir kadin gibisin. Hircin, cirkin, suratsiz ve kaprisli. Seni calismasi uzun surecek bir betik icin kullandigimda sacmaliyorsun. Karsilastirma bildirimlerin bazen dogru calismayabiliyor ve dengesizligin beni cildirtacak noktalara kadar varabiliyor. O kadar oluyor ki, seni tum sunucularin disklerinden silmek geliyor icimden. Ama yapamiyorum.

Python ile ne guzel hayallerimiz vardi. Yeni sistemi sadece Python kullanarak gelistirecektik ve seninle sadece eski platformda calisan servislerin bakimi veya guncellemeleri icin resmi bir iliski kuracaktim. Python ile de tutkulu ve heyecanli bir beraberligimiz olacakti. Ama olmadi. Super is arkadaslarimin yeni bir dil ogrenmek ve kullanmak konusundaki tembellikleri yuzunden, gelistirmekte oldugumuz yeni platformda senden kurtulma planlarim alt-ust oldu. Onlar sayesinde en azindan bir 2 yil daha seni kullanmam gerekecek back-end’de. Ustelik gecenlerde senin yaraticin Rasmus Lerdorf’un Brooklyn’deki PHPTalk’ta soyledigi “PHP web icin tasarlandi, arkaplan icin degil” sozlerine ragmen…

Daha once seninle yazdigim bazi betikleri, sirf uyku tutmadigi icin sabahin korunde bir de Python ile yazmayi denedim. Nerede senin kaprislerin, nerede Python’un uysalligi?…

Web’de yine gorusebiliriz ama arkaplan uygulamalari icin soruyorum: Ne zaman cikacaksin hayatimdan?

Oct 172009
 

Bir programa herhangi bir işlevsellik katmadığı müddetçe, programlarin kabuk destegi olmasına hep karşı olmuşumdur. Bu konuda yapılmış şu yoruma da tamamen katılıyorum:
Whenever a programmer thinks, “Hey, skins, what a cool idea”, their computer’s speakers should create some sort of cock-shaped soundwave and plunge it repeatedly through their skulls.

Sep 232009
 
  • Baska bir teknik konuyu anlatan kitap alma/okuma,
  • Baska bir teknik konuyla ilgili haberler okuyup, konunun icerisine girmeye kalkma,
  • Baska seylerle kafani doldurma,
  • Duzenli uyu,
  • Is yerine erken git ki erken cikabilesin, aksama ailenle ilgilenip, sonra da uykun gelmeden bilgisayar basinda proje hakkinda bir seyler yapabilecek vaktin kalsin,
  • Forumlardan uzak dur,
  • E-posta listelerini takip etmeyi bir sureligine kes,
  • Kullandigin isletim sisteminin orasini burasini kurcalamayi birak, cunku emin ol dunyadaki bilgisayar kullanicilarinin %95’i bunu yapmadan da islerini hallediyorlar.
Mar 052009
 

Nokia Trolltech’i satin aldigi zaman “aha” demistim, ortalik karisacak. Sonra Qt 4.5’in LGPL olacagini duyduk, sevindik. Son olarak 4.5’in cikisi, Qt Creator gibi bir urunun gelmesi ve bir de asagidaki yazida yazanlar. Oh oh oh, suyundan da koy Nokia.

http://arstechnica.com/open-source/news/2009/03/first-look-qt-45-rocks-for-rapid-cross-platform-development.ars