Священная война за скобки в коде

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

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

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

Наиболее полно эта тема раскрыта в книге Ричарда Хэзфилда "Искусство программирования на C". Да простит меня автор за копирование, но ниже я приведу выдержку из его работы, касающуюся способов расстановки скобок.



Сегодня имеется четыре наиболее распространенных стиля расстановки фигурных скобок (bracing style), используемых в С-сообществе. Не сомневаюсь, что вы будете иметь свое собственное мнение о том, какой из этих стилей правильный. Но давайте рассмотрим их по очереди.

Стиль фигурных скобок 1TBS

1TBS является аббревиатурой стиля One True Bracing Style. Это единственно истинный стиль расстановки скобок. Он получил такое прекрасное название потому что был использован Кернигеном (Kernighan) и Ричи (Ritchie) в их классической книге The С Programming Language — Язык программирования С. С-программисты смотрят на Кернигена и Ричи (везде далее в этой книге K&R) как на "полубогов", так что название One True Bracing Style имеет вполне подходящий религиозный оттенок. Некоторые люди предпочитают называть его K&R-стиль или рациональный (kernel) стиль. Сторонники этого стиля обычно используют отступы в восемь пробелов, но это не догма.
Ниже приведен отрывок кода, иллюстрирующий стиль 1TBS:
for(j=0; j<MAX_LEN; j++) {
        foo();
}
Большинство программистов обычно полагают, что преимущество такого стиля состоит в экономии вертикального пространства. Оборотной стороной такого преимущества является тот факт, что может оказаться трудно найти символ {, спрятанный в конце строки.

Стиль фигурных скобок Алмена

Эрик Алмен (Eric Allman) написал утилиты BSD в этом стиле, и некоторые любители называют его "стиль BSD". Отступы в стиле Алмена обычно (но не всегда) составляют четыре пробела:
for (j=0; j<MAX_LEK; j++)
{
    foo();
}
Этот стиль (и последующие) занимает больше вертикального пространства, чем стиль 1TBS. Аргументом в поддержку такого стиля является тот факт, что область видимости блочного оператора ясна и визуально ассоциируется с управляющим оператором.

Стиль Whitesmith

Одно время существовал С-компилятор, который назывался Whitesmith С. В его документации есть пример форматирования программного кода, подобного этому:
for (j=0; j<MAX_LEN; j++)
    {
    foo();
    }
Этот стиль имеет преимущество в том, что скобки более тесно ассоциируются с кодом, который они включают и разграничивают, однако при визуальном просмотре текста отыскать скобки оказывается чуть более сложно. Здесь приняты отступы в четыре пробела.

Стиль GNU

Программисты GNU фонда Free Software Foundation используют (в частности, в коде GNU EMACS) гибрид стилей Алмена и Whitesmith. (Между прочим, GNU установлен для "GNU, отличных от UNIX", и аббревиатура EMACS получена из названия "Editing MACroS". Это текстовый редактор UNIX, но называть его текстовым редактором только UNIX все равно что называть компьютер дополнительной машиной.) Ниже приведен пример стиля GNU:
for (j=0;  j<MAX_LEN; j++)
    {
        foo();
    }
Трудно сказать, дает ли такая комбинация стилей Алмена и Whitesmith преимущества или имеет недостатки.
Напрашивается вопрос: "Какой способ расстановки фигурных скобок правильный?", но, конечно, они все корректны. Самое главное, не следует смешивать разные стили в одной программе. Выберите для себя стиль и все время его придерживайтесь. Он может даже не подходить вам. Если вы работаете в формальной среде разработки, то почти наверняка имеете дело с некоторым документом стандарта кодирования, который носит обычно авторитарный характер и дает минимальную возможность придерживаться здравого смысла.
Однако намного легче читать код, в котором использован единый стиль, чем код, использующий несколько различных стилей одновременно. Рассмотрим следующий ужасный код, который содержит почти предельно возможную смесь разных стилей:
for(j  = 0; j < HAX_LEN; j++) {
        for(k = 0;  k < MAXWIDTH;  k++)
        {
        for(m = 0; m < MAXHEIGBT; m++)
        {
            for(n = 0; n < MAXTIME;  n++)
            {
                foo(jf k, m, n);
            }
        }
        }
}
Компилятор будет вполне доволен таким кодом, но ни вы, и никто из членов вашей команды не захотели бы иметь с ним дело. Так что если ваши руководители предложили некий стиль, выберите его и постарайтесь убедить других, менее проницательных членов вашей команды делать то же самое (если бы они были проницательными, то читали бы эту книгу и вам не нужно было бы убеждать их). Если же ваши руководители не сослались на некий устоявшийся стиль расстановки скобок, они должны сделать это. В действительности не имеет значения, какой стиль они предложат. Каким бы он ни был, используйте этот стиль для данного проекта и ваши товарищи-программисты (и группа сопровождения!) навсегда вас полюбят.
Если вы не работаете в команде разработчиков проекта и, следовательно, у вас нет руководителя, это прекрасно. Лишь выберите стиль расстановки фигурных скобок, с которым вы чувствуете себя наиболее комфортно, и последовательно его придерживайтесь.

3 комментария :

  1. Это значит я узаю стиль 1TBS в css. Будем знать

    ОтветитьУдалить
  2. А я иногда вот таким баловался. На примере, который был выше покажу, в жизни код был более специфичен, но общее - много вложений и сложные условия. В Java, C++ и C#

    for(j = 0; j < HAX_LEN; j++) {
    for(k = 0; k < MAXWIDTH; k++) {
    for(m = 0; m < MAXHEIGBT; m++) {
    for(n = 0; n < MAXTIME; n++) {
    foo(jf k, m, n);
    } } } }

    И таким

    for(j = 0; j < HAX_LEN; j++)
    { for(k = 0; k < MAXWIDTH; k++)
    { for(m = 0; m < MAXHEIGBT; m++)
    { for(n = 0; n < MAXTIME; n++)
    {
    foo(jf k, m, n);
    } } } }

    ОтветитьУдалить
  3. Отступы съелись. Перед for в первом случаи и перед { во втором - лесенка в 4 пробела.

    ОтветитьУдалить

Ваше мнение мне искренне интересно. Смелее!

Технологии Blogger.