Почему считается плохой практикой опускать фигурные скобки?

Почему все говорят мне, что написание кода - это плохая практика?

if (foo)
    Bar();

//or

for(int i = 0 i < count; i++)
    Bar(i);

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

using (Brush br = new SolidBrush(Color.FromArgb(15, GlowColor)))
{
    for (int x = 0; x <= GlowAmount; x++)
    {
        for (int y = 0; y <= GlowAmount; y++)
        {
            g.DrawString(Text, this.Font, br, new Point(IconOffset + x, y));
        }
     }
 }
 //versus
using (Brush br = new SolidBrush(Color.FromArgb(15, GlowColor)))
    for (int x = 0; x <= GlowAmount; x++)
        for (int y = 0; y <= GlowAmount; y++)
            g.DrawString(Text, this.Font, br, new Point(IconOffset + x, y));

Вы также можете получить дополнительное преимущество от цепочки usings вместе, без необходимости отступать миллион раз.

using (Graphics g = Graphics.FromImage(bmp))
{
    using (Brush brush = new SolidBrush(backgroundColor))
    {
        using (Pen pen = new Pen(Color.FromArgb(penColor)))
        {
            //do lots of work
        }
    }
 }
//versus
using (Graphics g = Graphics.FromImage(bmp))
using (Brush brush = new SolidBrush(backgroundColor))
using (Pen pen = new Pen(Color.FromArgb(penColor)))
{
    //do lots of work
}

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

if (foo)
    Bar();
    Biz();

Вопросы:

  1. Не правильно ли хотеть использовать более компактный синтаксис, который предлагает язык? Люди, которые проектируют эти языки, умны, я не могу себе представить, что они добавят функцию, которой всегда плохо пользоваться.
  2. Должны ли мы или не должны писать код, чтобы наименьший общий знаменатель мог понять и без проблем работать с ним?
  3. Есть еще один аргумент, который я пропускаю?

52 ответа

Решение

На самом деле, единственный раз, который меня действительно поразил, это когда я отлаживал и комментировал bar():

if(foo)
  // bar();
doSomethingElse();

Помимо этого, я склонен использовать:

if(foo) bar();

Который заботится о вышеупомянутом случае.

РЕДАКТИРОВАТЬ Спасибо за разъяснение вопроса, я согласен, мы не должны писать код с наименьшим общим знаменателем.

Скорость чтения...

Помимо того, что уже было упомянуто. К этому моменту я уже был подготовлен для анализа операторов с фигурными скобками и пробелами. Итак, я прочитал:

if (condition)
{
    DoSomething();
}

DoSomethingElse();

Чуть быстрее, чем я читаю:

if (condition) DoSomething();

DoSomethingElse();

Я читаю это немного медленнее, если это выглядит так:

if (condition) DoSomething();
DoSomethingElse();

Я прочитал это значительно медленнее, чем предыдущий:

if (condition) 
    DoSomething();
DoSomethingElse();

потому что я не могу не прочитать его еще раз на всякий случай и задаюсь вопросом, намеревался ли автор:

if (condition)
{
    DoSomething();
    DoSomethingElse();
}

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

if (condition) 
    DoSomething();
    DoSomethingElse();

Если это что-то маленькое, напишите это так:

if(foo()) bar();

Если это достаточно долго, чтобы разбить на две строки, используйте фигурные скобки.

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

Еще одна веская причина для того, чтобы всегда использовать фигурные скобки, кроме того, что кто-то добавляет второе выражение в if, может происходить примерно так:

if(a)
   if(b)
     c();
else
   d();

Заметили ли вы, что предложение else на самом деле относится к выражению if (b)? Вы, вероятно, сделали, но вы бы доверяли кому-либо, чтобы быть знакомым с этим Гоча?

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

Линии дешевые. Мощность процессора дешевая. Время разработчика очень дорого.

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

(а) Легко для любого другого разработчика следить за тем, что я делаю

(б) Прокомментируйте конкретные части кода, которые могут понадобиться

(c) Легко отлаживать, если что-то идет не так

(d) Легко изменить, если это необходимо в будущем (т.е. добавить / удалить код)

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

Опуская фигурные скобки в большинстве случаев, это для меня делает (b), (c) и (d) более трудным (однако, примечание не является невозможным). Я бы сказал, что использование фигурных скобок или нет не влияет на (а).

Это не всегда считается плохой практикой. http://www.mono-project.com/Coding_Guidelines предлагает не использовать фигурные скобки, если в этом нет необходимости. То же самое для стандартов кодирования GNU. Я думаю, что это вопрос личного вкуса, как всегда со стандартами кодирования.

Я предпочитаю ясность, которую предлагает фигурная скобка. Вы точно знаете, что имеется в виду, и вам не нужно догадываться, просто ли кто-то обманул и оставил их (и добавил ошибку). Единственный раз, когда я их опускаю, это когда я помещаю действия if и if в одну строку. Я тоже так делаю не очень часто. Я на самом деле предпочитаю пропуски, введенные в виде фигурной скобки в отдельной строке, хотя после многих лет программирования, подобного K&R C, окончание строки фигурной скобкой - это практика, которую мне нужно преодолеть, если IDE не применяет ее для мне.

if (condition) action();  // ok by me

if (condition) // normal/standard for me
{
   action();
}

Я думаю, что это вопрос руководящих принципов для проекта, над которым вы работаете, и личного вкуса.

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

if (something)
    just one statement; // i find this ugly
else
{
    // many
    // lines
    // of code
}

я предпочитаю

if (something)
{
    just one statement; // looks better:)
}
else
{
    // many
    // lines
    // of code
}

Я привык думать так же.

До одного дня (почему всегда есть тот "один день", который навсегда меняет вашу жизнь?), Мы тратим от 24 до 36 часов подряд без отладки рабочего кода, только чтобы узнать, что кто-то не поставил скобки в сочетании с изменением поиска / замены.,

Это было что-то вроде этого.

 if( debugEnabled ) 
      println( "About to save 1 day of work to some very important place.");
 saveDayData();

Что было после того, как

 if( debugEnabled ) 
 //     println( "About to save 1 day of work to some very important place.");
 saveDayData();

Оказывается, что система генерировала 500 МБ журналов в день, и нас попросили остановить это. Флаг отладки был недостаточен, поэтому поиск и замена println были в порядке.

Тем не менее, когда приложение было запущено в производство, флаг отладки был отключен, а важный "saveDayData" никогда не вызывался.

РЕДАКТИРОВАТЬ

Теперь единственное место, где я не использую фигурные скобки, это конструкция if/try.

if( object != null ) try { 
     object.close();
} catch( .....

После просмотра суперзвезда разработчик делает это.

Один из случаев, когда это может вас укусить, - это в старые времена макросы C/C++. Я знаю, что это вопрос C#, но часто стандарты кодирования переносятся без причин, по которым стандарт был создан в первую очередь.

Если вы не очень осторожны при создании макросов, вы можете столкнуться с проблемами в операторах if, которые не используют {}.

#define BADLY_MADE_MACRO(x) function1(x); function2(x);

if (myCondition) BADLY_MADE_MACRO(myValue)

Не поймите меня неправильно, я не говорю, что вы всегда должны делать {}, чтобы избежать этой проблемы в C/C++, но из-за этого мне пришлось столкнуться с некоторыми очень странными ошибками.

Чтобы быть тупым, я вижу это как:

Хорошие программисты программируют в обороне, плохие программисты - нет.

Так как есть несколько примеров выше и мой собственный подобный опыт с ошибками, связанными с забвением фигурных скобок, то я научился трудному пути ВСЕГДА РАЗМЕЩАТЬ БРАСЫ.

Все остальное - это выбор личного стиля, а не безопасности, и это явно плохое программирование.

Джоэл даже упоминает об этом в "Неправильный код выглядит неправильно"

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

Я очень рад:

foreach (Foo f in foos)
  foreach (Bar b in bars)
    if (f.Equals(b))
      return true;

return false;

Лично я не понимаю, почему

foreach (Foo f in foos)
{
  foreach (Bar b in bars)
  {
    if (f.Equals(b))
    {
      return true;
    }
  }
}

return false;

более читабелен.

Да, строки свободны, но почему я должен прокручивать страницы и страницы кода, когда он может быть вдвое меньше?

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

Кроме того, я всегда буду ставить скобки для вложенных, если там, где я вложил чужие

if (condition1)
  if (condition2)
    doSomething();
  else (condition2)
    doSomethingElse();

против

if (condition1)
  if (condition2)
    doSomething();
else (condition2)
  doSomethingElse();

ужасно сбивает с толку, поэтому я всегда пишу это так:

if (condition1)
{
  if (condition2)
    doSomething();
  else (condition2)
    doSomethingElse();
}

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

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

Я полагаю, это означает, что я не умный. Я сделал ошибки вокруг этого несколько раз. Я отлаживал ошибки других вокруг этого. Из-за этого я наблюдал, как программное обеспечение поставляется с ошибками (RDP к машине с VS2002 и ваш шрифт окна наблюдения будет работать неправильно).

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

Тем не менее, в мире изменились некоторые вещи, которые делают правило "используйте скобки на однолинейных блоках" менее актуальным сегодня, чем когда Моисей довел его до нас:

  • Некоторые популярные языки устраняют проблему, заставляя компьютер читать отступы, как это делает программист (например, Python).

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

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

  • Рефакторинг и языковая выразительность означают, что мои блоки намного короче, а однострочные блоки встречаются гораздо чаще, чем раньше. Гипотетически, с безжалостным применением ExtractMethod, я мог бы иметь только однострочные блоки во всей моей программе. (Интересно, как это будет выглядеть?)

На самом деле, есть явная выгода от беспощадного рефакторинга и пропуска фигурных скобок в однолинейных блоках: когда вы видите фигурные скобки, в вашей голове может возникнуть небольшая тревога, которая говорит: "Сложность здесь! Остерегайтесь!". Представьте, если это было нормой

if (condition) Foo();   // normal, everyday code

if (condition) 
{
    // something non-trivial hapening; pay attention!
    Foo();
    Bar();
}

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

Я согласен с тем, что "если вы достаточно умны, чтобы заставить кого-то платить вам за написание кода, вы должны быть достаточно умны, чтобы не полагаться только на отступы, чтобы увидеть поток кода".

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

Моя философия такова: если это делает код более читабельным, почему бы не сделать это?

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

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

Я иногда использую самый нижний код (множественные операторы использования), но кроме этого я всегда вставляю фигурные скобки. Я просто нахожу, что это делает код понятнее. Из не просто отступа очевидно, что оператор является частью блока (и, следовательно, вероятно, частью if и т. Д.).

Я видел

if (...)
    foo();
    bar();

ошибка укусила меня (точнее "я и коллеги" - я на самом деле не представил ошибку) один раз. И это несмотря на то, что наши стандарты кодирования в то время рекомендовали использовать фигурные скобки везде. Мне потребовалось удивительно много времени, чтобы увидеть - потому что ты видишь то, что хочешь видеть. (Это было около 10 лет назад. Может быть, я бы нашел это быстрее сейчас.)

Конечно, если вы используете "фигурную скобку в конце строки", это уменьшает дополнительные строки, но мне лично этот стиль все равно не нравится. (Я использую это на работе, и нашел это менее неприятным, чем я ожидал, но это все еще немного неприятно.)

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

if(x == y)
   for(/* loop */)
   {
      //200 lines
   }

//rampion's example:
for(/* loop */)
{
   for(/* loop */)
      for(/* loop */)
      {
         //several lines
      }
}

В противном случае у меня нет проблем с этим.

Из трех конвенций:

if(addCurleyBraces()) bugFreeSofware.hooray();

а также:

if(addCurleyBraces())
    bugFreeSofware.hooray();

и (которые представляют любой стиль отступа, используя открывающую и закрывающую скобки):

if(addCurleyBraces()) {
    bugFreeSofware.hooray();
}

Я предпочитаю последний как:

  • Мне легче читать, если все операторы if написаны одинаково.
  • Это может сделать программное обеспечение чуть более надежным и без ошибок. Тем не менее, все современные IDE и расширенные текстовые редакторы имеют прекрасные функции автоматического отступа, которые, я думаю, должен использовать каждый, если это не мешает форматированию комментариев или не соответствует групповым стандартам (во многих случаях можно создать собственную схему форматирования). и поделиться этим с командой). Моя точка зрения заключается в том, что, если отступы выполнены правильно, риск появления ошибки немного снижается.
  • Я предпочитаю, чтобы логические выражения и операторы выполнялись в разных строках. Мне нравится иметь возможность пометить строку для целей отладки. Даже если я использую IDE, где я могу пометить оператор и перейти к нему, это интерактивная операция, и я могу забыть, где я начал отлаживать, или, по крайней мере, мне потребуется немного больше времени, чтобы пройтись по коду несколько раз. раз (так как я должен отмечать позицию вручную каждый раз во время отладки).

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

Строки (почти) свободны, минимизация количества строк в вашем коде не должна быть целью.

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

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

Некоторые могут сказать, что это случай предпочтений, но я считаю, что логический поток программы намного легче следовать, если она внутренне согласована, и я не верю, что это непротиворечиво написать одно выражение IF, подобное этому;

if(x < y)
    x = y;
else
    y = x;

И другой, как это;

if(x < y)
{
    x = y;
    x++;
}
else
{
    y = x;
    y++;
}

Я предпочитаю просто выбрать один общий стиль и придерживаться его:)

Используйте некоторые личные суждения.

if (foo)
  bar();

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

if (foo)
  bar();
  baz();

Если вы не беспокоитесь о дебилах, у вас все в порядке (я не... если они не могут правильно понять основной синтаксис кода, это наименьшая из их проблем)>

В обмен это намного более читабельно.

Оставшееся время:

if (foo) {
  bar();
  baz();
}

Который был моим любимым, насколько я помню. Дополнительно:

if (foo) {
  bar();
  baz();
} else {
  qux();
}

Работает для меня.

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

Чтобы код с фигурными скобками не занимал много места, я использую технику, рекомендованную в книге Code Complete:

if (...) {
    foo();
    bar();
}
else {
    ...
}

Хорошо, это старый вопрос, на который был дан ответ до смерти. У меня есть что добавить.

Во-первых, я просто должен сказать, ИСПОЛЬЗУЙТЕ БРАКИ. Они могут только улучшить читаемость, а читаемость (для вас и других!) Должна быть очень высокой в ​​вашем списке приоритетов, если вы не пишете сборку. Нечитаемый код всегда, всегда приводит к ошибкам. Если вы обнаружите, что скобки заставляют ваш код занимать слишком много места, ваши методы, вероятно, слишком длинные. Большинство или все методы должны умещаться в пределах одной высоты экрана, если вы все делаете правильно, и Find (F3) - ваш друг.

Теперь для моего дополнения: есть проблема с этим:

if (foo) bar();

Попробуйте установить точку останова, которая будет срабатывать, только если bar() будет работать. Вы можете сделать это в C#, поместив курсор на вторую половину кода, но это неочевидно и немного болезненно. В C++ вы не могли этого сделать вообще. По этой причине один из наших самых старших разработчиков, работающих над кодом C++, настаивает на разбиении операторов if на две строки. И я с ним согласен.

Так что сделайте это:

if (foo)
{
    bar(); //It is easy to put a breakpoint here, and that is useful.
}

Раньше я был большим сторонником "фигурные скобки - это НЕОБХОДИМО!", Но с тех пор, как я принял модульное тестирование, я обнаружил, что мои модульные тесты защищают беспрепятственные утверждения от таких сценариев, как:

if (foo)
    snafu();
    bar();

С помощью хороших модульных тестов я могу с уверенностью опустить фигурные скобки для простых операторов для улучшения читабельности (да, это может быть субъективным).

В качестве альтернативы, для чего-то подобного выше, я бы, скорее всего, добавил это так:

if (foo) snafu();

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

Одна из основных проблем - когда у вас есть области с одним и не одним вкладышами, а также отделение от контрольного состояния (for, if-А что у тебя) и конец устава.

Например:

for (...)
{
  for (...)
    for (...) 
    {
      // a couple pages of code
    }
  // which for block is ending here?  A good text editor will tell you, 
  // but it's not obvious when you're reading the code
}

Допустим, у вас есть код:

if (foo)
    bar();

а потом приходит кто-то еще и добавляет:

if (foo)
    snafu();
    bar();

Согласно написанному, bar(); сейчас выполняется безоговорочно. Включая фигурные скобки, вы предотвращаете такую ​​случайную ошибку. Код должен быть написан таким образом, чтобы сделать такие ошибки трудными или невозможными для совершения. Если бы я делал обзор кода и увидел недостающие скобки, особенно разбросанные по нескольким строкам, я бы создал дефект. В тех случаях, когда это оправдано, держите его в одной строке, чтобы вероятность такой ошибки снова была сведена к минимуму.

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

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

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

Я вижу это как аргумент if ( foo == 0 ) против if ( 0 == foo ), Последнее может предотвратить ошибки для новых программистов (и, возможно, даже иногда для ветеранов), в то время как первое легче быстро прочитать и понять, когда вы поддерживаете код.

Ошибка на стороне более безопасной - еще одна ошибка, которую вам, возможно, не придется исправлять.

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

Если у меня есть одна строка, я обычно форматирую ее следующим образом:

if( some_condition ) { do_some_operation; }

Если строка слишком громоздкая, используйте следующее:

if( some_condition )
{
    do_some_operation;
}

В большинстве случаев это укоренилось в качестве стандарта кодирования, будь то для компании или проекта FOSS.

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

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

Другие вопросы по тегам