Введение дополнительных локальных переменных в качестве замены комментариев

12

Это хороший стиль, чтобы использовать дополнительные, технически лишние, локальные переменные для описания того, что происходит?

Например:

bool easyUnderstandableIsTrue = (/* rather cryptic boolean expessions */);

if(easyUnderstandableIsTrue)
{
    // ...
}

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

BooleanAssange
источник
10
«Это хороший стиль - использовать дополнительные, технически лишние, локальные переменные для описания того, что происходит?». Да. На самом деле больше ничего нельзя сказать здесь.
Дэвид Арно
3
Я нахожу такой стиль (то есть использование множества промежуточных переменных с описательными именами) весьма полезным при чтении моего кода позже. Конечно, вы можете писать сложные выражения и сохранять несколько имен, не вводя промежуточные переменные, но зачем вам это нужно? Чтение кода может быть довольно сложной задачей, даже если он написан относительно хорошо, поэтому я не думаю, что излишне усложнять его - это разумный путь.
Mael
Я полагаю, что это называется консолидированным условным выражением в каталоге рефакторингов Мартина Фаулера .
Брандин

Ответы:

16

Какова стоимость наличия дополнительной переменной? В большинстве языков нет, как на скомпилированных, так и на интерпретируемых языках.

В чем выгода этого?

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

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

  • Вы снижаете риск нарушения синхронизации документации с кодом . Разработчики, как правило, обновляют имена переменных и методов проще, чем комментарии. Таким образом, нередко можно увидеть такой код:

    // Find if the user is an actual author in order to allow her to edit the message.
    if (currentUser.isAdministrator || (message.author == currentUser && !message.locked))

Выражение, вероятно, начиналось с if (message.author == currentUser), а затем развивалось, чтобы обрабатывать случай заблокированных сообщений и администраторов, которые не должны быть авторами и не заботятся о заблокированных вещах; однако, комментарий не отразил ни одно из этих изменений.

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

Обратите внимание, что если ваше логическое выражение становится слишком сложным:

  • Распакуйте его в отдельный метод и:
  • Преобразуйте его в несколько простых логических выражений.

Пример выше становится:

class Message
{
    ...
    public boolean canBeEditedBy(User user)
    {
        ...
        if (user.isAdministrator) {
            return true;
        }

        return this.author == user && !this.locked;
    }
}

...
if (message.canBeEditedBy(currentUser)) // See? Much more readable now!
{
    ...
}

¹ Источник: мои собственные наблюдения моих коллег, разрабатывающих в основном программное обеспечение для бизнеса; YMMV. Настоящее исследование может показать разные результаты. Лично я предполагаю, что когда разработчики читают код, они сосредотачиваются на коде , а комментарии - это документация, а не код; поэтому они обычно не читают комментарии, поэтому было бы трудно ожидать, что они обновят их.

² Слишком сложный порог определяется простой формулой: если половина разработчиков, которые проверяют ваш код, выражают намерение убить вас, порог достигнут. Приведенное выше логическое выражение достаточно просто, чтобы потребовать рефакторинга; однако четыре части подряд if ((a && b) || (c && d))сделают его потенциально рефакторируемым. Обратите внимание, что если выражение плоское, количество частей в основном не имеет значения: if (a || b || c || d || ... || z)достаточно для чтения.

Арсений Мурзенко
источник