GoSuda

Почему в Go нет Try-Catch?

By Rabbit Princess
views ...

go намеренно не поддерживает try-catch, а поддерживает только синтаксис panic-recover. Это вызывает недовольство у многих разработчиков, привыкших к обработке ошибок с помощью try-catch. Так почему же try-catch не включен? Потому что try-catch имеет ряд проблем.

try-catch-finally

Конструкция try-catch предназначена для обработки ошибок и исключительных ситуаций, которые могут возникнуть во время выполнения программы (runtime). Кроме того, в блоке finally записывается код, который должен быть выполнен независимо от того, возникло исключение или нет.

Обработка ошибок и ответственность

В 80-х и 90-х годах обработка ошибок была очень простой. Сообщения об ошибках ограничивались фразами типа «гибкий диск заполнен», «в дисководе нет гибкого диска», «нет прав на запись на гибкий диск», и разработчики того времени, когда возникала ошибка, передавали ее (throw) до точки обработки ошибок для унифицированной обработки. В таких условиях конструкция try-catch работала эффективно.

Однако со временем ситуация изменилась. Бизнес-логика усложнилась, появились базы данных и транзакции, приходилось вызывать множество API через сеть и интерпретировать множество сообщений запросов, и даже с появлением параллельного программирования ошибки приходилось обрабатывать в других потоках, а не в основном.

Ошибки стали настолько сложными, что их больше невозможно было обрабатывать в одном месте, и ни одно место не могло нести ответственность за все ошибки. Здесь возникает серьезная проблема с try-catch.

Перекладывание ответственности в try-catch

try-catch, одним словом, это способ, с помощью которого субъект, вызвавший ошибку, перекладывает ответственность (за последующие действия) за ее возникновение на кого-то другого. Этим «кем-то» может быть блок catch, или его родительский метод, или родитель родителя родителя родителя... кто угодно. Другими словами, в мире, где обработка ошибок становится все более многочисленной и сложной, try-catch выбирает подход «кто-нибудь это сделает». Рассмотрим следующий код.

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}

Проблема вышеуказанного кода заключается в том, что неясно, кто обрабатывает printStackTrace, и невозможно узнать, в каком коде произошла ошибка. Более того, чем больше логики появляется внутри оператора try, тем ужаснее становится проблема. Но парадоксально, чем сложнее становилась разработка, тем больше разработчики «подсаживались» на try-catch, перекладывающий ответственность, не задумывались об обработке ошибок, их чувство ответственности ослабевало, и в конечном итоге они забывали о сути обработки ошибок и исключений. Так как же golang решил эту проблему?

panic, recover

Одним из преимуществ go является наличие различных систем, предназначенных для того, чтобы не дать разработчикам пойти по плохому пути и сделать их хорошими разработчиками. panic-recover также можно привести в качестве примера. ​ Panic и recover на первый взгляд кажутся ничем не отличающимися от try-catch, но они отличаются тем, что при возникновении проблемы они не перекладывают ответственность на внешнюю сторону. Когда в go происходит panic, вместо того чтобы передавать это значение наружу, проблему следует решать в том месте, где произошел panic. Это возлагает на разработчика ответственность за обработку ошибки, побуждая его более глубоко задуматься о том, где, кто и как должна быть обработана эта ошибка. Это обеспечивает автономию пользователя, оставляя при этом пространство для размышлений.

Кроме того, выбор слова «panic» также можно считать очень удачным: в отличие от try-recover, panic-recover уже одним словом накладывает на разработчика давление, указывая, что его следует использовать только в явных ошибочных ситуациях, а не в исключительных. Естественно, разработчик не злоупотребляет recover и использует его только там, где это необходимо. Это значительно помогает писать лаконичный код в go.