Правильный порядок логики структуры управления (истина/ложь, ложь/истина)?

StackOverflow https://stackoverflow.com/questions/229468

Вопрос

Я новичок в программировании, и мне интересно, существует ли правильный способ упорядочить логику структуры управления.

Кажется более естественным сначала проверить наиболее вероятный случай, но у меня такое ощущение, что некоторые структуры управления не будут работать, если они не проверят все ложное, чтобы прийти к чему-то истинному (логический вывод?)

Было бы трудно приспособиться к такому «негативному» мнению, я предпочитаю более позитивный взгляд, предполагая, что все правда :)

Это было полезно?

Решение

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

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

    if(arg == null){ 
      throw new IllegalArgumentException();  // harsh (correct)
    }
    // or 
    if(arg == null){
        arg = "";  // forgiving (lazy)
    }

Далее я пытаюсь проверить 1 условие только в каждом операторе if. вместо

    if(condition1 && condition2) {
        ...
    } else {
        ...
    }

я вообще предпочитаю

    if(condition1) {
        if(condition2) {
            ...
        } else {
            ...
        }
    } else {
        ...
    }

Этот подход проще для установки точек останова и делает логику более очевидной.

Я избегаю отрицаний; вместо

    if(! condition) {
        ...a...
    } else {
        ...b...
    }

все лучше переставить в

    if(condition) {
        ...b...
    } else {
        ...a...
    }

Наконец, все методы, которые возвращают логический результат, должны иметь " положительный " имя, которое указывает, что означают результаты:

    boolean checkSomething(Something x){ ... }     // bad -- whats the result?
    boolean isSomethingInvalid(Something x){ ... } // better, but ...
    boolean isSomethingValid(Something x){ ... }   // best, no "mental negation"

Другие советы

Прекрасно обсуждается только эта тема в Code Complete Макконнелла. Это книга, которую я очень рекомендую. Во всяком случае, соответствующее обсуждение на страницах 706-708 первого издания или стр. 749-750 второго издания (спасибо плинтусу). Из этой книги:

  

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

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

if( condition is true ) {
    do something small;
} else { 
    do something;
    and something else; 
    . . .
    and the 20th something;
}

Да, в условии есть некоторые языки, которые перестают оценивать выражение, если одна его часть ложна. Это важно помнить, если вы включаете какую-то определенную логику в свой код: если ваш язык оценивает все выражение, вы должны сделать это:

if( variable is defined ) {
    if( variable == value ) {
        ...
    }
}

а не это:

if( (variable is defined) && (variable == value) ) {
     ...
}

Я не думаю, что есть "правильный" ответ способ оформления ваших условий. Если вы работаете в компании, которая имеет стандарты кодирования, вам следует проверить, включено ли это в стандарты. (В последнем месте, где я работал, было определено разумное количество стандартов, но не было указано, как писать условную логику.)

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

Таким образом, я могу генерировать исключения / прерывать операции, прежде чем начать " настройку " для нормального выполнения программы.

Я стремлюсь структурировать свои условия таким образом, чтобы минимизировать объем информации, которую должен воспринимать читатель. Иногда легче проверить, что отрицательное доказывает положительное:

Пример - тест, чтобы увидеть, пересекается ли период из 2 дат с другим периодом из 2 дат, легче написать как тест на отсутствие пересечения 2 периодов

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

Либо/Или.Хотя я обычно использую «негативный» подход.

если что-то) {

}

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

С другой стороны, если проверка не проста, и я передам ее другому методу, который все равно будет проверять, я не буду повторять код для проверки в текущем методе. Как и в большинстве вещей, есть баланс.

(Контекст: Java)

READABILITY1: условие, которое разрешается в меньший блок кода, идет первым

if (condition) {
  smallBlock();
} else {
  bigBlockStart();
  ........
  bigBlockEnd();
}

READABILITY2: положительное утверждение идет первым, поскольку легче не заметить знак отрицания

MAKING SENSE: Утвердите все предварительные условия для метода, используя Assert.blabla (), и используйте условные выражения только для того, что делает метод.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top