Go'da Neden Try-Catch Yok?
Go, kasıtlı olarak try-catch'i desteklemez ve yalnızca panic-recover sözdizimini destekler. Bu durum, try-catch kullanarak hata işlemeye alışkın olan çok sayıda geliştiricinin tepkisine yol açmaktadır. Peki, neden try-catch eklenmiyor? Bunun nedeni, try-catch'in çeşitli sorunlara sahip olmasıdır.
try-catch-finally
Try-catch ifadesi, program çalışırken (runtime) meydana gelebilecek hata durumlarını ve istisnai durumları ele almak için kullanılan bir ifadedir. Ayrıca, finally ifadesi, istisna oluşup oluşmamasına bakılmaksızın mutlaka çalıştırılması gereken kodu içerir.
Hata İşleme ve Sorumluluk
1980'lerde ve 1990'larda hata işleme çok basitti. Hata mesajları sadece 'Disk dolu', 'Sürücüde disk yok' veya 'Diske yazma izni yok' şeklindeydi ve o dönemdeki geliştiriciler bir hata oluştuğunda, hatayı hata işleme noktasına kadar throw ederek ortak bir şekilde işlerlerdi. Bu durumda try-catch ifadesi verimli bir şekilde çalışıyordu.
Ancak, zamanla durum değişti. İş mantığı karmaşıklaştı, veritabanları ve işlemler ortaya çıktı ve ağ üzerinden çok sayıda API çağrılırken çok sayıda istek mesajı ayrıştırılması gerekiyordu ve hatta eşzamanlı programlamanın ortaya çıkmasıyla ana olmayan diğer iş parçacıklarında hatalar işlenmek zorundaydı.
Hatalar artık tek bir yerde işlenemeyecek kadar karmaşık hale geldi ve hiç kimse tüm hatalardan sorumlu olamazdı. İşte burada try-catch'te ciddi bir sorun ortaya çıkıyor.
try-catch'in Sorumluluk Devri
Try-catch, kısacası, hatayı tetikleyen tarafın, hata oluşumuna ilişkin sorumluluğu (sonrası) başkasına devretme yöntemidir. Bu devredilen taraf catch ifadesi olabilir, kendi üst metodu olabilir, kendi üstünün üstünün üstünün üstünün... birisi olabilir. Başka bir deyişle, hata işlemenin arttığı ve karmaşıklaştığı bir dünyada, try-catch'in seçtiği yöntem tam olarak 'birisi yapacaktır' şeklindedir. Aşağıdaki koda bakalım.
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'i işleyen tarafın ne olduğunun net olmaması ve hangi kodda hata olduğunun bilinememesidir. Hatta try ifadesinin içinde daha fazla mantık oluşursa sorun daha da korkunç hale gelir. Ancak ironik bir şekilde, geliştirme karmaşıklaştıkça geliştiriciler sorumluluğu devreden try-catch ifadesine bağımlı hale geldi, hata işleme konusunda düşünmeyi bıraktı, sorumluluk bilinci de zayıfladı ve sonuç olarak hata ve istisna işlemenin özünü unuttu. Peki, golang bu sorunu nasıl çözdü?
panic, recover
Go'nun avantajlarından biri, geliştiricilerin kötü yollara sapmasını engelleyerek onları iyi geliştiriciler yapmaya yönelik birçok sisteminin olmasıdır. Panic - recover da buna örnek olarak gösterilebilir.
Panic ve recover ilk bakışta try-catch'ten farklı görünmeyebilir, ancak bir sorun ortaya çıktığında, sorumluluğu dışarıya devretmemeleri bakımından farklıdırlar. Go'da bir panic meydana geldiğinde, bu değeri dışarıya devretmek yerine, panic'in meydana geldiği konumda çözülmesi gerekir. Bu, geliştiriciye hata işleme sorumluluğu vererek, hatanın nerede, kimin ve nasıl ele alınması gerektiğini daha derinlemesine düşünmesine neden olur. Kullanıcıya özerklik sağlarken, aynı zamanda düşünmesi için yer bırakır.
Ayrıca, panic kelimesinin seçimi de oldukça başarılıdır denebilir; try-recover'dan farklı olarak panic-recover, kelime olarak bile geliştiriciye yalnızca istisnai durumlarda değil, açık hata durumlarında kullanılmak zorunda olduğu baskısını yapar. Geliştirici doğal olarak recover'ı kötüye kullanmaz ve yalnızca gerektiğinde kullanır. Bu, go'da sade kod yazmaya büyük katkı sağlar.