Por que Go não possui Try-Catch?
Go não suporta intencionalmente try-catch, apenas a sintaxe panic-recover. Isso tem gerado reclamações de muitos desenvolvedores que estão acostumados a lidar com erros usando try-catch. Então, por que o try-catch não é incluído? É porque o try-catch tem vários problemas.
try-catch-finally
A construção try-catch é usada para lidar com erros e exceções que podem ocorrer durante a execução do programa (runtime). Além disso, a construção finally especifica o código que deve ser executado incondicionalmente, independentemente de ocorrer ou não uma exceção.
Tratamento de Erros e Responsabilidade
Nas décadas de 80 e 90, o tratamento de erros era muito simples. As mensagens de erro eram apenas 'Disquete cheio', 'Nenhum disquete na unidade', 'Sem permissão de escrita no disquete', e os desenvolvedores da época, quando ocorria um erro, lançavam o erro (throw) até o ponto de tratamento de erros para processá-lo de forma comum. Em tais situações, a construção try-catch funcionava de forma eficiente.
No entanto, com o tempo, a situação mudou. A lógica de negócios tornou-se mais complexa, surgiram bases de dados e transações, foi necessário interpretar inúmeras mensagens de requisição ao chamar inúmeras APIs através da rede e, com o advento da programação concorrente, tornou-se necessário processar erros em threads diferentes do principal.
Os erros tornaram-se tão complexos que não podiam mais ser tratados num único local e ninguém podia ser responsabilizado por todos os erros. É aqui que surge um problema sério com o try-catch.
A Transferência de Responsabilidade do try-catch
O try-catch, em suma, é uma forma de a entidade que causou o erro transferir a responsabilidade (o cleanup) da ocorrência do erro para outra pessoa. O destinatário pode ser a construção catch, o seu método pai, o pai do seu pai, o pai do pai do pai, o pai do pai do pai do pai.. alguém. Em outras palavras, num mundo onde o tratamento de erros se torna mais numeroso e complexo, o método escolhido pelo try-catch é precisamente 'alguém irá fazer'. Veja o código abaixo.
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}
O problema do código acima é que não está claro quem é o responsável por processar o printStackTrace e também não se sabe em qual código o erro ocorreu. Além disso, quanto mais lógica houver dentro da declaração try, mais terrível se torna o problema. Mas, paradoxalmente, à medida que o desenvolvimento se torna mais complexo, os desenvolvedores se tornaram viciados na construção try-catch que transfere a responsabilidade, não refletem sobre o tratamento de erros, a sua consciência de responsabilidade também diminuiu e, no final, esqueceram a essência do tratamento de erros e exceções. Então, como o golang resolveu este problema?
panic, recover
Uma das vantagens do go é que existem vários sistemas para tornar os desenvolvedores bons, em vez de levá-los por maus caminhos. panic - recover também é um exemplo disso. À primeira vista, panic e recover não parecem diferir do try-catch, mas a diferença é que, quando surge um problema, a responsabilidade não é transferida para o exterior. Quando ocorre um panic em go, em vez de passar o valor para o exterior, o problema deve ser resolvido no local onde ocorreu o panic. Isso responsabiliza os desenvolvedores pelo tratamento de erros, levando-os a considerar mais profundamente onde, quem e como o erro deve ser tratado. É como garantir autonomia aos utilizadores e, ao mesmo tempo, deixar espaço para reflexão.
Além disso, a seleção da palavra panic também é considerada excelente, pois, ao contrário de try-recover, panic-recover impõe aos desenvolvedores, apenas com as palavras, a pressão de que ela só deve ser usada em situações de erro claras e não em situações de exceção. Naturalmente, os desenvolvedores não usarão recover em excesso e a usarão apenas quando necessário. Isso é de grande ajuda para escrever código conciso em go.