GoSuda

Go'nun try-catch ile istisna fırlatmak yerine açık hata döndürme ve panic-recover mekanizmasını tercih etmesinin nedenleri

By Rabbit Princess views ...

Go, bilinçli bir tasarım tercihi olarak try-catch yapısını desteklemez; yalnızca panic-recover sözdizimini sunar. Bu durum, try-catch ile hata yönetimine alışkın pek çok geliştiricinin tepkisine yol açmaktadır. Peki try-catch neden eklenmemiştir? Bunun nedeni, try-catch'in birçok sorunu barındırmasıdır.

try-catch-finally

Try-catch (traykeç) yapısı, program çalışma zamanında (runtime) ortaya çıkabilecek hata durumlarını ve istisnai durumları ele almak için kullanılan bir yapıdır. Ayrıca finally bloğu, bir istisnanın meydana gelip gelmediğine bakılmaksızın mutlaka çalıştırılması gereken kodun yazıldığı yerdir.

Hata İşleme ve Sorumluluk

1980'li ve 1990'lı yıllarda hata işleme oldukça basitti. Hata mesajları yalnızca "disket dolu", "sürücüde disket yok" ve "disketa yazma izni yok" ifadelerinden ibaretti; bu dönemin geliştiricileri bir hata oluştuğunda, ilgili hatayı hata işleme noktasına kadar fırlatarak (throw) merkezi bir biçimde ele alıyordu. Bu koşullarda try-catch yapısı verimli biçimde çalışıyordu.

Ancak zamanla durum değişti. İş mantığı karmaşıklaştı, veritabanları ve işlemler (transaction) ortaya çıktı, ağ üzerinden çok sayıda API çağrısı yapılması ve bu sayede çok sayıda istek mesajının yorumlanması gerekti; hatta eşzamanlı programlamanın (concurrency) ortaya çıkmasıyla birlikte hataların ana iş parçacığı dışındaki iş parçacıklarında ele alınması gerekir hale geldi.

Hatalar artık tek bir noktada ele alınamayacak kadar karmaşıklaştı ve hiçbir tek noktanın tüm hatalardan sorumlu tutulması mümkün olmadı. İşte bu noktada try-catch ciddi bir sorunla karşılaşmaktadır.

try-catch'in Sorumluluğu Devretmesi

Try-catch, kısaca söylemek gerekirse, hatayı ortaya çıkaran öğenin, hatanın doğurduğu sorumluluğu (toparlama işlemlerini) başka birine devretme yöntemidir. Bu devredilen taraf catch bloğu olabileceği gibi, kendi üst metodu, onun da üst metodu, bir üst metodun üst metodunun üst metodunun.. herhangi biri de olabilir. Başka bir ifadeyle, hata yönetiminin giderek arttığı ve karmaşıklaştığı bir dünyada try-catch'in benimsediği yaklaşım tam olarak "birisi halleder" anlayışıdır. Aşağıdaki kodu inceleyelim:

1try {
2    data = readFile("hello.txt");
3    structuredData = parseData(data);
4    insertDBStatus(structuredData[1]);
5    startHTTPServer(structuredData[2]);
6} catch (Exception e) {
7    e.printStackTrace();
8}

Yukarıdaki kodun sorunu, printStackTrace çağrısını hangi öğenin üstlendiğinin açık olmaması ve hatanın hangi kodda meydana geldiğinin de anlaşılamamasıdır. Üstelik try bloğunun içindeki mantık arttıkça sorun daha da içinden çıkılmaz hale gelir. Paradoksal biçimde, geliştirme karmaşıklaştıkça geliştiriciler sorumluluğu devreden try-catch yapısına bağımlı hale geldi; hata yönetimi üzerine düşünmeyi bıraktılar, sorumluluk bilinci zayıfladı ve sonunda hata ve istisna yönetiminin özünü unuttular. Peki Golang bu sorunu nasıl çözdü?

panic, recover

Go'nun avantajlarından biri, geliştiriciyi yanlış yollara sürüklemeden onu iyi bir geliştirici haline getirmek için tasarlanmış birden fazla mekanizmaya sahip olmasıdır. Panic ve recover da bunun bir örneğidir.

Panic-recover, ilk bakışta try-catch'ten farklı görünmeyebilir; ancak bir sorun ortaya çıktığında sorumluluğu dışarıya aktarmaması bakımından ondan ayrılır. Go'da bir panic meydana geldiğinde, ilgili değer dışarıya aktarılmak yerine panic'in oluştuğu yerde çözülmelidir. Bu yaklaşım, geliştiriciye hata yönetimi sorumluluğunu yükleyerek, ilgili hatanın nerede, kim tarafından ve nasıl ele alınması gerektiği üzerine daha derinlemesine düşünmesini teşvik eder. Kullanıcıya özerklik tanırken ona düşünme alanı bırakmış olur.

Ayrıca "panic" kelimesinin seçimi de oldukça yerinde sayılabilir. Try-recover'ın aksine panic-recover, yalnızca kelimenin kendisi bile geliştiriciye istisnai durumlar değil, açık hata durumları için kullanılması gerektiğini hissettirir. Bu sayede geliştirici recover'ı gereksiz yere kullanmaktan kaçınır ve yalnızca gerektiği yerlerde kullanır. Bu da Go'da sade bir kod yazmaya büyük katkı sağlar.