Також відомий як: 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;
  }
}
Після
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).