Динамично меняющийся мир
Долгое время разработчики придерживались мнения, что архитектуру ПО следует разрабатывать до написания первой строки кода. Под влиянием строительной отрасли считалось, что признаком успешной архитектуры было то, что в ней не надо ничего менять в процессе разработки, это часто было связано с высокими затратами на переделку архитектуры.
С появлением гибких методов разработки такое представление об архитектуре изменилось. Изменения требований оказались просто необходимы для ведения бизнеса в современном динамично меняющимся мире. Стало необходимо обеспечить планирование проекта, позволяющее вносить контролируемые изменения.
Программное обеспечение со временем становится сложнее менять. Разные части системы не позволяют выполнять простые изменения и становятся со временем все более хрупкими.
Экосистема разработки программного обеспечения включает в себя все рабочие инструменты, фреймворки, библиотеки и практический опыт, накопленный в процессе разработки. Эта экосистема формирует равновесие. Однако это равновесие не стабильно. Непрерывно появляются новые вещи нарушающие баланс.
Постепенное ухудшение, которое часто называют битовой деградацией (bit rot), возникает во многих организациях. Разработчики архитектуры выбирают определенный паттерн архитектуры для выполнения требований той или иной области применения и соответствующие возможности, но эти характеристики часто начинают со временем ухудшаться.
Непрерывно меняющаяся архитектура
Если экосистема непрерывно меняется непредсказуемым образом и прогнозирование изменений невозможно, то что тогда является альтернативой жесткому планированию?
Непрерывно меняющаяся архитектура(Continual architecture) — построение архитектуры, не имеющей конечного состояния, предназначенной для эволюции с постоянно меняющейся экосистемой разработки программного обеспечения и содержащая встроенные средства защиты важных характеристик архитектуры.
Эволюционное развитие поддерживает управляемые, постепенные и последовательные изменения сразу в нескольких направлениях.
Архитектура с эволюционным развитием включает три основных аспекта: инкрементное изменение(incremental change), функции пригодности(fitness functions) и подходящая связанность(appropriate coupling).
Инкрементные изменения(Incremental change) описывают два аспекта архитектуры программного обеспечения:
- Разработка. Как разработчики создают программное обеспечение
- Ввод в эксплуатацию. Как команды развертывают программное обеспечение
Разработки на основе данных(data driven development) позволяет данным управлять изменениями и концентрировать усилия на изменении технической архитектуры.
Аналогичный подход, который использует предметную область, а не технические аспекты, носит название разработки на основе гипотез (hypothesis-driven development).
Для этого должна быть возможность делать небольшие и быстрые релизы. Это может обеспечить подходы DevOps.
Качественный дизайн обладает слабой связанностью (low coupling) и сильной связностью (high cohesion)
Подходящая связанность(appropriate coupling) — это еще одно условие для реализации эволюционной архитектуры.
Управляемые изменения
По мере эволюционирования архитектуры нам нужен механизм оценки того, как изменения влияют на важные характеристики архитектуры и предотвращают их ухудшения со временем.
После того как были выбраны важные характеристики их необходимо защищать. С этой целью используются функции приспособленности(fitness functions).
Функции приспособленности/пригодности являются целевой функцией, используемой для оценки того, как близко решение к достижению поставленных целей. Они определяют изменился ли со временем алгоритм в лучшую сторону. По мере создания каждого варианта алгоритма функция пригодности определяет, насколько пригоден каждый вариант, основываясь на том, как разработчик этого алгоритма определяет пригодность.
Функция пригодности охватывает различные механизмы, которые мы используем для гарантии того, что архитектура не меняется нежелательным образом, включая определенные показатели, тесты и другие инструменты проверки.
Архитектурная функция пригодности предоставляет оценку целостности некоторых архитектурных характеристик.
Функция пригодности всей системы имеет решающее значение в способности архитектуры эволюционировать, поскольку нам нужна основа, которая позволила бы разработчикам сравнивать и оценивать характеристики архитектуры друг относительно друга.
Категории fitness functions
Функции пригодности существуют в различных категориях, связанных с их областью применения, частотой, динамикой и другими факторами, включая комбинации категорий там, где это необходимо.
Атомарная и комплексная функции
Атомарная (atomic) функция пригодности используется в единичном контексте и затрагивает только один определенный аспект архитектуры. Удачным примером атомарной функции пригодности является модульное тестирование, которое проверяет некоторые характеристики архитектуры, такие как связанность модулей.
Таким образом, некоторые тесты уровня приложений попадают в категорию функций пригодности, но не все модульные тесты являются функциями пригодности, а только те, которые проверяют характеристики архитектуры.
Некоторые характеристики архитектуры разработчики должны тестировать больше, чем каждую ее область по отдельности. Комплексные (holistic) функции пригодности используются в общем контексте и затрагивают комбинации аспектов архитектуры, таких как безопасность и масштабируемость.
Триггерные и непрерывные функции
Порядок выполнения является еще одной отличительной чертой функции пригодности. Триггерные (triggered) функции пригодности запускаются при определенных событиях, таких как выполнение модульного теста, развертывание конвейера для выполнения модульных тестов или выполнение специалистом по обеспечению качества исследовательского тестирования. Эти события включают в себя традиционные тесты, такие как модульные, функциональные, разработку через реализацию поведения (BDD — behavior-driven development) и другие тесты, проводимые разработчиками.
Непрерывные (сontinual) тесты не выполняются по графику, но вместо этого проводится непрерывная проверка таких параметров архитектуры, как скорость транзакций.
Monitoring-driven development представляет другую технику тестирования. Вместо того чтобы надеяться только на тесты для проверки результативности системы, MDD использует систему контроля для оценки технического состояния и предметной области. Эти непрерывные функции пригодности более динамичны, чем стандартные триггерные тесты.
Статические и динамические функции
Статические (static) функции пригодности имеют неизменные результаты, такие как двоичные прошел/провалил, которые дают модульные тесты. Этот тип включает в себя любую функцию пригодности, которая имеет предварительно заданное требуемое значение: двоичное, диапазон числа, включение множества и т. п.
В качестве функций пригодности часто используют метрики.
Временная функция
Большинство функций пригодности запускается при изменениях системы, но иногда есть необходимость встроить компонент времени в процедуру оценки пригодности. Например, если проект использует библиотеку шифрования, можно создать временную функцию пригодности как напоминание о необходимости проверки того, были ли обновлены важные компоненты.
Другим распространенным применением этого типа функции пригодности является тест повреждений при обновлении (break upon upgrade).
Ранняя идентификация функций пригодности
Команды должны идентифицировать функции пригодности как часть их начального понимания общей функциональности архитектуры, которую их проект должен поддерживать.
Они также должны на ранней стадии идентифицировать функцию пригодности своей системы, чтобы определить те изменения, которые следует поддерживать.
Сравнения важности и сложности реализации различных характеристик архитектуры (наряду с функциями пригодности) помогает на ранней стадии расставить приоритеты связанных с риском работ для понимания того, как проектировать с учетом изменений.
Чем раньше будет обнаружена проблема, тем меньше усилий потребуется для ее разрешения.