Почему важно проверять ошибки при работе с базой данных и маршалингом
Что проверяют
Знаете ли конкретные места в database/sql и encoding/json, где пропущенная ошибка превращается не в падение, а в тихую порчу данных. Общие слова про важность обработки ошибок тут никого не устраивают.
Как отвечать
В Go ошибка это обычное возвращаемое значение, его легко не заметить. Опасность не в панике, а в том, что программа спокойно продолжает работать с неполными данными.
Больные места при работе с базой:
rows.Err()после цикла поrows.Next(). Цикл завершается и при обрыве соединения, без этой проверки получится молча укороченная выборка;tx.Commit()возвращает ошибку, и она бывает настоящей. Не проверили, значит ответили пользователю успехом, а транзакция откатилась;sql.ErrNoRowsуQueryRow().Scan()это не сбой, а «не нашли». Его сравнивают черезerrors.Isи переводят в свой ответ, а не в пятисотку;Execотдаёт число затронутых строк: ноль обновлённых часто и есть та самая ошибка.
С маршалингом похоже: json.Unmarshal вернёт ошибку при несовпадении типов, но отсутствующее поле молча оставит нулевое значение. json.Marshal падает на каналах, функциях, циклических ссылках и на нечисловых значениях с плавающей точкой.
Ошибки стоит оборачивать с контекстом через fmt.Errorf с глаголом %w, а наверху разбирать через errors.Is и errors.As.
Где спотыкаются
Глушат ошибку присваиванием в пустой идентификатор или не проверяют закрытие ресурса. Такие места находит errcheck в составе golangci-lint за секунды, обычно линтер просто не включён в проверку сборки.
Сравнивают ошибки по тексту сообщения. Текст меняется вместе с версией драйвера, и проверка тихо перестаёт срабатывать. Для этого есть типизированные ошибки, errors.Is и errors.As.
Пробрасывают ошибку наверх без единого слова контекста. На вершине остаётся EOF или сообщение про истёкший дедлайн, и непонятно, какой именно запрос отвалился. Обёртка через %w сохраняет и цепочку для сравнения, и смысл для человека.