Эволюция архитектуры | Малоэтажное строительство

Эволюция архитектуры

Эволюция архитектурыЭволюция архитектуры.

Соображения на тему проектирования архитектуры по методике Agile и подходы к реализации.

Серия контента:

Этот контент является частью # из серии # статей: Эволюционирующая архитектура и стихийное проектирование.

Этот контент является частью серии: Эволюционирующая архитектура и стихийное проектирование.

Следите за выходом новых статей этой серии.

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

Об этой серии.

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

Эта статья должна восполнить пробел, связанный с недостаточным количеством материалов об архитектуре Agile. В ней рассказывается об отличиях архитектуры от дизайна и описываются некоторые общие соображения разработки архитектуры. Кроме того, в статье рассматриваются аспекты проектирования сервис-ориентированной архитектуры (SOA) на основе методологии Agile, а также обсуждаются вопросы управления версиями.

Отличия архитектуры от дизайна.

По моему мнению, лучшее определение архитектуры дал Мартин Фаулер (Martin Fowler) в одной из наших бесед. Оно звучит следующим образом:

Архитектура – это то, что трудно изменить на поздних стадиях разработки. Поэтому ее должно быть как можно меньше.

Один из способов визуализации связи между архитектурой и дизайном представлен на рисунке 1.

Рисунок 1. Различия между архитектурой и дизайном.

Архитектура приложения, показанная в виде серых кубиков на рисунке 1, представляет собой фундамент, на который опираются все остальные компоненты системы, в том числе элементы дизайна, показанные в виде красных кубиков. Архитектурные компоненты, как правило, трудно передвигать с места на место, поскольку при этом приходится двигать все лежащие выше блоки, которые будут затронуты изменениями в фундаменте. В этом и заключается основное отличие архитектуры от дизайна. Например, Web-инфраструктура, использующаяся при создании Web-приложения, является элементом архитектуры, поскольку ее сложно сменить. При этом вы можете применять разные подходы к проектированию дизайна в рамках одной архитектуры, позволяющие достичь разные цели. Это говорит о том, что большинство приемов проектирования (design patterns) относится именно к дизайну, а не к архитектуре.

Следствием определения архитектуры, данного Фаулером, является необходимость конструирования компонентов архитектуры таким образом, чтобы их можно было заменить при острой необходимости. Но как это сделать? Рассмотрим пример.

Множество инфраструктур предлагают разработчикам использовать собственные классы вместо классов общего назначения, входящих в JDK либо в библиотеки, разработанные открытыми институтами по стандартизации (например, OASIS). Это пример фатальной связанности между компонентами: поддавшись на подобные предложения, вы навсегда окажетесь привязанными к данной конкретной инфраструктуре. Подобные инфраструктуры, как правило, гораздо легче использовать, если работать напрямую с их классами. Отличным примером может служить инфраструктура Apache Struts (см. раздел Ресурсы).

Классы внутри вашего приложения, реализующие бизнес-правила и другую логику, называются классами предметной области . Они отвечают за обработку данных, относящихся к области приложения. Struts предоставляет удобный класс ActionForm , выполняющий вспомогательные функции. Если вы наследуете свои классы предметной области от ActionForm , то начинается подлинное волшебство: поля форм автоматически заполняются параметрами запросов, данные автоматически валидируются как в слое клиента, так и сервера, и т.д. Все, что для этого нужно – это сделать ваш класс наследником ActionForm , как показано на рисунке 2.

Рисунок 2. Использование класса ActionForm в Struts.

Как видно из рисунка 2, модель приложения включает ваш класс предметной области. Он наследует класс ActionForm , являющийся частью Struts, что затрудняет последующее изменение структуры. Например, если в будущем вы решите, что класс ScheduleItem должен также использоваться в приложении на основе Swing, то возникнут серьезные проблемы. Перед вами встанет выбор меньшего из двух зол: перенести Struts в Swing-приложение, но не использовать его, либо отделить ваше приложение от Struts.

Более правильное проектирование заключается в использовании композиции вместо наследования (рисунок 3).

Рисунок 3. Ослабление связей между классами предметной области и инфраструктурой при помощи композиции.

В этой версии архитектуры класс предметной области (показан желтым цветом) содержит ссылку на объект, реализующий интерфейс, который определяет семантику элемента расписания (schedule item). Классы ScheduleItem и ScheduleItemForm реализуют этот интерфейс, что обеспечивает совместимость их семантики во всех случаях. При этом ScheduleItemForm в свою очередь содержит ссылку на бизнес-класс ScheduleItem , а все его методы для чтения и изменения свойств делегируют вызовы соответствующим методом класса ScheduleItemForm . Это позволяет использовать все преимущества Struts, в то же время избегая чрезмерной зависимости от этой инфраструктуры.

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

Некоторые архитектурные соображения.

При создании корпоративных приложений приходится решать множество архитектурных проблем помимо напрямую вытекающих из ее определения. Ниже мы рассмотрим несколько методик Agile для преодоления некоторых из подобных сложностей.

Политика проектирования инфраструктуры.

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

Запомните, что общение играет более важную роль в большинстве проектов по разработке ПО, чем технологии. Если вам приходилось участвовать в провалившемся проекте, задумайтесь над тем, почему он провалился. Это случилось из-за технических проблем или из-за проблем с взаимодействием внутри команды? Как правило, основная причина лежит в плоскости взаимодействия. Технические проблемы всегда имеют решения, пусть и не всегда простые. Социальные проблемы часто оказываются более неприятными и сложными в разрешении. На эту тему есть отличная цитата из книги «Человеческий фактор» (см. раздел Ресурсы):

Проблема всегда в людях.

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

Создавать или покупать.

Один из наиболее распространенных вопросов, возникающих во всех крупных компаниях, заключается в том, следует ли покупать готовое коммерческое программное обеспечение (Commercial Off-The-Shelf Software – COTS) или создавать его самостоятельно, учитывая текущие требования. Причины, по которым этот вопрос поднимается, совершенно очевидны: если компания может найти готовое приложение, выполняющее в точности необходимые функции, то оно сэкономит время и деньги. К сожалению, учитывая подобные соображения, множество компаний-разработчиков выпускают ПО, которое можно настраивать множеством способов, если оно не полностью удовлетворяет требованиям. Они стараются создавать ПО наиболее общего назначения, чтобы продавать его как можно большему числу клиентов. Однако чем менее специализированным является ПО, тем больше его приходится настраивать. Для этих целей существует целая армия консультантов, которые могут работать годами, конфигурируя систему под конкретного заказчика.

Вопрос, стоит ли покупать COTS, на практике сводится к другому вопросу: какое значение имеют бизнес-процессы, автоматизируемые этим ПО, – стратегическое или вспомогательное ? Покупка COTS имеет смысл во втором случае, в частности, для автоматизации кадровой, финансовой или другой хозяйственной деятельности. В свою очередь стратегическое ПО обеспечивает конкурентное преимущество на рынке, и его не следует упускать в пользу другой компании.

Избегайте ловушек.

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

Диаграмма на рисунке 4 должна помочь вам в принятии решения в пользу покупки и создания программного обеспечения.

Рисунок 4. Диаграмма ответа на вопрос «покупать или создавать?».

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

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

Далее вы должны решить, является ли рассматриваемое ПО расширяемым (не следует путать расширяемость и настраиваемость ). Расширяемые системы предоставляют четко определенные возможности по добавлению новой функциональности без необходимости изменения существующего кода. Подобные точки расширения включают в себя ясно описанные API, вызовы SOAP и тому подобное. При этом настраиваемость подразумевает необходимость всяческих «трюков», чтобы заставить систему выполнять нужные функции. Например, вам может потребоваться распаковать WAR-файл, чтобы заменить в нем файл index.gif на другую картинку (которая также обязана называться index.gif). Это именно настройка, а не расширение. Спросите себя, смогут ли ваши изменения успешно пережить переход на новую версию ПО. Если да, то вы смогли расширить систему, а в противном случае — всего лишь изменили ее. Настройки приводят к препятствиям к обновлению ПО, поскольку вы понимаете, насколько тяжело будет перенести изменения в новую версию. В итоге в один прекрасный день может оказаться, что вы используете систему, которая на пять версий старше текущего релиза а, следовательно, рискуете лишиться ее поддержки со стороны производителя.

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

Типизация в архитектуре.

В процессе созданий SOAP-систем часто встает вопрос типизации и управления версиями распределенных компонентов. Он имеет больше технический, чем коммерческий характер, однако часто является причиной грубых ошибок в проектах такого рода. Это происходит по двум причинам: во-первых, легко пойти на поводу у производителей программного обеспечения, а во-вторых, проблемы проявляются далеко не сразу. Более того, самые неприятные проблемы – это именно те, о которых вы не знали на ранних стадиях проекта.

Спор насчет того, можно ли создавать системы корпоративного уровня на языках с динамической типизацией, себя практически исчерпал, а новые аргументы только лишь добавляют эмоций. Тем не менее, эти дебаты говорят о важности типизации конечных точек в распределенных системах. Под конечными точками (endpoints) в данном случае понимается способ взаимодействия между двумя самостоятельными системами. В настоящее время существуют два конкурирующих подхода к типизации: SOAP, который, как правило, требует строгой типизации с использованием таких стандартов, как язык описания Web-сервисов (Web Services Description Language – WSDL) и технология REST (Representational State Transfer), предпочитающая более свободную типизацию на основе документов (см. раздел Ресурсы). Обсуждение преимуществ и недостатков обеих технологий выходит за рамки данной статьи. Мы затронем лишь преимущества свободной типизации на уровне конечных точек, которой вы можете достичь, используя оба подхода.

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

Рассмотрим пример. При традиционном, основанном на SOAP походе к интеграции приложений используются протоколы вроде удаленного вызова процедур (RPC), а также WSDL для описания деталей обмена данными. Схема показана на рисунке 5.

Рисунок 5. Взаимодействие между приложениями в стиле RPC.

При интеграции в стиле RPC WSDL используется для описания методов таким образом, чтобы их можно было вызывать в SOAP. Другими словами, каждый класс представляет собой тип в WSDL, также включающий типы всех параметров методов. Этот подход сильно связывает обе взаимодействующие системы, поскольку им приходится полагаться на единое описание отправляемых и получаемых данных в WSDL. Подобное строгое описание является корнем проблемы. Что делать, если необходимо модифицировать одно из приложений, например, добавить параметры вызова или изменить тип существующего параметра, а вы не можете позволить себе выполнять изменения синхронно в обеих системах? Как управлять версиями конечных точек? Существует несколько путей решения этой проблемы, но все они подразумевают серьезные компромиссы. Например, вы можете создать еще одну конечную точку с новым описанием WSDL. Если изначальная точка доступа называлась addOrder , то вторую можно назвать addOrder2 . Наверняка вы можете представить себе, куда ведет этот путь. Очень скоро у вас будет десяток слегка различающихся точек и немало дублирующегося кода, поскольку сложно предсказать то, как будет использоваться точка доступа после ее публикации. Кроме того, вы можете попробовать использовать средства разрешения имен конечных точек, например UDDI (Universal Description, Discovery, and Integration), который фактически представляет собой хеш-таблицу, но этот подход также страдает из-за плохой масштабируемости. Корень проблемы заключается в сильной связанности конечных точек, которая препятствует естественному развитию систем.

Альтернативный подход к интеграции конечных точек основан на идее свободной типизации (рисунок 6).

Рисунок 6. Свободная типизация конечных точек.

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

В условиях существования различных версий конечных точек необходимо в первую очередь распаковать документ, определить структуру переданных данных и согласовать ее с ожидаемой структурой. Лично я, как правило, применяю такие приемы проектирования, как «Фабрика» и «Стратегия» (см. раздел Ресурсы), чтобы определить, соответствуют ли полученные данные ожидаемым (рисунок 7).

Рисунок 7. Анализ содержимого внутри точки доступа для определения его типов данных.

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

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

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

Заключение.

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

Ресурсы для скачивания.

Похожие темы.

Оригинал статьи: Evolutionary architecture and emergent design: Evolutionary architecture (Нил Форд, developerWorks, январь 2010 г.). (EN) Прочитайте последнюю книгу Нила Форда под названием The Productive Programmer (O’Reilly Media, 2008 г.), в которой более подробно рассматриваются вопросы, затронутые в этой статье. (EN) Обратите внимание на классическую книгу Банды Четырех под названием Приемы объектно-ориентированного проектирования. Паттерны проектирования (Эрих Гамма и др., Erich Gamma et al., Addison-Wesley, 1994 г.), посвященную подходам к проектированию приложений. (EN) Ознакомьтесь с Apache Struts – популярной инфраструктурой с открытым кодом для создания Web-приложений на Java. (EN) В книге Человеческий фактор: успешные проекты и команды (Том Де Марко и Тимоти Листер, Tom DeMarco and Timothy Lister, Dorset House Publishing, 1999 г.) приводится ряд полезных советов по разрешению социальных проблем в процессе создания программного обеспечения. (EN) Прочитайте обсуждение технологий SOAP и REST в контексте создания SOA-приложений в статье Ресурс-ориентированные и процесс-ориентированные Web-сервисы (Джеймс Снелл, James Snell, developerWorks, октябрь 2004 г.). (EN)

Комментарии.

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

Добавить комментарий