Эволюционирующая архитектура и стихийное проектирование: Исследование архитектуры и проектирования

Пути к улучшению сопровождаемости проектов и архитектур

Вокруг архитектур и проектирования ПО идут горячие споры, но они практически не дают ответов на вопросы. Эта статья начинает серию «Эволюционирующая архитектура и стихийное проектирование», посвященную обсуждению альтернативных подходов к этим аспектам. Эволюционирующая архитектура и стихийное проектирование — это технологии быстрой разработки, откладывающие принятие решений до того времени, пока не наступит ответственный момент. В этой вступительной части автор серии Нил Форд дает определение архитектуры и проектирования, а затем затрагивает общие вопросы, которые будут подниматься по всей серии.

Нил Форд, Архитектор приложений, ThoughtWorks

Нил Форд (Neal Ford) работает архитектором приложений в ThoughtWorks, революционной компании, предоставляющей профессиональные IT-услуги и помогающей талантливым людям по всему миру эффективнее использовать программное обеспечение. Он также является проектировщиком и разработчиком приложений, учебных материалов, журнальных статей, учебных курсов, видео/DVD-презентаций и автором книг "Разработка с Delphi: Объектно-ориентированный подход", "JBuilder 3 Unleashed" и "Искусство разработки Web-приложений на Java". Он специализируется на консультациях по построению широкомасштабных корпоративных приложений. Он также является общепризнанным докладчиком и выступал на многочисленных конференциях разработчиков по всему миру. С ним можно связаться по адресу: nford@thoughtworks.com.



22.10.2009

Хотя понятия архитектуры и проектирования существуют уже много лет, они так и не имеют устоявшихся определений, поскольку в разработке программного обеспечения как дисциплине еще не в полной мере осознаны все связанные с ними сложности и последствия. Но для того, чтобы вести разумный разговор о таких темах, надо с чего-то начать. Эта статья является первой из серии, поднимающей проблемы эволюционирующей архитектуры и стихийного проектирования, так что есть смысл начать серию с некоторых определений, обсуждений и других основных принципов.

Определение архитектуры

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

Архитектура приложения

Архитектура приложения описывает основные крупные части, составляющие приложение. Например, в мире Java архитектура приложения описывает две вещи: комбинацию программных инфраструктур, используемую для создания конкретного приложения — т.н. архитектуры уровня инфраструктур— и более традиционное логическое разделение обязанностей, для которого я оставлю наименование архитектура приложения. Выделение архитектуры инфраструктур как отдельной сущности имеет смысл потому, что большинство практикующих специалистов по объектно-ориентированным языкам пришли к выводу, что отдельные классы как механизм повторного использования кода неэффективны. (Когда в последний раз вы загружали из Интернета для использования в проекте один-единственный класс?) Единица повторного использования в современных объектно-ориентированных языках — это библиотека или программная инфраструктура. При запуске нового проекта на языке с мощным набором программных инфраструктур, таком как язык Java, одной из первых архитектурных проблем является архитектура приложения на уровне инфраструктуры. Этот стиль повторного использования настолько глубоко укоренился в мире Java, что уже пора говорить о Java не как об объектно-ориентированном языке, а как о инфраструктурно-ориентированном. Во многих отношениях, архитектура уровня программной инфраструктуры представляет физическую структуру, описываемую конкретными строительными блоками.

С другой точки зрения, архитектура приложения описывает, как сочетаются логические части программы. Это сфера шаблонов проектирования и других структурных описаний, поэтому она имеет тенденцию к большей абстракции и скорее логическому, чем физическому описанию. Например, можно сказать, что Web-приложение придерживается паттерна Model-View-Presenter, без указания того, какая программная инфраструктура используется для достижения этой логической компоновки. Эта логическая компоновка, вероятнее всего, изображена на всех маркерных досках в вашем офисе после начала работы над новыми частями приложения.

Архитектура предприятия

Архитектура предприятия концентрирует внимание на том, как приложения используются на предприятии в целом (что обычно означает, что приложения работают внутри большой организации). Обычная полезная метафора сравнения архитектур предприятия и приложений уподобляет архитектуру предприятия планированию города, а архитектуру приложений— проектированию зданий. Планировщики города должны думать о том, как подвести воду, электричество, канализацию и другие службы, которые обеспечивают жизнедеятельность города. Никакое здание не может потреблять воды больше, чем ему выделено. Архитектор предприятия обдумывает такого же рода вещи для приложений: недопустимо, чтобы одно приложение заняло всю полосу пропускания сети и при инженерных коммуникаций (виртуально) затопило себя сточными водами.

Архитектуре предприятия уделяется в последнее время много внимания из-за сервис-ориентированной архитектуры (SOA). SOA является огромной темой для рассмотрения сама по себе, так что будущие части этой серии будут касаться ее частных случаев. Она имеется свои собственные интересные аспекты, поскольку размывает границы между архитектурой приложений и предприятия, когда диктует особенности структуры приложений.

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

Существующие определения

Определения архитектуры программного обеспечения давали много умных людей, поэтому я отошлю читателя за пищей для размышлений к ним. В своем классическом труде "Who Needs an Architect?" (см. Ресурсы) Мартин Фаулер рассматривает несколько определений. Первое определение взято из списка рассылки по экстремальному программированию:

"RUP, отталкиваясь от определения IEEE, определяет архитектуру как самый высокий уровень описания концепции системы в ее среде. Архитектурой программного обеспечения системы (на данный момент времени) является организация или структура существенных компонентов, взаимодействующих посредством интерфейсов; при этом эти компоненты в свою очередь составляются из более мелких компонентов и интерфейсов".

Это определение прекрасно подходит к архитектуре приложения, как я описывал ее выше. Хотя оно расплывчато, в нем отражена суть архитектуры как наивысшего уровня абстракции.

Затем Фаулер цитирует Ральфа Джонсона (Ralph Johnson), который оспаривает данное выше определение в ответе списка рассылки:

"На мой взгляд, более подходящим будет определение: 'В самых успешных программных проектах опытные разработчики, работающие над проектом, имеют общее понимание структуры системы. Это общее понимание называется "архитектура". Такое понимание включает в себя то, как система строится из компонентов и как компоненты взаимодействуют через интерфейсы".

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

В вышеупомянутой статье сам Фаулер дает одно из моих любимых определений архитектуры:

Архитектура определяет самое главное. Что бы это ни было".

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

Определение Фаулера также подчеркивает еще один важный аспект в определении таких тонких вещей, как архитектура. "Важное" не просто различно для разных людей и групп; эти различия могут быть взаимоисключающими. Например, практически все SOA балансируют между гибкостью и скоростью. Работающая у вас старая клиент/серверная система почти наверняка быстрее, чем идущая ей на смену новая версия с Web-интерфейсами, портлетными движками и сервисами. Если новое приложение написано не гениальными разработчиками, добавление дополнительных слоев гибкости приводит к увеличению времени отклика для пользователей, в результате чего ухудшается оперативность. Возможно, ваш архитектор из тех, кто говорит пользователям: "Да, кстати, новая SOA, которую мы устанавливаем, значительно облегчит вашу жизнь, но работать вы будете медленнее. Извините". Может быть, именно поэтому архитекторы получают больше, чем разработчики.

А теперь мое любимое определение архитектуры:

"То, что потом трудно изменить".

Это определение лучше всего соответствует идее эволюционирующей архитектуры. Одна из основных идей эволюционирующей архитектуры заключается в том, чтобы при любой возможности откладывать принятие решений до более позднего времени, что позволяет выбирать лучше всего зарекомендовавшие себя альтернативы. Многие строительные блоки такого архитектурного стиля пронизывают всю эту серию статей и стали мотивом для ее создания.

Заканчивая обсуждение архитектуры, было бы упущением не обсудить саму должность "архитектор". Кадровикам не нравится, что в нашей отрасли такие плохие определения должностей. Многие организации хотят продвинуть на более высокую должность своих лучших разработчиков — тех, кто принимает важные решения по поводу вещей, которые трудно изменить позднее, — но термина лучше, чем "архитектор" в отрасли не существует. Также нет и общее описания должностных обязанностей, поэтому каждая компания сама определяет, что эта роль означает. Некоторые из архитекторов напоминают Архитектора в конце второй части фильма "Матрица" (которого Фаулер квалифицирует как Architectus Reloadus). Это архитекторы, которые в последний раз писали программный код десяток лет назад, а сейчас принимают важные решения в компании. Единственный инструмент разработчика, который они используют — это Visio.

Альтернативный вариант архитектора, по Фаулеру, называется Architectus Oryzus (в честь моего коллеги Дэвида Райса). Такие архитекторы активно вносят код в проект, помогая другим разработчикам на самых тяжелых участках. В их обязанности также входит взаимодействие с другими участниками проекта, гарантирующее, что все говорят на одном языке, используют одни и те же определения и понимают те части системы, которые им положено понимать. Очевидно, такое активное участие имеет решающее значение для достижения поставленных целей в эволюционирующей архитектуре, и поэтому еще не раз будет упоминаться в этой серии.


Определение проектирования

Большинство разработчиков имеют хорошее понятие о том, что такое проектирование, поэтому я не буду тратить время на определение. Проект подробно описывает, как компоненты программы соединяются между собой. Проектирование включает в себя такие хорошо изученные области, как шаблоны проектирования, рефакторинг, инфраструктуры программирования и другие вещи, с которыми ежедневно имеет дело разработчик. Спектр подходов к проектированию простирается примерно от BDUF (Big Design Up Front — Большой Изначальный Проект) до Cowboy Hacking (Ковбойское хакерство), как показано на рисунке 1:

Рисунок 1. Спектр подходов к проектированию
Спектр подходов к проектированию

Левая часть спектра на рисунке 1 предполагает, что возможно предвидеть все сотни и тысячи проблем, которые появляются при разработке программного обеспечения, и пытается сократить затраты времени на их решение. Подробнее об этом будет сказано в последующих частях. Хотя я не стал тратить время на определение проектирования, это не значит, что я не буду много говорить о нем. Основная часть этой серии посвящена различным аспектам того, как сделать так, чтобы проект возникал сам в процессе разработки, а не вырубался из камня прежде, чем будут написаны первые строчки кода.


Общие вопросы архитектуры и проектирования

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

Капитал и проценты

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

Разработка программного обеспечения — это не рытье канавы. Компромиссы при рытье канавы означают, что вы просто получите не идеально ровную канаву. Недостатки сегодняшней канавы не мешают выкопать хорошую канаву завтра. Но программное обеспечение, построенное сегодня, является фундаментом для будущего. Компромиссы в программном обеспечении, допущенные сегодня во имя целесообразности, уже завтра становятся причиной возросшей энтропии. В книге The Pragmatic Programmer Энди Хант и Дэйв Томас говорят об энтропии в производстве ПО и причинах ее вредного воздействия (см. Ресурсы). Энтропия является мерой сложности, и если временное решение добавляет сложность сейчас, за него придется платить весь оставшийся срок жизни проекта.

Допустим, вы хотите добавить новые функции к существующему долгоживущему проекту. С этими новыми возможностями связаны определенные внутренние сложности. Однако если вы уже имеете технические долги, вам для добавления новых функций придется обходить уже имеющиеся компромиссные части своей системы. Связанные с этим дополнительные затраты оправдывают финансовый оттенок термина «технический долг». На рисунке 2 показана разница между усилиями, требуемыми для добавления новой функции в систему, разработанную «чисто» (т.е. практически без каких-либо технических долгов), по сравнению с типичной системой, которая содержит уйму технических задолженностей.

Рисунок 2. Технические долги и проценты
Технические долги и проценты

Можно сравнить собственную сложность решения с капиталом, а дополнительные усилия, связанные с прошлыми «срезаниями углов» — с процентами. Но сложность — это интересная тема сама по себе.

Сложность необходимая и привнесенная

Проблемы, которые решает программное обеспечение, имеют свою внутреннюю сложность, которую я называю необходимой. Другое дело — сложность, возникающая в связи с компромиссами, из-за технических долгов. Она включает все навязанные извне подходы, усложняющие программное обеспечение, и, в идеале, она должна отсутствовать. Я называю ее привнесенной сложностью. Эти термины подробно определяются и обсуждаются в книге The Productive Programmer (см. Ресурсы). Эти термины не являются четко определенными: как и понятие проекта, они характеризуют некоторые участки непрерывного спектра. Несколько приведенных ниже примеров помогут прояснить их различие.

Один из моих коллег работал над системой начисления заработной платы в компании, работники которой были объединены в профсоюз. Одной из льгот, оговоренных профсоюзом для некоторых своих членов, был дополнительный выходной день в начале охотничьего сезона. (Похоже, у них были хорошие переговорщики). Все затронутые работники трудились на одном заводе, но возможность предоставления дополнительного выходного была узаконенным требованием к системе начисления заработной платы для всей компании. Внесенное изменение добавило много сложностей в программу, но это была необходимая сложность, поскольку она решала часть бизнес-задачи.

Другой постоянно возникающий пример, расположенный чуть дальше по спектру: безопасность полей форм ввода. Многие люди со стороны бизнеса думают, что хотят детально контролировать все параметры безопасности каждого поля. На практике, когда такой контроль реализуется, они почти всегда возмущаются, поскольку это создает большую нагрузку на пользователей, которым необходимо определять и сохранять все эти метаданные. В одном из наших проектов представители бизнеса действительно хотели иметь эту функцию, поэтому мы реализовали ее для них частично, на одном экране. Как только они сами, на собственном опыте, увидели, сколько усилий требуется для использования такого контроля, они сразу решили, что поскольку доступ к приложению доступен только из запирающегося на ключ офиса, лучше использовать не столь детальное управление безопасностью. Это отличный пример проектного решения, возникающего стихийно после того, как представители бизнеса увидели в реальности, чего они требовали.

В дальнем конце этого спектра расположены привнесенные сложности чисто технической природы, подобные первым двум версиям технологии Enterprise JavaBeans (EJB) и инструментам BizTalk. В некоторых проектах дополнительные накладные расходы, связанные с этими средствами, оправданны, но в большинстве случаев они только добавляют сложности.

Привнесенная сложность часто проистекает из трех вещей. Первая уже обсуждалась: «времянки» в коде из-за графика и других внешних факторов. Во-вторых, дублирование, то, что в книге Pragmatic Programmers называется нарушением принципа DRY (Don't Repeat Yourself — не повторяйся). Дублирование – второй по значимости вредоносный фактор при разработке программного обеспечения, поскольку оно имеет тенденцию проникать повсеместно при полном неведении разработчиков. Очевидный пример — это копирование и вставка кода, но есть и множество более сложных случаев. Например, почти в каждом проекте, который использует инструменты объектно-реляционного отображения (подобные Hibernate или iBatis), встречается много дублирования. Схема базы данных, XML-файл отображения и соответствующие классы POJO содержат немного разную, но пересекающуюся информацию. Можно устранить эту проблему, создав канонический источник такой информации и генерируя из него другие элементы. Дублирование вредит проектам, поскольку мешает попыткам структурных изменений и рефакторинга. Если известно, что нечто нужно изменить в трех разных местах, вы будете избегать делать это, даже если это обещает сделать код лучше в долгосрочной перспективе.

Третий фактор, порождающий привнесенную сложность — это необратимость. Любое решение, которое не может быть обращено вспять, в конечном итоге приводит к появлению привнесенной сложности. Необратимость сказывается как на архитектуре, так и на проекте, хотя ущерб все-таки больше распространяется на архитектурный уровень, как на более общий. Необходимо всеми силами избегать решений, которые невозможно или обременительно обратить вспять. Одна из мантр, которую, по слухам, используют некоторые из моих коллег: дождаться последнего ответственного момента. Это не означает, что решение должно быть отложено на период, когда будет уже слишком поздно, но все-таки времени должно пройти достаточно много. Что представляет собой последний ответственный момент, в который вы можете выбрать некоторое архитектурное решение? Чем дольше возможно избегать этого решения, тем больше возможностей остаются открытыми. Спросите себя: "Мне действительно нужно принять это решение сейчас?" и "Что я могу сделать для того, чтобы можно было отложить это решение?". Удивительно, как много всего можно отложить до последнего при некоторой изобретательности в процессе принятия решений.

Разграничение, которое я ранее сделал между архитектурой уровня программной инфраструктуры и архитектурой приложения, естественным образом согласуется с принципом Последнего Ответственного Момента. Архитектура приложения, как правило, является логической. Например, предположим, что вы решили разделить задачи по шаблону Model-View-Presenter. Очень часто сразу делается большой шаг к физической реализации этой логической архитектуры путем выбора программной инфраструктуры, которая отвечает некоторым или всем из соответствующих требований. Подумайте, можно ли отложить это решение, так как уже выбранная физическая реализация ограничивает возможности принятия других решений. Максимальная отсрочка выбора программной инфраструктуры оставляет открытой не загрязненную реальностью возможность выбора лучших вариантов.

Безудержная общность

Последнюю из общих проблем архитектуры и проектирования я назвал безудержной общностью. Похоже, в мире Java появилась болезнь: чрезмерное усложнение решений в попытке сделать их максимально общими. Мотивация для этого ясна: чем больше добавляется слоев для расширения, тем легче будет расширять решение впоследствии. Однако это опасная ловушка. Общность добавляет энтропии и тем самым наносит ущерб способности развивать интересные пути решений в начале проекта. Добавление чрезмерной гибкости усложняет все последующие изменения исходного кода.

Конечно, расширяемость нельзя игнорировать. В идеологии agile-разработки имеется великая фраза, которая подытоживает весь процесс реализации функций приложения: YAGNI (You Ain't Gonna Need It — не делай то, что не нужно). Это мантра помогает избежать излишнего усложнения простых функций. Просто делайте то, что нужно сейчас, и если какой-то функционал понадобится позже, то потом и добавляйте. Я видел Java-решения, настолько набитые компромиссами в архитектуре и проектировании ради общности и расширяемости, что это приводило к провалу проекта. Парадоксально, но планирование проекта с расчетом на максимально долгую жизнь в итоге укорачивало ее. Научиться двигаться по тонкой грани между расширяемостью и чрезмерной сложностью непросто, и я буду к этому часто возвращаться.


Планы

Эта статья содержит много рукомашества и ни одной строчки программного кода — в отличие от будущих статей из этой серии. Одна из проблем при обсуждении сложных вопросов, таких как архитектура и проектирование — это необходимость четкой фиксации контекста, чтобы все участники говорили об одном и том же. Я заложил основу для остальных частей этой серии, где мы будем углубляться в конкретные области, связанные с эволюционирующей архитектурой и стихийным проектированием. В следующих статьях я буду подробно разбирать конкретные аспекты одного или обоих этих понятий, с большим количеством подробностей и исходным кодом. В следующей серии я буду говорить о стихийном проектировании на основе разработки через тестирование, которое я назвал проектирование через тестирование.

Ресурсы

Научиться

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java
ArticleID=438748
ArticleTitle=Эволюционирующая архитектура и стихийное проектирование: Исследование архитектуры и проектирования
publish-date=10222009