Файл: Руководство по стилю программирования и конструированию по.pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 30.11.2023
Просмотров: 826
Скачиваний: 2
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
ГЛАВА
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
и колес, число дверей — все это несущественные свойства. Можете также думать о них как о
второстепенных, произвольных, необязательных и случайных.
Брукс замечает, что главные несущественные проблемы раз- работки ПО уже давно решены. Например, несущественные проблемы, связанные с неудобным синтаксисом языков программирования, постепенно утратили свою значимость по мере эволюции языков. Несущественные проблемы, свя- занные с неинтерактивностью компьютеров, исчезли, когда на смену ОС, работающим в пакетном режиме, пришли системы с разделением времени. Среды интегрированной разработки избавили программистов от про- блем, обусловленных плохим взаимодействием инструментов.
В то же время Брукс утверждает, что решение оставшихся
существенных проблем разработки ПО будет более медленным. Это объясняется тем, что разработка программ по своей сути требует анализа всех деталей крайне сложного набора взаимосвязанных концепций. Причиной существенных проблем является не- обходимость анализа сложного неорганизованного реального мира, точного и полного определения зависимостей и исключений, проектирования абсолютно, но никак не приблизительно верных решений и т. д. Даже если б мы смогли придумать язык программирования, основанный на той же терминологии, что и требующая решения проблема реального мира, программирование все равно осталось бы сложным из-за необходимости точного определения принципов функционирования мира. По мере того как разработчики ПО берутся за решение все более серьезных проблем реального мира, им приходится анализировать все более сложные взаимодействия между сущностями, что в свою очередь приводит к повышению существенной сложности программных решений.
Источник всех этих существенных проблем — сложность как несущественная, так и существенная.
1 ... 7 8 9 10 11 12 13 14 ... 104
Важность управления сложностью
Программные проекты редко терпят крах по техническим причинам. Чаще всего провал объясняется неадекватной выработкой требований, неудачным планированием или неэффективным управлением. Если же провал обусловлен все-таки преимущественно технической причиной, очень часто ею оказывается неконтролируемая сложность. Иначе говоря, приложение стало таким сложным, что разработчики перестали по-настоящему понимать, что же оно делает. Если работа над проектом достигает момента, после которого уже никто не может полностью понять, как изменение одного фрагмента программы повлияет на другие фрагменты, прогресс прекращается.
Управление сложностью — самый важный технический аспект разработки
ПО.
По-моему,
управление сложностью настолько важно, что оно долж- но быть Главным Техническим Императивом Разработки ПО.
Сложность — не новинка в мире разработки ПО. Один из пионеров информати- ки Эдсгер Дейкстра обращал внимание на то, что компьютерные технологии —
Перекрестная ссылка В ранних средах несущественные пробле- мы проявляются сильнее, чем в зрелых (см. раздел 4.3).
Есть два способа разработки проекта приложения: сделать его настолько простым, чтобы было очевидно, что в нем нет недостатков, или сделать его таким сложным, чтобы в нем не было очевидных недостатков.
Ч. Э. Р. Хоар (C. A. R. Hoare)
76
ЧАСТЬ
II
Высококачественный код единственная отрасль, заставляющая человеческий разум охватывать диапазон, простирающийся от отдельных битов до нескольких сотен мегабайт информации, что соответствует отношению 1 к 10 9
, или разнице в девять порядков (Dijkstra,
1989). Такое гигантское отношение просто ошеломляет. Дейкстра выразил это так:
«По сравнению с числом семантических уровней средняя математическая теория кажется почти плоской. Создавая потребность в глубоких концептуальных иерар- хиях, компьютерные технологии бросают нам абсолютно новый интеллектуальный вызов, не имеющий прецедентов в истории». Разумеется, за прошедшее с 1989 г. время сложность ПО только выросла, и сегодня отношение Дейкстры вполне может характеризоваться 15 порядками.
Дейкстра пишет, что ни один человек не обладает ин- теллектом, способным вместить все детали современной компьютерной программы (Dijkstra, 1972), поэтому нам
— разработчикам ПО — не следует пытаться охватить всю программу сразу. Вместо этого мы должны попытаться ор- ганизовать программы так, чтобы можно было безопасно работать с их отдельными фрагментами по очереди. Целью этого является минимизация объема программы, о кото- ром нужно думать в конкретный момент времени. Можете считать это своеобразным умственным жонглированием: чем больше умственных шаров программа заставляет под- держивать в воздухе, тем выше вероятность того, что вы уроните один из них и допустите ошибку при проектиро- вании или кодировании.
На уровне архитектуры ПО сложность проблемы можно снизить, разделив систему на подсистемы. Несколько несложных фрагментов информации понять проще, чем один сложный. В разбиении сложной проблемы на простые фрагменты и заключается цель всех методик проектирования ПО. Чем более независимы подсистемы, тем безопаснее сосредоточиться на одном аспек- те сложности в конкретный момент времени. Грамотно определенные объекты разделяют аспекты проблемы так, чтобы вы могли решать их по очереди. Пакеты обеспечивают такое же преимущество на более высоком уровне агрегации.
Стремление к краткости методов программы помогает снизить нагрузку на ин- теллект. Этому же способствует написание программы в терминах проблемной области, а не низкоуровневых деталей реализации, а также работа на самом вы- соком уровне абстракции.
Суть сказанного в том, что программисты, компенсирующие изначальные ограни- чения человеческого ума, пишут более понятный и содержащий меньшее число ошибок код.
Как бороться со сложностью?
Чаще всего причинами неэффективности являются:
쐽
сложное решение простой проблемы;
쐽
простое, но неверное решение сложной проблемы;
쐽
неадекватное сложное решение сложной проблемы.
Одним из симптомов того, что вы погрязли в чрезмерной слож- ности, является упрямое приме- нение метода, нерелевантность которого очевидна по крайней мере любому внешнему наблю- дателю. При этом вы уподобляе- тесь человеку, который при по- ломке автомобиля в силу своей некомпетентности не находит ничего лучшего, чем заменить воду в радиаторе и выбросить окурки из пепельниц.
Ф. Дж. Плоджер
(P. J. Plauger)