Использование ELSE плохое программирование? [закрыто]


18

Я часто сталкивался с ошибками, которые были вызваны использованием ELSEконструкции. Ярким примером является что-то вроде:

If (passwordCheck() == false){
    displayMessage();
}else{
    letThemIn();
}

Для меня это крики проблема безопасности. Я знаю, что passwordCheck, вероятно, будет логическим, но я бы не стал защищать свои приложения. Что будет, если это строка, int и т. Д.?

Я обычно стараюсь избегать использования ELSE, и вместо этого выбираю два совершенно отдельных оператора IF, чтобы проверить, что я ожидаю. Все остальное либо игнорируется, либо обрабатывается специально.

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

Как вы, ребята, делаете это?


3
В чем проблема безопасности для вас? Что означает «passwordCheck»? Была проверка пароля? Там должна быть проверка пароля? Пользователь прошел? Пользователь не смог ввести правильный пароль?
LennyProgrammers

20
I know that passwordCheck is likely to be a boolean...Что вы имеете в виду? На любом строгом языке. passwordCheckбудет то, что вы хотите, чтобы это было.
Бобби

31
Я думаю, что плохие практики отступов приводят к большему количеству ошибок, чем использование elseвыражений ...
gablin

15
Это кажется странным. Во-первых, вы жалуетесь на возможный тип возврата, passwordCheck()возможно, не являющийся логическим (что может быть разумной проблемой), а затем вы обвиняете это else? Я не вижу, какие проблемы elseпричины.
Дэвид Торнли

8
ммм, я думаю, что спрашивать, плохо ли использовать другое, плохо программировать
Muad'Dib

Ответы:


90

elseБлок должен всегда состоять из того, что вы хотите по умолчанию быть.

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

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

If (passwordCheck)
{
   letThemIn();
}
else
{
   displayMessage();
}

то есть, если проверка пароля работает, впустите их, в противном случае всегда допустимо отображать какое-то сообщение об ошибке.

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


2
@ dave.b в контексте примера, я думаю, это было бы проблемой безопасности, но если это повсеместно в кодовой базе, которую вы просматриваете, это скорее признак того, кто бы его написал, нужно немного больше практика :)
RYFN

9
Может ли кто-нибудь уточнить этот аспект безопасности? if (! что-то) {do a} else {do ​​b} против if (что-то) {do b} else {do ​​a} логически эквивалентно no? Я пытаюсь понять, в чем разница с точки зрения безопасности этого?
Крис

11
@Chris: я думаю, что OP использует слабо типизированный язык. Поэтому passwordCheckможет быть что угодно, Fм null, который будет оказывать passwordCheck == falseна falseи будет пользователь позволяет вход из - за внутреннюю ошибку.
Бобби

1
@ Крис, я так понял, что по умолчанию разрешен доступ, что не всегда желательно.
RYFN

3
Да, это очень зависит от языка. В C #, где ifтребуется a bool, переменные должны быть однозначно назначены, все пути должны возвращать значение и т. Д., Я не могу думать о какой-либо причине, порядок ifи elseбудет иметь значение, кроме читабельности. То есть if(a){b();}{c();}должно быть эквивалентно if(!a){c();{b();}. В JavaScript, с другой стороны, вы должны знать, что passwordCheckможет бытьundefined и т. Д.
Тим Гудман

57

Нет, в этом нет ничего плохого ELSE. ELSEне новый GOTO. Фактически, использование двух IFs вместо ELSEможет привести к нескольким проблемам.

Пример первый:

if (this(is(a(very())==complex(check())))) {
   doSomething();
}

if (!this(is(a(very())==complex(check())))) {
   doTheOtherThing();
}

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

Пример два:

foreach(x in y) {
  if (first_time) {
    first_time = false;
    doSomething();
  }

  if (!first_time) {
    doTheOtherThing();
  }
}

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


12
Я согласен с этим. Скопируйте ifинструкцию и инвертируйте ее логическое выражение, чтобы избежать else- теперь это плохое программирование! Вы не только дублирования кода ( плохое программирование), вы также замедляя производительность (если проверка действительно сложная, вы сейчас делаете это дважды - ba-- ээ, ну, вы знаете , что они говорят о преждевременной оптимизации в наше время ... не очень хорошее программирование!).
Габлин

Чтобы быть честным, если проверка должна быть в своем собственном методе, чтобы возвратить true / false
billy.bob

Хорошие примеры, давайте не будем забывать производительность использования 2, если проверки против одного, если в паре с другим. Я предположил бы, что в большинстве языков использование if / else будет работать лучше, чем использование двух операторов if с одним оператором not on.
Крис

1
dave.b: конечно, но это может начаться просто и расти медленно; комплексная проверка в моем примере здесь, чтобы сделать проблему более очевидной.
user281377

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

18

Всегда есть ДРУГОЕ. Если ты пишешь

if(foo)
  bar();

ты на самом деле пишешь

if(foo)
{
  bar();
}
else
{
   // do nothing
}

Все, что вы вставите в ELSE-путь, является вашей ответственностью.


7
-1. Этот ответ слишком смешной. Я не говорю, что это не правда. Это просто упускает из виду. То, что компиляция генерирует из вашего кода, не имеет ничего общего с практикой кодирования и ошибками, которые вы пишете

3
Вопросы были «Используете ли ELSE плохое программирование?». Мой ответ: вы можете притворяться, что его там нет, но не избегать его.
LennyProgrammers

5
какой язык ? в Java остальное отсутствует в байт-коде: P
IAdapter

@ acidzombie24 - очень хорошая практика, чтобы рассмотреть, что «еще» из любого вопроса. Иногда это просто - делать все остальное в функции, но это показывает, что вы думали об этом
Мартин Беккет

14

Я лично стараюсь избегать elseкак можно больше, но это не из-за проблем с безопасностью .

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

if (checkPassword != OK) { displayMessage(); return; }

letThemIn();

Это также относится к forи whileциклам, в которых я буду использовать continueи breakвсякий раз, когда это избегает уровня отступа.

Крис Латтнер говорит, что это лучше, чем я в стандартах кодирования LLVM .


Я согласен. «еще» создает умственную «развилку», и мы, люди, являемся последовательными существами.
user187291


@Chad: ах, спасибо, всегда приятно получить название для вещей :)
Matthieu M.

1
+1. Это единственный ответ, который я могу вынести, который набрал> 1. *writes an answer*

Я не пытаюсь избегать других как таковых, но я думаю, что согласен с тем, что вы пишете. Дело в том, что то, что вы тестируете, должно быть исключением, а не обычным случаем ( stackoverflow.com/questions/114342/… ). Здесь ошибка аутентификации является исключением и (только), который должен быть проверен.
Хловдал

5

Тогда просто замени их,

If (passwordCheck == true)
{
     letThemIn();
}
else
{
     displayMessage();
}

21
Как насчет If ((passwordCheck == true) == true)? :-)
Бегемот

1
Ну, это мой стиль, чтобы улучшить читаемость. Вы можете написать if (! Value), но я предпочитаю if (value! = True)
Ахмет Какичи

7
Это не улучшает читаемость. Это просто добавляет шум. Еще хуже программисты, которые пишут вложенные конструкции if только потому, что боятся логических операторов.
ak2

3
Если имя переменной носит описательный характер, нет причины, почему: if (someBooleanValue == true) должна быть необходима. Это было бы лучше: if (validPassword) {...
Марк Фридман

Ну, я просто заменил блоки кода в вопросе. Если вы прочитали мой первый комментарий, я сказал, что предпочитаю использовать if (value! = True) вместо if (! Value). Я надеюсь, что вы можете увидеть разницу между if (value) и if (! Value). Я имел в виду, что я не использую оператор дополнения. В противном случае вы правы, истина означает истину.
Ахмет Какиджи

3

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

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

Обратите внимание, что некоторые сторонники функционального программирования предлагают полностью избавиться ifв пользу сопоставления с образцом ... Слишком экстремально, на мой вкус. :-)


1
в качестве примечания: если у вас есть конструкция if на чистом функциональном языке, то вам действительно нужно иметь else. Каждое выражение должно что-то возвращать!
Tokland

2

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

Попытайтесь удалить ELSE, если можете, но не будьте параноиком по этому поводу. Стив Макконнелл называет этот прямой код в Code Complete. Т.е. есть простой четкий путь через ваш код.

Подходы для решения вашей конкретной проблемы:

  • использовать полиморфизм. На границе с вашей системой проверьте учетные данные пользователя. Если они законны, верните объект сеанса - с доступом к соответствующим частям системы или сгенерируйте исключение. Однако это может сделать вашу систему более сложной. Таким образом, вы решаете, что легче понять и поддерживать.

В целом, следующее может помочь уменьшить количество ELSE в вашем коде:

  • Хорошие требования могут уменьшить потребность в таких решениях в коде. Возможно, вам вообще не понадобится реализовывать вариант использования (еще).
  • более четкий дизайн. Максимальное сцепление и минимизация сцепления. Это гарантирует, что компоненты не дублируют решения, принятые в других компонентах.
  • обработка исключений для управления ошибками.
  • полиморфизм (см. пример выше).
  • операторы switch - это прославленные ELSE, но они лучше в определенных ситуациях.

2
Я бы также включил «Переместить сложные логические проверки в отдельную функцию».
Габлин

2

Ваше предположение о том, что код является утечкой, может быть или не быть правдой в зависимости от языка, который вы используете. В коде C это может быть проблемой (особенно потому, что в C булево значение - это просто int, отличное от нуля или нуля), но в наиболее строго типизированных языках (например, проверка типа во время выполнения), если passwordCheckпеременная была объявлена ​​как логическое значение, нет никакого способа назначить что-то еще этому. Фактически, все в ifпредикате должно разрешаться до логического значения, используете ли вы логические операторы или просто используете значение. Если вам удалось привязать другой объект к passwordCheckсреде выполнения, то возникнет недопустимая исключительная ситуация приведения.

Простые конструкции if / else гораздо легче читать, чем конструкции if / if, и они менее подвержены непредвиденным проблемам, если кто-то попытается перевернуть конструкцию. Давайте возьмем тот же пример на секунду:

if(passwordCheck == false) {
    denyAccess();
}

if(passwordCheck) {
    letThemIn();
}

Смысл взаимоисключающих предложений, которые вы хотите выполнить выше, теряется. Вот что передает конструкция if / else. Две взаимоисключающие ветви исполнения, где всегда будет работать одна из них. Это важная часть безопасности - обеспечение того, чтобы letThemInпосле вашего звонка не было никакого способа denyAccess.

Для ясности кода и обеспечения максимальной защиты критических секций они должны находиться внутри основного предложения ( ifчасти). Неподходящее поведение по умолчанию должно быть в альтернативном предложении ( elseчасть). Например:

if(passwordCheck) {
    letThemIn();
} else {
    denyAccess();
}

ПРИМЕЧАНИЕ: работая с разными языками, я разработал привычку кодирования, которая помогает избежать вопроса "что если это строка?" По сути, это поставить константу на первое место в логическом выражении. Например, вместо проверкиpasswordCheck == false я проверяю false == passwordCheck. Это также позволяет избежать случайной проблемы присваивания, возможной в C ++. Используя этот подход, компилятор будет жаловаться, если я наберу =вместо ==. В таких языках, как Java и C #, компилятор будет рассматривать присвоение в предложении if как ошибку, но C ++ с радостью примет это. Вот почему я также склонен делать нулевую проверку сnull первым.

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


1

Сказать, что с помощью else при программировании - это плохоotherwise при разговоре - это плохо.

Конечно, они оба могут быть использованы не по назначению, но это не значит, что их следует избегать только потому, что вы допустили ошибку, в которую они попали. Я не удивлюсь, если много ошибок зависит от пропущенного defaultслучая в switchутверждении.


1

Думайте о том, Elseкак белый список вашего приложения потока. Вы проверяете условия, которые ДОЛЖНЫ разрешать продолжение потока приложения, и если они не выполняются, то Elseвыполняется либо решение проблемы, либо прекращение выполнения приложения, либо что-то подобное.

Else само по себе это не плохо, но если вы используете его плохо, вы можете увидеть нежелательные эффекты.

Кроме того, что касается вашего заявления о

«Я знаю, что passwordCheck, вероятно, будет логическим значением, но я бы не стал защищать свои приложения».

Для методов, которые вы разрабатываете, ВСЕГДА возвращайте один тип данных. Хотя PHP Core изобилует кодом, который возвращает два или более типов данных, это плохая практика, так как она угадывает вызовы функций. Если вам нужно вернуть более одного типа данных, рассмотрите возможность создания исключения (я считаю, что это часто является причиной, по которой я хотел бы вернуть другой тип данных - что-то пошло ужасно, ужасно неправильно), или рассмотрите возможность реструктуризации вашего кода, чтобы вы могли вернуть только один тип данных.


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

1
В свободно типизированных языках, особенно в PHP, функции могут возвращать более одного типа данных. Например: stristr- «Возвращает подходящую подстроку. Если игла не найдена, возвращает ЛОЖЬ»
Крейг,

@Michael, функция PHP может вернуть все, что вы хотите. Там нет никаких ограничений на тип данных. Моя самая сложная функция возвращает true / false / null, но ничто (кроме здравого смысла) не мешает вам написать функцию, которая возвращает true / integer / null / string / float / array.
TRiG

Интересный. Я никогда не работал с PHP. Спасибо за объяснение, хотя - возможно, поможет мне в будущем! вроде как Javascript тогда?
Майкл К

@Michael - Очень похоже на Javascript.
Крейг,

1

Прежде всего. ЛОЛ! Theres НИКАКОЙ ПРИЧИНЫ избегать, вообще. Это НЕ плохая практика в любом случае, форма или форма.

Если что-нибудь код должен быть

if(!IsLoggedIn) { ShowBadLoginOrNoAccessPage(); return }

Там нет двух, если там и нет больше. Это то, что я делаю во всех своих приложениях, кроме одного, в котором я выкидываю исключение. Исключение перехватывается в моей функции, которая проверяет URL-адрес для отображения нужной страницы (или, в качестве альтернативы, я могу поместить функцию catch / check в функцию ошибки asp.net). Он распечатывает общую страницу с надписью «не авторизовать» или любым другим сообщением, которое я использую в исключении (я всегда проверяю тип исключения и устанавливаю код состояния http).

- Редактировать - как показано в примере ammoQ два, если это смешно. На самом деле еще так же хорошо или лучше, чем если. Во всяком случае, если нужно избегать ifs (хотя я лично этого не делаю. Но я действительно использую return и много ломаюсь), как было сказано, больше путей кода увеличивают вероятность ошибок. См Цикломатическая Сложность

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

if(cond == false) {
    a()
    b()
    c()
    onetwothree()
}
else
{
    a()
    b()
    c()
    more()
    onetwothree()
    code()
    longer()
}

Скорее тогда

if(cond) 
{
    a()
    b()
    c()
    more()
    onetwothree()
    code()
    longer()
}
else
{
    a()
    b()
    c()
    onetwothree()
}

0

Мне нравится устанавливать по умолчанию до условных, когда я могу. Я чувствую, что это немного легче читать и немного яснее, но это всего лишь предпочтение. У меня есть тенденция, чтобы попытаться избежать негативных условий в моем коде. Я не большой поклонник проверки на! Foo или false == foo, и я чувствую, что else является условным эквивалентом отрицания.

foo = bar;

if ('fubar' == baz) {
    foo = baz;
}

вместо того ...

if ('fubar' == baz) {
    foo = baz;
} else {
    foo = bar;
}

Предыдущий блок кода кажется мне немного легче для чтения. Мне кажется более естественным иметь какую-то скептическую паранойю в отношении моего кода. Установка по умолчанию независимо от каких-либо условий заставляет меня чувствовать себя комфортно: P


0

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

Как пример, троичные операторы также обычно являются хорошими кандидатами:

If VIP Then 
  Discount = .25
Else
  Discount = 0
End If
Total = (1 - Discount) * Total

Используя троичный подход:

Discount = VIP ? .25 : 0
Total = (1 - Discount) * Total

Тернарные операторы хорошо смещают ветвление вправо.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.