Чтение онлайн

ЖАНРЫ

Кодеры за работой. Размышления о ремесле программиста

Сейбел Питер

Шрифт:

Насчет простейшей вещи из всех возможных - я “за” обеими руками. Основная аксиома проектирования API такова: “Сомневаешься - выкидывай”. Простейшая вещь должна быть достаточно велика, чтобы соответствовать всем намеченным сценариям использования. Это вовсе не означает, что надо склеивать воедино сырые фрагменты кода. На этот счет есть куча афоризмов. Мой любимый - тот, что ошибочно приписывают Телониусу Монку: “Сделать просто - непросто”.

Сырые программы никому не нужны. “Делайте простейшую вещь из всех возможных” и “Беспощадный рефакторинг!” - эти два призыва совсем не означают, что надо писать сырой код, отказавшись от предварительного проектирования. Я беседовал об этом с Мартином Фаулером. Он твердо стоит за продумывание целей и задач, чтобы придать

программе разумные размеры и структуру. “Не пишите 247-страничную спецификацию до того, как начнете писать код”, - говорит он, и я согласен.

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

Итак, между двумя лагерями есть разногласия. Но, по-моему, непреодолимой пропасти, как считает кое-кто, нет.

Сейбел: Раз уж вы упомянули Фаулера, написавшего несколько книг по UML, скажите: вы используете UML в качестве средства проектирования?

Блох: Нет. Думаю, это здорово - создавать понятные для других графические схемы. Но, если честно, не могу припомнить, какие там компоненты круглые, а какие квадратные.

Сейбел: Вы занимались всерьез литературным программированием в духе Кнута?

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

Зато я могу часами спокойно возиться с именами идентификаторов, переменных, методов и так далее, чтобы мой код был читаемым. Если выражение, содержащее эти идентификаторы, похоже на обычное английское предложение, ваш код, скорее всего, будет правильным и более легким в поддержке. Думаю, у тех, кто заявляет: “Не стоит труда, это же всего-навсего имя переменной”, - ничего не получится. С таким подходом не написать удобной в сопровождении программы.

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

Блох: Хороший вопрос. На самом деле я люблю хорошо написанные программы. Я знаю людей, способных взять большую неважно написанную программу и зарыться в код, пока не станет вырисовываться общая картина. Завидую такой способности - у меня ее никогда не было.

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

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

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

Сейбел: Вы применяли

пошаговое исполнение кода, чтобы его понять?

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

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

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

Блох: Нет. Вы, вероятно, знаете, что утверждения (assertions) - первый элемент, помещенный мною в Java, и я сознаю, что они так и не стали частью Java-культуры. Лишь немногие Java-программисты пользуются ими - даже не знаю, почему. Кстати, о математике: инварианты являются в высшей степени математической идеей.

Сейбел: Но для их понимания не нужно знать математику на “отлично”.

Блох: Не нужно. Но позвольте мне побыть адвокатом дьявола. Математика дает определенную четкость мышления. Я готовил к математической олимпиаде школьников четвертого и пятого классов. В этом возрасте некоторые дети уже понимают суть доказательства, что предположение должно быть явно и безапелляционнно истинным, а не думают: “По-моему, это верно, раз есть примеры того, как оно работает”.

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

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

Блох: В какой-то мере я согласен, но так можно зайти слишком далеко. Вернемся к Дейкстре. Уверен, вы читали его книгу “On the Cruelty of Really Teaching Computing Science” (О жестокости реального преподавания компьютерных наук), и полагаю, что в ней он абсолютно неправ. Деикстра говорит, что студентов нужно подпускать к компьютеру лишь после того, как те в течение семестра научатся обращаться с символами и понимать их подлинный смысл. Но это же бред! Ведь это удовольствие - приказать компьютеру сделать что-то и наблюдать, как он это делает. Я не в силах лишить студентов такого удовольствия. Да и не в состоянии - ведь компьютеры повсюду. Десятилетние дети пишут программы.

Сейбел: Как человек, пропагандирующий Java в Google, не находите ли вы, что этот язык мог бы использоваться более широко? Оставим в стороне поступь истории и уже сделанный людьми выбор и представим, что у вас есть волшебная палочка. Если бы могли заменить весь C++ на Java, это бы сработало?

Блох: До известной степени. Крупные программные блоки могут быть изменены таким образом, и все движется в этом направлении. Но если взять само ядро системы, к примеру внутренние циклы индексных серверов, то в нем даже крошечное улучшение показателей значит страшно много. Когда множество машин используют один фрагмент кода, увеличение скорости даже на пару процентов принесет серьезные выгоды для ваших финансов и для окружающей среды. Поэтому часть кода пишется на ассемблере, а что такое Си, как не ассемблер под другим названием?

Поделиться с друзьями: