Как правильно составлять сообщения об ошибках

ArgumentError: при назначении атрибутов вы должны передать хэш как аргумент
Assert Failed: значения в hash-map должны быть генераторами

Что не так с этими сообщениями об ошибках (и тысячами других, на них похожих)?

Что в них такого, что усложняет отладку приложения в несколько раз, особенно, если эти ошибки возникают в классе, который оборачивает какая-то используемая вами библиотека? Конечно, если стек вызовов уводит вас на двадцать уровней глубже вашего кода, то вы можете просмотреть все двадцать и таки найти ошибку, но ведь было бы гораздо лучше, если бы вам не пришлось этого делать?

Почему эта ошибка в CoffeeScript так часто появлялась в вопросах на StackOverflow?

[Mon Jun 08 2015 10:19:02 GMT+0100 (BST)] ERROR Unable to load /Users/tcrayford/proj/yeller/hubot/scripts/earl: SyntaxError: unmatched OUTDENT
  at exports.throwSyntaxError (/Users/tcrayford/proj/yeller/hubot/node_modules/hubot/node_modules/coffee-script/lib/coffee-script/helpers.js:197:13)
  at Lexer.exports.Lexer.Lexer.error (/Users/tcrayford/proj/yeller/hubot/node_modules/hubot/node_modules/coffee-script/lib/coffee-script/lexer.js:778:14)
  at Lexer.exports.Lexer.Lexer.pair (/Users/tcrayford/proj/yeller/hubot/node_modules/hubot/node_modules/coffee-script/lib/coffee-script/lexer.js:690:16)
  at Lexer.exports.Lexer.Lexer.outdentToken (/Users/tcrayford/proj/yeller/hubot/node_modules/hubot/node_modules/coffee-script/lib/coffee-script/lexer.js:378:16)
  at Lexer.exports.Lexer.Lexer.closeIndentation (/Users/tcrayford/proj/yeller/hubot/node_modules/hubot/node_modules/coffee-script/lib/coffee-script/lexer.js:550:19)
  at Lexer.exports.Lexer.Lexer.tokenize (/Users/tcrayford/proj/yeller/hubot/node_modules/hubot/node_modules/coffee-script/lib/coffee-script/lexer.js:34:12)
  at exports.compile.compile (/Users/tcrayford/proj/yeller/hubot/node_modules/hubot/node_modules/coffee-script/lib/coffee-script/coffee-script.js:35:36)
  at Object.loadFile (/Users/tcrayford/proj/yeller/hubot/node_modules/hubot/node_modules/coffee-script/lib/coffee-script/coffee-script.js:176:14)
  at Module.load (/Users/tcrayford/proj/yeller/hubot/node_modules/hubot/node_modules/coffee-script/lib/coffee-script/coffee-script.js:211:36)

Что, если бы каждая ошибка, которую вы встречали, будучи разработчиком, точно говорила вам, в чем проблема? Не просто почему что-то не работает, а что вы сделали такого, что это что-то перестало работать?

Контекст — наше все

Исправить проблему легко: достаточно лишь сделать так, чтобы в сообщении упоминался контекст, в котором произошла ошибка. Например:

ArgumentError: при назначении атрибутов вы должны передать хэш как аргумент,
но вы передали #<User id:12345 email:tom@example.com>

Может, это и отнимет у вас немного времени при разработке продукта, но оно окупится — каждый раз, когда кто-то совершит ошибку при написании кода, ему не надо будет тратить минуты и часы, чтобы разобраться в ней и исправить ее.

Особенно это важно для тех, кто только начинает использовать вашу библиотеку или фреймворк — порой сообщения об ошибках могут быть довольно пугающими, даже если они хорошо спроектированы, так что очень важно сделать их настолько понятными, насколько вы можете.

Для Clojure-истов: используйте ex-info

Следующая информация предназначена только для тех, кто пишет на Clojure. Используйте функцию ex-info при дизайне исключений и указании контекста:

(ex-info "какое-то сообщение об ошибке" {:wrong-args [1 2 3]})

Если инструмент, который вы используете в продакшене для трассировки исключений, понимает Clojure, то он автоматически выведет ex-data, т.е. весь нужный контекст. Кроме того, вы можете манипулировать ex-data как любыми другими данными, что особенно полезно при отладке сложных ошибок.

Как это касается меня?

Всякий раз, когда вы создаете исключение, или видите код, который делает это, включайте в сообщение об ошибке все локальные переменные, которые могут быть хоть как-то с ней связаны. Тем самым вы сэкономите другим разработчикам кучу времени и нервов, сами практически их не потратив.

Потратьте немного своего времени сейчас, чтобы сэкономить его себе и другим в будущем, и не повторяйте чужих ошибок.

Перевод статьи «The art of the good error message»