if err != nil: почему мы (не) любим обработку ошибок в Go? Обзор предложений по её улучшению
https://habr.com/ru/companies/avito/articles/944824/
Павел Агалецкий из Авито в очередной раз поднимает вечную холиварную тему — обработку ошибок в Go.
Суть проблемы (а вдруг кто-то не в курсе?🙃 ):
Go не использует исключения (exceptions) — ошибки это просто значения, которые функции возвращают наравне с другими. Код выглядит многословно:
Сравнение с другими языками:
- Python — исключения есть, но из сигнатуры непонятно, выбрасывает метод исключение или нет
- Java — есть checked exceptions, но большинство функций в языке и библиотеках их не декларируют, т.к. это необязательно
- Rust — есть тип
Что было предложено за годы существования Go:
На GitHub 195 закрытых и 14 открытых proposal по улучшению обработки ошибок. Автор группирует их:
1. check/handle — специальные ключевые слова, чтобы обрабатывать ошибки единообразно
2. try/catch — как в других языках
3. Спецсимволы (? или !) — вместо ключевых слов
4. Упрощение if — тернарные операторы и подобное
Все отклонялись по схожим причинам:
- Можно частично реализовать в userland (через panic/recover + defer)
- Ломается при оборачивании ошибок (fmt.Errorf)
- Появляется неявный control flow
- Код становится менее читаемым
Последний proposal от Ian Lance Taylor:
Ян предложил писать знак вопроса после функций, возвращающих ошибки:
С возможностью обработки:
Реакция сообщества неоднозначная, больше против. Дизлайков в полтора раза больше лайков.
Финал истории:
Robert Griesemer опубликовал статью в блоге Go, где команда объявила, что они больше не будут рассматривать предложения по изменению обработки ошибок. Решили, что на этапе создания языка стоило подумать лучше, но сейчас менять поздно — будет только хуже.
————
Автор делает правильные выводы:
Ошибки как обычные значения — это нормально, явная сигнатура — это хорошо, отсутствие исключений — это прекрасно. Да, многословно, но явно. Да, занимает много места, но зато всё понятно. А современные IDE с autocomplete (особенно с LLM) и code folding помогают справляться с многословностью (у меня в IDE вообще давно настроен хоткей для создания error handling блока:
Я полностью согласен. Лучше писать чуть больше, но понимать что происходит, чем получить "волшебный" синтаксис, который будет работать неявно. Go Team приняли мудрое решение — оставить всё как есть. Язык не должен становиться зоопарком из разных способов сделать одно и то же.
Да, в первые годы работы с Go мне тоже хотелось всячески его "облагородить", изобретать разные способы "упрощения" работы с ошибками, но со временем это проходит🙃
P.S. Мне кажется, что все эти годы сообщество пытается запихнуть в Go механики из других языков, вместо того чтобы просто принять философию Go🤡
#article #error_handling #proposals
https://habr.com/ru/companies/avito/articles/944824/
Павел Агалецкий из Авито в очередной раз поднимает вечную холиварную тему — обработку ошибок в Go.
Суть проблемы (а вдруг кто-то не в курсе?
Go не использует исключения (exceptions) — ошибки это просто значения, которые функции возвращают наравне с другими. Код выглядит многословно:
func doSomething() error {
if err := one(); err != nil {
return err
}
if err := two(); err != nil {
return err
}
if err := three(); err != nil {
return err
}
return nil
}
Сравнение с другими языками:
- Python — исключения есть, но из сигнатуры непонятно, выбрасывает метод исключение или нет
- Java — есть checked exceptions, но большинство функций в языке и библиотеках их не декларируют, т.к. это необязательно
- Rust — есть тип
Result<T, E>
и оператор ?
для проброса ошибок (более компактно)Что было предложено за годы существования Go:
На GitHub 195 закрытых и 14 открытых proposal по улучшению обработки ошибок. Автор группирует их:
1. check/handle — специальные ключевые слова, чтобы обрабатывать ошибки единообразно
2. try/catch — как в других языках
3. Спецсимволы (? или !) — вместо ключевых слов
4. Упрощение if — тернарные операторы и подобное
Все отклонялись по схожим причинам:
- Можно частично реализовать в userland (через panic/recover + defer)
- Ломается при оборачивании ошибок (fmt.Errorf)
- Появляется неявный control flow
- Код становится менее читаемым
Последний proposal от Ian Lance Taylor:
Ян предложил писать знак вопроса после функций, возвращающих ошибки:
func doSomething(in Dto) (err error) {
validate(in) ?
one() ?
two() ?
three() ?
return nil
}
С возможностью обработки:
validate(in) ? {
return fmt.Errorf("validation failed: %w", err)
}
Реакция сообщества неоднозначная, больше против. Дизлайков в полтора раза больше лайков.
Финал истории:
Robert Griesemer опубликовал статью в блоге Go, где команда объявила, что они больше не будут рассматривать предложения по изменению обработки ошибок. Решили, что на этапе создания языка стоило подумать лучше, но сейчас менять поздно — будет только хуже.
————
Автор делает правильные выводы:
Ошибки как обычные значения — это нормально, явная сигнатура — это хорошо, отсутствие исключений — это прекрасно. Да, многословно, но явно. Да, занимает много места, но зато всё понятно. А современные IDE с autocomplete (особенно с LLM) и code folding помогают справляться с многословностью (у меня в IDE вообще давно настроен хоткей для создания error handling блока:
CMD + J
).Я полностью согласен. Лучше писать чуть больше, но понимать что происходит, чем получить "волшебный" синтаксис, который будет работать неявно. Go Team приняли мудрое решение — оставить всё как есть. Язык не должен становиться зоопарком из разных способов сделать одно и то же.
Да, в первые годы работы с Go мне тоже хотелось всячески его "облагородить", изобретать разные способы "упрощения" работы с ошибками, но со временем это проходит
P.S. Мне кажется, что все эти годы сообщество пытается запихнуть в Go механики из других языков, вместо того чтобы просто принять философию Go
#article #error_handling #proposals
Please open Telegram to view this post
VIEW IN TELEGRAM
❤36👍23