Также известен как Replace Error Code with Exception

Рефакторинг Замена кода ошибки исключением

Проблема

Метод возвращает определенное значение, которое будет сигнализировать об ошибке.

Решение

Вместе этого следует выбрасывать исключение.
До
int withdraw(int amount) {
  if (amount > _balance) {
    return -1;
  }
  else {
    balance -= amount;
    return 0;
  }
}
После
void withdraw(int amount) throws BalanceException {
  if (amount > _balance) {
    throw new BalanceException();
  }
  balance -= amount;
}
До
int Withdraw(int amount) 
{
  if (amount > _balance) 
  {
    return -1;
  }
  else 
  {
    balance -= amount;
    return 0;
  }
}
После
///<exception cref="BalanceException">Thrown when amount > _balance</exception>
void Withdraw(int amount)
{
  if (amount > _balance) 
  {
    throw new BalanceException();
  }
  balance -= amount;
}
До
function withdraw($amount) {
  if ($amount > $this->balance)
    return -1;
  else {
    $this->balance -= $amount;
    return 0;
  }
}
После
/**
 * (Here you put some real function documentation.
 *  Note: the line below indicates that function
 *  can throw an exception of given type.)
 * @throws BalanceException
 */
function withdraw($amount) {
  if ($amount > $this->balance) {
    throw new BalanceException();
  }
  $this->balance -= $amount;
}
До
def withdraw(self, amount):
    if amount > self.balance:
        return -1
    else:
        self.balance -= amount
    return 0
После
def withdraw(self, amount):
    if amount > self.balance:
        raize BalanceException()
    self.balance -= amount

Причины рефакторинга

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

Достоинства

  • Избавляет код от множества условных операторов проверки кодов ошибок. Обработчики исключений намного чётче разграничивают нормальный и нештатный путь исполнения программы.

  • Классы исключений могут реализовывать собственные методы, а значит содержать часть функциональности по обработке ошибок (например, для перевода сообщений об ошибках).

  • В отличие от исключений, коды ошибок не могут быть использованы в конструкторе, т.к. он должен возвращать только новый объект.

Недостатки

  • Обработку исключений можно превратить в goto-подобный костыль. Не делайте так! Не используйте исключения для управления исполнением кода. Исключения следует выбрасывать только в целях сообщения об ошибке или критической ситуации.

Порядок рефакторинга

Старайтесь выполнять шаги этого рефакторинга только для одного кода ошибки за один раз. Так будет легче удержать в голове все важные сведения и избежать ошибок.

  1. Найдите все вызовы метода, возвращающего код ошибки, и оберните его в try/catch блоки вместо проверки кода ошибки.

  2. Внутри метода вместо возвращения кода ошибки выбрасывайте исключение.

  3. Измените сигнатуру метода так, чтобы она содержала информацию о выбрасываемом исключении (секция @throws).

Устали читать?

Сбегайте за подушкой, у нас тут контента на 7 часов чтения.

Или попробуйте наш новый интерактивный курс по рефакторингу. Он более информативный и гораздо более интересный, чем банальный текст.

Узнать больше...

Живой пример

Первый раз здесь? Ничего страшного!

У нас здесь всё просто – интерактивный пример очень похож на видео (но выглядит гораздо круче).

  1. После начала проигрывания, вам показываются разнообразные подсказки и сообщения. Вы продвигаетесь дальше, кликая на них.
  2. Вы можете перематывать шаги, используя стрелки слева.
  3. Кроме того, вы можете посмотреть разницу между первоначальным и получившимся кодом, нажав кнопку с глазом ().
  4. Кнопка компиляции () позвоялет проверить текущий код на наличие ошибок.