Чи інші блоки збільшують складність коду? [зачинено]


18

Ось дуже спрощений приклад . Це не обов'язково питання, що стосуються мови, і я прошу вас проігнорувати безліч інших способів написання функції та змін, які можуть бути внесені до неї. . Колір унікального типу

string CanLeaveWithoutUmbrella()
{
    if(sky.Color.Equals(Color.Blue))
    {
        return "Yes you can";
    }
    else
    {
        return "No you can't";
    }
}

Дуже багато людей, яких я зустрічав, ReSharper, і цей хлопець (чий коментар нагадав мені, що я хотів просити це запитати деякий час) рекомендував би рефакторинг коду для видаленняelse блок, залишаючи це:

(Я не можу згадати, що сказала більшість; я, можливо, не запитав цього інакше)

string CanLeaveWithoutUmbrella()
{
    if(sky.Color.Equals(Color.Blue))
    {
        return "Yes you can";
    }
    return "No you can't";
}

Питання: Чи збільшується рівень складності, не включаючи elseблок?

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

Крім того, я вважаю, що можу запобігти тонкі помилки в логіці, особливо після внесення змін до коду на більш пізніх термінах.

Візьмемо цей варіант мого спрощеного прикладу (Ігнорування факту orоператора, оскільки це цілеспрямовано спрощений приклад):

bool CanLeaveWithoutUmbrella()
{
    if(sky.Color != Color.Blue)
    {
        return false;
    }
    return true;
}

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

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

Звичайно, є й інші способи, коли конкретний приклад повинен бути визначений у будь-якому випадку, і все це запобігає цій ситуації, але це лише приклад.

Довжина прикладу, який я наводила, може спотворити візуальний аспект цього, тому припустимо, що простір, який займає дужки, є відносно незначним для решти методу.

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


Насправді, коли є заява "якщо" з "поверненням", це може розглядатися як "блок захисту">> 50% усіх випадків. Тому я думаю, що ваше помилкове уявлення тут полягає в тому, що "блок охоронців" - винятковий випадок, а ваш приклад - звичайний випадок.
Док Браун

2
@AssortedTrailmix: Я погоджуюся, що такий випадок, як описано вище, може бути читабельнішим під час написання elseпункту (на мій смак, він буде ще більш читабельним, коли залишати не потрібні дужки. Але я вважаю, що приклад недостатньо обраний, оскільки в випадок вище я б написав return sky.Color == Color.Blue(без if / else). Приклад з іншим типом повернення, ніж bool, мабуть, зробить це зрозумілішим.
Doc Brown

1
як зазначено в коментарях вище, запропонований приклад є надто спрощеним, тому він пропонує спекулятивні відповіді. Що стосується частини питання, що починається з "Хтось тепер може додати новий, якщо блок ..." , його вже багато разів задавали і відповіли, див. Наприклад Підходи до перевірки кількох умов? і кілька питань, пов'язаних з ним.
гнат

1
Я не бачу, які ще блоки стосуються принципу DRY. DRY має більше спільного з абстракцією та посиланнями на загальновживаний код у вигляді функцій, методів та об'єктів, ніж те, про що ви запитуєте. Ваше запитання пов’язане з читабельністю коду та, можливо, умовами чи ідіомами.
Шашанк Гупта

2
Голосування за повторне відкриття. Хороші відповіді на це питання не особливо ґрунтуються на думках. Якщо поданий приклад у запитанні є неадекватним, його вдосконалення шляхом редагування було б розумно робити, а не голосувати за закриття з причини, яка насправді не відповідає дійсності.
Майкл Шоу

Відповіді:


27

На мою думку, явний ще блок є кращим. Коли я бачу це:

if (sky.Color != Blue) {
   ...
}  else {
   ...
}

Я знаю, що маю справу з взаємовиключними варіантами. Мені не потрібно читати, що знаходиться всередині блоків if, щоб мати можливість розповісти.

Коли я бачу це:

if (sky.Color != Blue) {
   ...
} 
return false;

На перший погляд схоже, що вона повертається помилково незалежно і має необов'язковий побічний ефект, небо не синє.

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

Чому хто б віддав перевагу іншому, для мене загадка, сподіваюся, хтось займе протилежну позицію, просвітить мене своєю відповіддю.

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

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

Незабаром після оригінальної версії цієї відповіді такий код був виявлений у моєму проекті:

Foobar merge(Foobar left, Foobar right) {
   if(!left.isEmpty()) {
      if(!right.isEmpty()) {
          Foobar merged = // construct merged Foobar
          // missing return merged statement
      }
      return left;
   }
   return right;
}

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


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

1
Я варіююсь з цього приводу. Іноді явне інше не дуже заробляє вас, оскільки це навряд чи спровокує найтонші логічні помилки, про які йдеться в ОП - це просто шум. Але в основному я згоден, і інколи я зроблю щось на кшталт того, } // elseкуди інакше зазвичай піде компроміс між двома.
Теластин

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

2
Я думаю, у вас таке ж уявлення, що і в ОП - "якщо" з "поверненням" можна розглядати в основному як блок охорони, тому ви обговорюєте тут винятковий випадок, тоді як більш частий випадок блоків охорони є ІМХО більш читабельним без "інше".
Док Браун

... тож те, що ви написали, не помиляється, але ІМХО не варте багатьох отриманих результатів.
Док Браун

23

Основна причина для видалення elseблоку, який я знайшов, - це надмірне відступ. Коротке замикання elseблоків забезпечує набагато більш рівну структуру коду.

Багато ifтверджень по суті є охоронцями. Вони заважають перенаправити нульові вказівники та інші "не робіть цього!" помилки. І вони призводять до швидкого припинення поточної функції. Наприклад:

if (obj === NULL) {
    return NULL;
}
// further processing that now can assume obj attributes are set

Тепер може здатися, що ця elseстаття тут буде дуже розумною:

if (obj === NULL) {
    return NULL;
}
else if (obj.color != Blue) {
   // handle case that object is not blue
}

І справді, якщо це все, що ви робите, це не набагато відступніше, ніж приклад вище. Але це рідко все, що ви робите з реальними багаторівневими структурами даних (умова, яка виникає весь час при обробці загальних форматів, таких як JSON, HTML та XML). Отже, якщо ви хочете змінити текст усіх дітей певного вузла HTML, скажіть:

elements = tree.xpath(".//p");
if (elements === NULL) {
    return NULL;
}
p = elements[0]
if ((p.children === NULL) or (p.children.length == 0)) {
    return NULL;
}
for (c in p.children) {
    c.text = c.text.toUpperCase();
}
return p;

Охоронці не збільшують відступ коду. За допомогою elseпункту вся фактична робота починає рухатися вправо:

elements = tree.xpath(".//p");
if (elements === NULL) {
    return NULL;
}
else {
    p = elements[0]
    if ((p.children === NULL) or (p.children.length == 0)) {
        return NULL;
    }
    else {
        for (c in p.children) {
            c.text = c.text.toUpperCase();
        }
        return p;
    }
}

Це починає мати значний рух праворуч, і це досить тривіальний приклад, що має лише два умови охорони. Кожен додатковий охоронець додає ще один рівень відступу. Реальний код Я написав обробку XML або споживання детальних каналів JSON, можна легко скласти 3, 4 або більше умови захисту. Якщо ви завжди користуєтесь знаком else, ви отримуєте відступ 4, 5 або 6 рівнів дюйма. Можливо, і більше. І це, безумовно, сприяє відчуттю складності коду та витрачає більше часу на розуміння того, що поєднується з чим. Швидкий, плоский стиль з початком виходу усуває частину цієї «надлишкової структури» і здається більш простим.

Коментар доповнення до цієї відповіді дав мені зрозуміти, що, можливо, не було зрозуміло, що NULL / порожнє поводження не є єдиною причиною охорони умов. Не майже! Хоча цей простий приклад зосереджується на NULL / порожній обробці та не містить інших причин, наприклад, пошук глибоких структур, таких як XML та AST, для "відповідного" вмісту, часто має довгу серію конкретних тестів, щоб вилучити невідповідні вузли та нецікаво. справ. Серія тестів "якщо цей вузол не має значення, повернути" спричинить такий самий вигляд правого дрейфу, що і NULL / порожні охоронці. На практиці, наступні тести на відповідність часто поєднуються з NULL / порожніми захисниками для відповідно глибших структур даних, що шукаються - подвійним ударом для дрейфу вправо.


2
Це детальна і достовірна відповідь, але я збираюся додати це до питання (Спочатку це вирвалося з розуму); Є "виняток", коли я завжди вважаю elseблок зайвим, коли за допомогою ifблоку застосовувати обмеження, яке має бути логічно задоволеним для всіх наступних кодів, таких як нульова перевірка (або будь-яка інша охорона).
Selali Adobor

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

Я думаю, що розумно використовувати умови охорони, щоб викинути їх, як тільки ви покинули щасливий шлях. Однак я також вважаю, що у випадку обробки XML / JSON, якщо спочатку перевірити вхід до схеми, ви отримаєте кращі повідомлення про помилки та чистіший код.
Вінстон Еверт

Це ідеальне пояснення випадків, коли уникнути іншого.
Кріс Шиффхауер

2
Я б завернув API, щоб натомість не створювати дурні NULL.
Вінстон Еверт

4

Коли я бачу це:

if(something){
    return lamp;
}
return table;

Я бачу загальну ідіому . Загальна картина , яка в моїй голові означає:

if(something){
    return lamp;
}
else return table;

Оскільки це дуже поширена ідіома в програмуванні, програміст, який звик бачити такий вид коду, має неявний «переклад» у голові кожного разу, коли вони його бачать, що «перетворює» його на власне значення.

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

Наприклад, прочитайте наступний текст:

введіть тут опис зображення

Ви це читали?

Я люблю Париж навесні

Якщо так, ви помиляєтесь. Прочитайте текст ще раз. Те, що насправді написано, - це

Я люблю Париж в в весняне час

У тексті є два слова "". То чому ви пропустили одне з двох?

Це тому, що ваш мозок побачив загальну схему , і негайно перевів її на відоме значення. Не потрібно було детально читати всю деталь, щоб зрозуміти сенс, тому що вона вже розпізнавала модель , побачивши її. Ось чому він ігнорував зайве "the ".

Те саме з вищевказаною ідіомою. Програмісти , які читали багато коду звикли бачити цю картину , з if(something) {return x;} return y;. Їм не потрібен досвідчений персонал, elseщоб зрозуміти, що це сенс, тому що їхній мозок "прикладає його туди". Вони визнають це візерунком із відомим значенням: "те, що після закриття дужки, буде працювати лише як неявне elseпопереднє if".

Тож, на мою думку, elseнепотрібне. Але просто використовуйте те, що здається більш читабельним.


2

Вони додають у коді візуальне захаращення, так що так, вони можуть додати складності.

Однак справедливо і зворотне, надмірне рефакторинг для зменшення довжини коду також може додати складності (не в цьому простому випадку, звичайно).

Я згоден із твердженням, що elseблок заявляє про наміри. Але мій висновок інший, тому що ви додаєте складності у своєму коді для досягнення цього.

Я не погоджуюся з вашим твердженням, що це дозволяє вам запобігти тонкі помилки в логіці.

Давайте подивимось приклад, тепер воно повинно повернутись істиною лише в тому випадку, якщо Небо синє і висока вологість, вологість невисока або якщо небо червоне. Але тоді ви помиляєтеся однією дужкою і розміщуєте її неправильно else:

bool CanLeaveWithoutUmbrella() {
    if(sky.Color == Color.Blue)
    {
        if (sky.Humidity == Humidity.High) 
        {
            return true;
        } 
    else if (sky.Humidity != Humidity.High)
    {
        return true;
    } else if (sky.Color == Color.Red) 
    {
            return true;
    }
    } else 
    {
       return false;
    }
}

Ми бачили всі подібні дурні помилки у виробничому коді, і їх дуже важко виявити.

Я б запропонував таке:

Мені це легше читати, бо я з першого погляду бачу, що це за замовчуванням false.

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

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

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

    повернення (sky.Color == Color.Blue);

  • Якщо справа дещо складніша, з різними пунктами, я відповів би:

    bool CanLeaveWithoutUmbrella () {

    if(sky.Color == Color.Blue && sky.Humidity == Humidity.High) {
        return true;
    } else if (sky.Humidity != Humidity.High) {
        return true;
    } else if (sky.Color == Color.Red) {
        return true;
    }
    
    return false;
    

    }

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

    double CanLeaveWithoutUmbrella() {
    
        double risk = 0.0;
    
        if(sky.Color == Color.Blue && sky.Humidity == Humidity.High) {
            risk = 1.0;
        } else if (sky.Humidity != Humidity.High) {
            risk = 0.5;
        } else if (sky.Color == Color.Red) {
            risk = 0.8;
        }
    
        Log("value of risk:" + risk);
        return risk;
    

    }

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

Тому простота прикладу також є фактором, який слід враховувати.


Я відчуваю, що ви робите ту саму помилку, яку зробили інші, і перетворюючи приклад трохи занадто багато, таким чином вивчаючи нову проблему, але мені потрібно зайняти секунду і вивчити процес проходження вашого прикладу, так що зараз це виглядає справедливий для мене. І сторона, це не пов'язано з принципом відкритого / закритого типу . Область є занадто вузькою, щоб застосувати цю ідіому. Але цікаво відзначити, що його застосування на більш високому рівні дозволило б усунути весь цей аспект проблеми (усунувши необхідність будь-якої модифікації функції).
Selali Adobor

1
Але якщо ми не можемо модифікувати цей надто спрощений приклад додавання пунктів, а також не змінювати, як це написано, чи внести якісь зміни до нього, то слід врахувати, що це питання стосується лише тих саме рядків коду, і це вже не загальне питання. У такому випадку ви абсолютно праві, це не додає жодних складностей (ані прибирає їх), інше застереження, оскільки не було складності для початку. Однак ви не чесні, тому що ви пропонуєте ідею, що можна додати нові пропозиції.
FranMowinckel

І як зауважу, я не констатую, що це стосується добре відомого принципу відкритого / закритого типу. Я думаю, що ідея провести людей змінювати ваш код, як ви пропонуєте, схильна до помилок. Я просто беру цю ідею з цього принципу.
FranMowinckel

Тримайся редагувань, ти
переживаєш

1

Хоча описаний випадок «інше» має більшу складність, у більшості (але не у всіх) практичних ситуаціях це не має великого значення.

Роки тому, коли я працював над програмним забезпеченням, яке використовувалося в авіаційній галузі (воно повинно було пройти процес сертифікації), ваше питання виникло. З'ясувалося, що на цю "іншу" заяву були фінансові витрати, оскільки вона збільшувала складність коду.

Ось чому.

Наявність «іншого» створило неявний 3-й випадок, який потрібно було оцінити, - ні про «якщо», ні про «інше». Ви можете думати (як я був у той час) WTF?

Пояснення пішло так ...

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

Порівняйте це з випадком, коли є лише "якщо", а ні "інше". У цьому випадку є лише два варіанти - шлях "якщо" та шлях "не" якщо ". Два випадки оцінювання менш складні, ніж три.

Сподіваюсь, це допомагає.


в об’єктному файлі чи не буде виведено жоден випадок як однакові стрибки?
Вінстон Еверт

@WinstonEwert - Можна було б очікувати, що вони будуть однаковими. Однак те, що відображається і що очікується, що буде винесено, це дві різні речі, незалежно від того, наскільки вони перетинаються.
Спаркі

(Я здогадуюсь, що СЕ з'їв мій коментар ...) Це дуже цікава відповідь. Хоча я б сказав, що випадок, який він відкриває, є дещо нішевим, але він показує, що деякі інструменти знайдуть різницю між цими (Навіть найпоширеніша метрика коду, заснована на потоці, який я бачу, цикломатична складність, не
міняла

1

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

def value(key):
    if key == FROB:
        return FOO
    elif key == NIK:
        return BAR
    [...]
    else:
        return BAZ

Це досить зрозуміло - це еквівалент пошуку caseоператора чи словника, версії вищого рівня return foo == bar:

KEY_VALUES = {FROB: FOO, NIK: BAR, [...]}
DEFAULT_VALUE = BAZ

def value(key):
    return KEY_VALUES.get(key, default=DEFAULT_VALUE)

Це зрозуміліше, оскільки, хоча кількість лексем більша (32 проти 24 для вихідного коду з двома парами клавіш / значень), семантика функції тепер явна: Це просто пошук.

(Це має наслідки для рефакторингу - якщо ви хочете отримати побічний ефект, якщо у key == NIKвас є три варіанти:

  1. Поверніться до if/ elif/ elseстилю та вставте один рядок у key == NIKкорпус.
  2. Збережіть результат пошуку до значення та додайте ifзаяву до valueокремого випадку перед поверненням.
  3. Поставте ifзаяву у абонента.

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

Повертаючись до коду ОП, я думаю, що це може послужити керівництвом щодо складності elseвисловлювань: Код з явним elseтвердженням об'єктивно складніше, але важливіше, чи робить це семантику коду зрозумілою та простою. І на це потрібно відповідати в кожному конкретному випадку, оскільки кожен фрагмент коду має різний зміст.


Мені подобається переписати таблицю пошуку простого корпусу комутатора. І я знаю, що це переважна ідіома пітона. На практиці, однак, я часто виявляю, що багатосторонні умови (ака caseабо switchтвердження) менш однорідні. Кілька варіантів - це просто пряме повернення значення, але тоді один або два випадки потребують додаткової обробки. І коли ви виявите, що стратегія пошуку не підходить, вам потрібно переписати зовсім інший if elif... elseсинтаксис.
Джонатан Юніс

Ось чому я вважаю, що пошук зазвичай повинен бути однолінійним або функціональним, так що логіка навколо результату пошуку відокремлена від логіки пошуку його в першу чергу.
l0b0

Це питання приносить вищий рівень погляду на питання, яке, безумовно, слід згадати і пам’ятати, але я вважаю, що у справі було поставлено достатньо обмежень, що ви можете вільно розширити свою власну позицію
Selali Adobor

1

Я думаю, це залежить від того, який вигляд ifви використовуєте. Деякі ifтвердження можна розглядати як вирази, а інші можна розглядати лише як оператори контрольного потоку.

Ваш приклад для мене виглядає як вираз. У мовах, подібних С, потрійний оператор ?:дуже схожий на ifтвердження, але це вираз, а іншу частину не можна опустити. Має сенс, що інша гілка не може бути опущена в виразі, оскільки вираз завжди повинен мати значення.

Використовуючи потрійний оператор, ваш приклад виглядатиме так:

bool CanLeaveWithoutUmbrella()
{
    return (sky.Color == Color.Blue)
               ? true
               : false;
}

Оскільки це булевий вираз, його справді слід спростити до кінця

bool CanLeaveWithoutUmbrella()
{
    return (sky.Color == Color.Blue);
}

Включення явного іншого пункту робить ваш намір яснішим. Охоронці можуть мати сенс у деяких ситуаціях, але при виборі між двома можливими значеннями, жодне з яких не є винятковим або незвичним, вони не допомагають.


+1, ОП - це ІМХО, який обговорює патологічний випадок, який слід краще написати так, як ви показали вище. На мою думку, набагато частіший випадок "якщо" із "поверненням" - це справа "охоронця".
Док Браун

Я не знаю, чому це все відбувається, але люди продовжують ігнорувати перший пункт питання. Насправді ви всі використовуєте точний рядок коду, який я прямо кажу не використовувати. I ask that you ignore the many other ways the function can be written, and changes that can be made to it. (I know most people are itching to write return sky.Color == Color.Blue.)
Selali Adobor

І перечитуючи останнє запитання, ви, здається, неправильно розумієте намір питання.
Selali Adobor

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

Я б редагував це, але я не знаю, як зробити це більш зрозумілим, оскільки я використовую точний рядок коду, який ви робите, і кажу: "не роби цього". Існує нескінченний спосіб ви можете переписати код і видалити питання, я не можу їх охопити всім, але так багато людей зрозуміли моє твердження і його поважали ...
Selali Adobor

1

Ще одна річ, яку слід задуматися в цьому аргументі, - це звички, які просуває кожен підхід.

  • if / else переробляє зразок кодування в термінах гілок. Як ви кажете, іноді ця явність хороша. Дійсно є два можливі шляхи виконання, і ми хочемо виділити це.

  • В інших випадках існує лише один шлях виконання, і тоді всі ті виняткові речі, про які повинні хвилюватися програмісти. Як ви вже згадували, охоронні застереження чудово підходять для цього.

  • Звичайно, є 3 або більше випадку (n), де ми зазвичай заохочуємо відмовитися від ланцюга if / else та використовувати оператор case / switch або поліморфізм.

Основний принцип, про який я маю на увазі, полягає в тому, що метод або функція повинні мати лише одне призначення. Будь-який код із оператором if / else або switch призначений лише для розгалуження. Тож він повинен бути абсурдно коротким (4 рядки) і лише делегувати правильний метод або дати очевидний результат (наприклад, ваш приклад). Якщо ваш код такий короткий, важко пропустити ці багаторазові повернення :) Начебто "goto вважається шкідливим", будь-яке розгалуження може бути зловживано, тому вводити критичну думку в інші твердження, як правило, варто. Як ви вже згадували, просто наявність ще одного блоку забезпечує місце для збиття коду. Ви та ваша команда повинні будете вирішити, як ви ставитесь до цього.

На що інструмент насправді скаржиться - це той факт, що у вас є повернення / перерва / кидок всередині блоку if. Що стосується цього, ви написали охоронний застереження, але накрутили його. Ви можете обрати інструмент щасливим або можете "розважити" його пропозицію, не приймаючи.


Я ніколи не замислювався над тим, що цей інструмент може розглянути питання про те, якщо бути застережним застереженням, як тільки воно впишеться в шаблон для одного, це, мабуть, так, і це пояснює міркування однієї "групи прихильників" на її відсутність
Selali Adobor

@AssortedTrailmix Правильно, ви думаєте про elseсемантично, інструменти аналізу коду зазвичай шукають сторонні інструкції, оскільки вони часто підкреслюють нерозуміння контрольного потоку. elseЩе через ifякий повертає даремно біти. if(1 == 1)часто спрацьовує однакове попередження.
Стів Джексон

1

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

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

Перш ніж ви вирішите включити або виключити ELSE, вирішіть, що він являє собою, що підкаже, чи має він бути присутнім чи ні.


0

Відповідь трохи суб’єктивна. elseБлок може допомогти читаність, встановивши , що один блок коду виконується виключно до іншого блоку коду, без необхідності , щоб прочитати обох блоків. Це може бути корисно, якщо, скажімо, обидва блоки відносно довгі. Є випадки, хоча де ifбез elses може бути читабельніше. Порівняйте наступний код із кількістю if/elseблоків:

if(a == b) {
    if(c <= d) {
        if(e != f) {
            a.doSomeStuff();
            c.makeSomeThingsWith(b);
            f.undo(d, e);
            return 9;
        } else {
            e++;
            return 3;
        }
    } else {
        return 1;
    }
} else {
    return 0;
}

з:

if(a != b) {
    return 0;
}

if(c > d) {
    return 1;
}

if(e != f) {
    e++;
    return 3;
}

a.doSomeStuff();
c.makeSomeThingsWith(b);
f.undo(d, e);
return 9;

Другий блок коду змінює вкладені ifоператори в охоронні пропозиції. Це зменшує відступ та робить деякі умови повернення чіткішими ("якщо a != b, тоді ми повертаємося 0!")


У коментарях було зазначено, що в моєму прикладі можуть бути деякі дірки, тож я розберу її ще трохи.

Тут ми могли б виписати перший блок коду так, щоб зробити його більш читабельним:

if(a != b) {
    return 0;
} else if(c > d) {
    return 1;
} else if(e != f) {
    e++;
    return 3;
} else {
    a.doSomeStuff();
    c.makeSomeThingsWith(b);
    f.undo(d, e);
    return 9;
}

Цей код еквівалентний обом блокам, наведеним вище, але він представляє певні проблеми. elseПоложення тут з'єднує їх , якщо заяви разом. У версії запобіжного застереження, наведеної вище, захисні пропозиції не залежать одна від одної. Додавання нового означає просто написати нове ifміж останньою ifта іншою логікою. Тут це теж можна зробити, лише з незначною кількістю пізнавального навантаження. Різниця, однак, полягає в тому, коли перед цим новим захисним застереженням повинна виникнути додаткова логіка. Коли заяви були незалежними, ми могли б зробити:

...
if(e != f) {
    e++;
    return 3;
}

g.doSomeLogicWith(a);

if(!g.isGood()) {
    return 4;
}

a.doSomeStuff();
...

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

Але насправді це має сенс. Використання if/elseслабо означає взаємозв'язок між частинами. Ми могли б припустити, що a != bце так чи інакше пов’язано c > dз if/elseприкованою версією. Це припущення було б оманливим, як ми бачимо з версії запобіжного застереження, що вони насправді не пов’язані між собою. Це означає, що ми можемо зробити більше з незалежними пропозиціями, як-от переставити їх (можливо, для оптимізації виконання запитів або для поліпшення логічного потоку). Ми також можемо пізнавально ігнорувати їх, як тільки ми їх минули. У if/elseланцюжку я менш впевнений, що співвідношення еквівалентності між aі bпізніше не з’явиться.

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

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

Це приємна поступка, але вона насправді не скасовує жодної відповіді. Я можу сказати, що у вашому прикладі коду:

bool CanLeaveWithoutUmbrella()
{
    if(sky.Color != Color.Blue)
    {
        return false;
    }
    return true;
}

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

Що робити, якщо я скажу, що якщо колір неба чорний, це ясна ніч, тому парасолька не потрібна. (Є простіші способи написати це, але є більш прості способи написання всього прикладу.)

bool CanLeaveWithoutUmbrella()
{
    if(sky.Color == Color.Blue)
    {
        return true;
    }

    if(sky.Color == Color.Black)
    {
        return true;
    }

    return false;
}

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

Я також зазначу, що і ваш простий приклад не такий простий. Тест на небінарне значення не те саме, що обернене тесту з перевернутими результатами.


1
Моя редакція питання стосується цієї справи. Коли обмеження, яке має бути логічно задоволене для всіх наступних кодів, таких як нульова перевірка (або будь-яка інша охорона), я погоджуюся, що пропуск elseблоку є важливим для читабельності.
Selali Adobor

1
Вашу першу версію важко зрозуміти, але я не думаю, що це потрібно, використовуючи if / else. Подивіться, як я це напишу: gist.github.com/winstonewert/c9e0955bc22ce44930fb .
Вінстон Еверт

@WinstonEwert Дивіться правки, щоб відповісти на ваші коментарі.
cbojar

У вашій редакції є деякі дійсні моменти. І я, звичайно, думаю, що охоронним застереженням є місце. Але в загальному випадку я виступаю за інші пункти.
Вінстон Еверт

0

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

void DoOneOfTwoThings(bool which)
{
    if (which)
        DoThingOne();
    else
        DoThingTwo();
}

... читабельніше, ніж ...

void DoOneOfTwoThings(bool which)
{
    if (which) {
        DoThingOne();
        return;
    }
    DoThingTwo();
}

... тому що перший має паралельну структуру, а другий - немає. Але, коли основна частина функції присвячена одному завданню, і вам потрібно спочатку перевірити деякі передумови, ...

void ProcessInputOfTypeOne(String input)
{
    if (InputIsReallyTypeTwo(input)) {
        ProcessInputOfTypeTwo(input);
        return;
    }
    ProcessInputDefinitelyOfTypeOne(input);

}

... читабельніше, ніж ...

void ProcessInputOfTypeOne(String input)
{
    if (InputIsReallyTypeTwo(input))
        ProcessInputOfTypeTwo(input);
    else
        ProcessInputDefinitelyOfTypeOne(input);
}

... тому що навмисне не встановлення паралельної структури дає підказку майбутньому читачеві, що отримання інформації, яка "справді є другою", тут ненормальна . (У реальному житті ProcessInputDefinitelyOfTypeOneце не було б окремою функцією, тому різниця була б ще більшою.)


Можливо, краще вибрати конкретніший приклад для другого випадку. Моя негайна реакція на нього полягає в тому, що "це не може бути настільки ненормальним, якщо ти все-таки пішов і обробив його".
Вінстон Еверт

@ WinstonEwert ненормальне , можливо, неправильний термін. Але я погоджуюсь із Заком, що якщо у вас є дефолт (case1) та один виняток, його слід записати як » if-> Зробити винятковий і залишити« як стратегію раннього повернення . Подумайте про код, у якому за замовчуванням включено більше перевірок, було б швидше спочатку обробити винятковий випадок.
Thomas Junk

Це, здається, потрапляє у справу, з якою я говорив when using an if block to apply a constraint that must be logically satisfied for all following code, such as a null-check (or any other guards). Логічно, що будь-яка робота ProcessInputOfTypeOneзалежить від того, що !InputIsReallyTypeTwo(input)тому нам потрібно виловити це поза нашою звичайною обробкою. Зазвичай це ProcessInputOfTypeTwo(input);було б таким, throw ICan'tProccessThatExceptionщо зробило б подібність більш очевидною.
Selali Adobor

@WinstonEwert Я, можливо, міг би так краще сформулювати, так. Я думав про ситуацію , яка придумує багато при кодуванні tokenizers вручну: в CSS, наприклад, послідовність символів « u+» зазвичай вводить «Юнікод-діапазон» маркера, але якщо наступний символ не є шестнадцатеричной цифрою, тоді потрібно створити резервну копію та обробити 'u' як ідентифікатор. Таким чином, основний цикл сканера передає "сканування символу діапазону унікоду" дещо неточно, і він починається з "... якщо ми знаходимося в цьому незвичайному спеціальному випадку, створити резервну копію, а потім зателефонуємо на підпрограму сканування-ідентифікатор".
zwol

@AssortedTrailmix Навіть якщо приклад, про який я думав, не був зі застарілої кодової бази, в якій винятки можуть не використовуватися, це не умова помилки , це просто те, що код, який викликає, ProcessInputOfTypeOneвикористовує неточну, але швидку перевірку, що іноді ловить тип 2 замість цього.
zwol

0

Так, складність збільшується, оскільки інша стаття зайва . Таким чином, краще, щоб не залишати код слабким і середнім. Це на тому ж акорді, як пропущення надлишкових thisкласифікаторів (Java, C ++, C #) та опущення дужок у returnвиписках тощо.

Хороший програміст думає "що я можу додати?" тоді як великий програміст думає, "що я можу зняти?".


1
Коли я бачу опущення elseблоку, якщо це пояснюється в одноклапнику (що не часто), часто це трапляється з таким міркуванням, тому +1 для подання аргументу "за замовчуванням" я бачу, але я не вважаємо це досить сильним міркуванням. A good programmer things "what can I add?" while a great programmer things "what can I remove?".Здається, поширена приказка, що багато людей перебільшують без ретельного розгляду, і я особисто вважаю, що це один із таких випадків.
Selali Adobor

Так, читаючи ваше запитання, я одразу відчув, що ви вже вирішили, але хотів підтвердження. Ця відповідь, очевидно, не є тим, чого ви хотіли, але іноді важливо враховувати думки, з якими ви не згодні. Може, є щось теж?
vidstige

-1

Я помітив, передумавши цей випадок.

На питання про це рік тому я відповів би приблизно так:

»Для методу має бути лише один entryі один. exitІ зважаючи на це, я б запропонував переробити код на:

bool CanLeaveWithoutUmbrella()
{
    bool result

    if(sky.Color == Color.Blue)
    {
        result = true;
    }
    else
    {
        result = false;
    }

    return result;
}

З точки зору спілкування зрозуміло , що робити. Ifщось є, маніпулюйте результатом одним способом , else маніпулюйте ним іншим способом .

Але це передбачає непотрібне else . elseВисловлює по замовчуванням нагоди . Тож на другому кроці я міг би відновити це

bool CanLeaveWithoutUmbrella()
{
    bool result=false

    if(sky.Color == Color.Blue)
    {
        result = true;
    }
    return result;
}

Тоді виникає питання: навіщо взагалі використовувати тимчасову змінну? Наступний крок рефакторизації призводить до:

bool CanLeaveWithoutUmbrella()
{

    if(sky.Color == Color.Blue)
    {
        return true;
    }
    return false;
}

Тож це ясно в тому, що він робить. Я б навіть пішов на крок далі:

bool CanLeaveWithoutUmbrella()
{

    if(sky.Color == Color.Blue) return true;
    return false;
}

Або для слабкодухих :

bool CanLeaveWithoutUmbrella()
{

    if(sky.Color == Color.Blue) { return true; }
    return false;
}

Ви можете прочитати це так: "CanLeaveWithoutUmbrella повертає логічне значення . Якщо нічого особливого не відбувається, воно повертається помилковим «Це перше читання, зверху вниз.

І тоді ви «розбираєте» умову »Якщо умова виконана, вона повертається істиною « Ви могли повністю пропустити умовне і зрозуміли, що ця функція виконує у випадку за замовчуванням . Вашому оку та розуму залишається лише проглядати деякі букви з лівого боку, не читаючи частини праворуч.

Я маю враження, що інше, безпосередньо прямо заявляє про наміри, заявляючи про те, що код в обох блоках безпосередньо пов'язаний.

Так це правильно. Але ця інформація є зайвою . У вас є випадок за замовчуванням і один "виняток", який охоплюєтьсяif викладом.

Маючи справу зі складнішими структурами, я б обрав іншу стратегію, опускаючи ifабо зовсім некрасивого брата switch.


Надмірність +1 безумовно свідчить про збільшення не просто складності, але і плутанини. Я знаю, що мені завжди доводилося двічі перевіряти код, написаний так, саме через надмірність.
дієтабудда

1
Чи можете ви видалити справи після запуску справи So this is clear in what it does...і розширити її? (Раніше випадки також мають сумнівну актуальність). Я говорю це тому, що саме це питання ми задаємо. Ви висловили свою позицію, пропустивши блок "інше", і саме ця позиція потребує більше пояснень (і тієї, яка змусила мене задати це питання). Із запитання:I ask that you ignore the many other ways the function can be written, and changes that can be made to it. (I know most people are itching to write return sky.Color == Color.Blue.)
Selali Adobor

@AssortedTrailmix Звичайно! Що саме я повинен детально розробити? Оскільки ваше первинне запитання було «Чи інші блоки збільшують складність коду?», І моя відповідь: так. У цьому випадку його можна опустити.
Thomas Junk

І: Ні! Я не розумію голоси.
Thomas Junk

-1

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

return true;

Отже, якщо ifблок повинен був бути введений, весь решта функції, за визначенням, не виконується. Але якщо він не введений, оскільки немає поданих ifтверджень, вся решта функції виконується. Було б зовсім інше, якби returnзаява не була в ifблоці, і в цьому випадку наявність або відсутністьelse блоку матиме вплив, але тут це не мало би впливу.

У своєму запитанні, перевернувши свій ifстан і пропустивши else, ви вказали наступне:

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

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

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

Це, по суті, те, що тут відбувається. Ви повертаєтесь з ifблоку, так що ifумова, що оцінюється, false є обмеженням, яке має бути логічно задоволеним для всіх наступних кодів.

Чи збільшується рівень складності, не включаючи ще блок?

Ні, це призведе до зменшення складності вашого коду, і навіть може призвести до зменшення складеного коду, залежно від того, будуть відбуватися чи не відбудуться певні надтривіальні оптимізації.


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

@MichaelShaw Я думаю, що відповідь Авіва Конна йде в те, про що я говорю.
Panzercrisis

-2

У конкретному прикладі, який ви навели, це і є.

  • Він змушує рецензента ще раз прочитати код, щоб переконатися, що це не помилка.
  • Він додає (зайву) цикломатичну складність, оскільки додає один вузол до графіка потоку.

Я думаю, що це не могло стати простішим, що це:

bool CanLeaveWithoutUmbrella()
{
    return (sky.Color == Color.Blue);
}

6
Я спеціально звертаюсь до того факту, що цей дуже спрощений приклад можна переписати для видалення ifзаяви. Насправді я відверто переконую подальше спрощення, використовуючи точний код, який ви використовували. Крім того, цикломатична складність не збільшується elseблоком.
Selali Adobor

-4

Я завжди намагаюся написати свій код таким, щоб намір був максимально зрозумілим. У вашому прикладі бракує певного контексту, тому я трохи його зміню:

class Sky {
    Sky(Colour c)
    {
        this.color = c;
    }
    bool CanLeaveWithoutUmbrella()
    {
        if(this.color == Color.Blue)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

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

По-перше, є ваше запитання щодо elseгалузі. Я не проти будь-якого способу, але схильний залишати це else. Я розумію аргумент щодо явного, але моя думка полягає в тому, що ifзаяви повинні містити "необов'язкові" гілки, як та return true. Я б не назвав return falseгалузь «необов’язковою», оскільки вона діє як наш дефолт. Так чи інакше, я вважаю це дуже незначним питанням і набагато менш важливим, ніж наступні:

class Sky {
    Sky(Colour c)
    {
        this.color = c;
    }
    bool CanLeaveWithoutUmbrella()
    {
        if(this.color == Color.Blue)
        {
            return true;
        }
        return false;
    }
}

Набагато важливіше питання полягає в тому , що ваші філії роблять занадто багато! Гілки, як і все, повинні бути "максимально простими, але не більше". У цьому випадку ви використовували ifоператор, який розгалужується між кодовими блоками (колекціями висловлювань), коли все, що вам дійсно потрібно для розгалуження, - це вирази (значення). Це зрозуміло, оскільки: а) ваші кодові блоки містять лише поодинокі твердження; б) вони є одним і тим же твердженням ( return). Ми можемо використовувати потрійний оператор, ?:щоб звузити гілку лише до тієї частини, яка відрізняється:

class Sky {
    Sky(Colour c)
    {
        this.color = c;
    }
    bool CanLeaveWithoutUmbrella()
    {
        return (this.color == Color.Blue)
            ? true
            : false;
    }
}

Тепер ми досягаємо очевидної надмірності, з якою наш результат ідентичний this.color == Color.Blue. Я знаю, що ваше запитання просить нас ігнорувати це, але я думаю, що це дійсно важливо зазначити, що це дуже першочерговий процедурний спосіб мислення: ви руйнуєте вхідні значення та будуєте деякі вихідні значення. Це добре, але по можливості набагато потужніше мислити з точки зору взаємозв'язків або перетворень між входом і виходом. У цьому випадку стосунки очевидно, що вони однакові, але я часто бачу такий заплутаний процедурний код, як цей, який затемнює деякі прості відносини. Давайте далі і зробимо це спрощення:

class Sky {
    Sky(Colour c)
    {
        this.color = c;
    }
    bool CanLeaveWithoutUmbrella()
    {
        return (this.color == Color.Blue);
    }
}

Наступна річ , яку я б вказати на те , що ваш API містить подвійний негатив: це можливо , CanLeaveWithoutUmbrellaщоб бути false. Це, звичайно, спрощує NeedUmbrellaіснування true, тому зробимо так:

class Sky {
    Sky(Colour c)
    {
        this.color = c;
    }
    bool NeedUmbrella()
    {
        return (this.color != Color.Blue);
    }
}

Тепер ми можемо почати думати про ваш стиль кодування. Схоже, ви використовуєте об'єктно-орієнтовану мову, але, використовуючи ifзаяви для розгалуження між кодовими блоками, ви закінчили писати процедурний код.

В об'єктно-орієнтованому коді всі кодові блоки є методами, і все розгалуження здійснюється за допомогою динамічної відправки , наприклад. з використанням класів або прототипів. Сперечається, чи це спрощує справи, але це повинно зробити ваш код більш узгодженим з рештою мови:

class Sky {
    bool NeedUmbrella()
    {
        return true;
    }
}

class BlueSky extends Sky {
    bool NeedUmbrella()
    {
        return false;
    }
}

Зауважте, що використання потрійних операторів для розгалуження між виразами є загальним у функціональному програмуванні.


Перший абзац відповіді здається на шляху до відповіді на запитання, але він негайно розходиться в точній темі, я явно прошу ігнорувати цей дуже простий приклад . З питання : I ask that you ignore the many other ways the function can be written, and changes that can be made to it. (I know most people are itching to write return sky.Color == Color.Blue.). Насправді ви використовуєте точний рядок коду, який я згадую. Крім того, хоча ця частина питання поза темою, я б сказав, що ви занадто далеко виходите зі свого висновку. Ви докорінно змінили, що таке код.
Selali Adobor

@AssortedTrailmix Це суто питання про стиль. Має сенс дбати про стиль і має сенс ігнорувати його (орієнтуючись лише на результати). Я не думаю, що має сенс дбати про return false;vs, else { return false; }хоча не піклуватися про полярність гілки, динамічну відправку, тернарії тощо. Якщо ви пишете процедурний код на мові ОО, потрібні радикальні зміни;)
Warbo

Ви можете сказати щось подібне загалом, але це не застосовується, коли ви відповідаєте на запитання з чітко визначеними параметрами (особливо, коли без поваги до цих параметрів ви можете "абстрагувати" все питання). Я б також сказав, що останнє речення просто невірно. OOP - це про "процедурну абстракцію", а не про "процедурну абстракцію". Я б сказав, що факт, що ви перейшли від одного вкладиша до нескінченної кількості класів (по одному на кожен колір), показує, чому. Крім того, мені все ще цікаво, яка динамічна відправка повинна мати відношення до if/elseзаяви, і яка полярність гілки.
Selali Adobor

Я ніколи не казав, що рішення OO є кращим (насправді я віддаю перевагу функціональному програмуванню), я просто сказав, що воно більше відповідає мові. Під "полярністю" я мав на увазі, яка річ є "справжньою", а яка "помилковою" (я переключила її на "NeedUmbrella"). В OO-конструкції весь потік управління визначається динамічним відправленням. Наприклад, Smalltalk не дозволяє нічого іншого en.wikipedia.org/wiki/Smalltalk#Control_structures (див. Також c2.com/cgi/wiki?HeInventedTheTerm )
Warbo

2
Я б відмовився від цього, доки не дійшов до останнього пункту (про ОО), який замість цього заробив його скорочення! Ось саме такий недумний зловживання конструкціями OO, що створює код равіолі , який так само нечитабельний, як спагетті.
zwol
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.