Користується ELSE поганим програмуванням? [зачинено]


18

Я часто стикався з помилками, які були викликані використанням ELSEконструкції. Прекрасним прикладом є щось таке:

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

Для мене це кричить проблема безпеки. Я знаю, що парольCheck, ймовірно, буде логічним, але я не ставлю безпеку своїх програм на ньому. Що буде, якщо його рядок, 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
Чи може хтось детальніше зупинитися на аспекті безпеки цього? якщо (! щось) {do a} else {do ​​b} проти if (щось) {do b} else {do ​​a} логічно еквівалентно ні? Я намагаюся зрозуміти, в чому різниця в безпеці цього?
Кріс

11
@Chris: Я думаю, що ОП використовує слабко набрану мову. Тому passwordCheckможе бути що завгодно, Fм null, який буде надавати passwordCheck == falseна falseі буде користувач дозволяє вхід з - за внутрішню помилку.
Боббі

1
@Chris, моє розуміння полягало в тому, що стан за замовчуванням повинен бути доступним, що не обов'язково доцільно.
RYFN

3
Так, це дуже залежить від мови. У C #, де ifвимагається 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- тепер , що це погано програмування! Ви не тільки копіюєте код ( неправильне програмування), але й уповільнюєте продуктивність (якщо перевірка дуже складна, ви зараз робите це вдвічі - ба ... е , ну, ви знаєте, що вони говорять про передчасні оптимізації в наш час ... не так добре програмування!).
габлін

Якщо чесно, що якщо перевірка повинна бути у власному методі, щоб повернути true / false
billy.bob

Хороші приклади, дозволяють не забувати ефективність використання 2, якщо чеки проти одного, якщо в парі з іншим. Я б припустив, що в більшості мов використання if / else буде краще, ніж використання двох, якщо оператори з однією з них використовують умову не.
Кріс

1
dave.b: звичайно, але це може початися просто і повільно рости; тут є складна перевірка мого прикладу, щоб зробити проблему більш очевидною.
користувач281377

3
Так - і не забувайте, що умови можуть мати побічні ефекти на більшості мов, і якщо є функції в умовах, які ви дійсно не можете зрозуміти, дивлячись.
Девід Торнлі

18

Завжди є ELSE. Якщо ви пишете

if(foo)
  bar();

ти насправді пишеш

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

Що б ви не поставили на шляху ELSE, це ваша відповідальність.


7
-1. Ця відповідь занадто смішна. Я не кажу, що це неправда. Це просто пропускає суть. Те, що компіляція генерується з вашого коду, не має нічого спільного з практикою кодування та помилками, які ви пишете

3
Питання було "Чи використовується ELSE поганим програмуванням?". Моя відповідь: ви можете робити вигляд, що його немає, але не уникати цього.
LennyProgrammers

5
яка мова ? у Java іншого немає у байт-коді: P
IAdapter

@ acidzombie24 - це дуже хороша практика розглянути питання про те, що є "ще" з будь-якого питання. Іноді це просто - робити все інше в fucntion, але це показує, що ти думав про це
Мартін Бекет

14

Я особисто схильний уникати else, наскільки я можу, але це не для жодних проблем із безпекою .

Читаючи код, вкладені висловлювання ускладнюють дотримуватися логіки, тому що вам потрібно пам’ятати, який набір умов призведе туди. З цієї причини я величезний фанат раннього виходу:

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

letThemIn();

Це стосується forі whileциклів, в яких я буду використовувати, continueі breakколи це уникне рівня відступу.

Кріс Леттнер каже, що це краще, ніж я, у стандартах кодування LLVM .


Я згоден. "else" створює психічну "вилку", а ми, люди, є послідовними істотами.
користувач187291

Фій, це називається умовою охорони
CaffGeek

@Chad: а, дякую, завжди приємно отримувати назву для речей :)
Matthieu M.

1
+1. Це єдина відповідь, на яку я можу відповісти, що має бал> 1. *writes an answer*

Я не намагаюся уникати іншого як такого, але думаю, що згоден з тим, що ви пишете. Справа в тому, що тест, який ви тестуєте, повинен бути винятком, а не звичайним випадком ( stackoverflow.com/questions/114342/… ). Тут невдача аутентифікації є винятком і (тільки), який слід перевірити.
hlovdal

5

Тоді просто замініть їх,

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

21
Як щодо If ((passwordCheck == true) == true)? :-)
Гіппо

1
Ну це мій стиль, щоб покращити читабельність. Ви можете написати if (!
Value

7
Це не покращує читабельність. Це просто додає шум. Ще гірше - програмісти, які пишуть вкладені, якщо конструкції, тільки тому, що вони бояться булевих операторів.
ak2

3
Якщо назва змінної є описовим, немає причини, чому: якщо (someBooleanValue == вірно) потрібно. Це було б краще: якщо (дійснийPassword) {...
Марк Фрідман

Ну щойно я замінив кодові блоки в питанні. Якщо ви читали мій перший коментар, я сказав, що віддаю перевагу використанню if (value! = True), а не if (! Value). Сподіваюся, ви зможете побачити різницю між значенням if (value) та if (!). Я мав на увазі, що я не використовую оператор комплементу. Інакше ти маєш рацію, правда означає правду.
Ahmet Kakıcı

3

Як і Матьє М., я віддаю перевагу ранньому виходу до глибоко вкладених інших блоків ... Це ілюструє добре захисне програмування (якщо погані умови, немає сенсу продовжувати). Дуже багато людей не погоджуються з нами, віддаючи перевагу унікальній точці виходу; це не сенс дебатів (я думаю).

Зараз я, звичайно, використовую, elseколи це має сенс, особливо для простих, коротких альтернатив. Як було сказано, дублювання тесту - це марна трата часу (програміста та процесора), джерело плутанини і, пізніше, помилок (коли змінюється одна, а не інша).
Якось я додаю коментар до elseчастини, нагадуючи, яка умова була (особливо якщо ifдеталь довга, наприклад, у застарілому коді) або яка альтернатива.

Зауважимо, що деякі крайні прихильники функціонального програмування пропонують повністю позбутися if, на користь відповідності шаблону ... Трохи надто екстремальне на мій смак. :-)


1
як бічна примітка: якщо у вас є конструкція if на вашій чистій функціональній мові, то вам дійсно потрібно мати інше. Кожен вираз має щось повернути!
tokland

2

Немає нічого поганого у використанні ELSE. Однак це може призвести до надмірно складного коду, який важко читати і розуміти. Це може свідчити про поганий дизайн. Це, безумовно, вказує на додаткові випадки використання, які потрібно буде перевірити.

Спробуйте видалити ELSE, якщо можете, але не будьте параноїком щодо цього. Стів МакКоннелл називає цей прямий код у "Кодексі повним" Тобто існує простий чіткий шлях через ваш код.

Підходи до вирішення конкретної проблеми:

  • використовувати поліморфізм. На кордоні до вашої системи перевіряйте облікові дані користувача. Якщо вони законні, тоді поверніть об’єкт сеансу - з доступом до відповідних частин системи або викиньте виняток. Однак це може зробити вашу систему більш складною. Тож ви вирішите, що простіше зрозуміти та підтримувати.

Загалом - наступне може допомогти зменшити ELSE у вашому коді:

  • хороші вимоги можуть зменшити потребу в таких рішеннях у кодексі. Можливо, вам зовсім не знадобиться реалізувати випадок використання (інше).
  • чіткіший дизайн. Максимальна згуртованість і мінімізація зв'язку. Це гарантує, що компоненти не дублюють рішення, прийняті в інших компонентах.
  • обробка виключень для управління випадками помилок.
  • поліморфізм (див. приклад вище).
  • заяви переключення - це прославлені ELSE, але краще в певних ситуаціях.

2
Я б також включив "Перемістити складні булеві перевірки в окрему функцію".
габлін

2

Ваша думка про те, що код є витоком у безпеці, може бути, а може бути істинним, залежно від мови, якою ви користуєтесь. У коді C це може бути проблемою (особливо, тому що в C булевий символ - це лише int, який не дорівнює нулю або нулю) - але в більшості сильно набраних мов (тобто перевірка типу виконання), якщо passwordCheckзмінна була оголошена булевою, немає способу призначити щось інше. Насправді, усе в ifпредикаті має відповідати булевому, будь то ви використовуєте булеві оператори чи просто використовуєте значення. Якщо вам вдалося мати інший тип об'єктів, прив’язаний до passwordCheckвиконання, викине якийсь тип незаконного виключення.

Прості конструкції if / else читаються набагато простіше, ніж якщо / 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 само по собі непогано, але якщо ви його погано використовуєте, ви можете побачити небажані ефекти.

Також, стосовно вашої заяви о

"Я знаю, що парольCheck, ймовірно, буде логічним, але я не ставлю на це безпеку своїх програм."

Для розроблених методів ВИНАГО повертайте один тип даних. Хоча ядро ​​PHP вбито кодом, який повертає два або більше типи даних, це погана практика, оскільки він робить здогадки про виклики функцій. Якщо вам потрібно повернути більше одного типу даних, подумайте про викид виключення (я вважаю, що це часто причина, чому я хотів би повернути інший тип даних - щось пішло жахливо, жахливо неправильно), або подумайте про реструктуризацію коду, щоб ви могли повернути лише один тип даних.


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

1
У мовах, що друкуються слабко, особливо в PHP, функції можуть повертати більше одного типу даних. наприклад: stristr- "Повертає підрівняну підрядку. Якщо голка не знайдена, повертається FALSE"
Craige

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

Цікаво. Я ніколи не працював з PHP. Дякую за пояснення, хоча - напевно, допоможіть мені в майбутньому! на зразок Javascript тоді?
Майкл К

@Michael - Насправді схожий на Javascript.
Craige

1

Поперше. ЛОЛ! У цьому немає ПРИЧИНИ, щоб взагалі уникати іншого. Його НЕ погана практика в будь-якому вигляді, формі чи формі.

Якщо що-небудь повинен бути

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

У них немає двох ifs, і немає іншого. Це те, що я роблю у всіх своїх програмах, крім однієї, в якій я кидаю виняток. Виняток міститься в моїй функції, яка перевіряє URL-адресу для відображення належної сторінки (або, як альтернатива, я можу поставити функцію помилки catch / check in asp.net). Він виводить загальну сторінку, яка говорить про те, що я не надаю авторизацію чи будь-яке повідомлення, яке я використовую за винятком (я завжди перевіряю тип виключення та встановлюю код статусу http).

-Edit- як показано в прикладі ammoQ два ifs - це смішно. Дійсно інше так само добре чи краще, ніж якщо. Якщо чогось не можна уникати (хоча я особисто цього не роблю. Але я використовую повернення і багато ламаю), як було сказано, більше кодових шляхів збільшує ймовірність помилок. Див. Цикломатичну складність

-Редагуйте 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, і я відчуваю, що ще є свого роду умовним еквівалентом мінуса.

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.