Недавно я врезался в следующий код C++:
if (a)
{
f();
}
else if (b)
{
f();
}
else if (c)
{
f();
}
Где a, b и c являются всеми различными условиями, и они не очень коротки.
Я пытался изменить код на:
if (a || b || c)
{
f();
}
Но автор выступил против высказывания, что мое изменение уменьшит удобочитаемость кода. У меня было два аргумента:
1) Вы не должны увеличивать удобочитаемость путем замены одного переходящего оператора три (хотя я действительно сомневаюсь, что возможно еще сделать код более читаемым при помощи если вместо ||).
2) Это не самый быстрый код, и никакой компилятор не оптимизирует это.
Но мои аргументы не убедили его.
Что Вы сказали бы программисту, пишущему такой код?
Вы думаете, что сложное условие еще является оправданием за использование если вместо ИЛИ?
Замените три сложных условия одной функцией, делая очевидным, почему f()
должна быть выполнена.
bool ShouldExecute; { return a||b||c};
...
if ShouldExecute {f();};
Производительность здесь не проблема.
Многие люди заворачивают себя в флаг «читабельности», когда на самом деле это вопрос индивидуального вкуса.
Иногда я делаю это так, иногда - другим. Я думаю о том -
«Каким образом будет легче редактировать виды изменений, которые, возможно, придется внести в будущем?»
В целом я думаю, что вы правы в этом if (a || b || c) {f (); }
легче читать. Он также мог хорошо использовать пробелы, чтобы помочь разделить три блока.
Тем не менее, мне было бы интересно посмотреть, как выглядят a
, b
, c
и f
. Если f
- это всего лишь вызов одной функции, и каждый блок имеет большой , я могу как бы понять его точку зрения, хотя меня раздражает нарушение принципа DRY, вызывая f
] три разных раза.
Я думаю, что оба ваших аргумента (а также аргумент Developer Art о сопровождаемости) являются обоснованными, но, очевидно, ваш партнер по дискуссии не готов к обсуждению.
У меня такое чувство, что вы ведете эту дискуссию с кем-то, кто считается более старшим. Если это так, то вам нужно вести войну, а это всего лишь одна маленькая битва, победа в которой для вас не важна. Вместо того чтобы тратить время на споры по этому поводу, постарайтесь сделать так, чтобы ваши результаты (которые будут намного лучше, чем у вашего партнера по дискуссии, если он пишет такой код) говорили сами за себя. Просто убедитесь, что вы получаете благодарность за свою работу, а не вся команда или кто-то другой.
Возможно, это не тот ответ на вопрос, которого вы ожидали, но у меня такое чувство, что здесь есть что-то большее, чем просто этот небольшой спор...
Производительность даже не должна подвергаться сомнению
Возможно, позже он не будет вызывать f () во всех трех условиях
Я очень сомневаюсь, что это приведет к увеличению производительности, за исключением, по крайней мере, очень специфического сценария. В этом сценарии вы меняете a, b и c, и, таким образом, какой из трех, который запускает код, изменяется, но код все равно выполняется, а затем сокращение кода до одного оператора if может улучшить, поскольку ЦП может иметь код в кеш ветки, когда он доберется до него в следующий раз. Если вы утроите код, так что он будет занимать в 3 раза больше места в кэше ветвления, высока вероятность того, что один или несколько путей будут вытеснены, и, следовательно, у вас не будет наиболее производительного выполнения.
Это очень низкий уровень, поэтому я снова сомневаюсь, что это окажет большое влияние.
Что касается удобочитаемости, которую легче читать:
или в этом:
Поместите туда еще код, кроме простого вызова функции, и он становится трудно определить, что это на самом деле три идентичных фрагмента кода.
Из-за этого снижается ремонтопригодность при использовании организации с тремя операторами if.
У вас также есть дублированный код, что почти всегда является признаком плохой структуры и дизайна.
По сути, я бы сказал программисту, что если у него есть проблемы с чтением способа его написания с одним условным оператором, возможно, С ++ - не то, что ему следует делать.
Теперь давайте предположим, что части «a», «b» и «c» действительно большие, так что операционная система там теряется в большом количестве шума с круглыми скобками или чем-то еще.
Я бы все равно реорганизовал код так, чтобы он вызывал функцию (или выполнял код там) только в одном месте, так что, возможно, это компромисс?
bool doExecute = false;
if (a) doExecute = true;
if (b) doExecute = true;
if (c) doExecute = true;
if (doExecute)
{
f();
}
или, что еще лучше, этот способ воспользоваться преимуществом логического логическое короткое замыкание, чтобы не оценивать ненужные вещи:
bool doExecute = a;
doExecute = doExecute || b;
doExecute = doExecute || c;
if (doExecute)
{
f();
}
Этот код избыточен. Он склонен к ошибкам.
Если вы однажды замените f();
на что-то другое, есть опасность пропустить одну ошибку.
Однако может быть мотивация, что эти три тела условий могут однажды стать разными, и вы как бы готовитесь к этой ситуации. Если есть большая вероятность, что это произойдет, то можно сделать что-то подобное. Но я бы посоветовал следовать принципу YAGNI (You Ain't Gonna Need It). Не могу сказать, сколько раздутого кода было написано не из-за реальной необходимости, а просто в ожидании, что он понадобится завтра. Практика показывает, что это не приносит никакой пользы в течение всего срока службы приложения, но сильно увеличивает накладные расходы на обслуживание.
Что касается того, как подойти к объяснению этого коллеге, то этот вопрос уже много раз обсуждался. Посмотрите здесь:
Как сказать кому-то, что он пишет плохой код?
Как оправдаться перед коллегами, что они создают плохой код?
Как справиться с некачественным кодом от членов команды?
"Наставник" старшего программиста или коллеги без оскорблений
Повторение кода не делает вещи яснее, ваш (a|||b||c) намного яснее, хотя, возможно, можно было бы рефакторить его еще больше (поскольку это C++), например,
x.f()
Поскольку условия длинные, пусть он сделает так:
if ( (aaaaaaaaaaaaaaaaaaaaaaaaaaaa) || (bbbbbbbbbbbbbbbbbbbbbbbbbbbb) || (cccccccccccccccccccccccccccc) ) { f(); }
Хороший компилятор в любом случае превратит все это в один и тот же код, но приведенное выше - обычная конструкция для такого типа вещей. 3 вызова одной и той же функции - это некрасиво.