Следующая статья: Подводные камни внешнего подряда, freelance, free-lance.
Python стал весьма интересным явлением: это был первый серьезный язык программирования со времен FORTRAN на перфокартах, в котором пропуски (whitespace) играли важную роль. В Python блоки определяются не заключением фрагментов кода в пары begin/end или { }, а простыми отступами. Вот и все.
Многие программисты инстинктивно скривились. «Компилятор должен игнорировать пропуски!» - заявили они, совершенно забывая, почему. Главная причина состоит в том, что пропуски обычно остаются невидимыми глазу… на то они и пропуски. Так, например, у стандартной утилиты Unix make некоторые строки должны начинаться с символа табуляции; если ваш редактор заменяет символ табуляции восемью пробелами (как любезно с его стороны!), make-файл неожиданно перестает работать без каких-либо объяснений. Так мы все запомнили: пропуски должны игнорироваться.
Такие дела.
Возможно, мы зашли слишком далеко.
И в этом проявляется красота Python. В С-подобных языках (С, C++, Java) человеческий глаз воспринимает отступы как определение блока, но компилятор видит { и }. Следовательно, в тех случаях, где отступы не согласуются со скобками, предпочтение отдается тому, что менее заметно человеку - фигурным скобкам. Но зачем нужны два способа определения блоков, для человека и для компилятора? Почему нельзя придерживаться одного способа, чтобы внешний вид программы всегда соответствовал ее функциональности?
Кен Арнольд довел этот принцип, позаимствованный из Python, до логического завершения. Он предлагает нечто гораздо более радикальное - и его идея, как и многие великие идеи, настолько безумна, что вполне может сработать.
…И тогда я решил заняться стилем программирования - аналогом реслинга на TV в языках программирования…
Наверняка я не раз пожалею об этом, и все же публично признаюсь: я - еретик. (В этом конкретном случае речь идет лишь о ереси в области проектирования языков программирования. Прочие признания подождут до другого раза).
Скажу прямо: практически в любом зрелом языке (С, Java, C++, Python, Lisp, Ada, FORTRAN, Smalltalk, sh, JavaScript и так далее) все проблемы стиля программирования практически решены, и на них можно не обращать внимания. Но чтобы не возиться с ними в будущем, придется немало повозиться изначально: чтобы перейти от текущего положения дел к такому положению, при котором мы перестаем беспокоиться о стиле, следует внедрить его на уровне языка. Угу. Вы не ослышались. Я говорю, например, что следующее обновление стандарта ANSI С должно определить стиль С-программирования K&R на уровне грамматики языка. Программы, использующие новые возможности, либо оформляются в стиле K&R, либо отвергаются компилятором как синтаксически недопустимые.
Здесь стоит сделать паузу. Когда я завел речь на эту тему в списке рассылки, мне пришлось повторить несколько раз. Народ не сразу понял, потому что не мог поверить, что кто-то говорит нечто подобное. А я именно это имею в виду. Например, я хочу, чтобы в следующей грамматике С любое ключевое слово обязательно отделялось от открывающей круглой скобки пробелом: конструкция if (foo) должна быть разрешенной, a if(foo) - нет. Не предупреждение, не необязательная проверка, а реальный запрет. Конструкция без пробела попросту недопустима. Она не компилируется. А вот логическое обоснование в простейшей форме:
- Предпосылка 1: для любого языка существует один распространенный стиль программирования, или число таких стилей невелико. Как правило, стиль задается основоположником или первым автором документации, но со временем появляются и другие стили. Но даже в С стандартные стили можно пересчитать по пальцам (если не считать тривиальные разновидности).
- Предпосылка 2: не существует и никогда не будет существовать стиля программирования, который бы обладал очевидными преимуществами по сравнению с любым из стандартных стилей. Взгляните правде в глаза. Открыть новый стиль, который бы повышал производительность работы более чем на несколько процентов по сравнению со стандартными стилями, также маловероятно, как изобрести новую позицию в сексе (космонавты не в счет - пока сам не увижу, все равно не поверю) .
- Предпосылка 3: на разновидности стиля программирования тратится невесть сколько времени. Задумайтесь: сколько проектов переформатирования/красивой печати можно найти только на SourceForge3? Сколько разных настроек содержит любая конкретная IDE (в том числе и emacs) для форматирования кода? Сколько времени тратится на выбор стиля, его документирование, соблюдение и обновление? Сколько журналов CVS, ClearCase и так далее забивается мусором из-за изменений формата? Сколько умственных усилий затрачено на споры по этой теме?
- Предпосылка 4: в любом нетривиальном проекте желательно применять стандартный стиль программирования. Вероятно, здесь особых возражений не будет. Степень жесткости требований зависит от проекта, но если над одним кодом начнут работать несколько участников с конфликтными стилями программирования, это создаст куда больше проблем, чем любой конкретный стиль создает для одного программиста. Во всех известных мне проектах имеется принятый стиль, даже если он и не оговаривается явно
- Заключение: если рассматривать весь программный код в мире как единый проект с единым стилем, работа станет более эффективной, чем при разрешенных отклонениях в стиле.
Подумайте хорошенько. Все примеры программ оформляются одним стилем. Веб-страницы, журналы, газеты, электронная почта - один стиль. Исчезают проблемы переформатирования. Стихают споры на тему того, чей стиль лучше. Переформатирование становится историческим курьезом.
А самое главное: Не Будет Больше Стилевых Войн! Серьезно! Прикиньте, сколько попусту потраченного времени можно было бы потратить на что-нибудь более полезное, типа флейма «vi против emacs»! Или борьбу за мир во всем мире! Или изобретение классного рецепта шоколадного печенья! Выбирайте сами!
Конечно, глобальное введение единого стиля возможно только в том случае, если у людей буквально не останется выбора. Сколько программистов С заменяет ключевое слово while на «during», потому что оно лучше соответствует их представлениям о стиле? (Лиц, злоупотребляющих препроцессором, просим не беспокоиться. Хотя ладно, отзовитесь - мы вас запишем в свою программу по евгенике). А сколько опускает круглые скобки вокруг условия if? Они этого не делают, потому что не могут. А если могли - наверняка кто-нибудь попытался бы. Все эти «персональные стили» останавливает лишь то, что компилятор С их не принимает. Если код не компилируется, его нужно исправить. Все до смешного просто… Поэтому и работает.
Поэтому я хочу, чтобы владельцы языковых стандартов взялись за дело. Я хочу, чтобы следующие версии этих языков потребовали, чтобы любой код, использующий новые возможности, соответствовал некоторому стилю. Пусть комитеты по стандартам скрежещут зубами, ноют и заламывают руки, наблюдая за тем, какой из стандартных стилей станет победителем. Продавайте билеты. Мы все выскажемся, а умные головы разработчиков языковых стандартов пускай решают. Понятно, чем все кончится - С отправится по пути K&R; C++ выберет стиль Бьярна (от которого я, уж простите, не в восторге); для Java будет выбран стиль Sun, представленный в спецификации языка и большинстве книг Java от Sun (включая мою); стиль Lisp почти что выбит в камне. Perl представляет собой необъятную трясину лексических и синтаксических помоев; никто из программистов не умеет толком отформатировать даже свой собственный код, но зато это единственный из известных мне крупных языков, у которого нет даже одного приличного стиля (вероятно, не считая совсем новый, но очень похожий на Java язык С#).
Некоторые вещи либо не проверяются в принципе (венгерская запись, префиксы методов get и set), либо еще не стали общепринятыми (скажем, порядок import/ #include). Их можно оставить для будущих стандартов. А можно и не оставлять. Пускай владельцы стандартов решают. Но что бы они ни решили, пусть установят единый стиль и встроят его в эту чертову грамматику. Глобальная ересь включает одну серьезную ересь второго уровня: пропуски должны учитываться компилятором.
Многие правила стиля так или иначе связаны с расположением пропусков: новые строки до или после фигурных скобок, пропуски вокруг операторов, и так далее
Итак, я говорю, что эти языки должны учитывать пропуски.
И все же одна из вещей, которые нам вроде бы полагалось узнать из языков типа FORTRAN, что пропуски должны использоваться только для пометки границ между лексемами. Это считалось общим правилом, потому что в FORTRAN были столбцы: первые пять столбцов резервировались для номера команды или признака комментария, любой символ в шестом столбце был признаком продолжения предыдущей строки, столбцы 7-72 содержали программный код, а последние восемь резервировались для порядковых номеров, по которым было удобно собирать заново рассыпанные колоды. Да, колоды перфокарт - такие твердые, с прямоугольными дырками. Так что если символ попадал в неположенный столбец, команда могла превратиться в комментарий или еще что-нибудь, и это основательно раздражало. Кроме того, запись DO101 = 1,100 была эквивалентна DO 10 I = 1, 100 - DO было ключевым словом, за которым следовало число, а значит, пробел был не обязателен. Зато с записью DO101 = 1 все было еще интереснее, потому что она присваивала значение 1 переменной с именем DO101.
Я пережил этот кошмар и испытал его на себе. Но это не доказывает, что пропуски должны игнорироваться. В действительности это доказало лишь то, что правила использования пропусков в FORTRAN были идиотскими. Свобода размещать пропуски где угодно на практике обернулась большими затратами. Программы уже не набиваются на перфокартах, а программы переформатирования стали такими же распространенными, как спам. Мы можем воспользоваться этим обстоятельством: вводите код, как хотите, но прежде чем компилировать - переформатируйте его. В конечном счете, необходимо только одно: чтобы редакторы и IDE дали возможность ввести программу и придали ей нужный вид. Фактически речь идет о переформатировании «на лету» - эта функция уже поддерживается многими редакторами. Никто не заставляет вас вводить 0, 1 или 17 пробелов между if и открывающей круглой скобкой; редактор (для С в стиле K&R) сам помещает туда ровно один пробел. Но даже эта задача становится еще проще, если будет только один стиль. Это одна из тех вещей, для которых могут пригодиться средства переформатирования или адаптации стилей. В сущности, свобода стиля форматирования обходится чрезвычайно дорого, причем эти затраты не окупаются. Подумайте, сможете ли вы честно заполнить следующее заявление:
Мне, [имя], известен стиль программирования, влияние которого на производительность работы программиста и/или качество программ настолько велико, что мое право на выбор этого стиля вместо любых распространенных стилей оправдывает потери рабочего времени программистов и ресурсы, потраченные в масштабе отрасли на споры о стиле, выработку стилевых требований и переформатирование кода. Это стиль [описание стиля], и он обладает следующими преимуществами: [описание преимуществ].
И даже менее требовательное:
Мне, [имя], известен стиль программирования, влияние которого на производительность работы программиста и/или качество программ > 5 % по сравнению с любым распространенным стилем. Это стиль [описание стиля], и он обладает следующими преимуществами: [описание преимуществ].
Думаю, у большинства из вас даже сама мысль о заполнении подобных заявлений вызовет лишь усмешку. И хотя в отдельно взятом проекте можно потратить 5 процентов на проблемы стиля программирования (в основном на начальной стадии), на этом хлопоты не прекратятся: стилевые войны вокруг того, что еще не было определено; предложения новых утилит, их написание или интеграция; внесение исправлений людьми, забывающими применить нужный стиль, с захламлением журнала изменений; обучение новых работников нужному стилю; вразумление непокорных; общая грызня, нытье и стоны.
Так что 5 процентов даже отдаленно не покрывают затраты ресурсов и прочие неприятности, связанные с отсутствием обязательного стиля во всех программах в мире.
А может, вопрос лучше поставить наоборот: окупают ли преимущества от свободы стиля ту цену, которую мы за нее платим? Мне ответ кажется очевидным: не окупают даже отдаленно.