97 этюдов для программистов. Опыт ведущих экспертов — страница 10 из 41

Переопределите внутренние интерфейсы. Реструктурируйте модули. Реорганизуйте код, полученный путем копирования-вставки. Упростите архитектуру, сократив число зависимостей. Сложность кода можно существенно снизить, устранив из него патологические случаи, а они часто возникают из-за неправильно организованной взаимосвязи между частями системы. Медленно переходите от старой структуры к новой, не забывая в процессе о тестировании. Попытка осуществить рефакторинг «в один заход» может вызвать столько проблем, что возникнет сомнение в целесообразности переработки вообще.

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

Не прикалывайтесь с тестовыми даннымиРод Бегби

Был поздний вечер. Я подбирал фиктивные данные, что бы протестировать верстку страницы, находившейся в работе. Имена пользователей я придумал в честь участников группы «The Clash». Названия компаний? Сгодятся названия песен «Sex Pistols». Теперь нужны какие-нибудь биржевые символы — четырехбуквенные слова, состоящие из заглавных букв.

Я выбрал те самые четырехбуквенные слова.[11]

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

А на следующее утро руководитель проекта сделал несколько снимков экрана для презентации.

История программирования пестрит множеством подобных воспоминаний. Шалости разработчиков и дизайнеров, которые «никто никогда не увидит», вдруг представали всеобщему обозрению.

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

• Во время показа текущей версии клиент щелкает по кнопке, функциональность которой еще не реализована, и получает сообщение: «Придурок, не трогай эту кнопку».

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

• Человек перепутал интерфейс для ввода тестовых данных и интерфейс администрирования рабочей системы. Он вводит «прикольные» данные, и вот покупатели видят на витрине вашего интернет-магазина «Фаллоимитатор в виде Билла Гейтса» ценой 1000000 $.

Если старую поговорку «пока правда обувается, ложь уже обойдет полсвета» перевести на современный язык, то можно сказать, что в наше время такие ляпы прославятся в Twitter, LiveJournal или Facebook до того, как в часовом поясе разработчиков проснется кто-то, способный их исправить.

Вполне возможно, что и ваш исходный код не избежит пристального интереса. Когда в 2004 архивы с исходным кодом Windows 2000 появились в файлообменных сетях, некоторые весельчаки профильтровали их в поисках сквернословия, ругательств и прочих забавных вещей.[12] (Признаюсь, с той поры я иногда прибегаю к комментарию: // TERRIBLE HORRIBLE NO GOOD VERY BAD HACK (УЖАСНО ОТВРАТИТЕЛЬНО БЕСПОЛЕЗНО ДРЯННОЙ ТРЮК!)

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

Не проходите мимо ошибки!Пит Гудлиф

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

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

И все же я направился в сторону бара. Когда я добрался туда, мне было уже невыносимо больно. Вечер не особенно удался — боль не давала о себе забыть. Утром я пошел к доктору, и выяснилось, что у меня сломана голень. Остановись я, когда стало больно, мне удалось бы избежать многих осложнений, вызванных тем, что я продолжал идти дальше. Предположу, то было мое худшее в жизни утреннее похмелье.

Слишком многие программисты пишут код в духе моего поведения в тот вечер.

Ошибка? Какая еще ошибка? Это просто ерунда. Честно. Можно не обращать на нее внимания. Для создания надежного кода такая стратегия не годится. Скажу больше, это попросту лень. (Вредная ее разновидность.) Что бы вы там себе ни воображали по поводу отсутствия ошибок в собственном коде, их всегда нужно проверять и всегда обрабатывать. Обязательно. Поступая иначе, вы не экономите время, но запасаетесь потенциальными проблемами на будущее.

Сообщить об ошибке в коде можно разными способами, например:

• Вернуть в результате работы функции код ошибки, который означает, что функция отработала неверно. Код ошибки очень легко игнорировать. В коде ничто не укажет на проблему. Вообще теперь стало принято игнорировать значения, возвращаемые некоторыми стандартными функциями С. Часто ли вы проверяете значение, возвращаемое функцией printf?

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

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

try {

   //…что-то выполнить…

}

catch (…) {} // игнорировать ошибки

Единственное достоинство этой ужасной конструкции — подчеркнуть, что в коде происходит нечто сомнительное с точки зрения морали.

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

Если не обрабатывать ошибки, вот что вы получите:

• Нестабильный код. Код со множеством восхитительных и трудных для обнаружения ошибок.

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

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

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

Почему мы не выполняем проверку на ошибки? Вот некоторые стандартные оправдания:

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

• Это лишняя работа, а на меня давят сроки сдачи.

• Я уверен, что эта функция никогда не вернет ошибку (printf всегда работает, malloc всегда выделяет память, а если нет, наши проблемы гораздо серьезнее…)

• Это прототип, нет смысла делать его пригодным для коммерческого применения.

С какими из них вы согласны? Что вы могли бы на них возразить?

Не просто учите язык, поймите его культуруАндерс Норас

В средней школе мне пришлось изучать иностранный язык. В то время мне казалось, что достаточно хорошего знания английского языка, и потому я благополучно проспал три года уроков французского. Спустя несколько лет я поехал отдыхать в Тунис. Официальный язык этой страны — арабский, но так как это бывшая французская колония, в Тунисе широко распространен французский. По-английски говорят только в местах пребывания туристов. Из-за своего невежества в языках мне пришлось проводить время главным образом близ бассейна за чтением книги «Finnegans Wake» (Поминки по Финнегану), в которой Джеймс Джойс продемонстрировал свое владение как формой, так и языком. Джойс играючи соединил вместе более 40 языков, и чтение книги стало для меня удивительным, хотя и непростым опытом. Это переживание новых средств выражения, сотканных автором из иностранных слов и фраз, осталось со мной на протяжении всей моей карьеры программиста.

В своей новаторской книге «The Pragmatic Programmer: From Journeyman to Master»[13] (Addison-Wesley Professional) Энди Хант и Дэйв Томас рекомендуют каждый год изучать какой-нибудь новый язык программирования. Я попробовал последовать их совету и за годы работы приобрел опыт программирования на многих языках. Самый важный вывод из моих приключений полиглота: для изучения языка недостаточно освоить его синтаксис, нужно понять его культуру.

Можно на любом языке писать, как на Фортране, но, чтобы по-настоящему изучить язык, нужно принять его полностью.