Совершенный код. Совершенный код. Мастер-класс. Стив Макконнелл. Руководство по стилю программирования и конструированию по
Скачать 5.88 Mb.
|
ГЛАВА 2 Метафоры, позволяющие лучше понять разработку ПО 11 Алгоритмом называют последовательность четко определенных команд, которые необходимо выполнить для решения конкретной задачи. Алгоритм предсказуем, детерминирован и не допускает случайностей. Алгоритм говорит, как пройти из точки А в точку Б не дав крюку, без посещения точек В, Г и Д и без остановок на чашечку кофе. Эвристика — это метод, помогающий искать ответ. Результаты его применения могут быть в некоторой степени случайными, потому что эвристика указывает только способ поиска, но не говорит, что искать. Она не говорит, как дойти пря# мо из точки А в точку Б; даже положение этих точек может быть неизвестно. Эв# ристика — это алгоритм в шутовском наряде. Она менее предсказуема, более за# бавна и поставляется без 30#дневной гарантии с возможностью возврата денег. Вот алгоритм, позволяющий добраться до чьего#то дома: поезжайте по шоссе 167 на юг до городка Пюиолап. Сверните на аллею Сауз#Хилл, а дальше 4,5 мили вверх по холму. Поверните у продуктового магазина направо, а на следующем перекре# стке — налево. Доехав до дома 714, расположенного на левой стороне улицы, остановитесь и выходите из автомобиля. А эвристическое правило может быть таким: найдите наше последнее письмо. Езжайте в город, указанный на конвер# те. Оказавшись в этом городе, спросите кого#нибудь, где находится наш дом. Все нас знают — кто#нибудь с радос# тью вам поможет. Если никого не встретите, позвоните нам из телефона#автомата, и мы за вами приедем. Различия между алгоритмом и эвристикой тонки, и в чем#то эти два понятия пе# рекрываются. В этой книге основным различием между ними я буду считать сте# пень косвенности решения. Алгоритм предоставляет вам сами команды. Эвристика сообщает вам, как обнаружить команды самостоятельно или по крайней мере где их искать. Наличие директив, точно определяющих способ решения проблем программи# рования, непременно сделало бы программирование более легким, а результаты более предсказуемыми. Но наука программирования еще не продвинулась так далеко, а может, этого никогда и не случится. Самая сложная часть программиро# вания — концептуализация проблемы, и многие ошибки программирования яв# ляются концептуальными. С концептуальной точки зрения каждая программа уникальна, поэтому трудно или даже невозможно разработать общий набор ди# ректив, приводящих к решению во всех случаях. Так что знание общего подхода к проблемам не менее, а то и более ценно, чем знание точных решений конкрет# ных проблем. Как использовать метафоры, характеризующие разработку ПО? Используйте так, чтобы лучше разобраться в проблемах и процессах программирования, чтобы они помогали вам размышлять о выполняемых действиях и придумывать лучшие ре# шения задач. Конечно, вы не сможете взглянуть на строку кода и сказать, что она противоречит одной из метафор, описываемых в этой главе. Но со временем тот, кто использует метафоры, лучше поймет программирование и будет быстрее со# здавать более эффективный код, чем тот, кто их не использует. Перекрестная ссылка Об ис- пользовании эвристики при проектировании ПО см. подраз- дел «Проектирование — эври- стический процесс» раздела 5.1. 12 ЧАСТЬ I Основы разработки ПО 2.3. Популярные метафоры, характеризующие разработку ПО Множество метафор, описывающих разработку ПО, смутит кого угодно. Дэвид Грайс утверждает, что написание ПО — это наука (Gries, 1981). Дональд Кнут считает это искусством (Knuth, 1998). Уоттс Хамфри говорит, что это процесс (Humphrey, 1989). Ф. Дж. Плоджер и Кент Бек утверждают, что разработка ПО похожа на управле# ние автомобилем, однако приходят к почти противоположным выводам (Plauger, 1993, Beck, 2000). Алистер Кокберн сравнивает разработку ПО с игрой (Cockburn, 2002), Эрик Реймонд — с базаром (Raymond, 2000), Энди Хант (Andy Hunt) и Дэйв Томас (Dave Thomas) — с работой садовника, Пол Хекель — со съемкой фильма «Белоснежка и семь гномов» (Heckel, 1994). Фред Брукс упоминает фермерство, охоту на оборотней и динозавров, завязших в смоляной яме (Brooks, 1995). Ка# кие метафоры самые лучшие? Литературная метафора: написание кода Самая примитивная метафора, описывающая разработку ПО, берет начало в вы# ражении «написание кода». Согласно литературной метафоре разработка програм# мы похожа на написание письма: вы садитесь за стол, берете бумагу, перо и пи# шете письмо с начала до конца. Это не требует никакого формального планиро# вания, а мысли, выражаемые в письме, формулируются автором по ходу дела. На этой метафоре основаны и многие другие идеи. Джон Бентли (Jon Bentley) говорит, что программист должен быть способен сесть у камина со стаканом брен# ди, хорошей сигарой, охотничьей собакой у ног и «сформулировать программу» подобно тому, как писатели создают романы. Брайан Керниган и Ф. Дж. Плоджер назвали свою книгу о стиле программирования «The Elements of Programming Style» (Kernighan and Plauger, 1978), обыгрывая название книги о литературном стиле «The Elements of Style» (Strunk and White, 2000). Программисты часто говорят об «удобочитаемости программы». Индивидуальную работу над небольшими проектами метафора написа# ния письма характеризует довольно точно, но в целом она описывает разработку ПО неполно и неадекватно. Письма и романы обычно принад# лежат перу одного человека, тогда как над программами обычно работают группы людей с разными сферами ответственности. Закончив писать письмо, вы запечаты# ваете его в конверт и отправляете. С этого момента изменить вы его не можете, и письмо во всех отношениях является завершенным. Изменить ПО не так уж трудно, и вряд ли работу над ним можно когда#нибудь признать законченной. Из общего объема работы над типичной программной системой две трети обычно выполня# ются после выпуска первой версии программы, а иногда эта цифра достигает целых 90 % (Pigoski, 1997). В литературе поощряется оригинальность. При конструирова# нии ПО оригинальный подход часто оказывается менее эффективным, чем повтор# ное использование идей, кода и тестов из предыдущих проектов. Словом, процесс разработки ПО, соответствующий литературной метафоре, является слишком про# стым и жестким, чтобы быть полезным. ГЛАВА 2 Метафоры, позволяющие лучше понять разработку ПО 13 К сожалению, литературная метафора была увековечена в одной из самых попу# лярных книг по разработке ПО — книге Фреда Брукса «The Mythical Man#Month» («Мифический человеко#месяц») (Brooks, 1995). Брукс пишет: «Планируйте вы# бросить первый экземпляр программы: вам в любом случае придется это сделать». Перед глазами невольно возникает образ мусорного ведра, полного черновиков (рис. 2#1). Рис. 2'1. Литературная метафора наводит на мысль, что процесс разработки ПО основан на дорогостоящем методе проб и ошибок, а не на тщательном планировании и проектировании Подобный подход может быть практичным, если вы пише# те банальное письмо своей тетушке. Однако расширение метафоры «написания» ПО вплоть до выбрасывания первого экземпляра программы — не лучший совет в мире разработ# ки ПО, где крупная система по стоимости уже сравнялась с 10#этажным офисным зданием или океанским лайнером. Конечно, это не имело бы значения, если б вы имели бес# конечные запасы времени и средств. Однако реальные ус# ловия таковы, что разработчики должны создавать програм# мы с первого раза или хотя бы минимизировать объем до# полнительных расходов в случае неудач. Другие метафоры лучше иллюстрируют достижение таких целей. Сельскохозяйственная метафора: выращивание системы Некоторые разработчики заявляют, что создание ПО следует рассматривать по аналогии с выращиванием сельскохозяйственных культур. Вы проектируете от# дельный блок, кодируете его, тестируете и добавляете в систему, чуть расширяя с каждым разом ее функциональность. Такое разбиение задачи на множество не# больших действий позволяет минимизировать проблемы, с которыми можно стол# кнуться на каждом этапе. Иногда хороший метод описывается плохой метафорой. В таких случа# ях попытайтесь сохранить метод и обнаружить лучшую метафору. В дан# ном случае инкрементный подход полезен, но сельскохозяйственная метафора просто ужасна. Планируйте выбросить первый экземпляр программы: вам в лю- бом случае придется это сделать. Фред Брукc Если вы планируете выбросить первый экземпляр программы, вы выбросите и второй. Крейг Зеруни (Craig Zerouni) 14 ЧАСТЬ I Основы разработки ПО Возможно, идея выполнения небольшого объема работы зараз и напоминает рост растений, но сельскохозяйствен# ная аналогия неубедительна и неинформативна, к тому же ее легко заменить лучшими метафорами, которые описаны ниже. Сельскохозяйственную метафору трудно расширить за пределы идеи выполнения чего#либо небольшими час# тями. Ее приверженцы (рис. 2#2) рискуют в итоге заговорить об удобрении плана системы, прореживании детального проекта, повышении урожайности кода путем оптимизации землеустройства и уборке урожая самого кода. Вы начнете говорить о чередовании посевов C++ и о том, что было бы неплохо оставить систему под паром для повышения концент# рации азота на жестком диске. Слабость данной метафоры заключается в предположении, что у вас нет прямого контроля над развитием ПО. Вы просто сеете семена кода весной и, если на то будет воля Великой Тыквы, осенью получите невиданный урожай кода. Рис. 2'2. Нелегко адекватно расширить сельскохозяйственную метафору на область разработки ПО Метафора жемчужины: медленное приращение системы Иногда, говоря о выращивании ПО, на самом деле имеют в виду приращение, или аккрецию (accretion). Две этих метафоры тесно связаны, но вторая более убеди# тельна. Приращение характеризует процесс формирования жемчужины за счет отложения небольших объемов карбоната кальция. В геологии и юриспруденции под аккрецией понимают увеличение территории суши посредством отложения содержащихся в воде пород. Это не значит, что вы должны освоить создание кода из оса# дочных пород; это означает, что вы должны научиться добав# лять в программные системы по небольшому фрагменту за раз. Другими словами, которые в связи с этим приходят на ум, являются термины «инкрементный», «итеративный», «адап# тивный» и «эволюционный». Инкрементное проектирование, конструирование и тестирование — одни из самых эффективных концепций разработки ПО. При инкрементной разработке вы сначала создаете самую простую версию систе# мы, которую можно было бы запустить. Она может не принимать реальных дан# ных, может не выполнять над ними реальных действий, может не генерировать реальные результаты — она должна быть просто скелетом, достаточно крепким, Дополнительные сведения О дру- гой сельскохозяйственной мета- форе, употребляемой в контекс- те сопровождения ПО, см. гла- ву «On the Origins of Designer Intuition» книги «Rethinking Sys- tems Analysis and Design» (Wein- berg, 1988). Перекрестная ссылка О приме- нении инкрементных стратегий при интеграции системы см. раздел 29.2. ГЛАВА 2 Метафоры, позволяющие лучше понять разработку ПО 15 чтобы поддерживать реальную систему по мере ее разработки. Она может вызы# вать поддельные классы для каждой из определенных вами основных функций. Такая система похожа на песчинку, с которой начинается образование жемчужины. Создав скелет, вы начинаете понемногу наращивать плоть. Каждый из фиктивных классов вы заменяете реальным. Вместо того чтобы имитировать ввод данных, вы пишете код, на самом деле принимающий реальные данные. А вместо имитации вывода данных — код, на самом деле выводящий данные. Вы продолжаете добав# лять нужные фрагменты, пока не получаете полностью рабочую систему. Эффективность такого подхода можно подтвердить двумя впечатляющими при# мерами. Фред Брукс, который в 1975 г. предлагал выбрасывать первый экземпляр программы, заявил, что за десять лет, прошедших с момента написания им зна# менитой книги «Мифический человеко#месяц», ничто не изменяло его работу и ее эффективность так радикально, как инкрементная разработка (Brooks, 1995). Аналогичное заявление было сделано Томом Гилбом в революционной книге «Principles of Software Engineering Management» (Gilb, 1988), в которой он пред# ставил метод эволюционной поставки программы (evolutionary delivery) и разрабо# тал многие основы современного гибкого программирования (agile programming). Многие другие современные методологии также основаны на идее инкрементной разработки (Beck, 2000; Cockburn, 2002; Highsmith, 2002; Reifer, 2002; Martin, 2003; Larman, 2004). Достоинство инкрементной метафоры в том, что она не дает чрезмерных обеща# ний. Кроме того, она не так легко поддается неуместному расширению, как сель# скохозяйственная метафора. Раковина, формирующая жемчужину, — хороший вариант визуализации инкрементной разработки, или аккреции. Строительная метафора: построение ПО Метафора «построения» ПО полезнее, чем метафоры «написания» или «вы# ращивания» ПО, так как согласуется с идеей аккреции ПО и предостав# ляет более детальное руководство. Построение ПО подразумевает нали# чие стадий планирования, подготовки и выполнения, тип и степень выраженно# сти которых зависят от конкретного проекта. При изучении этой метафоры вы найдете и другие параллели. Для построения метровой башни требуется твердая рука, ровная поверхность и 10 пивных банок, для башни же в 100 раз более высокой недостаточно иметь в 100 раз больше пивных банок. Такой проект требует совершенно иного плани# рования и конструирования. Если вы строите простой объект, скажем, собачью конуру, вы можете пойти в хозяйственный магазин, купить доски, гвозди, и к вечеру у Фидо будет новый дом. Если вы забудете про лаз или допустите какую#нибудь другую ошибку, ничего страшного: вы можете ее исправить или даже начать все сначала (рис. 2#3). Все, что вы при этом потеряете, — время. Такой свободный подход уместен и в неболь# ших программных проектах. Если вы плохо спроектируете 1000 строк кода, то сможете выполнить рефакторинг или даже начать проект заново, и это не приве# дет к крупным потерям. 16 ЧАСТЬ I Основы разработки ПО Рис. 2'3. За ошибку, допущенную при создании простого объекта, приходится расплачиваться лишь потраченным временем и, возможно, некоторым разочарованием Построить дом сложнее, и плохое проектирование при этом приводит к куда более серьезным последствиям. Сначала вы должны решить, какой тип здания вы хоти# те построить, что аналогично определению проблемы при разработке ПО. Затем вы с архитектором должны разработать и утвердить общий план, что похоже на разработку архитектуры. Далее вы чертите подробные чертежи и нанимаете бри# гаду строителей — это аналогично детальному проектированию ПО. Вы готовите стройплощадку, закладываете фундамент, создаете каркас дома, обшиваете его, кроете крышу и проводите в дом все коммуникации — это похоже на конструи# рование ПО. Когда строительство почти завершено, в дело вступают ландшафт# ные дизайнеры, маляры и декораторы, делающие дом максимально удобным и привлекательным. Это напоминает оптимизацию ПО. Наконец, на протяжении всего строительства вас посещают инспекторы, проверяющие стройплощадку, фун# дамент, электропроводку и все, что можно проверить. При разработке ПО этому соответствуют обзоры и инспекция проекта. И в строительстве, и в программировании увеличение сложности и масштаба проекта сопровождается ростом цены ошибок. Конечно, для создания дома нуж# ны довольно дорогие материалы, однако главной статьей расходов является оплата труда рабочих. Перемещение стены на 15 см обойдется дорого не потому, что при этом будет потрачено много гвоздей, а потому, что вам придется опла# тить дополнительное время работы строителей. Чтобы не тратить время на ис# правление ошибок, которых можно избежать, вы должны как можно лучше вы# полнить проектирование (рис. 2#4). Материалы, необходимые для создания про# граммного продукта, стоят дешевле, чем стройматериалы, однако затраты на ра# бочую силу в обоих случаях примерно одинаковы. Изменение формата отчета обходится ничуть не дешевле, чем перемещение стены дома, потому что главным компонентом затрат в обоих случаях является время людей. ГЛАВА 2 Метафоры, позволяющие лучше понять разработку ПО 17 Рис. 2'4. Более сложные объекты требуют более тщательного планирования Какие еще параллели можно провести между сооружением дома и разработкой ПО? При возведении дома никто не пытается конструировать вещи, которые можно купить. Здравомыслящему человеку и в голову не придет самостоятельно разра# батывать и создавать стиральную машину, холодильник, шкафы, окна и двери, если все это можно приобрести. Создавая программную систему, вы поступите так же. Вы будете в полной мере использовать возможности высокоуровневого языка вместо того, чтобы писать собственный код на уровне ОС. Возможно, вы исполь# зуете также встроенные библиотеки классов#контейнеров, научные функции, клас# сы пользовательского интерфейса и классы для работы с БД. Обычно невыгодно писать компоненты, которые можно купить готовыми. Однако если вы хотите построить нестандартный дом с первоклассной меблиров# кой, мебель, возможно, придется заказать. Вы можете заказать встроенные посу# домоечную машину и холодильник, чтобы они выглядели как часть обстановки. Вы можете заказать окна необычных форм и размеров. Такое изготовление пред# метов на заказ имеет параллели и в мире разработки ПО. При работе над прило# жением высшего класса для достижения более высокой скорости и точности рас# четов или реализации необычного интерфейса иногда приходится создавать соб# ственные научные функции, собственные классы#контейнеры и другие компоненты. И конструирование дома, и конструирование ПО можно оптимизировать, выполнив адекватное планирование. Если создавать ПО в неверном порядке, его будет трудно писать, тестировать и отлаживать. Сроки затянутся, да и весь проект может завер# шиться неудачей из#за чрезмерной сложности отдельных компонентов, не позво# ляющей разработчикам понять работу всей системы. Тщательное планирование не значит исчерпывающее или чрезмерное. Вы може# те спланировать основные структурные компоненты и позднее решать, чем по# крыть пол, в какой цвет окрасить стены, какой использовать кровельный матери# ал и т. д. Хорошо спланированный проект открывает больше возможностей для изменения решения на более поздних этапах работы. Чем лучше вам известен тип создаваемого ПО, тем больше деталей вы можете принимать как данное. Вы про# 18 ЧАСТЬ I Основы разработки ПО сто должны убедиться в проведении достаточного планирования, чтобы его не# достаток не привел позднее к серьезным проблемам. Аналогия конструирования также помогает понять, почему разные программные проекты призывают к разным подходам разработки. Склад и медицинский центр или ядерный реактор также требуют разных степеней планирования, проектиро# вания и контроля качества, и никто не стал бы одинаково подходить к строитель# ству школы, небоскреба и жилого дома с тремя спальнями. Работая над ПО, вы обыч# но можете использовать гибкие упрощенные подходы, но иногда для обеспече# ния безопасности и других целей необходимы и жесткие, тщательно продуман# ные подходы. Проблема изменения ПО приводит нас к еще одной параллели. Перемещение не# сущей стены на 15 см обходится гораздо дороже, чем перемещение перегородки между комнатами. Аналогично внесение структурных изменений в программу тре# бует больших затрат, чем добавление или удаление второстепенных возможностей. Наконец, проведение аналогии с домостроительством позволяет лучше понять ра# боту над очень крупными программными проектами. При создании очень крупно# го объекта цена неудачи слишком высока, поэтому объект надо спроектировать тщательнейшим образом. Строительные организации скрупулезно разрабатывают и инспектируют свои планы. Все крупные здания создаются с большим запасом прочности; лучше заплатить на 10 % больше за более прочный материал, чем рис# ковать крушением небоскреба. Кроме того, большое внимание уделяется времени. При возведении Эмпайр Стейт Билдинг время прибытия каждого грузовика, постав# лявшего материалы, задавалось с точностью до 15 минут. Если грузовик не прибы# вал в нужное время, задерживалась работа над всем проектом. Аналогично, очень крупные программные проекты требуют планирования более высокого порядка, чем просто крупные проекты. Кейперс Джонс сообщает, что программная система из одного миллиона строк кода требует в среднем 69 видов документации (Jones, 1998). Спецификация требований к такой системе обычно занимает 4000–5000 страниц, а проектная документация вполне может быть еще в 2 или 3 раза более объемной. Маловероятно, чтобы один человек мог понять весь проект такого масштаба или даже прочитать всю документацию, поэтому подобные проекты требуют более тщательной подготовки. По экономическому масштабу некоторые программные проекты сравнимы с воз# ведением «Эмпайр Стейт Билдинг», и контролироваться они должны соответству# ющим образом. Метафора построения#конструирования может быть расши# рена во многих других направлениях, именно поэтому она столь эффективна. Благодаря этой метафоре отрасль раз# работки ПО обогатилась многими популярными термина# ми, такими как архитектура ПО, леса (scaffolding), констру# ирование и фундаментальные классы. Наверное, вы сможете назвать и другие примеры. Дополнительные сведения Гра- мотные комментарии по пово- ду расширения метафоры кон- струирования см. в статье «What Supports the Roof?» (Starr 2003). |