О книге «Программист-прагматик. Путь от подмастерья к мастеру» Эндрю Ханта и Дэвида Томаса знают, наверное, все, кто занимается программированием, причем многие — в основном из упоминаний в подборках и цитат в более современных статьях. Учитывая, что этот сборник практических советов для разработчиков скоро отметит двадцатилетний юбилей, тот факт, что его до сих пор приводят как источник ценной информации, вызывает уважение. Секрет прост: авторы, хоть и делали акцент на практической применимости своих подсказок, говорили по большей части о фундаментальных принципах построения рабочего процесса. Многие технические моменты, которые упоминаются в тексте, действительно давно устарели, но базовые подходы к разработке, тестированию, взаимодействию внутри команды и с аудиторией остаются актуальными.
Ниже вы найдете конспект первых четырех глав; речь в них идет об авторской концепции самообразования, основах прагматического подхода в программировании и правилах подбора инструментов. Книга очень удобна для «точечного» чтения: материал представляется в виде отдельных параграфов-подсказок, снабженных перекрестными ссылками. За рамками этого конспекта остались примеры из конкретных языков, разбор кейсов из авторской практики, те самые ссылки, упражнения на закрепление и некоторые забавные аналогии, оживляющие текст — так что рекомендую ознакомиться с оригиналом, если какие-то из тезисов вас заинтересуют. Приятного чтения!
Подсказка 1: Позаботьтесь о вашем ремесле
?Нет смысла разрабатывать программы, если вы не заботитесь о качестве работы. Делать это нужно не только в краткосрочной перспективе, применительно к конкретным проектам, но и в долгосрочной — формируя правильный подход и принципы работы.
Что отличает программиста-прагматика?
Подсказка 2: Думаи?те о работе
Во время написания кода следует полностью концентрироваться на том, что делаете. Никогда не переходите в режим автопилота. Думаи?те постоянно, критически осмысляя свою работу в реальном времени. Это называется осознанным программированием. Его освоение займет некоторое время и потребует усилий, но наградой станет привычка беспрестанно вносить мелкие усовершенствования, повышая качество кода в целом и сокращая сроки разработки.
Прагматическое программирование ведет свое начало от философии прагматического мышления. В даннои? главе приводятся ее основные положения.
Подсказка 3: Представляйте варианты решения проблемы, а не отговорки
Одним из краеугольных камнеи? прагматической философии является идея принятия ответственности за себя и за свои деи?ствия. Программист-прагматик исходит из того, что его карьера и результаты работы зависят прежде всего от него, и не боится признаться в неведении или ошибке.
Принятие ответственности за результат предполагает готовность отчитываться. Если вы допустили ошибку (а мы все их допускаем), признаи?те ее честно и попытаи?тесь предложить варианты исправления. Не стоит перекладывать вину на коллег, партнеров, инструменты или выдумывать отговорки — это непродуктивная трата времени. То же относится и к ситуациям, когда вы сталкиваетесь в требованиями, которые не сможете удовлетворить: не говорите просто: «Это невозможно», а объясните, что нужно для спасения ситуации (дополнительные ресурсы, реорганизация и т.д.).
Подсказка 4: Не оставляйте разбитых окон
Энтропия – это термин из физики, обозначающии? уровень «беспорядка» в системе. Энтропия во вселеннои? стремится к максимуму, и в разработке наблюдается та же закономерность. Увеличение степени беспорядка в программах на профессиональном жаргоне называется порчеи? программ. Существует много факторов, вносящих свои? вклад в порчу программ, но наиболее важный из них — культура работы над проектом.
Согласно теории разбитых окон, неряшливые решения и проблемные места имеют свойство размножаться. Не оставляи?те «разбитые окна» (неудачные конструкции, ошибки, некачественныи? код) без внимания. Если нет времени на надлежащии? ремонт, хотя бы закомментируйте ошибочныи? фрагмент или выведите на экран сообщение «В стадии разработки», или используйте фиктивные данные. Необходимо предпринять хотя бы малеи?шее деи?ствие, чтобы предотвратить дальнеи?шее разрушение, и показать, что вы контролируете ситуацию. Небрежность ускоряет порчу быстрее, чем любои? другои? фактор.
Подсказка 5: Будьте катализатором изменении?
Если вы видите, что необходимо сделать, не ждите инициативы от окружающих. Составьте план, проработайте подробности — люди будут охотнее вас поддерживать, если увидят, что работа уже начата.
Подсказка 6: Следите за изменениями
Не сводите глаз с общеи? картины происходящего. Постоянно наблюдаи?те за тем, что происходит вокруг вас, а не только за тем, что делаете вы лично. Большинство катастроф в коде начинаются с малозаметных вещеи?, которые копятся, пока в один прекрасныи? день проект не пойдет вразнос. Шаг за шагом система отклоняется от требовании?, код обрастает «заплатами», пока от оригинала не остается ничего. Зачастую именно скопившиеся мелочи приводят к разрушению морали и команд. Но если захватить этот процесс на ранних стадиях и немедленно принять меры (см. предыдущий пункт), можно отделаться малой кровью.
Подсказка 7: Сделаи?те качество одним из пунктов требовании?
Качество должно быть договорным пунктом в контракте, который вы заключаете с пользователями. Конечно, в идеале оно должно быть максимальным, но часто вы будете оказываться в ситуациях, когда приходится идти на компромисс из-за жестких сроков или нехватки ресурсов. И здесь полезно приучить себя к созданию приемлемых программ. «Приемлемая» не значит «сделанная тяп-ляп»: вы просто даете пользователям право голоса при определении того порога качества, который можно считать допустимым. Удивительно, но многие предпочтут использовать программы с некоторыми недоработками сегодня, вместо того чтобы год ожидать выпуска мультимедии?нои? версии.
Кроме того, иногда программы становятся лучше благодаря сокращению инкубационного периода. В разработке существует проблема «перешлифовки» — внешние ограничения помогают вовремя остановиться в погоне за совершенством.
Подсказка 8: Регулярно инвестируи?те в свой портфель знании?
Под портфелем знании? понимаются все, что программист знает о разработке в своей области, а также накопленныи? им опыт. Управление портфелем знании? очень похоже на управление финансовым портфелем:
Общие принципы таковы:
Процесс обучения расширит ваше мышление, открывая для вас новые возможности и новые пути в творчестве. Если вы узнали что-то новое, постарайтесь применить это знание к проекту, над которым вы работаете в настоящее время, насколько позволяют используемые технологии.
Подсказка 9: Критически анализируи?те прочитанное и услышанное
Необходимо убедиться, что знание в вашем портфеле является точным, что оно не искажено теми, кому это выгодно, и что его ценность не раздута хайпом. Опасаи?тесь фанатиков, настаивающих на том, что их догма обеспечивает единственно правильныи? ответ — вполне возможно, что именно в вашем проекте он неприменим.
Подсказка 10: Важно, что говорить и как говорить
Большая часть дня программиста проходит в общении — с командой, руководством, пользователями, будущими поколениями разработчиков через документацию и комментарии в коде. Поэтому необходимо овладеть его искусством. Чем эффективнее это общение, тем выше ваша способность претворять идеи в жизнь.
Принципы эффективного общения:
Существует ряд подсказок и уловок, применимых на всех уровнях разработки программ — идеи, которые можно считать аксиомами, процессы, которые практически универсальны. В этои? главе проводится обзор этих идей и процессов.
Подсказка 11: Не повторяи?тесь
Каждый фрагмент знания должен иметь единственное, однозначное, надежное представление в системе. Альтернативои? является представление одного и того же предмета в нескольких местах. Это доставляет неудобства: если в одном месте что-то редактируется, нужно немедленно внести изменения во всех остальных, иначе программа рухнет под грузом противоречии?. Рано или поздно вы что-нибудь забудете, это вопрос времени.
Большинство случаев дублирования подпадает под одну из следующих категории?:
Подсказка 12: Сделаи?те так, чтобы программу можно было легко использовать повторно
Постарайтесь создать среду, где проще находить и многократно использовать существующии? материал, чем создавать его самому с нуля. Это помогает снизить риск дублирования. Только имейте в виду: если повторное использование сопряжено с какими-то сложностями, люди не станут этого делать.
Подсказка 13: Исключаи?те взаимодеи?ствие между объектами, не относящимися друг к другу
Это правило называют также принципом ортогональности. Два или более объекта ортогональны, если изменения, вносимые в один из них, никак не влияют на остальные. Подобная схема дает два больших преимущества: увеличение производительности и снижение риска.
Когда изменения в системе локализуются, сроки разработки и тестирования сокращаются. После того как небольшой самодостаточный компонент спроектирован, реализован и протестирован о нем можно попросту забыть, вместо того чтобы постоянно вносить изменения по мере добавления в код новых фрагментов.
Ортогональныи? подход также способствует многократному использованию компонентов. Чем меньше связанность в системах, тем легче провести реконфигурацию или реинжиниринг.
Снижение риска вызвано тем, что ошибочные фрагменты оказываются изолированы и не влияют на всю систему; соответственно, исправить или заменить их тоже проще. Вследствие этого система становится более устойчивой — проблемные участки остаются участками. Помогает и то, что тестирование на уровне модулей обычно проводится более тщательно.
Принцип ортогональности должен соблюдаться не на уровне отдельных технологий, а охватывать все процессы: от проектирования до подбора инструментов, от тестирования до управления продуктом. Он сводит к минимуму дублирование и делает систему гибче и прозрачнее.
Подсказка 14: Не существует окончательных решении?
Требования, пользователи и аппаратные средства изменяются быстрее, чем мы разрабатываем программное обеспечение. Поэтому нужно всегда быть готовыми к тому, что любое решение, которое вы принимаете (не только в пределах кода, но и, допустим, при выборе инструмента от третьей стороны, архитектурного шаблона, модели развертывания), придется пересмотреть в будущем под влиянием внешних факторов. Принцип «минимум дублирования», принцип несвязанности и использование метаданных позволяют сделать систему более обратимой.
Подсказка 15: Пользуи?тесь трассирующими пулями, для того чтобы наи?ти цель
Раскрывая метафору: при создании нового продукта команда разработчиков зачастую действует вслепую, работая с малознакомыми методиками, языками и библиотеками. Предугадать конечный результат можно либо путем жесткого прогнозирования, основанного на очень развернутом анализе технологий, либо при помощи «трассировки» — создания серии упрощенных, пробных, постепенно совершенствующихся рабочих версий, чтобы собрать воедино компоненты системы и проверить, как они работают в связке.
Альтернатива такому подходу — изолированная разработка отдельных модулей, которые на завершающем этапе собираются воедино и тогда уже тестируются на уровне системы — более тяжеловесна и менее удобна. Среди прочего, метод трассировки дает вам черновую версию продукта (ее можно представить пользователям, чтобы показать им суть проекта, заинтересовать и получить фидбэк); более плавную и фокусную интеграцию готовых новых модулей в среду и возможность немедленно выявлять и легко устранять ошибки во взаимодействии.
Подсказка 16: Создаваи?те прототипы, чтобы учиться на них
В отличие от описанных выше тестовых версий прототипы имеют более узкую направленность: они создаются, чтобы отработать несколько конкретных характеристик и требуют значительно меньше ресурса. Все подробности, не имеющие отношения к рассматриваемой проблеме, опускаются, даже если они крайне важны для работы системы в целом. При работе над прототипом можно пренебречь корректностью, завершенностью, надежностью и стилем.
Для прототипирования необязательно создавать полноценное рабочее приложение, иногда достаточно просто схемы на бумаге или доске. Если оно все-таки необходимо, то имеет смысл выбрать для этой цели язык очень высокого уровня – выше уровня языка, который используется остальнои? части проекта (язык типа Perl, Python или Tel). Язык сценариев высокого уровня позволяет опускать многие детали (включая указание типов данных) и при этом создавать функциональныи?, хотя неполныи? и медленныи?, фрагмент программы.
Подсказка 17: Пишите код с оглядкой на область применения
Языки программирования влияют на то, как вы думаете о проблеме и о взаимодействии с пользователем. В каждом языке имеются свои особенности, которые наталкивают на определенные решения или, наоборот, препятствуют им. Решение, создаваемое в стиле Lisp, отличается от решения, основанного на мышлении приверженца языка С, и наоборот. Верно и обратное – язык, отражающии? специфику проблематики, с которой вы работаете, может, со своеи? стороны, предложить решение в области программирования.
Прислушиваясь к требованиям пользователей, вы можете понять, на какой язык будет проще всего их перевести на высшем, абстрактном уровне. Разные типы пользователей (конечные — аудитория, для которой вы делаете проект, и вторичные — менеджеры, будущие поколения разработчиков) могут потребовать генерации собственных мини-сред и языков.
Подсказка 18: Проводите оценки во избежание сюрпризов
Давать примерную оценку — это навык, и существенная часть этого навыка — умение определять приемлемую точность с опорой на контекст. Единица измерения, которую вы выбираете, также должна отражать степень точности (сравните: задача займет две недели и задача займет 75 рабочих часов).
Оценка проводится в несколько стадий. Сначала мы вникаем в суть заданного вопроса и оцениваем масштаб предметной области; при этом нередко сама формулировка вопроса наталкивает на ответ. Затем выстраивается модель проблемы — примерная последовательность стадий, которые нужно будет пройти при ее решении. Модель подвергается декомпозиции на компоненты, для каждого из которого задается параметр значимости. На базе этих параметров и примерных значений производятся расчеты. Последний шаг осуществляется постфактум — прогноз сопоставляется с действительным положением вещей, при серьезных отклонениях проводится работа над ошибками.
Подсказка 19: Уточняи?те график ведения проекта, если того требует код
Это может не понравиться руководству, которому обычно нужно, чтобы цифры были озвучены еще до начала проекта, и не подлежали изменению. Вам придется донести до них, что график выполнения задач будет определяться продуктивностью команды и обстоятельствами. Формализуя эту процедуру и уточняя график в ходе каждой итерации, вы сможете дать руководству максимально точные оценки сроков для каждого этапа.
Инструменты – средство усиления вашего таланта. Чем они лучше и чем лучше вы ими владеете, тем больше сможете сделать. Начните с универсального, «походного» набора инструментов, который будете использовать для всех базовых операций. Это набор будет пополняться по мере того, как вы копите опыт и сталкиваетесь со специфическими требованиями.
Подсказка 20: Сохраняи?те информацию в формате простого текста
Лучшим форматом для постоянного хранения знания является простои? текст, позволяющии? обрабатывать информацию как вручную, так и с помощью любых доступных инструментов. Проблема большинства двоичных форматов состоит в том, что контекст, необходимыи? для понимания данных, отделен от самих данных. А с помощью простого текста, доступного для чтения без дешифровки, вы можете создать самодокументированныи? поток данных, не зависящии? от программы, которая его породила.
Простои? текст обладает двумя основными недостатками: (1) при хранении он может занимать больше места, чем сжатыи? двоичныи? формат, и (2) с точки зрения вычислении? интерпретация и обработка фаи?ла с простым текстом может проводиться медленнее. В зависимости от приложения неприемлемыми могут оказаться одна или обе вышеописанные ситуации. Но и в этих случаях допустимо сохранять метаданные, которые будут описывать исходные данные в формате простого текста.
Простой текст — это:
Подсказка 21: Используи?те сильные стороны командных оболочек
Если вы работаете только с графическим интерфеи?сом, то используете далеко не все возможности, предоставляемые операционнои? системои? — не автоматизируете типовые задачи, не используете доступные инструменты в полную силу, не комбинируете разные решения для создания специализированных макроинструментов. Преимуществом графического интерфеи?са пользователя является то, что они работают по принципу «что видишь, то и получаешь». Главный недостаток графического интерфеи?са можно сформулировать так: «получаешь только то, что видишь». Сфера применения таких инструментов обычно ограничена задачами, для решения которых он изначально задумывался. Если вы хотите выйти за пределы этого шаблона (а рано или поздно придется захотеть), вам с ними не по пути.
?Приложите немного усилий для ознакомления с оболочкои?, и вы удивитесь, насколько продуктивнее станет ваша работа. Строчные команды могут быть непонятными, но они отличаются мощностью и краткостью. Сводя их в фаи?лы сценариев, вы можете создавать последовательности команд для автоматизации часто выполняемых процедур.
Подсказка 22: Используи?те один текстовыи? редактор, но по максимуму
Обработка текста должна отнимать минимум усилий, так что лучше овладеть одним-единственным редактором в совершенстве и использовать его для решения всех задач, связанных с редактированием: работа с текстом программ, документациеи?, записками, системное администрирование и т. д. Трудно быть экспертом сразу в нескольких программных средах, довести работу с каждой до рефлекса, учитывая что в каждои? из них имеется свои? набор команд и стандартов. Пытаясь комбинировать несколько редакторов, вы рискуете повторить ситуацию с вавилонским столпотворением.
Выбор редактора — это почти что религия, поэтому конкретных рекомендаций тут дать нельзя. Однако при принятии решения стоит учитывать следующие параметры:
Подсказка 23: Всегда используи?те управление исходным кодом
Системы управления исходным кодом отслеживают любые изменения, которые вносятся в текст и документацию. Лучшие из них также могут отслеживать изменения в версиях компилятора и операционнои? системы. С помощью системы управления исходным текстом, сконфигурированнои? надлежащим образом, всегда можно вернуться к предыдущеи? версии программы.
Система управления исходным текстом дает много больше, чем просто отмену ошибочных деи?ствии?. Хорошая система позволяет отслеживать изменения и дает ответы на характерные вопросы: «Кто внес изменения в данную строку текста? В чем состоит разница между версиеи?, существующеи? на данныи? момент, и версиеи?, существовавшеи? на прошлои? неделе? Сколько строк текста программы были изменены в даннои? версии? Какие фаи?лы изменяются чаще всего?». Подобная информация бесценна при отслеживании ошибок, аудите, оценке производительности и качества.
Как продвигается дебаггинг?
Подсказка 24: Занимаи?тесь устранением проблемы, а не обвинениями
Мы переходим к теме устранения багов — очень щекотливой и крайне актуальной для командной работы. Здесь, как нигде больше, важен правильный настрой. Проникнитесь тем фактом, что отладка представляет собои? такую же задачу, как и все остальные, и подходите к ней именно с этои? позиции. На самом деле, не важно, кто виноват в ошибке – вы или кто-то другои?. Это все равно остается вашеи? проблемои?.
Подсказка 25: Не паникуи?те
Очень важно сделать шаг назад, подавить первую эмоциональную реакцию, и подумать над тем, что же на самом деле является первопричинои? симптомов и как с этим разобраться. Не поддавайтесь искушению просто устранить симптомы и тем самым решить проблему на поверхностном уровне — работайте с глубинной причиной.
Перед тем как взглянуть на ошибку, убедитесь, что вы работаете над программои?, которая прошла стадию компиляции чисто – без предупреждении?. Тратить время на ошибки, которые видит даже компилятор, не имеет смысла. Соберите максимум доступной информации; если о баге сообщила третья сторона — подробно расспросите тех, кто с ним столкнулся.
Подсказка 26: Ищите ошибки вне пределов операционнои? системы
Исходите из предположения, что с операционной системой, базой данных и прочим ПО все в порядке. Если вы «внесли всего одно изменение», и система перестала работать, то, скорее всего, именно оно является причиной случившегося, каким бы абсурдным ни казалось это утверждение. Если не знаете, с чего начать, то всегда можете положиться на старыи? добрыи? двоичныи? поиск.
Исключение: если какой-то из ваших инструментов недавно обновлялся, возможно, проблема вызвана конфликтами с новой версией. Отслеживайте график грядущих изменений, чтобы минимизировать последствия таких конфликтов.
Подсказка 27: Не предполагаи?те – доказываи?те
То удивление, которое вы испытываете, когда что-то идет не так как надо, прямо пропорционально уровню веры в корректность программы. Поэтому, столкнувшись с неожиданным сбоем в работе программы, вы должны смириться с тем, что одно или более ваших предположении? неверны. Не доверяйте слепо фрагменту кода, вызвавшему ошибку, только потому, что «знаете», что он работает нормально. Вначале докажите это — в реальном контексте, с реальными данными и с реальными граничными условиями.
Столкнувшись с неожиданной ошибкой, постарайтесь принять меры, что исключить возможность ее распространения, влияния на другие фрагменты кода и повторного возникновения. Если она является результатом чьих-то ошибочных представлений, обсудите проблему со всеи? командои?.
Подсказка 28: Изучите язык обработки текстов
Время от времени нам приходится выполнять некоторые преобразования, которые не могут быть осуществлены с помощью походного инструментария. В таких случаях необходим универсальныи? инструмент для обработки текста. Используя языки обработки текстов, вы можете быстро решить все проблемы с утилитами и создать прототипы идеи? – при работе с обычными языками на это потребовалось бы раз в пять-десять больше времени.
Они также облегчают создание генераторов кода, которые будут рассмотрены далее.
Подсказка 29: Пишите код, который будет писать за вас код
От программистов часто требуется выполнять однотипные задачи: обеспечить ту же функциональность, но в другом контексте, воспроизвести информацию или просто перепечатывать один и тот же текст до бесконечности. Тут на помощь приходят шаблоны. Для их создания программист может построить генератор кода, который можно использовать всю оставшуюся жизнь проекта практически бесплатно.
Генераторы кода бывают активными и пассивными. Пассивные генераторы запускаются один раз для достижения результата, который затем становится независимым. Фактически они представляют собой настроенные шаблоны, которые экономят время, необходимое на набор текста, и используются для таких операций, как создание новых исходных файлов, осуществление двоичных преобразований или создание таблиц поиска и других ресурсов, вычисление которых слишком накладно.
Активные генераторы кода используются всякии? раз, когда возникает необходимость в результатах их работы. Они могут быть крайне полезны для следования принципу «минимум дублирования». С помощью активного генератора кода вы можете использовать представление некоторого фрагмента знания и преобразовать его во все формы, необходимые вашему приложению. Это не является дублированием, поскольку эти формы являются расходным материалом и создаются генератором по мере необходимости. Когда нужно организовывать совместную работу двух совершенно разных сред, стоит подумать об использовании активных генераторов кода.
Подсказка 30: Невозможно написать совершенную программу
За всю историю программирования никому не удалось написать ни одного совершенного фрагмента кода. Маловероятно, что вы станете первым. И когда вы примете это как факт, то перестанете тратить время и энергию впустую в погоне за призрачнои? мечтои?.
Подсказка 31: Проектируи?те в соответствии с контрактами
Методика проектирования по контракту предлагает выстраивать взаимодеи?ствие программных модулеи? на базе их задокументированных прав и обязанностей, чтобы обеспечить корректную работу программы. Под корректностью при этом понимается способность делать именно то, что заявлено.
Контракт между подпрограммои? и любои? потенциально вызывающеи? ее программои? может быть сформулирован так: «Если вызывающая программа выполняет все предусловия подпрограммы, то подпрограмма гарантирует, что по завершении ее работы все постусловия и инварианты будут истинными». Если одна из сторон нарушает условия контракта, то применяется предварительно согласованная мера, например, добавляется исключение или происходит завершение работы программы. В разработке придерживайтесь классических принципов заключения контракта: прописывая предусловия, будьте крайне въедливы, а в том, что касается постусловий, наоборот, не давайте лишних обещаний.
Самая большая польза от использования этого принципа состоит в том, что он ставит вопросы требовании? и гарантии? во главу угла. В период работы над проектом простое перечисление факторов – каков диапазон входных значении?, каковы граничные условия, что можно ожидать от работы подпрограммы (или, что важнее, чего от нее ожидать нельзя), – является громадным шагом вперед. Не обозначив эти позиции, вы скатываетесь к программированию в расчете на совпадение, на чем многие проекты и терпят крах.
Подсказка 32: Пусть аварии?ное завершение работы программы произои?дет как можно раньше
Во многих случаях такое завершение программы – это лучшии? выход из положения, так как альтернативы приведут к серьезным, иногда необратимым последствиям. Прагматики смотрят на ситуацию так: если ошибка имеет место, значит произошло что-то очень скверное и лучше перестраховаться.
Ясно, что в ряде случаев экстренный выход из выполняющеи?ся программы неуместен (возможно, вам необходимо сначала занести что-то в логи, завершить открытые транзакции или провести взаимодеи?ствие с другими процессами). Однако основнои? принцип остается тем же – если программа обнаруживает, что произошло событие, которое считалось невозможным, она теряет жизнеспособность. Начиная с этого момента, все деи?ствия, совершаемые программои?, попадают под подозрение, и ее выполнение должно быть прервано как можно быстрее. В большинстве случаев мертвая программа приносит намного меньше вреда, чем испорченная.
Подсказка 33: Если что-либо не может произои?ти, воспользуи?тесь утверждениями, которые гарантируют, что это не произои?дет
Всякии? раз, когда вы начинаете думать в ключе: «Ну конечно, такого просто не может произои?ти», удостоверьтесь в этом с помощью кода. Самыи? простои? способ осуществить это – использовать утверждения. В большинстве реализации? языков С и С++ имеется некоторая разновидность макроса assert или _assert, которыи? осуществляет проверку логического условия. Эти макрокоманды могут представлять огромную ценность. Допустим, если указатель, передаваемыи? к вашеи? процедуре, ни в коем случае не должен принимать значение NULL, пропишите обязательное выполнение этого условия.
Утверждения не должны использоваться вместо реальнои? обработки ошибок. Они лишь осуществляют проверку на то, что никогда не должно произои?ти. Существует точка зрения, согласно которой утверждения нужны только в период отладки, а когда проект сдан, превращаются в мертвый груз. Это чересчур оптимистичный взгляд: тестирование скорее всего не выявит всего, что может произойти в реальных условиях. Даже при наличии проблем с производительностью, отключайте только те утверждения, которые деи?ствительно оказывают на нее серьезное воздеи?ствие.
Подсказка 34: Пользуи?тесь исключениями только в исключительных случаях
На практике, однако, проверка на все вообразимые ошибки может привести к тому, что программа станет уродливои?; нормальная логика может сои?ти на нет из-за перенасыщенности процедурами обработки ошибок. Реализовать все изящнее помогут исключения.
Основная проблема с исключениями, заключается в том, что необходимо знать, когда их использовать. Не стоит злоупотреблять исключениями для нормального хода выполнения программы; они должны быть зарезервированы для внештатных ситуации?.
Исключение представляет собои? мгновенную нелокальную передачу управления – своего рода многоуровневыи? оператор goto. Программы, использующие исключения в своеи? обычнои? работе, испытывают те же проблемы с удобочитаемостью и сопровождением, которые свои?ственны классическим неструктурированным программам. В них нарушается принцип инкапсуляции: подпрограммы и программы, их вызывающие, оказываются сильнее связаны между собой за счет обработки исключении?.
Подсказка 35: Доводите до конца то, что начинаете
При написании программ нам приходится управлять ресурсами: памятью, транзакциями, потоками, фаи?лами, таи?мерами – словом, разными типами объектов, которые доступны в ограниченном объеме. Большую часть времени использование ресурса следует предсказуемои? схеме: ресурс назначается, используется, а затем освобождается. Однако многие разработчики не имеют четкого плана по распределению и освобождению ресурсов, что может привести к их нехватке. Выход здесь простой: подпрограмма или объект, которые запрашивают ресурс, должны нести ответственность за освобождение этого ресурса.
Если нескольким подпрограммам одновременно необходимо более одного ресурса, добавляется еще два правила:
В программах, которые используют динамические структуры данных, возникают моменты, когда основная схема распределения ресурсов не годится. В этом случае хитрость состоит в установлении семантического инварианта для выделения памяти.
Ниже вы найдете конспект первых четырех глав; речь в них идет об авторской концепции самообразования, основах прагматического подхода в программировании и правилах подбора инструментов. Книга очень удобна для «точечного» чтения: материал представляется в виде отдельных параграфов-подсказок, снабженных перекрестными ссылками. За рамками этого конспекта остались примеры из конкретных языков, разбор кейсов из авторской практики, те самые ссылки, упражнения на закрепление и некоторые забавные аналогии, оживляющие текст — так что рекомендую ознакомиться с оригиналом, если какие-то из тезисов вас заинтересуют. Приятного чтения!
Подсказка 1: Позаботьтесь о вашем ремесле
?Нет смысла разрабатывать программы, если вы не заботитесь о качестве работы. Делать это нужно не только в краткосрочной перспективе, применительно к конкретным проектам, но и в долгосрочной — формируя правильный подход и принципы работы.
Что отличает программиста-прагматика?
- Опережающее восприятие и быстрая адаптация. У прагматиков инстинкт на полезные технологии и методы, которые они с удовольствием проверяют на практике. Они способны быстро схватывать новую информацию и объединять ее с уже имеющимися знаниями.
- Любознательность. Прагматики задают вопросы, собирают мелкие факты, интересуются чужим опытом.
- Критическое осмысление. Прагматики не принимают ничего на веру, не ознакомившись предварительно с фактами.
- Реализм. Прагматики пытаются нащупать, где находятся подводные камни в каждои? проблеме, с которои? приходится сталкиваться.
- Универсальность. Прагматики стремятся познакомиться с большим числом технологии? и операционных систем и работают над тем, чтобы идти в ногу со временем.
Подсказка 2: Думаи?те о работе
Во время написания кода следует полностью концентрироваться на том, что делаете. Никогда не переходите в режим автопилота. Думаи?те постоянно, критически осмысляя свою работу в реальном времени. Это называется осознанным программированием. Его освоение займет некоторое время и потребует усилий, но наградой станет привычка беспрестанно вносить мелкие усовершенствования, повышая качество кода в целом и сокращая сроки разработки.
Глава 1: Прагматическая философия
Прагматическое программирование ведет свое начало от философии прагматического мышления. В даннои? главе приводятся ее основные положения.
Подсказка 3: Представляйте варианты решения проблемы, а не отговорки
Одним из краеугольных камнеи? прагматической философии является идея принятия ответственности за себя и за свои деи?ствия. Программист-прагматик исходит из того, что его карьера и результаты работы зависят прежде всего от него, и не боится признаться в неведении или ошибке.
Принятие ответственности за результат предполагает готовность отчитываться. Если вы допустили ошибку (а мы все их допускаем), признаи?те ее честно и попытаи?тесь предложить варианты исправления. Не стоит перекладывать вину на коллег, партнеров, инструменты или выдумывать отговорки — это непродуктивная трата времени. То же относится и к ситуациям, когда вы сталкиваетесь в требованиями, которые не сможете удовлетворить: не говорите просто: «Это невозможно», а объясните, что нужно для спасения ситуации (дополнительные ресурсы, реорганизация и т.д.).
Подсказка 4: Не оставляйте разбитых окон
Энтропия – это термин из физики, обозначающии? уровень «беспорядка» в системе. Энтропия во вселеннои? стремится к максимуму, и в разработке наблюдается та же закономерность. Увеличение степени беспорядка в программах на профессиональном жаргоне называется порчеи? программ. Существует много факторов, вносящих свои? вклад в порчу программ, но наиболее важный из них — культура работы над проектом.
Согласно теории разбитых окон, неряшливые решения и проблемные места имеют свойство размножаться. Не оставляи?те «разбитые окна» (неудачные конструкции, ошибки, некачественныи? код) без внимания. Если нет времени на надлежащии? ремонт, хотя бы закомментируйте ошибочныи? фрагмент или выведите на экран сообщение «В стадии разработки», или используйте фиктивные данные. Необходимо предпринять хотя бы малеи?шее деи?ствие, чтобы предотвратить дальнеи?шее разрушение, и показать, что вы контролируете ситуацию. Небрежность ускоряет порчу быстрее, чем любои? другои? фактор.
Подсказка 5: Будьте катализатором изменении?
Если вы видите, что необходимо сделать, не ждите инициативы от окружающих. Составьте план, проработайте подробности — люди будут охотнее вас поддерживать, если увидят, что работа уже начата.
Подсказка 6: Следите за изменениями
Не сводите глаз с общеи? картины происходящего. Постоянно наблюдаи?те за тем, что происходит вокруг вас, а не только за тем, что делаете вы лично. Большинство катастроф в коде начинаются с малозаметных вещеи?, которые копятся, пока в один прекрасныи? день проект не пойдет вразнос. Шаг за шагом система отклоняется от требовании?, код обрастает «заплатами», пока от оригинала не остается ничего. Зачастую именно скопившиеся мелочи приводят к разрушению морали и команд. Но если захватить этот процесс на ранних стадиях и немедленно принять меры (см. предыдущий пункт), можно отделаться малой кровью.
Подсказка 7: Сделаи?те качество одним из пунктов требовании?
Качество должно быть договорным пунктом в контракте, который вы заключаете с пользователями. Конечно, в идеале оно должно быть максимальным, но часто вы будете оказываться в ситуациях, когда приходится идти на компромисс из-за жестких сроков или нехватки ресурсов. И здесь полезно приучить себя к созданию приемлемых программ. «Приемлемая» не значит «сделанная тяп-ляп»: вы просто даете пользователям право голоса при определении того порога качества, который можно считать допустимым. Удивительно, но многие предпочтут использовать программы с некоторыми недоработками сегодня, вместо того чтобы год ожидать выпуска мультимедии?нои? версии.
Кроме того, иногда программы становятся лучше благодаря сокращению инкубационного периода. В разработке существует проблема «перешлифовки» — внешние ограничения помогают вовремя остановиться в погоне за совершенством.
Подсказка 8: Регулярно инвестируи?те в свой портфель знании?
Под портфелем знании? понимаются все, что программист знает о разработке в своей области, а также накопленныи? им опыт. Управление портфелем знании? очень похоже на управление финансовым портфелем:
Общие принципы таковы:
- Инвестируи?те на регулярнои? основе. Даже если объем инвестиции? невелик, эта привычка полезна сама по себе.
- Инвестируи?те в различные сферы. Чем больше областей вы захватываете, тем большую ценность представляете. Как минимум, вы обязаны знать конкретные технологии, с которыми работаете в данныи? момент, от и до. Но не останавливаи?тесь на этом. Спрос на технологии и их применимость постоянно меняются. Чем больше инструментов у вас в арсенале вы освоите, тем легче вам будет приспособиться.
- Взвешивайте риски. Технологии существуют в некоем диапазоне – от рисковых и потенциально высокодоходных до низкорисковых и низкодоходных. Вкладывать все в рискованные варианты, курс которых может внезапно обвалиться, не лучшая идея, но и излишняя осторожность, не позволяющая воспользоваться выгодными возможностями – тоже. Лучше держаться средней линии.
- Покупаи?те подешевле, продаваи?те подороже. Освоить передовую технологию до того, как она станет популярнои?, — сложная задача, но оно того стоит: ранние последователи часто делают головокружительную карьеру.
- Регулярно проводите пересмотр и повторную балансировку. Программирование – очень динамичная отрасль. Будьте готовы периодически критически пересматривать свои активы: отказываться от устаревших вариантов, восстанавливать поднявшиеся в цене и восполнять пустующие ниши.
Процесс обучения расширит ваше мышление, открывая для вас новые возможности и новые пути в творчестве. Если вы узнали что-то новое, постарайтесь применить это знание к проекту, над которым вы работаете в настоящее время, насколько позволяют используемые технологии.
Подсказка 9: Критически анализируи?те прочитанное и услышанное
Необходимо убедиться, что знание в вашем портфеле является точным, что оно не искажено теми, кому это выгодно, и что его ценность не раздута хайпом. Опасаи?тесь фанатиков, настаивающих на том, что их догма обеспечивает единственно правильныи? ответ — вполне возможно, что именно в вашем проекте он неприменим.
Подсказка 10: Важно, что говорить и как говорить
Большая часть дня программиста проходит в общении — с командой, руководством, пользователями, будущими поколениями разработчиков через документацию и комментарии в коде. Поэтому необходимо овладеть его искусством. Чем эффективнее это общение, тем выше ваша способность претворять идеи в жизнь.
Принципы эффективного общения:
- Знаи?те, что вы хотите сказать: Спланируйте, что будете говорить заранее, набросайте план и пару стратегий, как лучше донести мысль. Это работает и для составления документов, и для важных переговоров.
- Знаи?те вашу аудиторию: Вы общаетесь только в том случае, если передаете информацию. Для этого вам необходимо осознавать потребности, интересы и способности аудитории. Представляйте информацию так, чтобы она была понятна и интересна слушателю.
- Выбираи?те подходящии? момент: Важный момент для понимания аудитории — понимание ее сиюминутных приоритетов. То, что вы говорите, должно быть не только уместным по содержанию, но и своевременным. Если нужно, спросите прямо: «Удобно ли сеи?час поговорить о…?»
- Выбираи?те нужный стиль: Определите стиль подачи материала в соответствии с требованиями аудитории: кто-то предпочитает голые факты, кто-то — подробности, примеры и пространные введения. Опять же, если сомневаетесь, уточните.
- Встречают по одежке: Умейте должным образом «сервировать» свои идеи. В конечном документе должно быть выверено все: правописание, макет, стили текста, печатное оформление.
- Привлекаи?те свою аудиторию: По возможности привлекаи?те будущих читателеи? к процессу создания документов. Используи?те их идеи. Так вы получите лучший результат и укрепите рабочие взаимоотношения.
- Умеи?те слушать: Вступайте с людьми в беседу, задавая вопросы или заставляя их подытожить сказанное вами. Превратите собрание в диалог, и вы лучше донесете то, что хотели сказать, а возможно, заодно почерпнете что-то для себя.
- Не обрывайте разговор: Всегда отвечаи?те на запросы и сообщения хотя бы обещанием вернуться к этому вопросу позже. Если вы держите людеи? в курсе, они чувствуют, что о них не забыли, и намного легче прощают случаи?ные промахи.
Глава 2: Прагматическии? подход
Существует ряд подсказок и уловок, применимых на всех уровнях разработки программ — идеи, которые можно считать аксиомами, процессы, которые практически универсальны. В этои? главе проводится обзор этих идей и процессов.
Подсказка 11: Не повторяи?тесь
Каждый фрагмент знания должен иметь единственное, однозначное, надежное представление в системе. Альтернативои? является представление одного и того же предмета в нескольких местах. Это доставляет неудобства: если в одном месте что-то редактируется, нужно немедленно внести изменения во всех остальных, иначе программа рухнет под грузом противоречии?. Рано или поздно вы что-нибудь забудете, это вопрос времени.
Большинство случаев дублирования подпадает под одну из следующих категории?:
- Навязанное дублирование. Разработчики чувствуют, что у них нет выбора – дублирование необходимо по каким-то внешним причинам: стандартам документации, сочетанию нескольких платформ с разными средами, языкам и и библиотеками, спецификой самого языка. В некоторых случаях остается только смириться, но в других можно все-таки найти обходные пути при помощи фильтров, активных генераторов кода, метаданных и верного подхода к комментированию.
- Неумышленное дублирование. Разработчики не осознают, что дублируют информацию. Обычно это происходит как следствие ошибок или неувязок на глубинном уровне (например, один и тот же атрибут прописывается в нескольких объектах), и устранение требует реорганизации. В некоторых подобных случаях принцип позволительно нарушать ради производительности, но только в пределах класса.
- Нетерпеливое дублирование. Разработчики производят дублирование, потому что им кажется, что так проще. Обычно это происходит путем копирования кусков кода. Здесь все сводится к самодисциплине — не полениться потратить несколько лишних секунд, чтобы избежать головной боли в будущем.
- Коллективное дублирование. Фрагмент информации дублируется несколькими членами однои? команды разработчиков в ходе работы. Самый сложный случай с точки зрения как обнаружения, так и разрешения. На высоком уровне проблема решается за счет ясного проектного решения, сильного технического руководителя четкого и разделения обязанностеи?. На модулярном — за счет активной коммуникации между разработчиками: создавайте группы для общения, заведите в каталоге общедоступное место для хранения сервисных подпрограмм и скриптов, поощряйте изучение и обсуждение чужого кода.
Подсказка 12: Сделаи?те так, чтобы программу можно было легко использовать повторно
Постарайтесь создать среду, где проще находить и многократно использовать существующии? материал, чем создавать его самому с нуля. Это помогает снизить риск дублирования. Только имейте в виду: если повторное использование сопряжено с какими-то сложностями, люди не станут этого делать.
Подсказка 13: Исключаи?те взаимодеи?ствие между объектами, не относящимися друг к другу
Это правило называют также принципом ортогональности. Два или более объекта ортогональны, если изменения, вносимые в один из них, никак не влияют на остальные. Подобная схема дает два больших преимущества: увеличение производительности и снижение риска.
Когда изменения в системе локализуются, сроки разработки и тестирования сокращаются. После того как небольшой самодостаточный компонент спроектирован, реализован и протестирован о нем можно попросту забыть, вместо того чтобы постоянно вносить изменения по мере добавления в код новых фрагментов.
Ортогональныи? подход также способствует многократному использованию компонентов. Чем меньше связанность в системах, тем легче провести реконфигурацию или реинжиниринг.
Снижение риска вызвано тем, что ошибочные фрагменты оказываются изолированы и не влияют на всю систему; соответственно, исправить или заменить их тоже проще. Вследствие этого система становится более устойчивой — проблемные участки остаются участками. Помогает и то, что тестирование на уровне модулей обычно проводится более тщательно.
Принцип ортогональности должен соблюдаться не на уровне отдельных технологий, а охватывать все процессы: от проектирования до подбора инструментов, от тестирования до управления продуктом. Он сводит к минимуму дублирование и делает систему гибче и прозрачнее.
Подсказка 14: Не существует окончательных решении?
Требования, пользователи и аппаратные средства изменяются быстрее, чем мы разрабатываем программное обеспечение. Поэтому нужно всегда быть готовыми к тому, что любое решение, которое вы принимаете (не только в пределах кода, но и, допустим, при выборе инструмента от третьей стороны, архитектурного шаблона, модели развертывания), придется пересмотреть в будущем под влиянием внешних факторов. Принцип «минимум дублирования», принцип несвязанности и использование метаданных позволяют сделать систему более обратимой.
Подсказка 15: Пользуи?тесь трассирующими пулями, для того чтобы наи?ти цель
Раскрывая метафору: при создании нового продукта команда разработчиков зачастую действует вслепую, работая с малознакомыми методиками, языками и библиотеками. Предугадать конечный результат можно либо путем жесткого прогнозирования, основанного на очень развернутом анализе технологий, либо при помощи «трассировки» — создания серии упрощенных, пробных, постепенно совершенствующихся рабочих версий, чтобы собрать воедино компоненты системы и проверить, как они работают в связке.
Альтернатива такому подходу — изолированная разработка отдельных модулей, которые на завершающем этапе собираются воедино и тогда уже тестируются на уровне системы — более тяжеловесна и менее удобна. Среди прочего, метод трассировки дает вам черновую версию продукта (ее можно представить пользователям, чтобы показать им суть проекта, заинтересовать и получить фидбэк); более плавную и фокусную интеграцию готовых новых модулей в среду и возможность немедленно выявлять и легко устранять ошибки во взаимодействии.
Подсказка 16: Создаваи?те прототипы, чтобы учиться на них
В отличие от описанных выше тестовых версий прототипы имеют более узкую направленность: они создаются, чтобы отработать несколько конкретных характеристик и требуют значительно меньше ресурса. Все подробности, не имеющие отношения к рассматриваемой проблеме, опускаются, даже если они крайне важны для работы системы в целом. При работе над прототипом можно пренебречь корректностью, завершенностью, надежностью и стилем.
Для прототипирования необязательно создавать полноценное рабочее приложение, иногда достаточно просто схемы на бумаге или доске. Если оно все-таки необходимо, то имеет смысл выбрать для этой цели язык очень высокого уровня – выше уровня языка, который используется остальнои? части проекта (язык типа Perl, Python или Tel). Язык сценариев высокого уровня позволяет опускать многие детали (включая указание типов данных) и при этом создавать функциональныи?, хотя неполныи? и медленныи?, фрагмент программы.
Подсказка 17: Пишите код с оглядкой на область применения
Языки программирования влияют на то, как вы думаете о проблеме и о взаимодействии с пользователем. В каждом языке имеются свои особенности, которые наталкивают на определенные решения или, наоборот, препятствуют им. Решение, создаваемое в стиле Lisp, отличается от решения, основанного на мышлении приверженца языка С, и наоборот. Верно и обратное – язык, отражающии? специфику проблематики, с которой вы работаете, может, со своеи? стороны, предложить решение в области программирования.
Прислушиваясь к требованиям пользователей, вы можете понять, на какой язык будет проще всего их перевести на высшем, абстрактном уровне. Разные типы пользователей (конечные — аудитория, для которой вы делаете проект, и вторичные — менеджеры, будущие поколения разработчиков) могут потребовать генерации собственных мини-сред и языков.
Подсказка 18: Проводите оценки во избежание сюрпризов
Давать примерную оценку — это навык, и существенная часть этого навыка — умение определять приемлемую точность с опорой на контекст. Единица измерения, которую вы выбираете, также должна отражать степень точности (сравните: задача займет две недели и задача займет 75 рабочих часов).
Оценка проводится в несколько стадий. Сначала мы вникаем в суть заданного вопроса и оцениваем масштаб предметной области; при этом нередко сама формулировка вопроса наталкивает на ответ. Затем выстраивается модель проблемы — примерная последовательность стадий, которые нужно будет пройти при ее решении. Модель подвергается декомпозиции на компоненты, для каждого из которого задается параметр значимости. На базе этих параметров и примерных значений производятся расчеты. Последний шаг осуществляется постфактум — прогноз сопоставляется с действительным положением вещей, при серьезных отклонениях проводится работа над ошибками.
Подсказка 19: Уточняи?те график ведения проекта, если того требует код
Это может не понравиться руководству, которому обычно нужно, чтобы цифры были озвучены еще до начала проекта, и не подлежали изменению. Вам придется донести до них, что график выполнения задач будет определяться продуктивностью команды и обстоятельствами. Формализуя эту процедуру и уточняя график в ходе каждой итерации, вы сможете дать руководству максимально точные оценки сроков для каждого этапа.
Глава 3: Походныи? набор инструментов
Инструменты – средство усиления вашего таланта. Чем они лучше и чем лучше вы ими владеете, тем больше сможете сделать. Начните с универсального, «походного» набора инструментов, который будете использовать для всех базовых операций. Это набор будет пополняться по мере того, как вы копите опыт и сталкиваетесь со специфическими требованиями.
Подсказка 20: Сохраняи?те информацию в формате простого текста
Лучшим форматом для постоянного хранения знания является простои? текст, позволяющии? обрабатывать информацию как вручную, так и с помощью любых доступных инструментов. Проблема большинства двоичных форматов состоит в том, что контекст, необходимыи? для понимания данных, отделен от самих данных. А с помощью простого текста, доступного для чтения без дешифровки, вы можете создать самодокументированныи? поток данных, не зависящии? от программы, которая его породила.
Простои? текст обладает двумя основными недостатками: (1) при хранении он может занимать больше места, чем сжатыи? двоичныи? формат, и (2) с точки зрения вычислении? интерпретация и обработка фаи?ла с простым текстом может проводиться медленнее. В зависимости от приложения неприемлемыми могут оказаться одна или обе вышеописанные ситуации. Но и в этих случаях допустимо сохранять метаданные, которые будут описывать исходные данные в формате простого текста.
Простой текст — это:
- Гарантия того, что данные не устареют
- Более короткии? путь к цели
- Более простое тестирование
Подсказка 21: Используи?те сильные стороны командных оболочек
Если вы работаете только с графическим интерфеи?сом, то используете далеко не все возможности, предоставляемые операционнои? системои? — не автоматизируете типовые задачи, не используете доступные инструменты в полную силу, не комбинируете разные решения для создания специализированных макроинструментов. Преимуществом графического интерфеи?са пользователя является то, что они работают по принципу «что видишь, то и получаешь». Главный недостаток графического интерфеи?са можно сформулировать так: «получаешь только то, что видишь». Сфера применения таких инструментов обычно ограничена задачами, для решения которых он изначально задумывался. Если вы хотите выйти за пределы этого шаблона (а рано или поздно придется захотеть), вам с ними не по пути.
?Приложите немного усилий для ознакомления с оболочкои?, и вы удивитесь, насколько продуктивнее станет ваша работа. Строчные команды могут быть непонятными, но они отличаются мощностью и краткостью. Сводя их в фаи?лы сценариев, вы можете создавать последовательности команд для автоматизации часто выполняемых процедур.
Подсказка 22: Используи?те один текстовыи? редактор, но по максимуму
Обработка текста должна отнимать минимум усилий, так что лучше овладеть одним-единственным редактором в совершенстве и использовать его для решения всех задач, связанных с редактированием: работа с текстом программ, документациеи?, записками, системное администрирование и т. д. Трудно быть экспертом сразу в нескольких программных средах, довести работу с каждой до рефлекса, учитывая что в каждои? из них имеется свои? набор команд и стандартов. Пытаясь комбинировать несколько редакторов, вы рискуете повторить ситуацию с вавилонским столпотворением.
Выбор редактора — это почти что религия, поэтому конкретных рекомендаций тут дать нельзя. Однако при принятии решения стоит учитывать следующие параметры:
- Настраиваемость. Все свои?ства редактора должны настраиваться по вашему пожеланию, включая шрифты, цвета, размеры окон и горячие клавиши.
- Расширяемость. Редактор не должен устареть, как только появится новыи? язык программирования. Он должен обладать способностью интегрироваться в любую компиляторную среду, которую вы используете в данныи? момент. У вас должна быть опция «обучить» его нюансам любого нового языка программирования или текстового формата.
- Программируемость. Вы должны располагать возможностью запрограммировать редактор для осуществления сложных многоступенчатых операции?.
Подсказка 23: Всегда используи?те управление исходным кодом
Системы управления исходным кодом отслеживают любые изменения, которые вносятся в текст и документацию. Лучшие из них также могут отслеживать изменения в версиях компилятора и операционнои? системы. С помощью системы управления исходным текстом, сконфигурированнои? надлежащим образом, всегда можно вернуться к предыдущеи? версии программы.
Система управления исходным текстом дает много больше, чем просто отмену ошибочных деи?ствии?. Хорошая система позволяет отслеживать изменения и дает ответы на характерные вопросы: «Кто внес изменения в данную строку текста? В чем состоит разница между версиеи?, существующеи? на данныи? момент, и версиеи?, существовавшеи? на прошлои? неделе? Сколько строк текста программы были изменены в даннои? версии? Какие фаи?лы изменяются чаще всего?». Подобная информация бесценна при отслеживании ошибок, аудите, оценке производительности и качества.
Как продвигается дебаггинг?
Подсказка 24: Занимаи?тесь устранением проблемы, а не обвинениями
Мы переходим к теме устранения багов — очень щекотливой и крайне актуальной для командной работы. Здесь, как нигде больше, важен правильный настрой. Проникнитесь тем фактом, что отладка представляет собои? такую же задачу, как и все остальные, и подходите к ней именно с этои? позиции. На самом деле, не важно, кто виноват в ошибке – вы или кто-то другои?. Это все равно остается вашеи? проблемои?.
Подсказка 25: Не паникуи?те
Очень важно сделать шаг назад, подавить первую эмоциональную реакцию, и подумать над тем, что же на самом деле является первопричинои? симптомов и как с этим разобраться. Не поддавайтесь искушению просто устранить симптомы и тем самым решить проблему на поверхностном уровне — работайте с глубинной причиной.
Перед тем как взглянуть на ошибку, убедитесь, что вы работаете над программои?, которая прошла стадию компиляции чисто – без предупреждении?. Тратить время на ошибки, которые видит даже компилятор, не имеет смысла. Соберите максимум доступной информации; если о баге сообщила третья сторона — подробно расспросите тех, кто с ним столкнулся.
Подсказка 26: Ищите ошибки вне пределов операционнои? системы
Исходите из предположения, что с операционной системой, базой данных и прочим ПО все в порядке. Если вы «внесли всего одно изменение», и система перестала работать, то, скорее всего, именно оно является причиной случившегося, каким бы абсурдным ни казалось это утверждение. Если не знаете, с чего начать, то всегда можете положиться на старыи? добрыи? двоичныи? поиск.
Исключение: если какой-то из ваших инструментов недавно обновлялся, возможно, проблема вызвана конфликтами с новой версией. Отслеживайте график грядущих изменений, чтобы минимизировать последствия таких конфликтов.
Подсказка 27: Не предполагаи?те – доказываи?те
То удивление, которое вы испытываете, когда что-то идет не так как надо, прямо пропорционально уровню веры в корректность программы. Поэтому, столкнувшись с неожиданным сбоем в работе программы, вы должны смириться с тем, что одно или более ваших предположении? неверны. Не доверяйте слепо фрагменту кода, вызвавшему ошибку, только потому, что «знаете», что он работает нормально. Вначале докажите это — в реальном контексте, с реальными данными и с реальными граничными условиями.
Столкнувшись с неожиданной ошибкой, постарайтесь принять меры, что исключить возможность ее распространения, влияния на другие фрагменты кода и повторного возникновения. Если она является результатом чьих-то ошибочных представлений, обсудите проблему со всеи? командои?.
Подсказка 28: Изучите язык обработки текстов
Время от времени нам приходится выполнять некоторые преобразования, которые не могут быть осуществлены с помощью походного инструментария. В таких случаях необходим универсальныи? инструмент для обработки текста. Используя языки обработки текстов, вы можете быстро решить все проблемы с утилитами и создать прототипы идеи? – при работе с обычными языками на это потребовалось бы раз в пять-десять больше времени.
Они также облегчают создание генераторов кода, которые будут рассмотрены далее.
Подсказка 29: Пишите код, который будет писать за вас код
От программистов часто требуется выполнять однотипные задачи: обеспечить ту же функциональность, но в другом контексте, воспроизвести информацию или просто перепечатывать один и тот же текст до бесконечности. Тут на помощь приходят шаблоны. Для их создания программист может построить генератор кода, который можно использовать всю оставшуюся жизнь проекта практически бесплатно.
Генераторы кода бывают активными и пассивными. Пассивные генераторы запускаются один раз для достижения результата, который затем становится независимым. Фактически они представляют собой настроенные шаблоны, которые экономят время, необходимое на набор текста, и используются для таких операций, как создание новых исходных файлов, осуществление двоичных преобразований или создание таблиц поиска и других ресурсов, вычисление которых слишком накладно.
Активные генераторы кода используются всякии? раз, когда возникает необходимость в результатах их работы. Они могут быть крайне полезны для следования принципу «минимум дублирования». С помощью активного генератора кода вы можете использовать представление некоторого фрагмента знания и преобразовать его во все формы, необходимые вашему приложению. Это не является дублированием, поскольку эти формы являются расходным материалом и создаются генератором по мере необходимости. Когда нужно организовывать совместную работу двух совершенно разных сред, стоит подумать об использовании активных генераторов кода.
Глава 4: Прагматическая паранойя
Подсказка 30: Невозможно написать совершенную программу
За всю историю программирования никому не удалось написать ни одного совершенного фрагмента кода. Маловероятно, что вы станете первым. И когда вы примете это как факт, то перестанете тратить время и энергию впустую в погоне за призрачнои? мечтои?.
Подсказка 31: Проектируи?те в соответствии с контрактами
Методика проектирования по контракту предлагает выстраивать взаимодеи?ствие программных модулеи? на базе их задокументированных прав и обязанностей, чтобы обеспечить корректную работу программы. Под корректностью при этом понимается способность делать именно то, что заявлено.
Контракт между подпрограммои? и любои? потенциально вызывающеи? ее программои? может быть сформулирован так: «Если вызывающая программа выполняет все предусловия подпрограммы, то подпрограмма гарантирует, что по завершении ее работы все постусловия и инварианты будут истинными». Если одна из сторон нарушает условия контракта, то применяется предварительно согласованная мера, например, добавляется исключение или происходит завершение работы программы. В разработке придерживайтесь классических принципов заключения контракта: прописывая предусловия, будьте крайне въедливы, а в том, что касается постусловий, наоборот, не давайте лишних обещаний.
Самая большая польза от использования этого принципа состоит в том, что он ставит вопросы требовании? и гарантии? во главу угла. В период работы над проектом простое перечисление факторов – каков диапазон входных значении?, каковы граничные условия, что можно ожидать от работы подпрограммы (или, что важнее, чего от нее ожидать нельзя), – является громадным шагом вперед. Не обозначив эти позиции, вы скатываетесь к программированию в расчете на совпадение, на чем многие проекты и терпят крах.
Подсказка 32: Пусть аварии?ное завершение работы программы произои?дет как можно раньше
Во многих случаях такое завершение программы – это лучшии? выход из положения, так как альтернативы приведут к серьезным, иногда необратимым последствиям. Прагматики смотрят на ситуацию так: если ошибка имеет место, значит произошло что-то очень скверное и лучше перестраховаться.
Ясно, что в ряде случаев экстренный выход из выполняющеи?ся программы неуместен (возможно, вам необходимо сначала занести что-то в логи, завершить открытые транзакции или провести взаимодеи?ствие с другими процессами). Однако основнои? принцип остается тем же – если программа обнаруживает, что произошло событие, которое считалось невозможным, она теряет жизнеспособность. Начиная с этого момента, все деи?ствия, совершаемые программои?, попадают под подозрение, и ее выполнение должно быть прервано как можно быстрее. В большинстве случаев мертвая программа приносит намного меньше вреда, чем испорченная.
Подсказка 33: Если что-либо не может произои?ти, воспользуи?тесь утверждениями, которые гарантируют, что это не произои?дет
Всякии? раз, когда вы начинаете думать в ключе: «Ну конечно, такого просто не может произои?ти», удостоверьтесь в этом с помощью кода. Самыи? простои? способ осуществить это – использовать утверждения. В большинстве реализации? языков С и С++ имеется некоторая разновидность макроса assert или _assert, которыи? осуществляет проверку логического условия. Эти макрокоманды могут представлять огромную ценность. Допустим, если указатель, передаваемыи? к вашеи? процедуре, ни в коем случае не должен принимать значение NULL, пропишите обязательное выполнение этого условия.
Утверждения не должны использоваться вместо реальнои? обработки ошибок. Они лишь осуществляют проверку на то, что никогда не должно произои?ти. Существует точка зрения, согласно которой утверждения нужны только в период отладки, а когда проект сдан, превращаются в мертвый груз. Это чересчур оптимистичный взгляд: тестирование скорее всего не выявит всего, что может произойти в реальных условиях. Даже при наличии проблем с производительностью, отключайте только те утверждения, которые деи?ствительно оказывают на нее серьезное воздеи?ствие.
Подсказка 34: Пользуи?тесь исключениями только в исключительных случаях
На практике, однако, проверка на все вообразимые ошибки может привести к тому, что программа станет уродливои?; нормальная логика может сои?ти на нет из-за перенасыщенности процедурами обработки ошибок. Реализовать все изящнее помогут исключения.
Основная проблема с исключениями, заключается в том, что необходимо знать, когда их использовать. Не стоит злоупотреблять исключениями для нормального хода выполнения программы; они должны быть зарезервированы для внештатных ситуации?.
Исключение представляет собои? мгновенную нелокальную передачу управления – своего рода многоуровневыи? оператор goto. Программы, использующие исключения в своеи? обычнои? работе, испытывают те же проблемы с удобочитаемостью и сопровождением, которые свои?ственны классическим неструктурированным программам. В них нарушается принцип инкапсуляции: подпрограммы и программы, их вызывающие, оказываются сильнее связаны между собой за счет обработки исключении?.
Подсказка 35: Доводите до конца то, что начинаете
При написании программ нам приходится управлять ресурсами: памятью, транзакциями, потоками, фаи?лами, таи?мерами – словом, разными типами объектов, которые доступны в ограниченном объеме. Большую часть времени использование ресурса следует предсказуемои? схеме: ресурс назначается, используется, а затем освобождается. Однако многие разработчики не имеют четкого плана по распределению и освобождению ресурсов, что может привести к их нехватке. Выход здесь простой: подпрограмма или объект, которые запрашивают ресурс, должны нести ответственность за освобождение этого ресурса.
Если нескольким подпрограммам одновременно необходимо более одного ресурса, добавляется еще два правила:
- Освобождаи?те ресурсы в последовательности, обратнои? тои?, в которои? происходило их распределение. При этом можно избежать появления «осиротевших» ресурсов, если один из них содержит ссылки на другои?.
- При распределении одного и того же набора ресурсов в различных местах программы необходимо осуществлять эту операцию в одном и том же порядке. Это уменьшает вероятность взаимоблокировки.
В программах, которые используют динамические структуры данных, возникают моменты, когда основная схема распределения ресурсов не годится. В этом случае хитрость состоит в установлении семантического инварианта для выделения памяти.
poxvuibr
Перевод на человеческий — Избегайте входа в состояние потока всеми силами.
Inine
В моем понимании это разные вещи.
Состояние потока — это когда ты не отвлекаешься на окружающий мир, а полностью погружен в то, что ты делаешь. При этом ты держишь в оперативке, что ты делаешь, в какой последовательности и с какими объектами.
Автопилот — это когда ты начинаешь что-то делать, не задумываясь, надо или нет. Обычно — от усталости. На автопилоте можно написать кучу лишнего кода и только потом понять, что сначала надо было подумать, нужен ли он. Или можно на автопилоте постоянно жать ненужную кнопку, или переключаться не на то окно и тупо смотреть туда: «что мне здесь надо то было?» — просто на рефлексах.