Bu makale http://www.hacknot.info (şuan yayından kalktı gördüğüm kadarıyla, link kırık çıkabilir) sitesindeki Debugging 101 konulu yazı çevirilerek hazırlanmıştır.
Geçenlerde bir meslektaşımla beraber, yazmış olduğu bir kod parçasındaki küçük bir hatayı(bug) çözmek için beraber çalışıyorduk. Hata bir exception oluşturmuştu ve neyden kaynakladığı konusunda ikimizin de herhangi bir fikri yoktu. Daha da kötüsü hata kullanmakta olduğumuz açık kaynak (open-source) bir kütüphaneden(library) kaynaklanmaktaydı. Bir açık kaynak klasiği olarak dökümantasyon azdı ve problemi teşhis etmekte bize fazla bir yardım sağlamıyordu. Görünen oydu ki bu kütüphanenin kaynak kodunu indirecek ve içine girecektik.
Kaynak kodu indirmeden önceki son çare olarak hatanın kendisini webde aramayı önerdim, hata metninin son bir kaç satırını arama moturununun kutucuğuna yapıştırarak.. Arama sonucunda bir başkasınında online forumlarda "aşağıdaki hata ile karşılaştım, ne yapmam gerekiyor" türünden bir mesaj ve akabinde hata mesajının tamamı yada bir kısmının yer aldığı sayfalar görmeyi umuyordum. Belki forumdaki bu mesaja verilen cevaplar bize de yardım edebilirdi.
Meslektaşım yazılım geliştirmede epeyce yeni biriydi ve fikrim karşısında şaşırarak, bunu denemeyi hiç düşünemeyeceği yorumunu yaptı. Onun bu cevabı beni hata ayıklama yöntemleri genel olarak düşünmeye itti.
Bilgisayar bilimleri üzerine aldığım eğitimlerde, nasıl hata ayıklanması ile ilgili verilen herhangi bir eğitim yada konunun değinildiği bir ders hatırlamıyorum. Bu arada belirteyim ki bu derslerde aldığım çoğu şeyi hatırlamıyorum, belki bu konuya da değinildi ve ben unuttum. Yine de hata ayıklama ihmal edilen bir konu, neden acaba?
Ortalama bir programcının zamanının ne kadarını hangi oranda hata ayıklamaya harcadığını düşündüğümüzde, sonuç özellikle dikkat çekici. Kendim için ölçmedim fakat 1/3 yada günün çoğu hata ayıklamayla geçiyorsa hiç şaşırmam. Bir programı debug etmeyi metodsal bir şekilde hiç görmemiş olmamız oldukça tuhaftır. Hata ayıklama konusunda tüm bildiğim tecrübelerimden, deneme-yanılmalardan ve başkalarından görerek elde ettiğim şeylerdir. Tecrübelerime dayanarak söylüyorum ki, hata ayıklama teknikleri tüm geliştiriciler için hayati bir ilgi alanı oluşturmalıdır. Hala bazı programcılar bu konuda konuşmak noktasında çekimser görünmekteler.
Bunun ana nedeninin gurur olduğunu sanıyorum. Hatasız kod yazmak çoğu programcı için iftihar meselesi. Hata ayıklama teknikleri hakkındaki bilgisini sergilemek kusur yada zayıflık itiraf etmek gibi. Fakat bu konuyu ihmal ederek insanın kaçınılmaz zayıflığıyla mücadele etmenin yöntemlerini öğrenmenin önemli imkanlarını kaybederiz, dolayısıyla yaptığımız işin kalitesini iyileştirmeyi.
Bunlardan dolayı hata ayıklama konusunda edindiğim teknikleri listeleme görevini üzerime aldım. Çoğu için bunlar eski ve basit olabilir. Çok tecrübeli olanlar için bile bu denenmiş ve doğru teknikleri hatırlamak iyi olacaktır. Umarım bunlar sinir bozucu hataların aldığı zamanlarınızı size kazandırır.
Debugging : Genel Prensipler
Kullandığınız spesifik debug tekniklerine bakılmaksızın hataları ayıklarken aklınızda bulunması gereken birkaç önemli yönerge vardır.
Yeniden Oluşturmak
Herhangi bir debug sürecinde ilk görev hatayı tutarlı bir şekilde tekrar oluşturmayı öğrenmektir. Hatalı davranışı manuel olarak tetiklemek birkaç adımdan daha fazla ise programatik olarak hatayı tetikleyecek küçük bir program yazmayı deneyin. Sonuç olarak debug işleminiz daha hızlı şekilde sonuçlanacaktır.
Kapsamı Daraltarak İlerle
Hatanın kaynağını bulmanın temelde iki yöntemi vardır :
Analiz hatanın kaynak noktası üzerine düşünmektir ve kod yapısı bilgisine dayanır. Kaba kuvvet yaklaşımı ise hatalı parça bulunana kadar execution(kodun işletilmesi) sürecinde yapılan geniş bir mekanik araştırmadır.
Pratikte bu metodların muhtemelen ikisini de kullanırsınız. İlk analiz size hatanın olabileceği muhtemel bölgeyi söyleyecek, ikincisi(kaba kuvvet) bu bölgedeki hatayı tam olarak size gösterecektir.
Değişikliklikleri bir bir Yapın
Hata ayıklama döngüsel bir süreçtir ki bir değişiklik yaparsınız, hatanın giderilip giderilmediğini kontrol edersiniz, başka bir değişiklik yaparsınız, tekrar test edersiniz ve bu hatayı tespit edene kadar devam edder gider. Her değişiklikte kodun sadece bir noktasını değiştirmek önemli. Hata giderildiğinde böylelikle hatanın tam olarak neden kaynaklandığını anlarsınız ki bu yaptığınız son düzeltmedir. Eğer aynı anda birden fazla şeyi değiştirirseniz gereksiz değişikliklerle risk oluşturursunuz ve bunlar başka hataların oluşmasına neden olabilir ve hatanın başlangıç noktasını anlamanızı zorlaştırabilir.
Debugging : Teknik Metodlar
Hata ayıklama manuel olarak yapılan, mantıksal problemlerin çözümü gibi yoğun ve programlamadan daha can sıkıcı bir iştir. Detaylı araçların yardımı çok az olacaktır ve onların yerine zekice uygulanan az miktardaki tekniklere başvuracaksınız.
İzleme(trace) İfadeleri Koyun
Bu kullandığım en temel bir hata ayıklama metodudur. Trace ifadesi hata içerdiği sanılan kod parçasına eklenen log mesajıdır. Tabi hata bulundukta sonra bu mesaj silinir. Trace ifadeleri sadece kodun nasıl çalıştığını izlemek için değil aynı zamanda program boyunca kullanılan değişkenlerin durumunu izlemek için de kullanılır. İyi seçilmiş trace ifadeleri ile hatanın sebebini tam olarak belirlemek genellikle çok az zaman alır. Hatayı bulduktan sonra konsol mesajlarını dosya tabanlı mesajlara çevirmek ilerdeki hata ayıklama işleri için yardımcı olabilir.
3. Parti Ürünlerin Log Dosyalarına Başvurun
Eğer 3. parti bir uygulama sunucusu, sunucu yazılımı, veritabanı yazılımı yada komponent kullanıyorsanız, bu yazılımların kendi log dosyalarında en son karşılaşılan hatalarla ilgili kullanışlı bilgilere ulaşabilirsiniz. Belki komponentin istediğiniz çeşit bilgilerin kaydını tutması için konfigurasyonunu yapmak durumunda kalabilirsiniz. Genel olarak eğer karşılaştığınız hatanın, kodlarına sahip olmadığınız bir 3. parti yazılımdan kaynaklandığını düşünüyorsanız (tabi içine trace ifadeleri de koyamayacaksınızdır eğer öyleyse), bu durumda üreticinin size ürünün arka planda gerçekleşen işlemlerle ilgili bilgi sağladığı bir yol olup olmadığını öğrenin. Örneğin bir ORM kütüphanesi (ORM library), hiçbir log çıktısı (output) üretmese de konfigurasyon dosyası veya komut satırı (command line) ile veritabanına gönderilen tüm SQL ifadelerinin çıktısını verebilir.
Hata Mesajını Web'de Aratın
Hata mesajını aynen kopyalayarak istediğiniz bir web arama motorunda aratın. Böylece, yöneltilen sorularda hata mesajının aynen sorunun içinde geçtiği tartışma forumlarından sonuçlar getirilecektir ki yazılan cevaplardan biri de sizin hatanızla ilgili olabiilr. Webde ayrıca hata numarasını da aratabilirisiniz.
En Başından Tekrar Başlayın
Bazan bir hatayı uzunca süre araştırdıktan sonra onu bulmak konusunda umutsuzlaşırsınız. Daha bakmanız gereken biton kaynak vardır veya araştırdığınız durum/davranış biraz tuhaf ve alışılmadık olabilir. Böyle durumlarda en başından tekrar başlamak faydalı olabilir. Fonksiyonu sizin hatanızın yerini göstermek olan bütünüyle yeni ve küçük bir uygulama oluşturun. Eğer böyle demo bir programcık yazabilirseniz, hatanızın sebebinin izini sürmekte doğru yoldasınız demektir. Hataya sebep olan potansiyel komponentleri birbir deneyerekten demo programınızı hatadan izole edilmiş hale getiriniz. Örneğin demo programınız database connection pooling kütüphanesi kullanıyorsa, bu komponenti çıkarın ve tekrar deneyin. Hata hala devam ediyorsa hatalı davranışın sebebi olmayan komponentlerden birini tespit ettiniz demektir. Bu usulde ilerleyerek hatayı kaybeden bir komponenti çıkarttığınızda işte bu komponent, son çıkardığınız, hataya sebep oluyordur.
Süreksiz Hatalar
Aralklı olarak ortaya çıkan ve sürekli oluşmayan hatalar programcı için talihsizliktir. Bunlar genelde ortak kaynakların asenkron(asynchronous) kullanımından olabileceği gibi aynı memory alanını kullanan multiple thread'lerden yada lokal bi değişkene aynı anda ulaşmaya çalışan fonksiyonlardan olabilir. Ayrıca farklı uygulamaların aynı memory yada IO kaynaklarını kullanmasından da kaynaklanabilir.
İlk olarak paralel olarak çalışan işlemlerin seri halde çalışmasını sağlayın. Örneğin n tane hesaplama için n tane thread yerine n tane hesaplamayı seri olarak yaptırın. Eğer hata kaybolursa hesaplamayı yapan kod parçalarında senkronizasyon probleminiz var demektir. Thread'lerin senkronizasoynunu düzeltemezseniz multi-thread çalışan 3. parti bir kütüphane deneyin.
Eğer programlama diliniz değişkenlerin ilk değerleri ile ilgili garanti vermiyor ise, ilk değer verilmeyen değişkenler de süreksiz meydana gelen bug'ların sebebi olabilir. Yüzde 99 değişken 0 veya null ile başlatılır. Fakat diğer yüzde 1 ihtimal rastegele bir ilk değer alır ve hataya neden olur. System Purterbers tipi yazılımlar bu tarz problemlerin izini sürmede yardımcı olabilir. Böyle araçlar sıfır olan memory alanları ile işlem yapmaya yada memory alanını rastgele data ile doldurmaya yarar.
Hatayı Doğru Yerde Arayın
Araştırmalar göseriyorki bug'lar birlikte kümelenme eğilimindedir. Bundan dolayı yeni bir bug ile karşılaştığınızda, daha önce çözdüğünüz bug'ların yer aldığı kodları gözden geçirin veya bu bug'ın çevresindeki kod parçasını inceleyin.
Doküman Okuyun
Eğer diğer hepsinden sonuç çıkmaz ise talimatlara başvurun. Programcılar yeni bir API kullanırken deneme yanılma ile hareket ederler. API ile ilgili dokümantasyon yok ise bu uygun bir yöntem olabilir. Fakat API programcı için düşük seviye dokümantasyona sahip ise okumak için biraz zaman ayırmakta fayda var. Karşılaştığınız bug'ın API'nin yanlış kullanımından yada gerekli önşartlara uymadığınızdan kaynaklanmış olması muhtemeldir.
Tekrar Compile Edin
Mide bulandırıcı hata tiplerinden birisi de çeşitli compile(derleme) işlemlerinden sonra oluşan .exe ile ortaya çıkar. Bu hatalı davranış oldukça gariptir.
En son böyle bir hata ile Java kodları içindeki constant string tipindeki değişkenlerin değerlerini değiştirdiğimde karşılaşmıştım. Sanki compiler(derleyici) referans noktasında string tipindeki sabitleri(constant) literal olarak ekleyerek optimizasyon yapıyordu. Böylece constant değer herbir class dosyasına kopyalanıyordu. Eğer constant string değeri değiştirdikten sonra bu class dosyalarını regenerate etmez iseniz, bu class dosyaları constant değişkenin eski değerini içerecektir. Fakat tam bir derleme işlemi bunun oluşmasını engelleyecektir. Son olarak derleyicinin debug bilgisini çalışma zamanında göstermesini ve warning seviyesini maximum'da ayarlayın.
Sınır Noktalarına ve Özel Durumlara Bakın
Tecrübeli programcılar algoritma kurarken hatalara neden olabilecek uç noktaları da düşünürler. Örneğin 1 den N'e kadar tüm kayıtları silmek ile 0 noktasındaki kaydı silmek farklıdır. Artık bir yılı belirlemek yılın 400 ile bölünebilir olması farklıdır. Bir string ifadesindeki kelimeleri boşluklarla ile ayırırken, string ifadesinin sadece tek bir kelimeden oluştuğu veya null değer aldığı durumlar vardır. Genel koşullara göre kodlamak ve özel durumları unutmak çok yaygın hata sebebidir.
Kaynağı belirsiz olan birçok hata 3. parti yazılımların versiyonlarının uyumsuz olmasından kaynaklanır. Bu tabi diğer debug tekniklerini denedikten sonra kontrol edilecek son şeydir. Eğer bir kütüphanenin 1.0.2 versiyonu diğer bir kütüphanenin 2.4 versiyonuna bağımlı ise ve siz onun yerine 2.5 versiyonuyla çalışıyorsanız, sonucu teşhisi imkansız yada zor ince hatalar olabilir. Bu durumda hatanın ortaya çıktığı en son kütühenyi bir önceki kullandığınız ile upgrade etmeyi düşünebilirsiniz.
En Son Değiştirdiğiniz Kodu Kontrol Edin
Herhangi bir anda herhangi bir fonskiyonda aniden bir hata ortaya çıkarsa, bunun sebebinin en son değiştirdiğiniz kod parçasından kaynaklanacağını düşünmelisiniz. Bu tür durumlarda version source control sisteminiz devreye girer ve kodun tarihçesine göz atmanızı sağlar.
Hata Mesajına Her Zaman Güvenmeyin
Nomalde hata mesajlarını dikkatle irdelersiniz, acaba bir ipucu varmı diye umarsınız. Bu yaklaşımla bir sonuca varamıyorsanız hata mesajlarının bazan yanlış yönlendirdiğini hatırlayın. Bu durumlarda hata mesajını birebir çevirmekten kaçınmak ve diğer ihtimalleri düşünmek gerekir.
Grafiksel Buglar
GUI(Graphical User Interface) ile veya grafiksel bug'lar üzerinde çalışırken kullanacağınız birkaç teknik vardır. Kullandığınız grafik pipeline debug mod destekliyormu diye kontrol ediniz; bu modda grafiksel işlemlerin hızı birbir gözlemleme yapabileceğiniz şekilde çalışır. Bu mod seri halde çalışan grafiksel uygulamaların beklediğiniz etkiyi verip vermediğini belirlemek için kullanışlı bir yoldur.
Kontrollerin yerleşimleriyle ilgili problemleri debug ederken panellerin ve komponentlerin arkaplan renklerini koyu ve yoğun renklere set ederim. Bu komponentin sınırlarını görmeyi sağlar.
Debugging : Psikolojik Metodlar
Dürüst olmak gerekirse önümüze çıkan hataların büyük çoğunluğu kendi perspektif sınırlarımızdan kaynaklanıyor. Özel olarak kullandığımız bir API'nin sonuçlarını idrak edememekten, ayırdığımız memory alanını boşaltmayı unutmaktan yada düşündüğümüz şeyi tam olarak koda aktaramamaktan... Tabi birisi çıkıp diyebilir ki debugging, bilgisayarın ne yapacağını söylemek ile bilgisayarın ne yapacağını düşünmek arasındaki farkı bulmaktır. Öyleyse bug'ları ayıklarken daha etkili düşünmek için ne tür mantıksal teknikler işleteceğimize dair kafa yormak anlamlı olacaktır.
Yardım Alın
Bir bug üzerinde saplanmış kalmışken, bir meslektaşınızı yakalayıp hatayı onlarla da paylaşmak ve beraber gayret sarfetmek faydalı olabilir. Meslektaşınızın tavsiyeleri gerçekten çözüm üretmese de yardımcı olabilir. Meslektaşınızın rolü sadece sizi pasif bir halde dinlemektir ve bu belki size daha önce olmadığı şekilde bir bakış açısı sunabilir.
Spekülasyon Yapmayın
Arthur C. Clarke şöyle yazar;
Yeteri kadar ilerlemiş bir teknoloji sihirden farksızdır.
Bence yeteri kadar gizemli bir bug için de bu böyledir. Debugging sürecindeki en büyük tuzaklardan biri sebebi üzerine anlamsız spekülasyonlara başvurmaktır. Bu tarz spekülasyonlar ile belki başarılı olabilecek deneme yanılma çabaları olarak çözüm bulmaya çalışılır ve bu verimsiz artı zaman tüketen bir uğraştır. Eğer zihninizde bütüncül bir strateji ve yaklaşım kurgulamadan rastgele denemeler yapıyorsanız bundan vazgeçin ve daha rasyonel bir metod düşünün.
Araçları Sorumlu Tutmak için Acele Etmeyin
Belki, hatayı kendi yazdığınız kodda bulmadan önce, tecrübelerinize dayanaraktan
Bu mutlaka derleyici hatası olmalı
şeklinde yaklaşmış olabilirsiniz. Hatayı halletiğinizde ise gelecekte yargılamada bulunmak için acele etmeyeceksinizdir. Geliştirme araçlarında bug olması ihtimalini tahmin etmek hata ayıklamanın makul bir yönüdür. Eğer henüz beta aşamasında olan kararsız bir geliştirme aracı kullanıyorsanız, hatalı olduğu konusunda haklı olabilirsiniz. Ama yıllarca piyasada olan ve alanında güvenilirliğini kanıtlamış bir derleyici kullanıyorsanız dereleyicinin hatalı exe oluşturduğu sonucuna varmak için diğer tüm ihtimalleri değerlendirmiş olmanız gerekir.
Problemi de Sorunu da Anlamış Olmalısınız
Programcıların
Bug kendiliğinden kayboldu
yada
Diğer birşeylerin yan etkisi olarak hata düzeldi
türünden iddiaları yaygın olmayan şeyler değil. Bu tarz ifadeler gösteriyorki; programcı hatanın komple bir sebebini yada çözümünü araştırmıyor. Hatalar gizemli bir şekilde kaybolmazlar. Eğer bir hata, birisi onunla kasten ilgilenmeden aniden düzelmişse, hala kodlarda bir yerde sorunu bulmak için şansınız vardır. Sadece akabindeki değişiklikler onun davranış şeklini değiştirmiştir. Hatanın kendiliğinden düzeldiğini yada kaybolduğunu asla kabul etmeyin. Benzer şekilde; yaptığınız bazı değişiklikler hatayı düzeltmiş gibi görünüyorsa ve nasıl olduğu konusunda tam emin değilseniz, değişikliğin akıllıca olduğunu düşünerek kendiniz kandırmayın. Tekrar söyleyelim;
Gerçek sorunu gidermekten ziyade hatanın sadece karakterini değiştirmiş olursunuz.
Ara Verin
Hata ayıklarken yada problemleri çözerken aşağıdaki olaylar dizisini hatırladığımdan çok daha fazla kere tecrübe etmişimdir. Bir problemle saatlerce uğraştıktan ve sinir bozucu bir hal aldıktan sonra, öyle bir noktaya gelirimki artık bıkar, yorgun düşerim ve eve giderim. Sonraki sabah tekrar hatanın üzerine gitmek için otururum ve ve ilk yarım saat içinde çözüme ulaşırım.
Birçoğumuz rastlamıştır; problemin üzerinde yoğun bir konsantrasyondan sonraki ufak bir dinlenmeden sonra çözümler daha bi kolaylaşır.
Birden Fazla Sebep Olabileceğini Gözönünde Bulundurun
Problemlerin teşhislerini fazlaca basitleştirmek konusunda güçlü bir eğilim vardır. Teşhisin böyle basitleşmesi cazibeli ve kesinlikle adreslemesi daha kolaydır. Birçok kere hataların gerçekten tek bir sebepten kaynaklandığı gerçeğine rağmen her zaman böyle olmayacağı durumlar vardır.
Debugging : Hata Önleme Yöntemleri
Önlem tedaviden evladır
sözü beden hastalıklarında olduğu kadar kodlamada yapılan hatalarda da doğrudur. Geliştirme yaparken debug işlemininin maliyeti ve kaçınılmazlığı gözönünde bulundurulduğunda, önceden hazırlıklı olmak ve nihai etkisini azaltmak daha akıllıca olacaktır.
Alışkanlık Haline Gelen Hatalarınızı İzleyin
Dikkatinizi çekmiştir, bir zaman sonra özellikle bazı türden hataları yapma eğilimdesinizdir. Bu şekilde süreklilik arzeden zayıf noktaları belirleyebiliyorsanız, önlemini de alabilirsiniz. Kodlar için bir kontrol listeniz varsa, favori bug'larınızı da ekleyerek listeyi genişletebilirsiniz.
Loose Coupling ve Information Hiding
Gevşek bağlaşım(Loose Coupling) ve kapsülleme(Information Hiding); bu iki kurala dayanan uygulamalar yönetimi ve esnekliği arttırdığı kadar kapsamlı uygulamalardır. Ayrıca bug'ları önlediğini unutmamak gerekir. Yeteri kadar modüler bir kodda karşılaşılan hatanın diğer modüllerde debug sürecini zorlaştıran ve hatanın asıl kaynağını gizleyecek olan beklenmedik yanetkiler üretmeyecektir.
Debugging : Sonuç
Debug işlemi üzerinde fazlaca zaman harcarsanız, artık bu işten usanmaya başlarsınız. Kendinize bir yol çizmeni ve belli kalıpları(pattern) kullanmanız debug sürecini kolaylaştırır. Programcıların iş hayatındaki zamanlarının çoğunu bununla geçirdiği düşünüldüğünde bu kesinlike büyük bir dezavantaj. Programcılar arasında debug teknikleri üzerine ciddi ve derin bir araştırma yapmama tarzında bir eğilim var.
Ayrıca karşılaştığımız her bir debug işlemi üzerine biraz düşünmek, en hızlı ve akıllıca yolu bulmak iyi bir başlagıçtır ve buna değer.