Exception: İstisnalar ve İstisnai Durumlar

Yine uzunca bir aradan sonra yeniden blog yazmaya vakit bulabildim. Geçtiğimiz ay işlerimizde asırı bir yoğunluk vardı. Bu nedenle, çok sayıda konu biriktiği halde blog yazacak vakit bulamadım. Bu ay telafi etmeye çalışacağım.

Biriken konular arasında ilk bahsetmek ıstediğim, başlıktan da anlaşılacağı üzere .NET "exception"ları. "Exception"ların ne olduğundan bahsetmeyeceğim, çünkü .NET uygulaması geliştirmiş olan herkes mutlaka bunu biliyordur. Ancak pek bilinmeyen birşey, "exception" "throw" etmenin ne kadar pahalı bir iş olduğudur.

Uygulama geliştirirken, özellikle de ASP.NET uygulamaları geliştirirken, sorun yaşanabilecek yani hata alınabilecek her kod parçasını "try" bloğunda tutarız. Genelde hata durumunda almak istediğimiz aksiyon için de "catch" bloğunu kullanırız. Böylece beklenmedik bir sorun oluştuğunda, bu sorunun kullanıcılara yansımasını ve uygulamanın çalışmasının kesintiye uğramasını önlemiş oluruz. Buradaki kritik kelime "beklenmedik" kelimesidir. "Exception"lar, beklenmedik durumlardır, yani istisnai durumlardır. Ancak çok yaygın bir şekilde bunları yanlış kullanırız.

Yanlış kullanıma çok sık rastladığım bir örnek şudur:

try
{
Label1.Text = Session["kullanici"].ToString();
}
catch (Exception ex)
{
Response.Redirect("login.aspx");
}

Pek çok web uygulamasında, sayfamızın bir yerinde, o an uygulamaya logon olmuş kullanıcının adını gösteririz.Bu bilgiyi de çoğu zaman "session"da tutarız. Bu açıdan bakınca yukarıdaki kod parçası son derece normal ve hatta masum görünüyor; ama değil.

Session bilgisi bir nedenle yok olmuş veya zaman aşımına uğramış bir kullanıcının bu sayfaya istekte bulunduğunu düşünelim. "try" bloğundaki kodumuz NullReferenceException döneceğinden "catch" bloğuna girilip kullanıcı login.aspx sayfasına yönlendirilecektir. Aşağıdaki kod parçası da tıpatıp aynı kontrolü ve işlemi yapmaktadır:

if (Session["kullanici"] != null)
{
Label1.Text = Session["kullanici"].ToString();
}
else
{
Response.Redirect("login.aspx");
}

O zaman bu iki kod parçası arasındaki fark nedir? Bu iki koddan ilki, ikinciye oranla yuzlerce kat daha fazla CPU kullanarak bu işi gerçekleştirecektir. İşte en başta "exception throw etmek pahalı bir iştir" derken kastettiğim şey tam olarak da buydu. Eğer bir işi, bir "exception" oluşmadan yapabiliyorsak, mutlaka o yolu kullanalım.

Yukarıdaki örnek kodları kullanarak hazırladığım iki web uygulamasını aynı ortamda tabi tuttuğum yük testlerine göre, birincisi saniyede 30 isteğe ortalama 1.2 saniyede yanıt verebilirken, ikincisi saniyede ortalama 45 isteğe ortalama 0.9 saniyede yanıt verebilmektedir.

SONUÇ:

Uygulamalarımızı geliştirirken, beklenmedik hatalara karşı try/catch kullanalım. Ancak "exception" oluşmasını engelleyebileceğimiz her noktada bunun önüne geçecek şekilde kod yazalım. Bu arada yanlış anlaşılmaların önüne geçmek için şunu da belirtmeliyim: CPU açısından pahalı olan şey try/catch kullanmak değil, exception yaratmaktır.

Uygulmamız hakkında bu noktada bize fikir verebilecek olan şey, "" isimli performans sayacıdır. Bunun değeri ideal ortamda hep 0 (sıfır) olmalıdır, ancak elbette bu mümkün değildir. Bu sayacın değerini mümkün olan en düşük seviyede (saniyede 1-2 gibi) tutmanızı önereceğim.

CENK ISCAN