Стиль кодирования... условие ошибки первое или последнее?

Что лучше вообще с точки зрения заказа? Вы помещаете условие неисправности вверху или внизу?

if (noProblems == true) {
    // do stuff
} else {
    // deal with problem
}

ИЛИ

if (noProblems == false) {
    // deal with problem
} else {
    // do stuff
}

Ответ 1

Мне нравится сначала устранять ошибки - и вернуться из функции раньше, чтобы "счастливый путь" оставался не вложенным, например.

if (some error condition)
{
    //handle it
    return;
}
//implicit else for happy path
...

если легко определить условия, приводящие к счастливому пути, тогда непременно положите эту статью в первую очередь (спасибо Marcin!)

Ответ 2

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

Из раздела "Code complete, 2nd edition" 15.1:

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

Ответ 3

если его 1 или 2 строки и раннее возвращение, я бы поставил его наверху, особенно если он находится в начале функции. который почти читается как контракт. в противном случае я иду с правилом "положительные условия до отрицательного".

Ответ 4

Это зависит от того, что вам более понятно. Я имею в виду, что имеет смысл, что noProblems имеет истинное значение или что оно имеет ложное значение.

Например, для isDeviceEnabled() я всегда проверял бы истинный результат, поскольку "Enabled" имеет неявное положительное значение. Для неявного отрицательного значения мы могли бы проверить, например, для "isMemoryAvailable()", возможно, потому, что вам нужно проверить, нет ли места для новых объектов/массивов или других данных.

Ответ 5

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

Ответ 6

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

Кроме того, вы создали вещи, чтобы вы действительно не могли

// do stuff

после

// deal with problem

так что за этим он кажется таким же хорошим, как и другой.

Ответ 7

Как и при использовании try/catch, я делаю обычный поток, а затем обрабатываю условия исключения.

Это не означает, что проверка ошибок/очистка не происходит сначала, но если я не доверяю тому, что было передано мне.

например.

if (foo is null) then
    // bail
end if

if (bar == foo) then
    // foo hasn't been changed... print the regular report
else
    // foo has changed, run the reconciliation report instead.
end if

Мне нравится, что счастливая история течет, как прямая линия, и несчастная история, чтобы отбросить свою собственную шпору.

Ответ 8

Почему бы не создать одну точку выхода из функции и сделать правильную очистку там вместо того, чтобы иметь несколько возвратов...


DWORD bRetVal= TRUE;
if(foo is null) 
{
   bRetVal = FALSE;
   goto Error;
}
else
{
// do something
}

Exit:
 return bRetVal;