De ce nu există Try-Catch în Go?
Go nu suportă în mod intenționat try-catch, ci doar sintaxa panic-recover. Acest lucru atrage nemulțumirea multor dezvoltatori obișnuiți cu gestionarea erorilor prin try-catch. Atunci, de ce nu a fost inclus try-catch? Motivul este că try-catch prezintă multiple probleme.
try-catch-finally
Instrucțiunea try-catch este utilizată pentru a gestiona situațiile de eroare și excepție care pot apărea în timpul execuției programului (runtime). În plus, instrucțiunea finally conține codul care trebuie executat indiferent dacă o excepție a apărut sau nu.
Gestionarea erorilor și responsabilitatea
În anii '80 și '90, gestionarea erorilor era foarte simplă. Mesajele de eroare erau limitate la „Dischetă plină”, „Nicio dischetă în unitate” sau „Permisiuni de scriere dischetă insuficiente”, iar dezvoltatorii din acea perioadă gestionau erorile prin aruncarea acestora (throw) către un punct comun de gestionare. În acest context, instrucțiunea try-catch funcționa eficient.
Totuși, odată cu trecerea timpului, situația s-a schimbat. Logica de business a devenit mai complexă, au apărut baze de date și tranzacții, a fost necesară interpretarea a numeroase mesaje de cerere prin apeluri API peste rețea, și chiar și cu apariția programării concurente, erorile trebuiau gestionate în fire de execuție diferite de cel principal.
Erorile au devenit prea complexe pentru a fi gestionate într-un singur loc, iar nicio entitate nu mai putea fi responsabilă pentru toate erorile. Aici apare o problemă serioasă cu try-catch.
Transferul responsabilității în try-catch
Try-catch, într-un cuvânt, este o metodă prin care entitatea care a cauzat eroarea transferă responsabilitatea (gestionarea ulterioară) către altcineva. Această entitate poate fi clauza catch, metoda sa părinte, sau părintele părintelui părintelui părintelui său... Cu alte cuvinte, într-o lume în care gestionarea erorilor devine tot mai abundentă și complexă, abordarea try-catch este pur și simplu „cineva o va rezolva”. Să analizăm codul de mai jos.
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}
Problema cu codul de mai sus este că nu este clar cine este entitatea care procesează printStackTrace, și nici nu se poate determina din ce parte a codului a provenit eroarea. Mai mult, pe măsură ce logica din instrucțiunea try devine mai extinsă, problema se agravează. Însă, în mod paradoxal, pe măsură ce dezvoltarea a devenit mai complexă, dezvoltatorii au devenit dependenți de instrucțiunea try-catch care transferă responsabilitatea, neglijând reflecția asupra gestionării erorilor, diminuându-și simțul responsabilității și, în cele din urmă, uitând esența gestionării erorilor și excepțiilor. Atunci, cum a rezolvat golang această problemă?
panic, recover
Unul dintre avantajele Go este că include diverse sisteme menite să transforme dezvoltatorii în profesioniști buni, evitând căile greșite. Panic-recover este un exemplu în acest sens.
La prima vedere, panic și recover par să nu difere de try-catch, dar se deosebesc prin faptul că nu transferă responsabilitatea către exterior atunci când apare o problemă. În Go, atunci când se produce un panic, rezolvarea trebuie să aibă loc în locația unde a apărut panicul, mai degrabă decât să se transfere valoarea către exterior. Acest lucru impune dezvoltatorului responsabilitatea gestionării erorilor, încurajându-l să reflecteze mai profund asupra locului, persoanei și modului în care eroarea ar trebui gestionată. Astfel, se oferă autonomie utilizatorului, lăsând totodată loc pentru reflecție.
De asemenea, alegerea termenului „panic” este remarcabilă; spre deosebire de try-recover, panic-recover impune dezvoltatorului, doar prin denumire, presiunea de a-l utiliza numai în situații clare de eroare, nu doar în cazuri de excepție. În mod natural, dezvoltatorii nu abuzează de recover și îl utilizează doar acolo unde este necesar. Acest lucru contribuie semnificativ la scrierea unui cod concis în Go.