Руководство по стилю программирования и конструированию по
Скачать 7.6 Mb.
|
ГЛАВА 4 Основные решения, которые приходится принимать при конструировании 67 Контрольный список: основные методики конструирования Кодирование Решили ли вы, какая часть проекта приложения будет разработана предва- рительно, а какая во время написания кода? Выбрали ли вы конвенции именования программных элементов, оформле- ния комментариев и форматирования кода? Выбрали ли вы специфические методики кодирования, определяемые архи- тектурой приложения? Определили ли вы, как будут обрабатываться ошиб- ки, как будут решаться проблемы, связанные с безопасностью, какие конвенции будут использоваться при разработке интерфейсов классов, каким стандар- там должен будет отвечать повторно используемый код, сколько внимания нужно будет уделять быстродействию приложения при кодировании и т. д.? Определили ли вы стадию развития используемой технологии и адаптиро- вали ли к ней свой подход? Если это необходимо, определились ли вы с тем, как будете программировать с использованием языка, вместо того чтобы ограничиваться программированием на нем? Работа в группе Определили ли вы процедуру интеграции? Иначе говоря, какие специфи- ческие действия программист должен будет выполнить перед включением своего кода в исходный код всего проекта? Будут ли программисты программировать парами, индивидуально или эти подходы будут скомбинированы? Гарантия качества Должны ли будут программисты разработать тесты для своего кода до написания самого кода? Должны ли будут программисты разработать блочные тесты для своего кода? Должны ли будут программисты перед включением своего кода в исходный код всего проекта проанализировать его в отладчике? Должны ли будут программисты выполнить интеграционное тестирование своего кода до его включения в исходный код проекта? Будут ли программисты выполнять взаимные обзоры или инспекцию кода? Инструменты Выбрали ли вы инструмент управления версиями? Выбрали ли вы язык, версию языка и версию компиля- тора? Выбрали ли вы платформу программирования (такую как J2EE или Microsoft .NET) или явно решили не использовать ее? Приняли ли вы решение о том, можно ли будет использовать нестандарт- ные возможности языка? Определили ли вы другие средства, которые будете применять: редактор, инструмент рефакторинга, платформу для тестирования, модуль проверки синтаксиса и т. д.? Приобрели ли вы их? http://cc2e.com/0496 Перекрестная ссылка Гарантия качества рассматривается в гла- ве 20. Перекрестная ссылка Об инст- рументах программирования см. главу 30. 6 8 ЧАСТЬ I Основы разработки ПО Ключевые моменты 쐽 Каждый язык программирования имеет достоинства и недостатки. Вы долж- ны знать отдельные достоинства и недостатки используемого языка. 쐽 Определите конвенции программирования до начала программирования. Позднее адаптировать к ним код станет почти невозможно. 쐽 Методик конструирования слишком много, чтобы использовать все в одном проекте. Тщательно выбирайте методики, наиболее подходящие для вашего про- екта. 쐽 Спросите себя, являются ли используемые вами методики программирования ответом на выбранный язык программирования или их выбор был определен языком. Помните, что программировать следует с использованием языка, а не на языке. 쐽 Эффективность конкретных подходов и даже возможность их применения за- висит от стадии развития соответствующей технологии. Определите стадию раз- вития используемой технологии и адаптируйте к ней свои планы и ожидания. ГЛАВА 4 Основные решения, которые приходится принимать при конструировании 69 Часть II ВЫСОКОКАЧЕСТВЕННЫЙ КОД 쐽 Глава 5. Проектирование при конструировании 쐽 Глава 6. Классы 쐽 Глава 7. Высококачественные методы 쐽 Глава 8. Защитное программирование 쐽 Глава 9. Процесс программирования с псевдокодом 70 ЧАСТЬ II Высококачественный код Г Л А В А 5 Проектирование при конструировании Содержание 쐽 5.1. Проблемы, связанные с проектированием ПО 쐽 5.2. Основные концепции проектирования 쐽 5.3. Компоненты проектирования: эвристические принципы 쐽 5.4. Методики проектирования 쐽 5.5. Комментарии по поводу популярных методологий Связанные темы 쐽 Разработка архитектуры ПО: раздел 3.5 쐽 Классы: глава 6 쐽 Характеристики высококачественных методов: глава 7 쐽 Защитное программирование: глава 8 쐽 Рефакторинг: глава 24 쐽 Зависимость конструирования от объема программы: глава 27 Некоторые программисты могут заявить, что проектирование не связано с кон- струированием, но при работе над небольшими проектами конструирование часто включает другие процессы, в том числе проектирование. В некоторых бо- лее крупных проектах формальная архитектура может давать ответы только на во-просы системного уровня, при этом значительная часть проектирования может быть намеренно оставлена на этап конструирования. В других крупных проектах проектирование может быть проведено в таком объеме, что кодирование стано- вится почти механическим, однако это случается редко — официально или нет, программисты обычно сами проектируют некоторые фрагменты программы. В случае небольших неформальных проектов значительная часть проектирования выполняется за клавиатурой. «Про- ектирование» может выражаться в простом написании ин- терфейса класса на псевдокоде до разработки его деталей. Оно может выражаться в рисовании диаграмм отношений http://cc2e.com/0578 Перекрестная ссылка Об уров- нях формальности, требуемой при работе над крупными и не- большими проектами, см. гла- ву 27. ГЛАВА 5 Проектирование при конструировании 71 нескольких классов перед написанием их кода. Оно может выражаться в обсужде- нии оптимального шаблона проектирования вместе с коллегой. Какую бы форму проектирование ни принимало, от тщательного его выполнения выигрывают проекты любого масштаба, и, рассматривая проектирование как явный процесс, вы извлечете из него максимальную выгоду. Проектирование — очень обширная тема, поэтому в данной главе мы рассмотрим только несколько ее аспектов. Эффективность проектирования классов или ме- тодов во многом определяется архитектурой системы, поэтому убедитесь, что вы выполнили предварительные условия, связанные с разработкой архитектуры (см. раздел 3.5). Еще больший объем проектирования выполняется на уровне отдельных классов и методов, что мы обсудим в главах 6 и 7. Если вы уже хорошо знакомы с проектированием ПО, можете только бегло про- смотреть основные моменты раздела 5.1, посвященного проблемам проектиро- вания, и раздела 5.3, в котором обсуждаются основные эвристические принципы проектирования. 5.1. Проблемы, связанные с проектированием ПО Под «проектированием ПО» понимают разработку или изо- бретение схемы преобразования спецификации приложения в готовое приложение. Проектирование — это тот процесс, который связывает выработку требований с кодированием и отладкой. Структура удачного высокоуровневого проекта приложения может успешно охватывать целый ряд более низкоуровневых проектов. Хорошее проектирование полезно при работе над не- большими приложениями и просто необходимо при работе над крупными. Однако с проектированием связано множество проблем — их-то мы и обсудим. Проектирование — «грязная» проблема Хорст Риттел и Мелвин Веббер определили «грязную» про- блему как проблему, которую можно ясно определить только путем полного или частичного решения (Rittel and Webber, 1973). По сути данный парадокс подразумевает, что про- блему нужно «решить» один раз, чтобы получить ее ясное определение, а затем еще раз для создания работоспособного решения. Этот процесс уже несколько десятилетий нераз- рывно связан с разработкой ПО (Peters and Tripp, 1976). Одним драматическим примером подобной грязной про- блемы является проектирование первого варианта моста Tacoma Narrows. В то время главным соображением при проектировании мостов было обеспечение прочности, адек- ватной планируемой нагрузке. В случае моста Tacoma Nar- rows оказалось, что ветер вызывает непредвиденные вол- нообразные гармонические колебания моста из стороны в Перекрестная ссылка О разли- чии между эвристическим и де- терминированным процессами см. главу 2. Образ разработчика, проекти- рующего программу рациональ- ным безошибочным способом на основе ясно сформулиро- ванных требований, совершенно нереалистичен. Никакая система так никогда не разрабатывалась и, наверное, не будет разраба- тываться. Даже примеры раз- работки небольших программ, встречающиеся в учебниках, нереалистичны. Авторы пере- проверяют и улучшают их до тех пор, пока не продемонстрируют нам то, что они хотели бы по- лучить, а не то, что получается на самом деле. Дэвид Парнас и Пол Кле- ментс (David Parnas and Paul Clements) 72 ЧАСТЬ II Высококачественный код сторону. В один ветреный день 1940 г. колебания неконтролируемо усилились, и часть моста обрушилась (рис. 5-1). Это наглядный пример грязной проблемы: до разрушения моста инженеры не знали, что аэродинамика играет такую большую роль. Только построив мост (ре- шив проблему), они смогли обнаружить дополнительный аспект проблемы, что позволило им возвести новый мост, действующий и поныне. Рис. 5-1. Мост Tacoma Narrows — пример грязной проблемы Одно из главных отличий программ, которые вы разрабатывали в институте, от программ, которые разрабатываете теперь, став профессиональным программи- стом, в том, что проблемы проектирования, решаемые институтскими про- граммами, редко бывают грязными, если вообще бывают таковыми. В институте задания по программированию составлены так, чтобы вы по кратчайшему пути двигались от начала решения к его результату. Преподавателя, который дает студентам задания и свободно изменяет их по завершении проектирования и даже перед сдачей готовых программ, вероятно, облили бы дегтем и вываляли в перьях. Однако в мире профессионального программирования такие изменения происходят ежедневно. Проектирование — неряшливый процесс (даже если оно приводит к аккуратному результату) Завершенный проект приложения должен выглядеть хорошо организованным и ясным, но процесс разработки этого проекта далеко не так аккуратен, как конеч- ный результат. ГЛАВА 5 Проектирование при конструировании 73 Проектирование неряшливо потому, что вы выполняете много неверных действий и попадаете во множество ту- пиков, т. е. совершаете массу ошибок. В действительности ошибки являются сутью проектирования: дешевле допустить ошибки и исправить проект программы, чем найти их после кодирования и исправлять готовый код. Проектирование неряшливо потому, что удачное решение часто лишь чуть-чуть отличается от неудачного. Проектирование неряшливо еще и потому, что трудно узнать, когда проект «достаточно хорош». Какого уровня детализации достаточно? Какую часть проектирования вы- полнить с использованием формальной нотации, а какую — прямо за клавиатурой? Когда проектирование считать завершенным? Улучшать проект программы можно посто- янно, поэтому чаще всего на последний вопрос отвечают: «Когда у вас вышло время». Проектирование связано с определением компромиссов и приоритетов В идеальном мире все системы обладали бы бесконечным быстродействием, не предъявляли никаких требований к подсистеме хранения данных, давали нулевую нагрузку на сеть, никогда не содержали никаких ошибок и создавались без всяких затрат. Однако в реальном мире один из важнейших аспектов работы проекти- ровщика — анализ конкурирующих характеристик проекта и достижение баланса между ними. Если быстрота отклика системы важнее, чем минимизация времени разработки, проектировщик выберет один вариант. Если во главе угла быстрота разработки, оптимальным может оказаться другой вариант проекта. Проектирование подразумевает ограничение возможностей Проектирование предполагает не только обеспечение возможностей, но и их ограничение. Если бы люди, создавая физические структуры, обладали бесконеч- ным объемом времени и ресурсов, мы увидели бы на улицах невероятно странные здания с диковинными башенками и сотнями комнат на отдельных этажах. При отсутствии целенаправленно заданных ограничений ПО может оказаться именно таким. Ограниченные объемы ресурсов при конструировании зданий требуют упрощения решения, что в итоге приводит к его улучшению. Проектирование ПО в этом смысле ничем не отличается. Проектирование — недетерминированный процесс Если вы попросите трех человек спроектировать одну и ту же программу, они вполне могут разработать три совершенно разных, но вполне приемлемых про- екта. Как правило, спроектировать компьютерную программу можно десятками разных способов. Дополнительные сведения См. обсуждение этой точки зрения в статье «A Ratio nal Design Process: How and Why to Fake It» (Parnas and Clements, 1986). Перекрестная ссылка Лучший ответ на этот вопрос см. в под- разделе «Какую степень про- ектирования можно считать достаточной?» раздела 5.4. 74 ЧАСТЬ II Высококачественный код Проектирование — эвристический процесс Так как проектирование не детерминировано, методы проектирования чаще всего являются эвристическими методами, т. е. «практическими пра- вилами» или «способами, которые могут сработать», а не воспроизводи- мыми процессами, которые всегда приводят к предсказуемым результатам. Про- ектирование — метод проб и ошибок. Инструменты или методы проектирования, оказавшиеся эффективными в одном случае, в другой ситуации могут оказаться куда менее эффективными. Универсальных методик проектирования не существует. Проектирование — постепенный процесс Можно довольно удачно обобщить названные аспекты про- ектирования, сказав, что проектирование — «постепенный» процесс. Проекты приложений не возникают в умах разработ- чиков сразу в готовом виде. Они развиваются и улучшаются в ходе обзоров, неформальных обсуждений, написания кода и выполнения его ревизий. Практически во всех случаях проект несколько меняется во время первоначальной разработки системы и еще боль- ше — при ее модернизации. Степень, в которой изменение выгодно или приемлемо, зависит от особенностей созда- ваемого ПО. 5.2. Основные концепции проектирования Успешное проектирование ПО требует понимания нескольких важных концепций. Здесь мы обсудим роль сложности при проектировании, желательные характери- стики проектов и уровни проектирования. Главный Технический Императив Разработки ПО: управле- ние сложностью Чтобы лучше понять важность управления сложностью, об- ратимся к известной работе Фреда Брукса «No Silver Bullets: Essence and Accidents of Software Engineering» (Brooks, 1987). Существенные и несущественные проблемы Брукс утверждает, что сложность разработки ПО объясняется существенными и несущественными проблемами. Используя два этих термина, Брукс опирается на философскую традицию, уходящую корнями к Аристотелю. В философии существен- ными называют свойства, которыми объект должен обладать, чтобы быть именно этим объектом. Автомобиль должен иметь двигатель, колеса и двери — если объект не обладает каким-нибудь из этих существенных свойств, это не автомобиль. Несущественными (акцидентными) свойствами называют свойства, которыми объект обладает в силу случайности, — свойства, не влияющие на его суть. Так, автомобиль может иметь четырехцилиндровый двигатель с турбонаддувом, вось- мицилиндровый или любой другой и все же являться автомобилем. Тип двигателя http://cc2e.com/0539 Дополнительные сведения ПО — не единственный тип струк- тур, изменяющихся с течением времени. Физические структуры также развиваются; см. об этом книгу «How Buildings Learn» (Brand, 1995). Перекрестная ссылка О влиянии сложности на другие аспекты про- граммирования см. раздел 34.1. ГЛАВА 5 Проектирование при конструировании 75 и колес, число дверей — все это несущественные свойства. Можете также думать о них как о второстепенных, произвольных, необязательных и случайных. Брукс замечает, что главные несущественные проблемы раз- работки ПО уже давно решены. Например, несущественные проблемы, связанные с неудобным синтаксисом языков программирования, постепенно утратили свою значимость по мере эволюции языков. Несущественные проблемы, свя- занные с неинтерактивностью компьютеров, исчезли, когда на смену ОС, работающим в пакетном режиме, пришли системы с разделением времени. Среды интегрированной разработки избавили программистов от про- блем, обусловленных плохим взаимодействием инструментов. В то же время Брукс утверждает, что решение оставшихся существенных проблем разработки ПО будет более медленным. Это объясняется тем, что разработка программ по своей сути требует анализа всех деталей крайне сложного набора взаимосвязанных концепций. Причиной существенных проблем является не- обходимость анализа сложного неорганизованного реального мира, точного и полного определения зависимостей и исключений, проектирования абсолютно, но никак не приблизительно верных решений и т. д. Даже если б мы смогли придумать язык программирования, основанный на той же терминологии, что и требующая решения проблема реального мира, программирование все равно осталось бы сложным из-за необходимости точного определения принципов функционирования мира. По мере того как разработчики ПО берутся за решение все более серьезных проблем реального мира, им приходится анализировать все более сложные взаимодействия между сущностями, что в свою очередь приводит к повышению существенной сложности программных решений. Источник всех этих существенных проблем — сложность как несущественная, так и существенная. |