Debug yapmak derde deva mı yoksa cefa mı ?

Uzun süredir ara verdiğim blog yazılarına bu yazıyla yeniden başlama niyetindeyim. İlk konu olarak da sevdiğim bir konu olan Debug ile başlamak istedim. Umarım arkası da gelir :)  İşe Debug kavramını tanımlayarak başlayalım: Debug, bir yazılımda beklenilenin dışında çalışan, kodun çalışmasına engel olan veya olması muhtemel hataların saptanması ve kaldırılması sürecidir. Debug bir yazılım veya sistemin hatalı çalışmasını önlemek için hata veya kusurların bulunup çözülmesi için yapılır. Küçük boyutlu yazılımlarda debug ile hata ayıklama nispeten kolayken; alt sistem veya modüllerden oluşan bir yazılımın debug edilmesi daha zor ve vakit alıcı olacaktır. Bu durumda bir modülden yapılan herhangi bir değişikliğin diğer modüllerde hataya sebep olabileceğinden, debug ve etki analizi daha da önemli bir hale gelmektedir. Etki analizi demişken unit testlerin yazılmazı ve ölçeklenebilirlik konularının ayrı bir yazı konusu olduğunu ekleyerek yazımıza devam edelim.

Birkaç ay önce twitter’da sektördeki bir çok insanın görüş bildirdiği bir Debug yapılmalı mı ? yapılmamalı mı ? minvalinde bir tartışma başladı.

Her şey bu tweetle başladı :) Ve twitterda bizim sektörde gördüğüm en çok görüş bildirilen tartışmalaradan biri böylece start aldı 😀

Gerçekten de debug yapıyorsak; kodu anlamamış mı oluyorduk. Debug yaparken kodu anladığımızı düşünüyorsak, aslında debuga ihtiyacımız yok mudur ? şeklinde soruları soran bir tweetti. Oldukça iddialı bir fikir olsa da oluşturduğu tartışma ortamı açısından faydalı bir tweet oldu. Bu fikre destekleyen kullanıcılar olduğu kadar çoğu kullanıcı da kendi argümanlarıyla bu fikirlere karşı çıktı.

Debug yapmayla ilgili bu faydalı tartışmayı geride bıraktığımıza göre şimdi yazımızın esas konusu olan Debug ve debug pratiklerine gelebiliriz.

Debug yapmanın faydalı olduğunu düşünen biri olarak yazının bu kısmından sonrası bunun gerekçelerini anlatmaya çalışacağım. Debug (hata ayıklama), kodun satır satır nasıl işlediğini gösterir. Bir nevi kodun sonuca hangi adımlardan geçerek gittiğini bize gösterir. Sonuca giden yolu bulmanın daha kolay yolları da olabilir.

Eğer kodumuz standartlara uygun yazılmış, okunabilir bir kod ise debug yapmaya gereksinim duymadan da kodun nasıl çalıştığını görebiliriz. Küçük sistemler ya da kod blokları için bu mümkündür. Ancak büyük sistemlerde kod okunur olsa bile kodun çalışma mantığını kavramak daha zor olabilir. Üstelik debug yapmadan birbirini çağıran kod bloklarını okuyarak ne yaptığını anlamaya çalışmak vaktimizin boşa geçmesine neden olabilir. Çünkü kodu gözle okurken kodun çalışmasını engelleyen bir durumu göremeyebiliriz. Kodu okurken yeterli gördüğümüz kontrollerden birini kod hata veriyor olabilir. O yüzden debug yapmayı son başvurulacak çözümlerden biri olarak görmüyor; aksine bir çok zamanlar ilk başvurduğum inceleme şekli oluyor. İki durumda debugger’ı kullanıyorum.

  1. Mevcut, çalışmakta olan bir kodu devraldığımda
  2. Hata ayıklamada

Bir projeye sonradan dahil olduğunuzda ya da know-how bilgisine sahip birisi olmadığında kodun nasıl çalıştığını, hangi aşamalardan geçtiğini görmek için debug etmeyi tercih ediyorum.

Hata ayıklamada ise öncelikle exception veya log bilgisinden hatanın sebebini anlamaya, kodun hata verdiği kısmı incelemeye çalışıyorum. İlk aşamada problemi tespit edemeyince case’i oluşturarak debug yapıyorum.  Daha önceden bilmediğim bir sistemde debug yapıp sonuç elde edince keşif yapmış gibi mutlu oluyorum :) Tabii bir de mutsuz eden sonuç vermeyecek debug süreçleri oluyor. Özellikle karmaşık sistemlerde debug yapmak bazen o ihtiyaç için gerekli yazılımı yapmaktan daha uzun süre alabiliyor.

Verimli ve etkili debug yapabilmek için bazı adımlar var: Kimisi altı kimisi yedi adım diyor. Yazmaya başlayalım bakalım kaç olacak :)

  1. Problemi gerçekleştirebiliyor, yeniden oluşturabiliyor olmak. (Benim localde çalışıyor diyenler; haklısınız bende de çalışıyor ama hep çalışması gereken kişilerde çalışmıyor )              
  2. Hatayı kullanıcısından  tanımla : Hatayla karşılaşılan kullanıcıdan hatayı hangi aşamalarda, hangi işlemi yaparken aldığını anlamak. Hatanın kesin nedenini tam anlamak için kullanıcıdan mümkün olduğu kadar detay almaya çalışın.
  3. Hata alındığındaki durumda olan durumu not et. Programında tüm değişken değerlerini ve durumlarını o anda almaya çalışın
  4. Hatayı oluştur.
  5. Bir üst maddedeki duruma göre analizi yaparak hatayı bulmaya çalışın.
  6. Mevcut hatayı fixleyin             
  7. Testlerinizle hatanın fixlendiğine emin olun.
  8. Çalışmanızın yeni bir hataya sebep olmadığını kontrol edin.
  9. Son olarak bu çalışmanızı bir yere not alarak dökümante edin. Daha sonra benzer problemlerle karşılaşıldığında hızlı aksiyon alınmasını sağlar.

Debugdan bahsettiğimiz bu yazıda doğru hata mesajları fırlatmanın önemine değinmemek olmaz. Öncelikle mümkün mertebe hataya sebep olabilecek caselerin kontrol yapılarıyla kontrol edilmesi sağlanmalıdır. Öngörülemeyen durumlarda ise  exception döndürmemiz gerekiyor. Exceptionları doğru şekilde fırlatmak üst katman, log ve son kullanıcıda anlaşılır olacak şekilde handle edilmesi problemin sebebini hızlıca saptama noktasında oldukça fayda sağlayabilir. En basitinden ex’ı döndürmek yerine ex. Message şeklinde dönüş yapılması küçük, basit görünse de mesajın daha çabuk anlaşılmasını sağlayacaktır. Ayrıca hata ayıklama da try catch ile kontrollerin yapılmasındansa kontrol yapılarıyla kontrollerin yapılması performansa da olumlu yönde katkı sunacaktır.

O sebeple öngörülen tüm hata case’lerinin kontrol yapılarıyla kontrol edilmesi, öngörülemeyen caseler için exception fırlatılması tercih edilmelidir. Burada da direkt Exception yerine belli amaçlara hizmet eden exception class’larının fırlatılması daha doğru olacaktır.

Yazının son bölümünde ise  debug yapanların aşikar olduğu Visual Studio’nun bir kaç özelliğinden bashetmek istiyorum.

Breakpoint: Breakpoint, Debug’un temel taşı diyebiliriz. Kodun execute zamanında durmasını istediğimiz kısımda durmasını sağlar. Uygulamanızın çalışması esnasında süreç bu kod satırına geldiğinde durur. Debug adımlarıyla bundan sonraki sürecin işleyişi kontrol edilir.

Condition :  Breakpoint konulan satırda belli şartlar sağlandığında durmasını sağlar.
Watch window: Değişkenlerin değerlerinin görüntülenebileceği kısımdır.
Locals window: Lokal değişkenlerin değerlerini gösteren kısımdır.

Immediate Window: Değişkenleri görüntüleme, kod yazabileceğimiz penceredir.
CallStack : Stack içerisinde kullanılan fonksiyonları görüntülemimizi sağlar. Bu sayede sürecin nasıl olduğumuz noktaya geldiğini görebiliriz.

Kaynak :

https://www.codementor.io/mattgoldspink/how-to-debug-code-efficiently-and-effectively-du107u9jh

https://economictimes.indiatimes.com/definition/debugging

Leave a Reply