Введение проверки утверждения
Здесь и далее под проверками подразумеваются вызовы функции
assert
.
Проблема
Корректная работа участка кода предполагает наличие каких-то определённых условий или значений.
Решение
Замените эти предположения конкретными проверками.
double getExpenseLimit() {
// Should have either expense limit or
// a primary project.
return (expenseLimit != NULL_EXPENSE) ?
expenseLimit :
primaryProject.getMemberExpenseLimit();
}
double getExpenseLimit() {
Assert.isTrue(expenseLimit != NULL_EXPENSE || primaryProject != null);
return (expenseLimit != NULL_EXPENSE) ?
expenseLimit:
primaryProject.getMemberExpenseLimit();
}
double GetExpenseLimit()
{
// Should have either expense limit or
// a primary project.
return (expenseLimit != NULL_EXPENSE) ?
expenseLimit :
primaryProject.GetMemberExpenseLimit();
}
double GetExpenseLimit()
{
Assert.IsTrue(expenseLimit != NULL_EXPENSE || primaryProject != null);
return (expenseLimit != NULL_EXPENSE) ?
expenseLimit:
primaryProject.GetMemberExpenseLimit();
}
function getExpenseLimit() {
// Should have either expense limit or
// a primary project.
return ($this->expenseLimit !== NULL_EXPENSE) ?
$this->expenseLimit:
$this->primaryProject->getMemberExpenseLimit();
}
function getExpenseLimit() {
assert($this->expenseLimit !== NULL_EXPENSE || isset($this->primaryProject));
return ($this->expenseLimit !== NULL_EXPENSE) ?
$this->expenseLimit:
$this->primaryProject->getMemberExpenseLimit();
}
def getExpenseLimit(self):
# Should have either expense limit or
# a primary project.
return self.expenseLimit if self.expenseLimit != NULL_EXPENSE else \
self.primaryProject.getMemberExpenseLimit()
def getExpenseLimit(self):
assert (self.expenseLimit != NULL_EXPENSE) or (self.primaryProject != None)
return self.expenseLimit if (self.expenseLimit != NULL_EXPENSE) else \
self.primaryProject.getMemberExpenseLimit()
getExpenseLimit(): number {
// Should have either expense limit or
// a primary project.
return (expenseLimit != NULL_EXPENSE) ?
expenseLimit:
primaryProject.getMemberExpenseLimit();
}
getExpenseLimit(): number {
// TypeScript and JS doesn't have built-in assertions, so we'll use
// good-old console.error(). You can always extract this into a
// designated assertion function.
if (!(expenseLimit != NULL_EXPENSE ||
(typeof primaryProject !== 'undefined' && primaryProject))) {
console.error("Assertion failed: getExpenseLimit()");
}
return (expenseLimit != NULL_EXPENSE) ?
expenseLimit:
primaryProject.getMemberExpenseLimit();
}
Причины рефакторинга
Участок кода создает предположения о чем-то (например, о текущем состоянии объекта, значении параметра или локальной переменной). Обычно это предположение никогда не будет нарушено разве что при наличии какой-то ошибки.
Сделайте эти предположения явными, добавив соответствующие проверки. Как и подсказки типов в параметрах методов, эти проверки могут играть роль живой документации кода.
Хорошим признаком того, что нужна проверка каких-то условий, являются комментарии в коде. Если вы видите комментарии, описывающие условия, при которых метод корректно работает, значит здесь неплохо было бы вставить проверку-утверждение этих условий.
Достоинства
- Если какое-то предположение неверно и в результате код производит также неверный результат, лучше сразу остановить выполнение, пока это не привело к фатальным последствиям и порче данных. Кроме того, это означает, что вы упустили написание какого-то теста в наборе тестов вашей программы.
Недостатки
-
Иногда вместо простой проверки лучше вставить исключение. При этом вы можете выбрать необходимый класс исключения и дать остальному коду возможность корректно его обработать.
-
В каких случаях исключение лучше простой проверки? Если к нему может привести деятельность пользователя или системы, и вы можете обработать это исключение. С другой стороны, обычные безымянные необрабатываемые исключения равносильны простым проверкам — вы их не обрабатываете, они могут быть вызваны только как результат бага в программе, который никогда не должен был возникнуть.
Порядок рефакторинга
Когда вы видите, что предполагается какое-то условие, добавьте проверку этого условия, чтобы проверить его наверняка.
Добавление проверки не должно изменять поведение программы.
Не перебарщивайте с использованием проверок для всего, что только можно, на выбранном участке кода. Нужно проверять лишь те условия, без которых код перестанет корректно работать. Если ваш код нормально работает, в том числе, в случае, когда проверка не проходит успешно, такую проверку можно убрать.