Вы занимались разработкой в 1990-х годах? Помните, как Всемирная паутина изменила все вокруг? Помните, с каким презрением мы смотрели на наши старые архитектуры клиент/сервер перед лицом новой сверкающей технологии «Веб»?
На самом деле Веб ничего не изменил. По крайней мере не должен был ничего изменить. Веб — это всего лишь последнее из последовательности колебаний, которые наша индустрия пережила с 1960-х годов. Эти колебания заставляют переносить всю вычислительную мощность то на центральные серверы, то на терминалы.
Только за последние десять лет (или около того), пока Веб занял заметное место, мы видели несколько таких колебаний. Сначала мы думали, что вся вычислительная мощность будет сосредоточена в фермах серверов, а браузеры будут просто отображать информацию. Затем мы начали добавлять апплеты в браузеры. Но нам это не понравилось, поэтому мы переместили динамическое содержимое обратно на серверы. Но это нам тоже не понравилось, и мы изобрели Веб 2.0, переместив почти всю обработку обратно в браузер, используя для этого Ajax и JavaScript. Мы зашли так далеко, что создали целые приложения, выполняющиеся в браузерах. И теперь мы снова возбуждены перемещением JavaScript обратно на сервер в виде Node.
(Вздох.)
Бесконечный маятник
Конечно, было бы неправильно думать, что колебания начались с появлением Веб. До Веб существовала архитектура клиент/сервер. До этого были центральные мини-компьютеры с массивами неинтеллектуальных терминалов. До этого были мейнфреймы с интеллектуальными терминалами (зеленого свечения, которые были очень похожи на современные браузеры). До этого были машинные залы и перфокарты...
Так выглядит история. Мы никак не можем определить, где должна быть сосредоточена вычислительная мощность. Мы все время то централизуем ее, то распределяем. И я думаю, что эти колебания будут еще продолжаться в течение какого-то времени.
С точки зрения истории развития информационных технологий Веб вообще ничего не изменил. Это просто одно из множества колебаний, которые начались еще до того, как многие из нас появились на свет, и продолжатся после того, как многие из нас уйдут на пенсию.
Однако как архитекторы мы должны быть нацелены на долгосрочную перспективу. Эти колебания — лишь кратковременные проблемы, которые не должны проникать в центральное ядро с нашими бизнес-правилами.
Я хочу рассказать вам одну историю о компании Q. Компания Q создала очень популярную систему управления персональными финансами. Это было приложение для настольного компьютера с очень удобным графическим интерфейсом. Мне нравилось пользоваться им.
Затем появился Веб. В следующей версии системы компания Q изменила пользовательский интерфейс — он стал выглядеть и действовать подобно веб-интерфейсу в браузере. Я был в шоке! Какой гений маркетинга решил, что программа управления персональными финансами, действующая на настольном компьютере, должна выглядеть как веб-браузер?
Конечно, я возненавидел новый интерфейс. Все остальные, видимо, тоже, потому что после выпуска нескольких версий компания Q отказалась от внешнего вида, напоминающего браузер, и вернула системе графический интерфейс обычного настольного приложения.
Теперь представьте, что в ту пору вы работали программным архитектором в Q. Вообразите, что какой-то гений от маркетинга убеждает высшее руководство в необходимости переделать весь пользовательский интерфейс, чтобы он напоминал веб-интерфейс. Что бы вы сделали? Точнее, что вы должны были бы сделать до этого момента, чтобы защитить приложение от этого гения маркетинга?
Вы должны были бы отделить бизнес-правила от пользовательского интерфейса. Я не знаю, как поступили архитекторы в Q. Я хотел бы когда-нибудь услышать их рассказ. Если бы в то время я работал там, я бы точно изолировал бизнес-правила от пользовательского интерфейса, потому что никто не знает, что взбредет в голову гениям маркетинга в следующий раз.
Теперь рассмотрим пример с компанией A, выпускающей замечательные смартфоны. Недавно она выпустила обновленную версию своей «операционной системы» (это так необычно — говорить об операционной системе внутри телефона). Кроме всего прочего модернизация кардинально изменила внешний вид всех приложений. Зачем? Я полагаю, что вновь не обошлось без какого-то гения маркетинга.
Я не эксперт по программному обеспечению в этих устройствах, поэтому не знаю, вызвали ли эти изменения какие-либо трудности для программистов приложений, выполняющихся на смартфонах компании A. Я надеюсь, что архитекторы в A и архитекторы приложений изолировали бизнес-правила и пользовательский интерфейс друг от друга, потому что всегда найдутся гении маркетинга, которые только и ждут, чтобы наброситься на что-то, созданное вами.
Вывод
Вывод из всего вышесказанного прост: пользовательский интерфейс — это деталь. Веб — это пользовательский интерфейс. То есть Веб — это деталь. И как архитектор вы должны размещать детали, как эта, за границами, отделяющими их от основной бизнес-логики.
Подумайте об этом с такой позиции: Веб — это устройство ввода/вывода. Еще в 1960-х годах мы поняли ценность методики создания приложений, не зависящих от устройств ввода/вывода. Побудительные мотивы такой независимости не изменились. Веб не является исключением из этого правила.
Или я не прав? Можно утверждать, что графический интерфейс, как и Веб, настолько уникален и богат, что абсурдно продолжать создавать архитектуры, независимые от устройства. Когда вы думаете о тонкостях проверки входных данных на JavaScript, особенностях технологии «перетащил и бросил» в AJAX или о том, какие еще виджеты/гаджеты вставить в веб-страницу, легко можно скатиться до утверждения, что независимость устройства непрактична.
Все это верно до определенной степени. Взаимодействия приложения с пользовательским интерфейсом обширны, многообразны и порой очень специфичны для данного интерфейса. Веб-приложение и веб-браузер взаимодействуют совершенно иначе, чем настольное приложение и графический интерфейс. Попытка абстрагироваться от этих взаимодействий, подобно тому, как в UNIX абстрагируются устройства, выглядит невероятной.
Но границу между пользовательским интерфейсом и приложением можно абстрагировать. Бизнес-логику можно рассматривать как набор вариантов использования, каждый из которых выполняет некоторую функцию от имени пользователя. Каждый вариант использования можно описать как комплекс входных данных, выполняемую обработку комплекс и выходных данных.
В какой-то момент в череде взаимодействий пользовательского интерфейса и приложения подготовка входных данных будет закончена и появится возможность выполнить вариант использования. По завершении полученные данные можно вернуть обратно, включив их во взаимодействия между пользовательским интерфейсом и приложением.
Входные и выходные данные можно поместить в структуры и использовать как входные и выходные значения для процесса, выполняющего вариант использования. При таком подходе можно считать, что каждый вариант использования работает с пользовательским интерфейсом как с устройством ввода/вывода независимо от этого устройства.
Заключение
Достичь такой абстракции очень непросто, и, скорее всего, потребуется несколько итераций, чтобы достичь желаемого результата. Но это возможно. А поскольку мир полон гениев от маркетинга, это не самое сложное, потому что часто бывает необходимо.
Глава 32. Фреймворки — это деталь
Фреймворки обрели большую популярность. Вообще говоря, это хорошая штука. Существует много бесплатных, мощных и полезных фреймворков.
Но фреймворки не определяют архитектуру, хотя некоторые пытаются.
Авторы фреймворков
Большинство авторов фреймворков предлагают результаты своего труда бесплатно, потому что хотят быть полезными для сообщества. Они хотят внести свой вклад. Это похвально. Однако, независимо от благородства мотивов, авторы не думают о ваших интересах. И не могут думать, потому что они не знают ни вас, ни ваших проблем.
Но они знают свои проблемы и проблемы своих коллег и друзей. И они пишут свои фреймворки для решения этих проблем, а не ваших.
Конечно, ваши проблемы, скорее всего, частично будут совпадать с этими другими проблемами. Иначе фреймворки не были бы столь популярны. Поэтому фреймворки могут быть очень полезными — в той мере, в какой существует совпадение.
Неравный брак
Отношения между вами и автором фреймворка чрезвычайно асимметричны. Вы должны обладать огромной приверженностью фреймворку, но его автор не несет никаких обязательств перед вами.
Задумайтесь над этим. Когда вы используете фреймворк, вы читаете документацию, предоставленную его автором. В этой документации автор и другие пользователи фреймворка рассказывают вам, как интегрировать ваше программное обеспечение с фреймворком. Обычно это означает, что вы должны обернуть фреймворк своей архитектурой. Автор рекомендует использовать базовые классы и импортировать инструменты фреймворка в свои бизнес-объекты. Автор настоятельно рекомендует вам привязать ваше приложение к фреймворку настолько, насколько это возможно.
Для автора тесная связь с его собственным фреймворком не является проблемой. Для автора такая связь желательна, потому что он обладает абсолютным контролем над этим фреймворком.
Более того, автор хочет привязать вас к фреймворку, потому что, привязавшись, будет очень трудно отвязаться. Ничто не подтверждает авторитет автора так, как группа пользователей, готовых порождать свои классы на основе базовых классов автора.
Фактически автор предлагает вам вступить в союз с фреймворком — выразить ему большую и долговременную приверженность. Но при этом сам автор ни при каких обстоятельствах не выражает ответной приверженности вам. Это однонаправленный союз. Вы принимаете на себя все риски и неудобства; автор фреймворка не берет на себя ничего.
Риски
Какие риски, спросите вы? Вот лишь некоторые из них.
• Часто архитектура фреймворков не отличается особой чистотой. Фреймворкам свойственно нарушать правило зависимости. Авторы предлагают вам наследовать их код в ваших бизнес-объектах — ваших сущностях! Они хотят внедрить свои фреймворки в самый внутренний круг. Как только это произойдет, убрать фреймворк оттуда будет почти невозможно. Надев обручальное кольцо на палец, он останется жить там.
• Фреймворк может помочь с реализацией первых возможностей приложения. Однако, достигнув некоторого уровня зрелости, ваш продукт перерастет фреймворк. Если вы надели это обручальное кольцо, то со временем заметите, что вам все чаще и чаще приходится бороться с фреймворком.
• Фреймворк может развиваться в направлении, бесполезном для вас. Вы можете столкнуться с необходимостью обновления до следующей версии, не несущей ничего, что могло бы пригодиться вам. Вы можете даже обнаружить, что старые особенности, которыми вы пользовались, исчезают или изменяются так, что вам трудно поспевать за ними.
• Может появиться новый, более удачный фреймворк, на который вы захотите перейти.
Решение
И каково решение?
Не заключать союзов с фреймворками!
О, вы можете использовать фреймворк — просто не привязывайтесь к нему. Держите его на расстоянии вытянутой руки. Рассматривайте фреймворк как деталь, принадлежащую одному из внешних кругов архитектуры. Не впускайте его во внутренние круги.
Если фреймворк предложит вам породить свои бизнес-объекты от его базовых классов, скажите «нет»! Определите прокси-классы и держите их в компонентах, являющихся плагинами для ваших бизнес-правил.
Не позволяйте фреймворкам проникать в ваш основной код. Внедряйте их в компоненты, которые лишь подключаются к вашему основному коду, как того требует правило зависимости.
Например, возможно, вам нравится Spring — хороший фреймворк внедрения зависимостей. Возможно, вы используете Spring для автоматического внедрения своих зависимостей. Это замечательно, но вы не должны окроплять аннотациями @autowired свои бизнес-объекты. Бизнес-объекты не должны знать о существовании Spring.
Но вы с успехом можете использовать Spring для внедрения зависимостей в своем компоненте Main. Этот компонент может знать о фреймворке Spring, потому что он является самым грязным и самым низкоуровневым компонентом в системе.
Объявляю вас
Есть некоторые фреймворки, с которыми вы просто обязаны вступить в союз. Если, например, вы пишете на C++, вам почти наверняка придется вступить в союз с STL — избежать этого очень сложно. Если вы пишете на Java, вы будете вынуждены вступить в союз со стандартной библиотекой.
Это нормально — но все равно это должно быть осознанное решение. Вы должны понимать, что, заключив союз между фреймворком и вашим приложением, вам придется придерживаться этого фреймворка в течение всего жизненного цикла этого приложения. В радости и в горе, в болезни и в здоровье, в богатстве и в бедности, отказавшись от всех остальных, вы будете использовать этот фреймворк. Этот шаг нельзя делать по легкомыслию.
Заключение
Встретившись с фреймворком, не торопитесь вступать с ним в союз. Посмотрите, есть ли возможность отложить решение. Если это возможно, удерживайте фреймворк за архитектурными границами. Может быть, вам удастся найти способ получить молоко, не покупая корову.