понедельник, 11 марта 2013 г.

Табуляция или пробелы?


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

По моему наблюдению, среди матёрых программистов в большинстве случаев всё же побеждают сторонники пробелов, и решающим аргументом здесь служит визуальная одинаковость выровненных строк вне зависимости от настроек программы у каждого конкретного программиста. А о количестве пробелов в отступе они предпочитают договариваться внутри команды. Что им мешает так же договориться о величине таба — непонятно :)

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


Различия в поведении пробелов и табов

Рассмотрим следующий показательный фрагмент кода:

if (mStatus != Status.PENDING) {
    switch (mStatus) {
        case RUNNING:
            throw new IllegalStateException("Cannot execute task: "
                                          + "the task is already running.");
        case FINISHED:
            throw new IllegalStateException("Cannot execute task: "
                                          + "the task has already been executed "
                                          + "(a task can be executed only once)");
    }
}

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

Если же мы будем выравнивать не пробелами, а табуляцией, то мы сами получим тот же самый вид, а вот у другого программиста, у которого редактор настроен на другую кратность табуляции, например, не 4, как у нас, а 8, строчки сильно сместятся вправо, а при кратности табуляции 2 — влево. При этом у нас неминуемо поползут вторые строчки текстового сообщения. То же самое будет происходить и с выравниванием комментариев в конце строк кода. Они уже не будут красиво выровнены по левому краю на протяжении некоторого блока, имеющего разные уровни вложенности.

Промежуточным вариантом называют создание отступов — табуляцией, а выравнивания — комбинированным методом. Начало выравнивания осуществляется табуляцией, а по достижении уровня предыдущей строки — пробелами. Минусом такого способа является относительная трудоёмкость такого метода и потенциальная путаница — ведь без включения визуализации управляющих символов, сразу непонятно, где табуляция, а где пробелы. Непонятно также, как они поведут себя при копировании в другие места кода.

Более того, вышеописанный способ не спасёт от нарушения выравнивания комментариев в конце строк. Да и не все программисты, которые впоследствии будут редактировать ваш код, поймут или примут вашу задумку.

Так как же правильно оформлять код — пробелами или табуляцией? А может и тем и другим? Давайте попробуем разобраться с этим.


История табуляции — интересные факты

Небольшой экскурс в историю. Табуляция (горизонтальная табуляция) изначально была введена ещё в механических печатных машинках для удобства построения таблиц и применялась также для создания абзацного отступа. Она и не имела жёсткого размера. Перед работой пользователь сам устанавливал нужные ему позиции табуляции с помощью специального механизма. Так же, как это сейчас можно сделать в MS Word. В результате, при последовательных нажатиях на клавишу табуляции (обозначалась как ←) каретка под действием пружины автоматически перемещалась влево по всем установленным ранее позициям, перемещая тем самым область ввода вправо.

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

Почему же выбор размера фиксированной табуляции пал именно на 8 знакомест? Как правило, печатные машинки имели длину строки 80 знакомест. Телетайпы, применявшиеся в первых ЭВМ для вывода информации, тоже, поскольку являлись наследниками пишущих машинок. Даже на перфокартах информация стала храниться строками по 80 символов. Таким образом, печатные машинки задали некий стандарт на длину строки.

Поскольку в первую очередь табуляция использовалась для создания колонок таблиц, то наиболее удобный размер должен был быть не меньше разницы в длине наиболее употребительных слов, если их писать в столбик (чтобы для перехода к следующему столбцу не надо было делать разное число табуляций). В то же время, размер этот должен был позволять делать максимально возможное количество столбцов. Третье условие — размер должен укладываться в длину строки 80 символов кратное число раз.

Согласно последнему условию, у разработчиков был выбор из следующих пяти реальных вариантов: 4, 5, 8, 10 и 16. Первые два варианта были не очень удобными, поскольку разница в длинах слов английского языка часто превышала эти значения. Отступы в 16 символов выглядели чрезмерно большими, снижали удобство пользования этим инструментом и сильно ограничивали число столбцов в таблицах. Оставался выбор между 8 и 10 символами.

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

Несколько слов про абзацный отступ, поскольку он тоже проходит где-то рядом с нашей темой. Согласно ОСТ 29.115-88, при печати на пишущих машинках абзацный отступ должен быть равным трём ударам, но допускается использовать отступ и в пять ударов. Кроме того, предписывается размещать на одной странице 29 (+-1) строк (что примерно соответствует полуторному интервалу на печатной машинке). Требование отступа в 3 удара при полуторном интервале довольно странное, и ниже я объясню, почему.

В типографической вёрстке абзацный отступ равен полуторному размеру кегля шрифта, то есть, грубо говоря, вертикальному размеру строки (т.е. расстоянию от низа одной строки до низа другой), умноженному на 1,5. Поскольку в типографической вёрстке полутроный интервал почти не используется, а строчки следуют сразу одна за другой, то правильный абзац в этом случае приблизительно равен трём средним символам кириллицы.

Вероятно, составители ОСТ 29.115-88, не вдаваясь в подробности типографики, приняли это значение за константу и для моноширинных фиксированных шрифтов печатных машинок, и вместе с тем установили стандартом полуторный межстрочный интервал, поскольку при моноширинном шрифте и низком качестве печати одинарный интервал смотрелся реально очень плохо.

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

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


Стратегический взгляд на решение проблемы

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

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

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

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


Проблемы пробелов

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

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

Кроме того, для удаления лишнего отступа вместо привычного нажатия на Backspace приходится нажимать сочетание клавиш Shift+Tab. Но это уже, конечно, дело привычки.


Проблемы табуляции

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

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


Выводы

Сначала скажу пару слов о размере отступов, как таковых. Применительно для большинства распространённых языков программирования идеальным размером отступов является ровно 4 символа. Почему ровно? Потому что уже сложилось так, что большинство исходников отформатированы именно таким образом, и тонкая подгонка под субъективный «идеал» в 3 или 5 символов теряет смысл.

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

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

Если программисты будут придерживаться золотой середины в 4 символа, то спор между сторонниками пробелов и табуляции станет неактуальным. А пока можно дать следующие рекомендации:

  1. Используйте отступы стандартного де-факто размера. Для Java, Pascal, C, C++  и т.п. стандартом де-факто является отступ в 4 символа, как бы нам ни хотелось использовать другой размер.
  2. Если соблюдён пункт 1, то абсолютно неважно, чем вы будете делать отступы. Если вы сделаете их пробелами, то будет хорошо — ваш код везде будет выглядеть читаемо, и никогда ничего не поползёт. Другие программисты при чтении вашего кода будут привыкать к правильному форматированию. Если же вы сделаете отступы табуляцией, то будет ещё лучше — вы дадите другим программистам выбор — включить в редакторе правильный размер табуляции и читать правильно отформатированный код, или  читать его с привычными им отступами, но поползшими комментариями и отдельными строками, в которых применялось выравнивание.
  3. Выбор в пункте 2 можно осуществлять в зависимости от того, как ваш код будет использоваться в дальнейшем. Если его блоки будут вставляться в чужой код, тогда точно имеет смысл выбрать табуляцию, чтобы вставляющему проще было подогнать форматирование. Если исходник предназначен для публикации в Интернете, где табуляция либо съедается, либо зафиксирована на 8 символов, то тогда можно выбрать пробелы, чтобы исключить дополнительный шаг подготовки исходника к публикации. Если же в вашей организации уже установлены определённые правила форматирования, то выбора у вас уже нет :)

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

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

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


Если у вас одно, а нужно другое

Есть такой замечательный редактор — Notepad++. В нём замена табуляции на пробелы и наоборот выполняется одним щелчком мыши, сделанным разделе в меню «Правка →  Операции с Пробелами». Я использую этот редактор для перегона табулированных кусков кода, предназначенных для публикации в блоге, поскольку последний автоматом меняет один знак табуляции на один пробел, что неприемлемо.


Заключение

Многие могут задать вопрос, а что же выбрал для себя автор этой статьи? А выбрал он табуляцию размером 4 знакоместа. Я не нашёл достаточно веских причин для использования пробелов ради того, чтобы мой код открывался у кого-то, кто не соизволил настроить отступ в своём редакторе кода на де-факто стандарт в 4 символа.

Что касается Notepad из состава Windows, который не имеет настройки размера табуляции, и прочих подобных редакторов, делающих табуляцию принудительно в 8 символов, то я не могу себе представить причину, по которой программист открывал бы мой код именно в них, тогда как уже давно для всех ОС существуют удобные специализированные редакторы для исходного кода.

Работать в блокноте не круто. Круто работать в шестнадцатеричном редакторе :)

Комментариев нет:

Отправить комментарий