Как не надо использовать Assert, если реализуете подход Design by Contract
Использовать Assert вместо if err != nil { return err}
Одно из неправильных применений Assert — это замена им проверки, которая действительно должна быть и на которую нужно реализовать реакцию в коде.
Выполнять вычисления при вызове Assert
Еще одна распространенная и трудно выявляемая ошибка — это выполнение вычислений и присваивание значений переменным прямо при вызове Assert, которые могут быть упразднены при оптимизации кода компилятором:
e.g. Assert(i++ > 0, “осторожно, не факт, что в релизе i увеличится”),
Assert(call_to_f1(), “осторожно, не факт, что call_to_f1() будет вызвана в релизе”).
Удалять Assert, несмотря на то, что это часть описания контракта
Непонимание, что Assert — это реализация контракта, может привести к тому, что разработчик, незнакомый с DbC, захочет просто удалить проверку. Однако нужно всегда помнить, что срабатывание Assert говорит о нарушении контракта одной из сторон. То есть, если срабатывает Assert, надо прежде всего найти баг и пофиксить. А уж если контракт действительно должен быть изменен, Assert подскажет, где находятся участки кода, на которые нужно обратить внимание.
Например, вызывающая сторона может полагаться на некоторое поведение вызываемого кода. И если вызываемый код существенно изменился и контракт не выполнен, то вызываемая сторона тоже должна быть существенно переосмыслена.
В реализации пакета Go 1.23 fmt-функция Printf
всегда возвращает err = nil
. И практически все игнорируют возвращающееся значение ошибки, тогда как могли бы проверять постусловие assertion.Assert
(err == nil
). Так, рано или поздно в последующих версиях можно научить код реагировать на err, отличный от nil
.
Как правильно применять assertions, если реализуете подход Design by Contract для улучшения производительности кода в продакшене? Читайте в статье →