/
Tags: языки программирования компьютерные технологии программирование программное обеспечение информационные технологии
ISBN: 978-5-9775-2109-3
Year: 2026
Text
Principles of
Software Architecture
Modernization
Delivering engineering excellence with the art offixing
microservices, monoliths, and distributed monoliths
The Author:
Diego Pacheco
Co-author:
Sam Sgro
www.bpbonline.com
Диего Пачеко, Сэм Сгро
ПРИНЦИПЫ
МОДЕРНИЗАЦИИ
ПРОГРАММНЫХ
АРХИТЕКТУР
Санкт-Петербург
« БХВ-Петербург»
2026
УДК
ББК
004.43
32.973.26-018.2
П21
Пачеко,Д.
Принципы модернизации проrраммных apxиreК"l)'J): пер. с англ.
П21
С.
Crpo. -
СПб.: БХВ-Петербург,
/ Д.
Пачеко,
ил.
2026. - 496 с.:
ISBN 978-5-9775-2109-3
Подробное руководство по проектированию масnrrабируемого и поддерживае
мого программного обеспечеНИJ1, написанное признанными экспертами в обласrи
программных
apxиreК"l)'J).
Рассматриваются
основные
сложносrи
монолиrных
приложений и апrипатrерны, которые привод.ат к проблемам их масшrабированн.я
и сопровождени.я. Изложены принципы качественного проектировани.я, вкmоча.я
слабую связность и инкапсуляцию. Подробно описаны архиrеК"l)'J)ные патrерны,
позволяющие с-rроить масштабируемые и поддерживаемые приложени.я, такие как
многоуровневая apxиreК"l)'J)a и модель микросервисов. Показаны подходы к гра
мотной миграции монолитов в распределенные системы. Рассмотрены проверен
ные методы тестировани.я и развертывани.я распределенных систем, обеспечиваю
щие их надежность и эффективность.
Для разработчиков и архитекторов программного обеспечения
ББК
УДК 004.43
32.973.26-018.2
Группа подготовки издании:
Руководиrель проекта
ПавелШалин
Зав. редакцией
Людмила Гауль
Редакrор
Людмила Гауль
Компьютерная версп:а
Ольги Сергиенко
Дизайн обложки
Зои Канторович
Copyright 2024 ВРВ PuЬlications, India. All rights reserved.
First puЫished in the Eog)ish language under the title Principles о/Softwtue Arclшedllre Modernizalion,
ISBN 9789355519535 Ьу ВРВ PuЬlications India (sales@bpЬonline.com). Russian translation rights arтanged
with ВРВ PuЬlications, India.
2024 ВРВ PuЬlications, Индю~. Все права защищены. Впервые опубликовано на английском языке
Principles о/Sojtwtue Arcllitedllп Modemivltion, ISBN 9789355519535 издательством
ВРВ PuЬlications lndia (sales@bpЬoniine.com). Права на перевод на русский язык предоспвлены издательством
С
под названием
ВРВ PuЬlications, Индю~.
Подписано в печать 05.11.25.
Формат 70х100 1 / 16 . Печать офсетная. Усл. печ. л. 39,99.
Тираж 1000 экз. заказ N2 16026.
"БХВ-Петербурr", 191036, Санкт-Петербург, Гончарная ул., 20
Отпечатано с готового оригинал-макета
ООО "Принт-М'',
ISBN 978-93-5551-953-5
ISBN 978-5-9775-2109-3
(англ.)
(рус.)
142300,
М.О., г. Чехов, ул. Полиrрафистов, д.
О ВРВ PuЬlications,
1
lndia, 2024
О Перевод на русский язык, оформление. ООО "БХВ-Петербурr",
ООО "БХВ", 2026
Оrлавление
Об авторах ....................................................................................................................... 15
О рецензенте ................................................................................................................... 17
Благодарности ................................................................................................................ 18
Предисловие
................................................................................................................... 19
Почему мы написали эту книгу? .................................................................................................. 19
Комплект кодов и цветных изображений .................................................................................... 21
Глава
1. Что
не так с монолитами? ............................................................................ 23
Структура главы
............................................................................................................................ 24
Что такое монолиты? ..................................................................................................................... 25
Большая кодовая база ............................................................................................................ 26
Несколько модулей развертывания ...................................................................................... 26
............................................................................................. 27
.............................................................................................................. 27
Неновый ......................................................................................................................... 28
Имеет ли значение размер? ................................................................................................... 29
Неувязки с монолитами ................................................................................................................ 31
Шаблоны в разработке программного обеспечения ................................................................... 33
Что такое антипаттерн? ......................................................................................................... 34
Жизнь с монолитами: антипаттерны, побочные эффекты и усилители ................................... 34
Антипаттерны монолитов ..................................................................................................... 34
Высокая степень связности .......................................................................................... 35
Неправильные абстракции ........................................................................................... 36
Отсутствие изоляции .................................................................................................... 37
Побочные эффекты монолитов ............................................................................................ 38
Сложность развертывания ........................................................................................... 38
Недостаточный уровень тестирования ....................................................................... 40
Отсутствие владельца ................................................................................................... 40
Медленное внедрение новых технологий ................................................................. .41
Медленный цикл разработки ....................................................................................... 44
Автоматизация и антипаттерны ........................................................................................... 45
Усилители ............................................................................................................................... 46
Разбитые окна/ копирование и вставка ...................................................................... 46
Зависть к микросервисам ............................................................................................. 49
Другие особенности монолита
Централизация
6
■
Оглавление
............................................................ 49
Страх перемен ............................................................................................ ,.................. 51
Все ли монолиты плохие? ............................................................................................................. 51
Монолиты - это форма архитектуры программного обеспечения .................................. 52
Преимущества монолитов ............................................................................................................ 53
Влияние рефакторинга и изменений .................................................................................... 53
Упрощение некоторых миграций ......................................................................................... 54
Хорошая отправная точка ..................................................................................................... 54
У прощенная инфраструктура ............................................................................................... 54
Типы монолитов ............................................................................................................................ 54
Классические, распределенные и модульные монолиты ................................................... 54
Модульные монолиты: хороший вид монолита .................................................................. 56
Модульные монолиты: Istio .................................................................................................. 58
Модульные монолиты: мобильные суперприложения ....................................................... 60
Можно ли избежать плохих монолитов? ..................................................................................... 61
Что нужно запомнить .................................................................................................................... 64
Нехватка квалифицированных специалистов
Глава
2. Антипаттерны:
отсутствие изоляции ........................................................ 67
............................................................................................................................ 67
Что такое изоляция? ...................................................................................................................... 69
Изоляция в программном обеспечении ....................................................................................... 70
Соблазны изоляции ....................................................................................................................... 71
Внешнее воздействие ............................................................................................................ 71
Существующий компонент, BFF ................................................................................. 74
Существующий компонент, изменение существующей конечной точки ............... 74
Существующий сервис, добавление новой конечной точки .................................... 75
Новый сервис, общий доступ к базе данных .............................................................. 75
Что такое бэкенд для фронтенда (BFF)? ..................................................................... 77
Новый сервис, общий доступ к данным ..................................................................... 77
Что такое обработка событий? .................................................................................... 77
Обработка событий в программном обеспечении ..................................................... 78
CQRS и ее связь с ES .................................................................................................... 80
Новый сервис, общий доступ через API ..................................................................... 80
Централизация ....................................................................................................................... 81
Преимущества централизации инженерных команд ................................................. 81
Проблемы, связанные с чрезмерной централизацией ............................................... 82
Проблемы с поставками и инновациями .................................................................... 82
Структура главы
Централизация в сравнении со стандартизацией для обеспечения
................................................................................ 84
Плохие общие библиотеки ........................................................................................... 85
Разрушение изоляции .................................................................................................................... 85
Совместное использование баз данных ............................................................................... 85
Когда можно использовать базы данных совместно? ............................................... 88
Базы данных приложений для совместного использования в Big Data ................... 88
Скрытые контракты и сохранение изоляции ............................................................. 90
Интеграция с устаревшими системами ....................................................................... 91
Общие библиотеки ................................................................................................................ 91
Бинарная связь .............................................................................................................. 92
Отсутствие стабильных контрактов ..................................................................................... 94
наблюдаем ости и развертывания
Оглавление
■
7
Повышение сложности ........................................................................................................ ! 00
Детализация и распространение: побочные эффекты ............................................. 1О 1
Давайте изолируем вс!! ................................................................................................................ 104
......................................................................................................................... 104
Общие библиотеки .............................................................................................................. 104
Стабильные контракты ........................................................................................................ 104
Насыщенные модули и философия проектирования программного обеспечения ........ 105
Операционные системы и инфраструктура ....................................................................... 106
Расширенная изоляция ........................................................................................................ 107
Сооружение переборок и изоляция сбоев ................................................................ 107
Резервные варианты ................................................................................................... 11 О
Изоляция пользовательского опыта: деградация и изыскания ............................... 111
предотвратить проблемы с изоляцией ................................................................................ 113
Обзор конструкций и оснастки ........................................................................................... 113
нужно запомнить .................................................................................................................. 114
Базы данных
Как
Что
Глава
3. Антипаттерны:
распределенные монолиты ........................................... 116
.......................................................................................................................... 116
Что такое распределенный монолит? ........................................................................................ 118
Особенности распределенных монолитов ......................................................................... 118
Как создаются распределенные монолиты? .............................................................................. 119
Совместное использование баз данных разными сервисами ........................................... 120
Общие библиотеки доступа к данным ............................................................................... 122
Общие контракты ................................................................................................................ 123
Проблемы с распределенными монолитами ............................................................................. 124
Бинарная связь ..................................................................................................................... 124
Временная взаимосвязь ....................................................................................................... 125
Повышение сложности ............................................................................................... 126
Внедрение асинхронности с архитектурой, управляемой событиями ................... 127
Уязвимости и исправления в системе безопасности ........................................................ 130
Тестирование ........................................................................................................................ 130
Проблемы с управлением .................................................................................................... 132
Проблемы с логикой ............................................................................................................ 133
Усилители ..................................................................................................................................... 134
Размывание команды ........................................................................................................... 134
Владелец программного обеспечения ....................................................................... 136
Антинаучное мышление ..................................................................................................... 137
Новые функции и исправление багов ................................................................................ 138
Мины ............................................................................................................................ 141
Плохая среда ........................................................................................................................ 142
Типы распределенных монолитов ............................................................................................. 143
Серверная часть ................................................................................................................... 144
BFF и интерфейс .................................................................................................................. 144
Бессерверная архитектура ................................................................................................... 145
Сложность бессерверных архитектур ....................................................................... 14 7
Обратный эффект: снова хуже! .................................................................................................. 149
Архитекторы как контролеры не масштабируются .......................................................... 149
Новые возможности/функции ............................................................................................ 150
Новая таблица ...................................................................................................................... 151
У старевшая технология ....................................................................................................... 151
Структура главы
8
■
Оглавление
Предотвращение дальнейших повреждений ............................................................................. 152
Подумайте о возвращении к монолиту ..............................................................................
152
Советы по команде и процессу .................................................................................. 152
Советы по технологиям и архитектуре программного обеспечения
..................... 153
Что нужно запомнить .................................................................................................................. 154
Глава
4. Антипапервы:
внутренние общие библиотеки .................................... 157
.......................................................................................................................... 157
Что такое библиотека? ................................................................................................................ 159
Типы библиотек ........................................................................................................................... 160
Библиотеки и фреймворки .................................................................................................. 161
Проблемы с библиотеками ......................................................................................................... 162
Постоянные миrрации ......................................................................................................... 162
Отсутствие стабильных контрактов ................................................................................... 162
Бинарная связь / сломанная изоляция ................................................................................ 163
Стимулы для создания библиотек ...................................................................................... 164
Антипаттерн: фреймворк .................................................................................................... 165
В защиту библиотек .................................................................................................................... 167
Производительность ............................................................................................................ 168
Путь к надежности ............................................................................................................... 168
Языковые идиомы ................................................................................................................ 168
Централизация кода ............................................................................................................. 169
Перестаньте заново изобретать велосипед ........................................................................ 169
Подводные камни - неправильные методы, которых следует избеrать ............................... 170
Внутренние общие библиотеки .......................................................................................... 170
Эффект короткого одеяла ................................................................................................... 170
Большие фреймворки .......................................................................................................... 171
Раздутые библиотеки ........................................................................................................... 172
Очень популярные библиотеки .......................................................................................... 172
Библиотеки доставки конфигурации ................................................................................. 172
Размывание команды в общих библиотеках ..................................................................... 173
Драйверы сервисов ..................................................................................................... 174
Утилиты ................................................................................................................................ 176
Обёртки ................................................................................................................................. 177
Расширение ................................................................................................................. 177
Новые абстракции ....................................................................................................... 178
Отсутствие управления ....................................................................................................... 179
Улучшенные возможности ......................................................................................................... 180
Когда нам следует создавать библиотеку? ........................................................................ 180
Когда нам не следует создавать библиотеку? ................................................................... 181
Использование сервисов ..................................................................................................... 182
Отсутствие бинарной связи ....................................................................................... 182
Значительно улучшенная гибкость ........................................................................... 182
Простая миграция или отсутствие миграции ........................................................... 183
Критический уровень надежности ............................................................................ 183
В некоторых случаях производительность .............................................................. 184
Паттерн Sidecar .................................................................................................................... 186
Современный Sidecar.................................................................................................. 186
Sidecar и прокси .......................................................................................................... 189
Sidecar и Kubemetes .................................................................................................... 190
Структура главы
Оглавление
Как можно построить
■
9
Sidecar? Типы Sidecar ........................................................... 193
Сетки сервисов ............................................................................................................ 195
........................................................................................................ 196
SDK и библиотеки ...................................... 196
Сделать это самостоятельно ...................................................................................... 196
Скопировать и вставить код ...................................................................................... 197
Внести свой вклад в работу с открытым исходным кодом ..................................... 197
Правильная конструкция библиотеки ....................................................................................... 197
Дублирование против повторного использования ........................................................... 197
Плохое дублирование: бизнес-код ............................................................................ 197
Плохое дублирование: выполнение .......................................................................... 198
Хорошее дублирование: миграция ............................................................................ 198
Хорошее дублирование: конфигурация и код установки ....................................... 198
Повторное использование: палка о двух концах ..................................................... 199
Грамотное управление зависимостями .............................................................................. 200
Сливки зависимостей ................................................................................................. 201
Избегайте использования родительского РОМ ....................................................... 203
Объявляйте зависимости явно ................................................................................... 204
Экономичные библиотеки .................................................................................................. 204
Спектр возможностей .................................................................................................................. 205
Что нужно запомнить .................................................................................................................. 206
Простые альтернативы
Использовать существующие пакеты
Глава
5. Оценка ........................................................................................................... 209
.......................................................................................................................... 209
........................................................................................................................ 211
Зачем проводить оценку? ............................................................................................................ 211
Типичные проекты модернизации ..................................................................................... 212
Успешные проекты модернизации ..................................................................................... 212
Мотивация ................................................................................................................... 213
Оценка ......................................................................................................................... 214
Следите за конусом неопределенности .................................................................... 215
Технологические и бизнес-потребности ................................................................... 216
Стратегия модернизации ............................................................................................ 217
Гибкий процесс разработки ....................................................................................... 217
Решения и компромиссы ............................................................................................................. 218
Создание или покупка ......................................................................................................... 218
Обоснование покупки ................................................................................................ 219
Обоснование создания ............................................................................................... 219
Переписывание или рефакторинr ....................................................................................... 221
Сила обратной совместимости ................................................................................................... 225
Элементы надлежащей оценки ................................................................................................... 227
Масштабный анализ кода .................................................................................................... 227
Классификация и принятие решений ........................................................................ 229
Владелец ...................................................................................................................... 230
Скорость изменения бизнеса ..................................................................................... 231
Публичные контракты ................................................................................................ 232
Нижестоящие зависимости ........................................................................................ 233
Вышестоящие зависимости ....................................................................................... 234
Код ориентирован на пользователя? ......................................................................... 234
Структура главы
Что такое оценка?
1О
■
Оглавление
Сложность
................................................................................................................... 234
.............................................................. 236
Анализ базы данных ............................................................................................................ 236
Классификация уровня независимости ..................................................................... 237
Классический монолит ............................................................................................... 23 7
Микросервисы или надлежащие сервисы ................................................................ 237
Распределенный монолит .......................................................................................... 238
Различные фреймворки доступа к данным .............................................................. 238
Изолированные схемы ................................................................................................ 238
Изолированные таблицы ............................................................................................ 239
Сопоставление бизнес-областей ......................................................................................... 239
Список всех бизнес областей ..................................................................................... 24 l
Помещение системы в карантин ............................................................................... 242
Результаты оценки ....................................................................................................................... 243
Быстрые результаты ............................................................................................................ 243
Определение приоритетов, ожиданий и стратегии ........................................................... 244
Влияние на бизнес в сравнении с затраченными усилиями ............................................ 245
Порядок действий ................................................................................................................ 24 7
Радикальные изменения ...................................................................................................... 248
Что нужно запомнить .................................................................................................................. 249
Уровень прохождения/ покрытие тестами
Глава
6. Принципы
Структура главы
надлежащего предоставления сервисов ............................. 252
.......................................................................................................................... 252
Сервис-ориентированная архитектура ...................................................................................... 253
Типы сервисов ...................................................................................................................... 254
Когда следует использовать сервисы ................................................................................. 255
Когда следует отказаться от сервисов ............................................................................... 256
Преимущества SOA ............................................................................................................. 256
Сокращение сроков вывода на рынок ....................................................................... 257
Сокращение затрат и упрощение обслуживания ..................................................... 260
Расширяемость и адаптивность ................................................................................. 263
Независимость ............................................................................................................ 263
Краткое описание преимуществ SOA ....................................................................... 265
Вначале контракт ......................................................................................................................... 268
Новый сервис ....................................................................................................................... 268
Существующий компонент ................................................................................................. 269
Кодирование контракта с помощью ОрепАРl ................................................................... 270
Обратная совместимость ..................................................................................................... 272
SOA и изоляция ........................................................................................................................... 276
Изоляция хранилищ данных ............................................................................................... 277
Изоляция библиотек ............................................................................................................ 279
Противопоставление вкусов и мостов в библиотеках и монолитах ....................... 282
Изоляция публичных контрактов ....................................................................................... 286
Анализ проекта ........................................................................................................... 289
Автоматизация работоспособности контрактов ...................................................... 290
Неочевидные моменты ............................................................................................... 291
Обработка ошибок в контрактах ............................................................................... 293
Доступность сервиса .................................................................................................. 294
Что нужно запомнить .................................................................................................................. 296
Оглавление
Глава
7. Надлежащее тестирование
■
11
сервисов ........................................................ 301
.......................................................................................................................... 301
Зачем нужно тестирование? ....................................................................................................... 303
Корректность ........................................................................................................................ 304
Влияние изменений ............................................................................................................. 304
Готовность к эксплуатации ................................................................................................ .304
Особенности тестов программного обеспечения ..................................................................... 305
Типы тестов .......................................................................................................................... 305
Признаки плохих тестов ............................................................................................................. 307
Непоследовательная частота отказов ................................................................................. 307
Хрупкость при рефакторинге ............................................................................................. 308
Зависимость от данных ....................................................................................................... 309
Неэффективные циклы тестирования ....................................................................... 309
Постоянная настройка тестов ............................................................................................. 31 О
Независимость тестов .......................................................................................................... 31 О
Характеристики хороших тестов ............................................................................................... 311
Постоянная вероятность успеха ......................................................................................... 312
Устойчивость к рефакторингу ............................................................................................ 312
Изоляция зависимости от данных ...................................................................................... 313
Прямые входные данные ............................................................................................ 314
Внутренние состояния ................................................................................................ 314
Быстрые циклы обратной связи .......................................................................................... 315
Самостоятельные тесты ...................................................................................................... 315
Автономные тесты ............................................................................................................... 315
Манифест тестирования .............................................................................................................. 318
Тестирование на всем протяжении важнее, чем в конце ................................................. 318
Предотвращение ошибок важнее, чем их поиск ............................................................... 319
Понимание при тестировании важнее, чем проверка функциональности ..................... 319
Создание наилучшей системы важнее, чем ее разрушение ............................................. 320
Ответственность команды за качество важнее, чем ответственность тестировщика ...... 320
Разнообразие тестирования ........................................................................................................ 320
Почему тестирование важно для архитектуры программного обеспечения .................. 320
Лучшие практики тестирования сервисов ......................................................................... 321
Практическое стресс-тестирование .................................................................................... 322
Gatling для тестирования производительности ........................................................ 323
Пирамида тестирования ...................................................................................................... 324
Стратегии для тестирования на продуктиве ...................................................................... 326
Пограничный маршрутизатор ................................................................................... 328
Пользователи бета-версии ......................................................................................... 329
Аудит в реальном времени/ сравнение и сброс результатов ................................. 330
Воспроизведение трафика .......................................................................................... 332
Хаотическое тестирование .................................................................................................. 333
«Обезьянья армия» Netflix ......................................................................................... 336
Toxiproxy ..................................................................................................................... 337
Матрицы отказоустойчивости ................................................................................... 338
Внутреннее состояние - продвинутое глубокое погружение ........................................ 339
Генерация синтетических данных ............................................................................. 340
Тестирование интерфейсов ........................................................................................ 341
Настройка тестовых данных ...................................................................................... 343
Макетирование интерфейсов ..................................................................................... 344
Что нужно запомнить .................................................................................................................. 345
Структура главы
12
■
Глава
Оглавление
8. Внедрение
новых технолоrий .................................................................... 348
Структура главы
.......................................................................................................................... 348
Применяем новые принципы ...................................................................................................... 349
Ресурсы по требованию - облачные вычисления ................................................................... 350
Стабильные контракты ........................................................................................................ 352
Надлежащая изоляция ......................................................................................................... 353
Одна учетная запись на сервис ........................................................................................... 355
Одна учетная запись для каждой бизнес-области ............................................................. 358
Одна учетная запись для всего ........................................................................................... 359
Организация учетных записей влияет на степень детализации контрактов .................. 359
Внутренние общие библиотеки .......................................................................................... 360
Бессерверность ..................................................................................................................... 361
Влияние облака на организацию работы команды ........................................................... 362
Готовые возможности - облачные сервисы и SaaS ................................................................ 362
Реляционные хранилища данных и хранилища данных NoSQL ..................................... 363
Искусственный интеллект и аналитика ............................................................................. 365
Изолированные модули развертывания .................................................................................... 366
Контейнеры и Kubemetes .................................................................................................... 366
Облачный спектр ................................................................................................................. 371
Доступ к потоковой передаче данных в режиме реального времени ..................................... 374
Apache Katka ........................................................................................................................ 3 74
Архитектура Katka ............................................................................................................... 376
Katka и CQRS/ES ................................................................................................................. 378
База данных ksqlDB ............................................................................................................. 380
Эффективные инженеры ............................................................................................................. 381
Современные языки программирования ........................................................................... 382
Спектр языков программирования ..................................................................................... 383
Языки программирования JVM .......................................................................................... 385
Гибкие модели данных ................................................................................................................ 386
Базы данных NoSQL ............................................................................................................ 386
Выход за рамки реляционной модели ................................................................................ 389
Бережливые коммуникации - бинарные API и GraphQL ....................................................... 39 I
Взаимодействие между сервисами: REST, gRPC и GraphQL .......................................... 391
Что в REST получилось правильным ................................................................................. 392
Совместимость в сравнении с производительностью ...................................................... 394
GraphQL ................................................................................................................................ 394
Фреймворк gRPC ................................................................................................................. 397
Что нужно запомнить .................................................................................................................. 399
Глава
9. Миграция
Структура главы
кода ............................................................................................. 403
.......................................................................................................................... 403
Почему миграция кода имеет такое значение? ........................................................................ .404
Инвентаризация, варианты использования и РОС .......................................................... .406
Красная миграция в сравнении с зеленой ................................................................................ .408
Элементы надлежащей миграции кода ...................................................................................... 409
Цель миграции ..................................................................................................................... 409
Сложность ............................................................................................................................ 412
Влияние на клиентов - онлайн и офлайн ........................................................................ 416
Онлайн-режим миграции ........................................................................................... 417
Офлайн-режим миграции ........................................................................................... 417
Команда сервисов по сравнению с командой платформы .............................................. .419
Оглавление
Шаблоны миграции кода
■
13
............................................................................................................ 421
Обратная совместимость ..................................................................................................... 421
Оrложенная миграция ......................................................................................................... 421
Strangler Fig .......................................................................................................................... 424
Преобразование классического монолита в надлежащий SOA ............................. .425
Преобразование классического монолита в модульный монолит ......................... 428
Преобразование распределенного монолита в надлежащий SOA ......................... 429
Двусторонние двери Amazon .............................................................................................. 433
Препятствия при миграции ......................................................................................................... 433
Препятствие - остаточные явления .................................................................................. 433
У двоение усилий по инвентаризации и проверке концепций ............................... .434
Распределенные миграции и зависимость от команды .......................................... .434
Повторение, повторение, повторение ....................................................................... 434
Препятствия - трения и энтропия .................................................................................... 434
Препятствия - высокие WIР-лимить1, давление бизнеса, соблюдение требований
и другие ловушки ................................................................................................................. 435
Пост-миграционный период ....................................................................................................... 436
Стратегии отката .................................................................................................................. 436
Что нужно запомнить .................................................................................................................. 437
Глава
1О.
Миграция данных ...................................................................................... 440
Структура главы
.......................................................................................................................... 440
Риски миграции данных .............................................................................................................. 441
Подготовка миграции данных .................................................................................................... 442
Инвентаризация и анализ .................................................................................................... 442
........................................................ 446
.......................................................................................................448
Повторный просмотр отложенных миграций ................................................................... 448
Экспорт и импорт ................................................................................................................ 450
Репликация базы данных .................................................................................................... 452
Сравнение таблиц ................................................................................................................ 454
Триггеры ............................................................................................................................... 455
Захват изменения данных ................................................................................................... 456
Двойная запись ..................................................................................................................... 458
Незавершенные данные ............................................................................................. 459
Сбой при выполнении одной операции записи ...................................................... .459
Задержка и сложность транзакций ............................................................................ 460
Стратегии миграции данных ...................................................................................................... 460
Онлайн или офлайн ............................................................................................................. 461
Вначале схема или несколько миграций ........................................................................... 461
Пересмотр: Strangler Fig ......................................................................................................462
Классические монолиты, Strangler Fig и миграция данных ................................... .463
Выполнение миграции ................................................................................................................ 465
Тестирование ........................................................................................................................ 466
Проверка работоспособности перед миграцией .............................................................. .466
Тестирование производительности .................................................................................... 468
Планирование и определение быстрых выигрышей
Шаблоны миграции данных
Практическое тестирование производительности базы данных
с помощью
NDBench ........................................................................................................... 469
Проверка работоспособности: структура и данные после миграции ............................. .470
Наблюдаемость
.................................................................................................................... 470
14
■
Оглавление
После миграции данных .............................................................................................................. 474
Охота на призраков .............................................................................................................. 474
Очистка и вывод из эксплуатации ..................................................................................... .476
Что нужно запомнитъ .................................................................................................................. 476
Глава
11.
Эпилоr .......................................................................................................... 481
Структура главы
......................................................................................................................... .481
.......................................................................................................................................... 481
Принципы важнее всего .............................................................................................................. 483
Образование ................................................................................................................................. 484
Городское планирование ............................................................................................................ 485
Концепция .................................................................................................................................... 487
Далее ............................................................................................................................................. 488
На бис!
Предметный указатель ............................................................................................... 489
Об авторах
Автор Диего Пачеко
-
опытный бразильский архитектор программного обеспе
чения, автор, спикер, технологический наставник и практик
DevOps
с более чем
20-летним опытом работы. Более десяти лет он создает команды и наставляет лю
дей, ежедневно обучая их навыкам программирования и технологиям. Это сообще
ство объединяет практикующих специалистов и архитекторов, занимающихся про
дажей проектов, наймом персонала, разработкой решений, проведением тренингов
по программированию, а также долгосрочными ретроспективами, еженедельными
занятиями в формате
С
2005
1: 1,
дизайн-сессиями, код-ревью и дискуссионными клубами.
года тренерские группы помогают многим компаниям найти более эффек
тивные способы работы, используя принципы и методы бережливого, гибкого про
изводства, такие как ХР и
DT А.
Диего Пачеко руководил сложными и масштабны
ми архитектурными и инженерными командами, руководствуясь принципами
SOA.
В своей работе он применял различные языки программирования с открытым
исходным кодом, такие как Java, Scala, Rust, Go, Python, Groovy, JavaScript и
TypeScript, пользовался услугами облачных сервисов, таких как А WS Cloud
и Google GCP, применял потрясающие решения, такие как Akka, ActiveMQ, Netty,
Tomcat и Gatling, базы данных NoSQL, такие как Cassandra, Redis, Elasticache Redis,
Elasticsearch, Opensearch, RabbitMQ, библиотеки, такие как Spring, Hibernate и
Spring Boot, а также стек NetflixOSS: Simian Army, RxJava, Karyon, Dynomite,
Eureka и Ribbon. Он реализовывал комплексные решения для обеспечения безопас
ности, используя А WS КМS, SЗ, Containers (ECS и EKs), Terraform и Jenkins. Более
десяти лет работал консультантом по программированию, дизайну и обучению
персонала у крупных заказчиков в Бразилии, Лондоне, Барселоне, Индии и США
(Кремниевая долина и Средний Запад). У Диего Пачеко есть страсть к функцио
нальному программированию и распределенным системам, базам данных
NoSQL,
к повышению наблюдаемости информационных систем и постоянному изучению
новых языков программирования.
В настоящее время работает главным архитектором программного обеспечения
в публичном облаке А WS,
Kubemetes/EKS,
выполняет сложные миграции в облако,
миграции библиотек и серверов, обеспечивает масштабную безопасность с помо
щью многоуровневых решений для шифрования с использованием
KMS
и SЗ, а
также нанимает, обучает, наставляет и развивает инженеров и архитекторов. В сво
бодное время любит проводить время со своей дочерью, играть на гитаре, зани
маться играми, программировать и вести блог.
16
■
Об авторах
Соавтор Сэм Сгро
опытный технолог, архитектор и руководитель инженеров
-
с многолетним практическим опытом. Сэм твердо верит в то, что сочетание логики
и здравого смысла с
правильными принципами может сделать мир лучше, и его
карьера бьmа направлена на то, чтобы, наилучшим образом применяя архитектуру
и инженерное дело, помогать людям решать сложные бизнес- и технологические
проблемы.
Раннее образование Сэма сочетало в себе как молекулярную биологию, так и ком
пьютерные науки. Он работал в проектах, охватывающих криптографию с откры
тым исходным кодом и высокопроизводительные вычисления. Постепенно перехо
дя от работы с
Solaris и Linux к разработке
программного обеспечения на
Java,
Сэм
присоединился к начинающему стартапу в области биоинформатики и анализа дан
ных и успешно перешел в
Thomson Reuters.
С тех пор Сэм возглавлял инженерные
и архитектурные подразделения в США, Канаде, Великобритании, Испании, Ин
дии, на Украине и в Бразилии, реализуя многомиллионные проекты по росту и
трансформации многих отраслей, включая фармацевтические исследования и ана
лиз академической литературы.
Главная страсть Сэма
-
решение проблем, разработка программного обеспечения
и помощь людям в поиске своего места в мире и раскрытии их истинных возмож
ностей. Сэму нравится предлагать интересные и инновационные технологические
решения, например на начальном этапе использовать стек из
ElasticSearch, находить
Netflix, Cassandra
и
способы творческого переноса технологий на А WS или соз
давать мобильные приложения, объединяющие мировые знания, на основе голосо
вой связи. Сэм любит бегать, ходить в походы и проводить время со своей семьей
и детьми, а также играть в видеоигры, когда позволяет время.
В настоящее время Сэм работает руководителем отдела архитектуры и потреби
тельского инжиниринга в финтех-компании, базирующейся в районе залива Бэй.
О рецензенте
Гарен Мвацакавов
-
директор по инжинирингу в финтех-компании в районе за
лива Бэй. Он имеет две степени бакалавра в области компьютерных информацион
ных систем и бизнес-администрирования. Гарен работал в большинстве технологи
ческих областей: разработка, тестирование, инфраструктура
DevOps,
продукты и
дизайн. Он по-прежнему остается практичным программистом. Гарен обладает
опытом создания сильных команд разработчиков продуктов и страстью к решению
сложных задач, классическим монолитам
(classical monolith)
и распределенным
монолитам в масштабе облака.
Посвящается Диего и Сэму
Я хочу поблагодарить вас за предоставленную возможность поработать техниче
ским редактором этой книги. Вы, ребята, в душе настоящие архитекторы про
граммного обеспечения, талантливые инженеры, лидеры и наставники. Темы, ана
лиз, тематические исследования, ссылки и подходы, которые вы приводите в этой
книге, бесценны. Эrа книга также о создании сильной инженерной культуры, по
зволяющей компаниям расти, добиваться успеха и масштабироваться с помощью
технологий, а не бьпь обремененными ими.
Моей маме Ларисе, моему папе Виктору, моей сестре Элине и моему замечатель
ному племяннику Арсену спасибо за вашу поддержку, самопожертвование и лю
бовь. И моей прекрасной жене Андреа, которая бьmа терпеливой, поддерживала и
воодушевляла меня с самого первого дня. Спасибо вам, и я люблю вас. Я уверен,
что вам эта книга понравится так же, как и мне.
Гарен, технический рецензент
Благодарности
Автор: Диего Пачеко
Спасибо, Господи, спасибо, Господи, спасибо, Господи! Я ценю все свои благосло
вения, я писал эту книгу с любовью, увлечением и большим трудом. Я хотел бы,
чтобы вы разделили мою страсть к архитектуре программного обеспечения, дизай
ну и решению сложных задач. Глубоко верьте в то, что вы можете оказать значи
тельное влияние на свою организацию, вырасти в карьере и как личность. Спасибо,
что купили мою книгу, я действительно ценю это. Я надеюсь, что мой опыт и
взгляды помогут вам в вашем путешествии. Неважно, являетесь ли вы архитекто
ром программного обеспечения, инженером-программистом, техническим менед
жером, DеvОрs-инженером, QА-инженером, фронтенд-инженером, директором,
вице-президентом или техническим директором.
Я испытываю глубокую страсть к технологиям, особенно к архитектуре программ
ного обеспечения. Мое увлечение стало возможным только благодаря огромной
поддержке моей любимой семьи, моей жены Андрессы и моей дорогой дочери
Клары. Мои дорогие друзья Маргарида, Адао, Израэль и Тейлс, Джун, Адриан, Тай
и многие другие друзья, имена которых здесь не указаны, но будьте уверены, что
в моем сердце для вас найдется место ... Бразилия!
Небольшая оговорка: эта книга не отра:жает идей, решений или мнений кого-либо
из моих прошлых uли будущих работодателей или клиентов за последние более
20 лет моего
опыта работы с распределенными и масштабируемыми система.ми,
работы в компаниях и в качестве консультанта.
Соавтор: Сэм Сгро
Идеи, изложенные в этой книге, были сформированы на основе более чем десяти
летнего практического опыта разработки архитектуры программного обеспечения
в масштабе различных команд, компаний и технологий. С первых дней совместной
работы в лондонском Грин-парке мы с Диего заложили основы для многих идей,
изложенных в этой книге; и мы рады поделиться ими с вами. Пусть они помогут
вам выполнять работу, которая вызывает у вас страсть и трепет.
Моим друзьям и родственникам в Канаде, США, Испании, Великобритании и Бра
зилии, и особенно моей любимой жене Клаудии и детям, Кэт и Эрике, спасибо за
ваше терпение и за то, что предоставили мне возможность проделать всю необхо
димую работу, чтобы эти идеи попали в печать.
Предисловие
Почему мы написали эту книгу?
Архитектура программного обеспечения
удивительная дисциплина, в которой
-
с течением времени появляется и выходит из моды множество стилей и форм. Не
которые стремятся к централизации, такие как
Blackboard
и монолиты; другие
фокусируются на распределении, например на управляемой событиями сервис
ориентированной архитектуре
которая дорога и согревает наше сердце),
микросервисах,
удаленном вызове процедур
(SOA,
Peer-2-Peer, REST или
(RPC).
Некото
рые стили хороши для систем принятия решений, например основанные на прави
лах; другие отлично подходят для параллелизма, такие как
Share-Nothing
и
Actor,
или ориентированы на многоуровневость, например клиент-серверная, многоуров
невая или компонентная. Некоторые стили хороши для обработки данных и дли
тельных фоновых задач, таких как
Архитектура
-
SEDA и
потоковая передача.
это круто, захватывающе, мотивирующе и согревает наши сердца,
но в ней есть и ловушки: плохие практики, мрачные антипаттерны и монолиты,
которые живут в самом сердце этой тьмы.
Как часто вы слышали жалобы от бизнеса или другого инженера на то, что система
ужасна, ее трудно поддерживать и она сдерживает нас? Как часто вы слышали от
бизнеса, что техническая организация работает медленно и не обеспечивает резуль
тат? Как часто вы слышали от инженеров, что они погрязли в технических долгах и
работают не так продуктивно, как могли бы?
Ответ кроется в архитектуре; плохая архитектура создала эти проблемы, а хорошая
архитектура их устранит. Возможно создать более совершенные системы, которые
можно поддерживать и которые являются разумными, масштабируемыми, соответ
ствуют надлежащим
принципам проектирования и архитектуры, а также удовле
творяют потребности бизнеса и желания инженеров. Вы можете взять свой торт и
съесть его. В этой работе нет ничего невозможного, но мы не будем лукавить: это
трудная, запутанная, нескончаемая битва, требующая чудовищной дисциплины и
внимания к деталям. Вы не сможете справиться с такой задачей без воодушевления
и страсти: ради себя, своих коллег, своей компании и работы, которую вы выпол
няете.
Мы написали эту книгу, чтобы поделиться своим увлечением и взглядами на общие
проблемы, с которыми сталкиваются компании во всех отраслях. Проблемы вклю-
20
■
Предисловие
чают техническую
задолженность,
отсугствие
правильных
принципов,
распреде
ленные монолиты, внуrренние общие библиотеки, миграцию кода и данных и дру
гие существенные сложности. Такие проблемы не новы; они существуют уже давно
и, вероятно, будуг актуальны до тех пор, пока люди или искусственный интеллект
будуг писать программное обеспечение.
Наша книга не даст вам простых ответов или волшебной формулы успеха; мы здесь
для того, чтобы заставить вас задуматься, провести анализ компромиссов и принять
максимально обоснованное решение. Если вы ищете волшебную палочку, способ
ную решить ваши задачи, то эта книга не для вас.
В нашей книге мы будем очень наглядны, поэтому приготовьтесь увидеть множе
ство рисунков, которые помогуг донести нашу мысль. Книга ориентирована на
Java,
но не перегружена кодом. Вы увидите несколько примеров псевдокода, но не
ожидайте, что приложения будуг созданы полностью. Это не учебное пособие.
Наша цель при написании книги
-
помочь вам полностью разобраться в пробле
мах, связанных с монолитами, и научиться правильно и эффективно их решать. Мы
поможем вам остановить кровотечение, разобраться в вашей реальности и проло
жить пугь к лучшим дням и более совершенным системам, используя надежные
архитектурные принципы и творческий подход.
В этой книге мы будем очень техничны и будем затрагивать множество различных
тем, но не волнуйтесь. Мы подробно объясним все с помощью большого количест
ва практических сценариев и примеров. Темы, которые мы будем освещать, разно
образны, и иногда мы будем рассматривать одни и те же вопросы с разных сторон,
чтобы раскрыть различные точки зрения. Мы надеемся, что вам понравится, и за
ранее благодарим вас за то, что вы с нами.
Читая эту книгу, вы можете рассчить1вать на:
♦
Примеры: практические примеры из нашего опыта в области технологий.
♦ Анализ компромиссов: архитектура
-
это прежде всего компромиссы, поэто
му ожидайте много сравнений плюсов и минусов.
♦ Рисунки: множество диа_грамм и рисунков, иллюстрирующих сценарии, ком
промиссы и варианть1.
♦
Разнообразие вариантов: мы предоставим несколько вариантов и наилучший
анализ, который поможет вам рассмотреть все проблемные области.
♦ Повторении: мы будем повторять некоторые принципы снова и снова, анализи
руя их в разных контекстах, чтобы найти новое понимание.
♦ Краткое содержание и усвоение: в каждой главе будет приведено краткое опи
сание того, что нужно запомнить из данной главы. Это длинная книга, и вам,
возможно, придется прочитать ее несколько раз; делайте заметки шобым удоб
ным для вас способом и отмечайте то, что вы считаете интересным или с чем не
согласны. (Авторам нравятся продуктивные разногласия!) Помните, что когда
вы просто пассивно читаете (вводите данные), вы узнаете не так много, как
в случае, когда вы создаете (выводите результаты). Вы можете написать сооб
щение в блоге, провести молниеносную беседу или презентацию для своих ин-
Предисловие
■
21
женеров или компании или поговорить с другом. Важно получить результат,
и мы считаем, что это лучший способ научиться чему угодно, и не только по
этой книге.
Однако в нашей книге не будет:
♦
Простых ответов: не существует волшебной формулы, которая исправит ваши
ошибки,
-
только варианты, которые помогут вам сориентироваться и усвоить
информацию для поиска своих собственных ответов. Никаких быстрых решений
ваших сложных проблем, только реальность.
♦
Инструкций: вы не найдете пошаговых инструкций по созданию приложений.
Это не учебное пособие.
Комплект кодов и цветных изображений
Пожалуйста, перейдите по ссылке, чтобы загрузить комплект исходников и ориги
нш~ьные цветные изобра:жения к книге:
https://rebrand.ly/x39a8ep
Набор исходных кодов программ для книги также размещен на
GitHub
по адресу
https://github.com/Ьpbpublications/Principles-of-Software-Architecture
Modernization.
В случае обновления кода он будет обновлен в существующем репозитории
GitHub.
У нас есть подборки кодов из нашего обширного каталога книг и видеоматериалов,
доступных по адресу https://github.com/Ьpb puЫications.
Ознакомьтесь с ними!
Цветные иллюстрации русской версии издания доступны для скачивания по ссылке
https://zip.bhv.ru/9785977521093.zip,
https://bhv.ru/.
а также со страницы книги на сайте
ГЛАВА
1
Что не так с монолитами?
Осознанность
-
это велики!! фактор перемен.
Экхарт Толле
Монолиты
(monolith) - это великий монстр в современной разработке программ
(software engineering). Разработчики соберутся у (виртуального)
ного обеспечения
костра, рассказывая страшные истории об ужасном настольном приложении для
Windows,
которое неделю простаивало из-за того, что
NM
зависала каждые
24
часа,
или о банковском приложении 1990-х годов, для выпуска которого требовалась
команда из
40
человек. У каждого из нас был коллега или друг, которому вы выра
жали сочувствие, когда он застревал в большом монолите и мечтал сбежать оттуда.
В поисках более совершенных решений люди переметнулись к микросервисам
(micro-
service).
Результат: проект по разработке программного обеспечения стоимостью в
8-9 мил
лионов долларов, сотни участников, половина функций отменена, и теперь прихо
дится обслуживать ДВЕ ужасные платформы, а не одну. Лекарство может оказаться
хуже болезни.
Позвольте нам стать теми, кто подарит вам надежду. Настоящую надежду. Ее мож
но найти не в следовании последним тенденциям в разработке программного обес
печения, а в реальной тактике, в реальном прогрессе, которые могут привести
к улучшению архитектуры программного обеспечения и качества жизни разработ
чиков, команд и предприятий по всему миру.
Но все начинается в этой главе. Понимание монолитов
-
ключ к глубокому осоз
нанию некоторых присущих им недостатков. В конце концов, не все так плохо, как
кажется. Понимая недостатки и преимущества монолитной архитектуры, вы смо
жете избежать распространенных ошибок и предложить реальные решения для
бизнеса и проектирования информационных систем.
■
24
Глава 1
Структура главы
В этой главе мы рассмотрим следующие темы:
♦ Что такое монолиты?
•
Большая кодовая база.
•
Несколько модулей развертывания.
•
Другие особенности монолита.
•
□
Централизация.
□
Неновый.
Имеет ли значение размер?
♦ Неувязки с монолитами.
♦ Шаблоны в разработке программного обеспечения.
•
Что такое антипаттерн?
♦ Жизнь с монолитами: антипаттерны, побочные эффекты и усилители.
•
•
Антипаттерны монолитов.
□
Высокая степень связности.
□
Неправильные абстракции.
□
Огсутствие изоляции.
Побочные эффекты монолитов.
□
Сложность развертывания.
□
Недостаточный уровень тестирования.
□
Огсутствие владельца.
□
Медленное внедрение новых технологий.
□
Медленный цикл разработки.
•
Автоматизация и антипаттерны.
•
Усилители.
□
Разбитые окна/ копирование и вставка.
□
Зависть к микросервисам.
□
Нехватка квалифицированных специалистов.
□
Страх перемен.
♦ Все ли монолиты плохие?
•
Монолиты
-
это форма архитектуры программного обеспечения.
♦ Преимущества монолитов.
•
Влияние рефакторинга и изменений.
•
У прощение некоторых миграций.
Что не так с монолитами?
♦
♦
•
Хорошая отправная точка.
•
Упрощенная инфраструктура.
■
25
Типы монолитов.
•
Классические, распределенные и модульные монолиты.
•
Модульные монолиты: хороший вид монолита.
•
Модульные монолиты:
•
Модульные монолиты: мобильные суперприложения.
Istio.
Можно ли избежать плохих монолитов?
♦ Что нужно запомнить.
Что такое монолиты?
Во-первых, нам нужно глубоко разобраться в монолитах, чтобы бороться с ними.
В противном случае, с чем мы боремся? Как мы узнаем, что побеждаем? Как вы
можете определить успех? Монолиты
-
очень распространенная тема в индустрии
программного обеспечения. У каждого есть свое определение того, что такое моно
лит, и множество предубеждений. Однако нам нужно начать с общего понимания.
Следовательно, нам нужно дать определение монолиту. Итак, что же такое моно
лит? Что приходит вам на ум, когда вы думаете о монолите?
Чтобы ответить на этот вопрос, обратитесь к рис.
1.1, на
котором изображены неко
торые монолиты.
Пользовательский интерфейс (UI}
Профиль
Продажи
Отчеты
База данных (Бд}
Источник:
Рис. 1.1. Монолиты.
https://en.wikipedia.org/wiki/List_of_works_similar_to_the_2020_Utah_monolith
Что общего у всех этих изображений? На первых рисунках мы видим большие бло
ки, которые трудно перемещать и в которых нелегко разобраться. Мы видим те же
черты, когда дело доходит до кода.
Монолиты
-
это стиль архитектуры программного обеспечения, при котором
большой объем кода развертывается с использованием небольшого количества мо-
26
■
Глава 1
дулей, таких как ехе,
JAR, WAR
и т. д. Короче говоря, большая кодовая база с не
сколькими артефактами развертывания. Это естественное состояние при разработке
большинства приложений на начальном этапе: наличие всего кода в одном репози
тории
и
модуле развертывания упрощает жизнь,
когда поиск продукта,
нужного
рынку, важнее преждевременной оптимизации.
Большая кодовая база
В монолитах обычно содержится много кода. Он может храниться в одном или
нескольких
репозиториях
с
исходным
кодом
для
некоторых
типов
монолитов,
о которых мы поговорим позже. Но ВСЕГДА задействовано много кода. Конечно,
«большой»
-
относительное понятие. Большие кодовые базы
(codebase)
сами по
себе не являются проблемой, так же как и маленькие. Но они встречаются доста
точно часто, чтобы стать ключевой характеристикой монолита.
Иногда монолиты могут быть большими и в других отношениях. Монолитные при
ложения могут быть довольно сложными с множеством функций и часто требуют
больших команд. Активное управление монолитом требует больших ресурсов
(и храбрых сердец!). У монолитов может быть множество пользователей, а может и
не быть, или для достижения своих целей они могут нуждаться в значительных вы
числительных ресурсах. Однако монолиты всегда обладают крупными и сложными
кодовыми базами.
Несколько модулей развертывания
Когда мы создаем и выпускаем программные решения, то часто применяем для
этого специальные системы. Мы используем инструменты управления версиями
кода, такие как
Git.
У нас есть средства для отслеживания ошибок, мы фиксируем
требования и потребности в ЛRА-тикетах Кроме того, мы умеем организовать ра
боту людей для преобразования потребностей в решения, часто с помощью гибких
и бережливых (lean) методов разработки, таких как Scrum, ХР, Kanban и
многие другие. Команды используют эти и многие другие системы, чтобы разбить
(agile)
свою работу на более мелкие и понятные части.
Однако все эти разнообразные процессы формируются в монолит по своей природе
из-за одного простого факта: монолиты, как правило, имеют немного модулей раз
вертывания 1 (deployment unit), вплоть до того, что представляют собой всего лишь
один массивный бинарный файл. Представьте себе большой исполняемый файл для
настольного приложения
Windows
или
JAR или WAR
на
Java2 •
Модуль развертывания определяет, как приложение устанавливается в рабочей среде, обычно на сервере.
Java он может быть файлом EAR, WAR или JAR. Для приложения Windows это может
быть файл .ЕХЕ, для библиотеки С++ в Linux это может быть файл .so.
1
Например, в случае
2
Хотя здесь мы говорим «двоичный», поскольку программное обеспечение часто создает артефакты ском
пилированного кода, но для некоторых языков это также может быть обычный текстовый код, интерпрети
руемый во время выполнения. В данной книге мы часто будем ссылаться на двоичные файлы, поскольку
часто эти артефакты сжимаются или иным образом проходят большую часть жизненного цикла развертыва
ния в виде двоичного файла. Но учитывайте особенности различных языков, которые описываются в нашей
книге.
Что не так с монолитами?
■
27
Наличие одного или нескольких крупных артефактов естественным образом при
водит к необъятному процессу подготовки и тестирования модуля развертывания.
И этот процесс реализуется независимо от того, вносит ли команда изменения
в одну строку кода или в масштабную функцию. Для работы по-прежнему привле
кается та же армия разработчиков и тестировщиков, потому что все необходимое
находится в одном пакете артефактов (или чуть больше), содержащем всё прило
жение целиком.
Здесь вы можете увидеть отличный пример того, как архитектура программного
обеспечения формирует организационную структуру компании. Структура и ди
зайн влияют на способ реализации той или иной задачи и возможных исполните
лей. Как архитектор вы можете думать, что ваша роль ограничивается программ
ным обеспечением, его кодом и тем, как оно структурировано и развернуто. На са
мом деле ваши системы формируют структуру компании и лежат в основе
способности организации к масштабированию. Компания выберет безопасный
путь, и если ваша архитектура подразумевает, что безопасный путь к выпуску кода
требует, чтобы все команды работали день и ночь над выпуском, отладкой и после
дующим исправлением вашего монолита в указанном порядке
... ваша организация
- отличный инст
будет это делать. Это не самое радостное занятие. Архитектура
румент, который способствует или препятствует работе. Даже такая простая вещь,
как «мое приложение развернуто
15
командами, обновляющими один
WAR
в про
цессе производства», может привести к сбоям в работе и страданиям ... страданиям,
которые только вы можете исправить 3 •
Другие особенности монолита
Монолиты, как правило, большие и имеют мало модулей развертывания. Но у них
есть и другие часто встречающиеся характеристики. Хотя эти характеристики не
являются гарантией монолитной архитектуры, они настолько часто встречаются
в монолитах, что становятся тесно связанными с ними.
Если вы столкнулись с подобным, скорее всего, вы имеете дело с монолитом. Мы
называем подобные моменты «запахом». Термин «код с запаmком» 4 (code smell)
был введен Кентом Беком в конце 90-х годов. Код с запашком
- это то, что может
привести к более серьезной проблеме. В контексте монолитов запахи более ковар
ны, они могут указывать на неисправность или симmом, а не на первопричину, а
проблема может быть в чем-то другом.
Централизация
Монолиты предпочитают централизацию
(centralization), когда все функции, кон
фигурации и тесты собраны в одном месте. Проще говоря, весь наш код будет вы
полняться на одном компьютере, как в настольном приложении. Весь наш код раз
вертывается совместно и использует только один компьютер для обеспечения всех
3 Используйте
4
инструменты, описанные в этой книге!
Концепция кода с запашком бьша популяризирована в книге «Рефакторинr», написанной Мартином Фау
лером в
1999 году.
В главе
3
Кент Бек написал эссе о коде с запашком
(https://wiki.c2.com/?CodeSmell).
28
■
Глава 1
возможностей, необходимых вашему бизнесу. Все функции, возможности и со
трудники будут использовать одни и те же ресурсы: процессор, память, диск и сеть.
Противоположностью
централизованных систем являются распределенные,
при
которых все разделено. Представьте себе архитектуру микросервисов, в которой
ваше программное обеспечение выполняется на нескольких компьютерах, получая
доступ к ресурсам, таким как базы данных или конфигурации, которые также нахо
дятся на других устройствах.
Плоха ли централизация по своей сути? Если бы это было та~<, у нас было бы про
стое решение: разделить кодовую базу. Давайте внедрим микросервисы и разделим
наш монолит на множество частей. Монолит исчез бы, и наша проблема была бы
решена. Используя архитектуру в стиле микросервисов
architecture, MSA),
(Microservices style of
мы отказываемся от централизации и переходим к распределе
нию. Мы перешли от одной крайности к другой. Но действительно ли этот подход
решил все наши проблемы? На следующем рисунке (рис.
1.2)
показан спектр меж
ду централизацией и распределением.
Монолиты
Централизации
Рис.
1.2.
Микросервисы
, ...
Распределение
Спектр от централизации до распределения
Микросервисы распределены, но могут совместно использовать элементы, кото
рые, по сути, позволяют им оставаться централизованными. Внутренние общие
библиотеки, скрытые контракты, общие базы данных. Если вы взглянете глубже,
т. е. за пределы развернутых артефактов, рассмотрите все компоненты вашей сис
темы, сможете ли вы убедиться в том, что все они должным образом изолированы и
по-настоящему распределены? Или это глубоко централизованная система, просто
маскирующаяся под распределенную? Мы обсудим это позже в нашей книге.
Соотношение централизации и распределения не означает «все или ничего». Одна
ко в случае микросервисов вы больше склонны к распределению, чем к централи
зации. Монолиты больше склонны к централизации. Некоторые монолиты, скажем,
«классические» монолиты, почти полностью централизованы. Но у более совре
менных монолитов также есть распределенные элементы. По правде говоря, моно
литы могут находиться в различных точках этого спектра.
Но пока давайте все согласимся с тем, что монолиты имеют тенденцию к централи
зации.
Неновый
Монолиты не только большие, но и часто не новые. В конце концов, на сбор ин
формации о местоположении и наборе функций может уйти много времени. Ко
нечно, здесь есть определенный разброс: огромной команде может потребоваться
всего
2
года, чтобы накопить миллионы строк кода, или
вище накопило новые возможности с течением времени.
20 лет,
чтобы старое чудо
Что не так с монолитами?
■
29
Старое программное обеспечение не обязательно является устаревшим. Большей
части программного обеспечения, на котором основаны интернет-компании, уже
несколько десятилетий. Тем не менее оно стабильно, проверено в бою и «просто
работает»: вспомните
Linux,
реляционные базы данных, такие как
Postgres, Java,
и многие другие решения с открытым исходным кодом. Но из-за древнего про
граммного обеспечения часто бывает трудно найти разработчиков, обладающих
опытом работы с такими языками или фреймворками.
Таким образом, хотя монолиты часто бывают не новыми, они не всегда такие уж
и устаревшие.
Имеет ли значение размер?
Микросервисы
-
это архитектурный стиль, который часто противопоставляется
монолитам, как показано на рис.
1.2.
Микросервисы представляют собой независи
мо развертываемые сервисы, крошечные с точки зрения ответственности и детали
зации
(granularity),
что прямо противоположно крупным решениям с большим ко
личеством функций (таким как монолиты).
Возможно, в реальной жизни вы слышали следующее утверждение: «Микросервис
лучше монолита! Первый из них маленький, а второй большой, и проблема в этом
большая! Дело закрыто!».
Но ответ на этот вопрос гораздо сложнее. Действительно ли малый размер хорош,
зависит от потребностей проекта.
В реальном мире сложность всегда должна где-то присутствовать. Чтобы иметь
ценность, сервис обязан обеспечивать функциональность, доступную через абст
ракции. В зависимости от природы этих абстракций, не всегда возможно свести все
к минимуму и добавить необходимую ценность с помощью нескольких строк кода.
Короче говоря, наличие обширной базы кода внутри одного сервиса не обязательно
означает, что он ужасен.
Хотя наличие «большого» сервиса может быть проблемой, при проведении любой
оценки предлагаемого дизайна или существующей архитектуры важно учитывать
и другие аспекть1 решения. И для этого вы должны задать следующие вопросы.
♦ Насколько сложно инженерам поддерживать решение в рабочем состоянии?
♦ Как часто члены команды создают ошибки при внесении простьJХ изменений
в код?
♦ Проводятся ли модульные, интеграционные или сквозные тесты? Стабильно ли
они выполняются? Автоматизированы ли они?
♦ Надежен ли дизайн/архитектура и хорошо ли они подходят для предметной об
ласти, легко ли добавляются новые функции без существенных изменений или
требуют участия нескольких команд и межкомандной координации?
♦ Можете ли вы легко разобраться в коде и понять, что происходит?
♦ Можете ли вы легко отлаживать решение? Можете ли вы быстро выявлять про
блемы и тестировать отдельные части приложения независимо друг от друга?
■
30
Глава 1
♦ Автоматизирован ли процесс выпуска нового релиза? Сколько ручной работы
требуется для создания, тестирования и развертывания решения?
Можно бьmо бы возразить, что в целом мы говорим о технической задолженности,
и это правда! Размер часто ассоциируется с проблемами, потому что, когда у вас
увеличивается количество сотрудников, координация становится сложнее, поддер
живать высокую планку технического качества, как правило, сложнее, и под давле
нием необходимости выпускать новые функции команды идут на компромиссы.
В этом смысле размер имеет значение: чем больше людей, тем больше изменений,
больше возможностей, тем больше технических проблем накапливается. Однако
дело
не только в размере
-
качество, как правило,
снижается,
когда множество
людей работают с одной и той же базой кода в сочетании с низким или нулевым
уровнем владения кодом.
Монолиты велики по своим размерам, и поскольку размер коррелирует с количест
вом задач, легко запутаться и сказать: «Монолиты
-
это проблема, потому что они
большие». Более того, крупные проекты, как правило, имеют большую техниче
скую задолженность независимо от того, являются ли они монолитными или нет.
Если перейти к другой крайности (рис.
1.3),
то при использовании распределенной
системы может показаться, что проблема волшебным образом исчезнет. Однако
сложность, присущая вашему решению, не изменилась. Изменение сложности мо
жет быть связано с переходом на другой уровень обслуживания, упрощением поль
зовательского интерфейса, с добавлением агрегирующего слоя для базы данных
или клиентской части. Но эта сложность должна быть реализована в какой-то форме.
Какой размер является идеальным?
Возможно, вы делаете слишком
много
== Высокая степень связности
Сложность переносится
в другое место
Большой/Крупный
Рис.
1.3.
МаленькийЛv!икро
Спектр размеров систем
Мы бы сказали, что нет однозначного правильного или неправильного ответа на
вопрос о размере решения, но необходимо осознавать риски. Если решение слиш
ком крупное, то вы рискуете возложить на себя слишком много ответственности
или функций или связать элементы, которые не должны быть связаны. Если же
решение слишком маленькое, вы можете пойти на неправильный компромисс
в организации его сложности 5 , что приведет к проблемам координации между ко
мандами, технической задолженности и замедлению развития компании.
Короче говоря, оценка влияния размера на архитектуру программного обеспече
ния
5
-
это комплексное решение. Это не просто вопрос о том, что «монолиты
Джон К. Остерхаут во 2-м издании книги «Философия разработки программного обеспечения>> определяет
сложность как степень неясности:
https://www.amazon.com/Philosophy-Software-Design-2nd-ebook/dp/В09B8LFKQL.
Что не так с монолитами?
большие, а большой
■
31
это плохо». По мере изучения данной главы вы увидите не
-
которые компромиссы на практике, а в главе
6
«Принципы надлежащего предос
тавления сервисов» мы изучим искусство подбора сервисов оптимального размера.
Неувязки с монолитами
Теперь, когда мы определили монолит, каковы последствия наличия монолита? Как
он влияет на систему, дизайн и организацию?
Разработка программного обеспечения
-
дело непростое, и сегодня как никогда
актуально утверждение, что каждая компания занимается разработкой программно
го обеспечения. Итак, независимо от отрасли и реальности вашей компании, руко
водители вашего бизнеса возлагают определенные надежды на программное обес
печение, которое вы разрабатываете и/или которым управляете. И, в свою очередь,
когда эти ожидания
(expectations)
не оправдываются, мы снова и снова сталкива
емся с одним и тем же негативным восприятием, независимо от того, имеете ли вы
дело с унаследованными монолитами или нет и насколько они соответствуют дей
ствительности.
Итак, давайте начнем с того, чего компании ожидают от технологий (табл.
1.1).
И как обстоят дела, когда их требования не выполняются?
Таблица
Ожидание
1.1. Ожидания бизнеса в сравнении с восприятием
Восприятие
Лучший пользовательский
Сложное и труднодоступное для пользователя программное
опыт
обеспечение
Инновационные решения
Старые технологии, отсутствие дифференциации, едва
для клиентов
работающие решения, проблемы со стабильностью, слишком
много багов
Короткое время вывода
на рынок (или время
Медленно, всегда не вовремя, дорого, преподносит неприятные сюрпризы, на него трудно положиться. Такое ощущение,
выполнения заказа)
что техническая организация не хочет совершенствоваться.
Следует ли нам передать технологии на аутсорсинг или вме-
сто этого создать теневую ИТ-компанию?6
Разумные предсказуемые
Высокие затраты на техническое обслуживание. Огромные,
затраты на техническое
скрытые, непредсказуемые и растущие эксплуатационные
обслуживание и эксплуатацию
расходы
Аналогичным образом у технологических организаций (табл.
1.2)
по всему миру
есть свои ожидания. Инженеры стремятся внести свой вклад в развитие бизнеса
или своей карьеры, и у них есть представление о коде и возможных технологиче
ских решениях ... даже если их идеи могут стать источником проблемы.
Когда такое негативное восприятие управляет взаимодействием между технологией
и бизнесом, это никому не идет на пользу и создает менталитет «мы против них».
6
Определение теневой ИТ-компании: https://en.wikipedia.org/wiki/Shadow_lТ.
32
■
Глава 1
Таблица
1.2. Технологические ожидания в сравнении с восприятием
Ожидание
Восприятие
Технологическая свобода
Отсутствие доверия. Отсутствие гибкости, трудности
с внедрением новых идей или свободным изменением кода.
Такое ощущение, что бизнес не хочет улучшаться
задачи, требующие решения
Скучные задачи. Выматывающая борьба с техническими проблемами, которые затрудняют соэдание ценностм для бизнеса
Работа в стабильных
Огромный технический долг, огромное количество негативных
Захватывающие и сложные
и разумных системах
практик, антипапернов, отсутствие тестирования, нехвап:а
талантов, удушение огромной бюрократией. Вое это сильно
подрывает моральный дух. Стоит ли мне искать новую работу?
Эта реальность может возникнуть независимо от того, есть у вас монолиты или нет,
не важно в каком программном обеспечении или отрасли вы работаете. Или даже
независимо от истины: восприятие может управлять реальностью, а фиксированное
мышление может ограничивать рост и изменения.
Мы описываем подобное здесь, потому что это ключ к пониманию того, как моно
литы могут нанести ущерб организациям. Дело в том, что монолиты приводят
к антипаттернам
(anti-pattem)7
и нежелательным явлениям и подвержены усили
вающимся эффектам, которые еще больше усугубляют эти проблемы:
♦ Тестирование занимает слишком много времени, часто не полностью автомати
зировано и не имеет идеального покрытия.
♦ На внедрение изменений уходит слишком много времени
-
больше, чем следо
вало бы.
♦
Много времени уходит на отладку, устранение неполадок и борьбу с техниче
ским долгом вместо того, чтобы приносить пользу бизнесу.
♦ Миграция библиотек, фреймворков и инструментов выполняется очень сложно
и болезненно.
♦ Существует страх вносить изменения в код из-за неудачных попыток в про
шлом.
♦
Эмоциональное выгорание и низкий моральный дух разработчиков.
♦
Благоприятная среда для антипаттернов и технических долгов, которые не
устраняются, а увеличиваются со временем.
Сейчас мы обсудим каждый из этих элементов более подробно. Но еще раз под
черкнем, что ключевое значение имеет правильная архитектура. Она может способ
ствовать формированию правильной культуры, внедрению деловых и технологиче-
7
Антипаrrерн (англ. anti-pattem) -
это распространенный подход к решению класса часто встречающихся
проблем, являющийся неэффективным, рискованным или непродуктивным. В отличие от шаблона проекти
рования, рассмотрение антипаrrерна включает в себя как неправильное решение проблемы с его признака
ми и последствиями, так и выход из ситуации.
-
Пер.
Что не так с монолитами?
■
33
ских инноваций и обеспечить наличие мотивированных и способных разработ
чиков.
Шаблоны в разработке
программного обеспечения
Прежде чем мы поговорим об антипаттернах
давайте вкратце опи
(Anti-Pattem),
шем шаблоны проектирования. Шаблоны проектирования в объектно-ориентиро
ванном программировании (ООП,
ООР) существуют
Object Oriented Programming,
с 90-х годов. Они были изначально представлены в книге «Шаблоны проектирова
ния
-
элементы повторно используемого объектно-ориентированного программ
ного обеспечения» 8 .
Шаблоны проектирования
это набор часто встречающихся шаб
(Design Pattem) -
лонов в архитектуре программного обеспечения, описывающих типичные структу
ры и проекты и предоставляющих набор общих слов и концепций для облегчения
коммуникации. Шаблоны 9 делятся на
3
группы: творческие, структурные и пове
денческие. Они стали очень популярны в таких языках, как
Оригинальная книга банды четырех содержит
23
Java,
С++ и
Smalltalk.
классических шаблона, но в раз
работке программного обеспечения существуют сотни шаблонов. Их обзор приве
ден на рис.
1.4.
Священные элементы веры
божественное
божественная
происх ождение
структура
"'
FM
f''""'"'
........
117
11r
..
.,
.,
,_..
™
17)
CD
и
......
ш
),J
fulf4"
8
1.4.
МD
,..,
JCS
,,,,
о
IN
'"
СР
"'
D
..
Сt~,ф,СК,Ь:
о.с., ьw
'""
1&;
••s
111
FA
РХ
о-
u,
))
IT
........
BU
Рис.
R
ci..,.t
поведение
ш
_....,
т
божественное
s
РТ
AF
..........
.....
А
.....
BR
·f~ ...
Периодическая таблица Винса Хадсона - шаблоны проектирования.
Источник: http://www.vincehuston.org/dp/
Книга опубликована в 1994 г. и написана легендарной «бандой четырех» Эрихом Гаммой, Ричардом Хел
мом, Ральфом Джонсоном и Джоном Влиссидесом. Книги «банды четырех» являются одними из самых
важных в области архитектуры программного обеспечения, и их принципы не утратили своей актуальности
даже спустя три десятилетия после выхода.
9
Концепция шаблонов проектирования была в значительной степени вдохновлена книгой Кристофера
Александера «Язык шаблонов
-
города, здания, строительство». опубликованной в
1977
году.
■
34
Глава 1
Определение шаблона очень интересно: каждый из них обладает контекстом, опи
сывающим
конкретное
намерение,
цель
и
мотивацию,
лежащие
в
основе
этого
шаблона. Каждый из них имеет специфические структуры, которые проявляются
в сочетании объектно-ориентированного кода с практическими примерами его ис
пользования.
Шаблоны полезны тем, что при правильном применении они ускоряют обсуждение
и снижают когнитивную нагрузку: в конце концов, код читается гораздо чаще, чем
пишется. Однако, применяя шаблоны проектирования без какой-либо необходимо
сти или используя их неправильно, мы создаем технические проблемы.
Что такое антипаттерн?
В
1995
году Эндрю Кениг ввел термин «антипаттерн»
Антипаттерн
-
(Anti-Pattem)1°:
это то же ca.Atoe, что шаблон, за исключением того, что
вместо решения он выдает нечто, что внешне выглядит как решение, но тако
вым не является.
Подобно
шаблонам
проектирования
антипаттерны
представляют
собой
часто
встречающиеся способы решения проблемы, которые явно усугубляют ее. Анти
паттерны приводят к техническому долгу и дополнительной ненужной сложности
при решении проблем. Преимущество четкого определения этих антипаттернов за
ключается в том, что мы также можем определить лучший шаблон, который может
быть применен, и, следовательно, найти лучшее решение.
Жизнь с монолитами: антипаперны,
побочные эффекты и усилители
Жизнь с монолитами означает мир проблем, где кодовой базой правят антипаттер
ны,
побочные
а усилители
эффекты
(amplifier)
затрудняют
прогнозирование
последствий
изменений,
подкрепляют и еще больше распространяют негативные по
следствия.
Антипапернымонолитов
Поскольку монолиты являются крупными, как правило, старыми, имеют мало мо
дулей развертывания и стремятся к централизации, в них часто встречаются неко
торые антипаттерны.
Социологические и промышленные факторы также приводят к появлению общих
антипаттернов, таких как цифровая трансформация, переход к публичному облаку,
бимодальные ИТ, гибкие методы разработки и многие другие движения. Мы не го-
10 Подробный обзор смотрите на странице Мартина Фаулера, посвященной антипаттернам:
https://martinfowler.com/bliki/ AntiPattern.html.
Что не так с монолитами?
■
35
ворим, что эти движения обязательно плохие. Иногда компании используют подоб
ные изменения в качестве побудительных факторов для развития бизнеса, привле
чения инвестиций и обоснования более масштабных изменений. Независимо от
мотивации, эти процессы приводят к масштабным инвестициям и дорогостоящим
миграциям, требующим быстрых результатов. Когда вам необходимо внести суще
ственные технологические изменения и ускорить развитие вашей организации, а
количество квалифицированных специалистов не идеально, у вас есть формула
решения проблем. В то же время, какую ценность вы приносите бизнесу? По сути,
для бизнеса вы просто тратите много капитала без видимой отдачи.
Таким образом, хотя эти антипатерны не являются специфичными для монолитов,
их находят так часто потому, что так уж монолиты устроены, что ассоциируются
с ними. Короче говоря, особенности монолитов часто приводят к возникновению
этих антипаттернов.
Высокая степень связности
Связность
(Coupling)
можно рассматривать как характеристику того, как много ин
формационные и программные зависимости знают друг о друге. Связность
положительное качество,
-
это
необходимое для работы программного обеспечения.
Компоненты должны быть подключены, ваш пользовательский интерфейс должен
вызывать сер верную часть, которая должна вызывать вашу базу данных ... связность
неизбежна.
Но вам нужны правильные границы. Ваш пользовательский интерфейс не должен
быть осведомлен о схеме вашей базы данных, и ваш серверный интерфейс не дол
жен быть необходим для предоставления правильно сформированного
вам не удается очертить эти границы
-
CSS 11 •
Когда
заключить четко определенные, редко из
меняемые соглашения о коммуникациях и действиях
-
изменение компонентов
может иметь серьезные и неожиданные последствия.
Когда компоненты связаны друг с другом без необходимости, мы называем это
явление высокой степенью связности
(high coupling),
и монолиты
-
идеальная
площадка для создания кошмара высокой степени связности.
Монолиты создают множество соблазнов и приманок, которые могут привести ко
манду к высокой степени связности
цов, код находится
в одном
месте:
-
обзор представлен на рис.
команды
1.5.
В конце кон
имеют доступ к чтению внутренних
методов и общедоступных классов. После всего лишь одного быстрого изменения
эта функция заработает, и вы станете героем бизнеса! Но было ли изменение оце
нено на корректность? На долговечность? Следовало ли вообще использовать эти
методы? Монолиты разрушают барьеры и легко позволяют принимать такие ужас
ные архитектурные решения, создавая болота с высокой степенью связности, кото
рые вызывают у инженеров ночные кошмары.
11
CSS, cascading style sheets -
Пер.
каскадные таблицы стилей, язык описания внешнего вида веб-страницы. -
36
■
Глава 1
Проверка
Проверка
Проверка
о~етов
конфигурации
продаж
Дублирование кода.
Одна и та же проверка выполняется в 3 разных модулях.
Но каждый модуль на 100% не связан .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . ' .................................. .
Низкая связность между общими проверками и модулями.
Но каждый модуль на
100% не связан.
Лучший вариант на данный момент ...
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . · : ...................................
'
Благие намерения со временем загнивают ...
Высокая степень связности между общими проверками
и модулями.
Проверки проводятся в обоих местах,
а модули связаны друг с другом.
+
Здесь нет преимуществ
Бизнес-логика
для всех модулей
Рис.
-
только сложность
и технологический долг.
1.5.
Высокая степень связности в монолитах
Неправильные абстракции
Возвращаясь к шаблонам проектирования, можно сказать, что существует целый
ряд эффективных способов решения конкретных задач. Путей, с помощью которых
вы сопоставляете контекст проблемы с ее решением. Антипаттерны по своей сути
описывают способы, с помощью которых, как нам кажется, мы подобрали правиль
ный шаблон для решения проблемы, но на самом деле мы только усугубили ситуа
цию. Короче говоря, наш антипаттерн «неправильные абстракции» на самом деле
относится к общему случаю, когда мы неправильно применили шаблон проектиро
вания.
Давайте возьмем простой пример.
Инженер видит код в одной части монолита и понимает, что ему нужно использо
вать этот код в совершенно другой части. «Нет проблем»,
ное использование кода
-
-
думает он.
-
Повтор
отличная вещь, поэтому позвольте мне создать многора
зовый метод». (Вероятно, в утилитарном классе 12 util, содержащем около
1ООО
дру
гих подобных методов.) Оба экземпляра указывают на этот общий метод: отлично,
проблема решена.
За исключением того, что все оказалось не так однозначно. Со временем другой
инженер столкнулся с запросом функции, который затрагивает этот код, и внезапно
столкнулся с проблемой: для первой реализации нужна одна версия первого мето
да, а ко второй теперь предъявляются другие требования. Поэтому они решили
пойти дальше и модифицировать общий метод, снова подумав о том, что повторное
использование кода
12
Утилитарный класс -
-
это наивысшее благо, а значит, лучший выбор.
это класс-помощник, содержащий статические переменные и статические методы,
которые выполняют определенный перечень задач, объединенных одним смыслом.
-
Пер.
Что не так с монолитами?
Теперь перенесемся на несколько лет вперед
■
помните, монолиты устарели!
-
37
-
и увидим множество других примеров той же проблемы, с которой сталкивались
разные инженеры. Внезапно у вас появляется утилитарный класс и метод длиной
в тысячи строк, который излишне сложен и вызывает страх при необходимости из
менений. И все потому, что инженер решил, что повторное использование кода
-
это самое важное.
Возможно, мы несправедливы к этому инженеру
в конце концов, почти неиз
-
бежно, что некоторые из наших правильных решений со временем могут оказаться
ошибочными. Но это наглядный пример того, когда попытка принудительно по
догнать абстракцию
-
новый общий метод
-
некорректна и не удается распо
знать, что два случая, которые вы пытаетесь абстрагировать, не совпадают.
В монолитах чаще встречаются неправильные абстракции, поскольку у них нет
четких границ
-
общий обзор представлен на рис.
1.6.
Благодаря тривиальной
возможности повторного использования кода, как в нашем примере с высокой сте
пенью связанности, легко взглянуть на реализацию и «принудительно подогнать»,
абстракцию, которая неприменима. Неправильная абстракция может проявляться
в различных формах, например в отсутствующих или негерметичных абстракциях,
в которых не соблюдаются границы, как показано на рис.
1.6.
Классы обслужива
ния отвечают за сохранение бизнес-правил. Объекты доступа к данным
Access Objects,
(Data
ОАО) должны обеспечивать сохраняемость и доступ к данным.
Здесь не применяются никакие правила, что плохо, и границы не соблюдаются.
Прямой вызов объекта доступа к данным является неправильной абстракцией, по
скольку он пропускает бизнес-правила и создает высокую степень связности.
Отчет
Сервис
Сервис
о прогнозе
профилей
продаж
Объект доступа
Объект доступа
к данным
к данным
профилей
продаж
Рис.
1.6.
Неправильная абстракция
Микросервисы могут страдать от тех же проблем из-за концепции внутренних об
щих библиотек, которую мы рассмотрим более подробно в главе
4
«Антипаттер
ны: внутренние общие библиотеки».
Отсутствие изоляции
Изоляция
-
это ключ к быстрому развитию. Если вы хотите, чтобы несколько ко
манд работали параллельно, и хотите обеспечить безопасность при одновременном
38
■
Глава 1
внедрении сотен изменений, вам необходима изоляция. Изоляция
-
это основа
безопасности, скорости и всего, что нужно бизнесу и технологиям. Хотя высокая
степень связности
-
это одна из форм, при которой монолиты могут способство
вать отсутствию изоляции, этих форм гораздо больше. Вы узнаете о них в следую
щей главе (глава
2 «Антипаттерн:
отсутствие изоляции»).
Побочные эффекты монолитов
-
Как только у вас появляются три ключевых антипаттерна
ности, неправильные абстракции и недостаточная изоляция
высокая степень связ
вы сталкиваетесь
-
с разрушительными последствиями.
Сложность развертывания
Некоторые проблемы не связаны с противодействием шаблонам, созданным непра
вильной культурой или предыдущими техническими решениями, а присущи архи
тектурной модели монолитов. Одной из них является сложность развертывания, а
также повсеместные трудности со стабильностью и частые перезагрузки.
Вернемся к основным принципам: за исключением языков или фреймворков, кото
рые допускают быстрое или частичное развертывание, как правило, вам необходи
мо устанавливать монолит как единое целое (рис.
1.7).
Вы не можете безопасно
устанавливать элементы или обновлять фрагменты монолита независимо друг от
друга, что является следствием централизации и небольшого количества модулей
развертывания. Все команды настроены на развертывание как в непроизводствен
ном, так и в производственном режиме, ожидая подтверждения того, что внесенные
ими изменения присутствуют и работают должным образом.
Развертывание
+ перезагрузка
Приложение версии
Приложение версии
2
1
в промышленной
эксплуатации
Рис.
1.7.
Недостатки монолита: развертывание+ перезагрузка
Необходимость развертывать программный элемент как законченный элемент по
своей сути не является чем-то плохим. Вы хотите избежать простоев и, как следст
вие, отсутствия доступности приложений.
Простоя классических монолитных систем, особенно серверных сервисов, иногда
можно избежать. Для обеспечения высокой доступности, как правило, существует
несколько экземпляров сервиса, распределенных по физической инфраструктуре,
например в компании
Amazon
используют веб-сервисы
(Amazon Web Services,
Zones, AZ) путем развертыва
применять такие методы DevOps,
А WS), использующие зоны доступности (Avai\aЬility
ния по одному экземпляру на зону. Это позволяет
Что не так с монолитами?
как
Blue/Green,
когда
развертывание,
последовательное
узле 2А, потом на узле
28,
сначала
выполняется
■
установка
39
на
а затем на узле 2С. Также можно использовать режим
при котором программное обеспечение хранится в скрытом пуле, пре
жде чем оно будет переведено в статус реального экземпляра. И то и другое позво
ляет сократить время простоя при развертывании.
Реальная проблема, затрудняющая развертывание и неизбежно приводящая к про
стоям, относится к более серьезному препятствию: антипаттерн отсутствия изоля
ции, который мы обсуждали ранее (рис.
1.8).
В монолитах с их высокой степенью
связанности скрытые взаимосвязи делают любое изменение рискованным, что при
суще отсутствию изоляции сбоев
(failure isolation).
Каскадный сбой очень опасен.
Например, ваш модуль оперативной или аналитической отчетности может вывести
из строя всю онлайн-систему, что приведет к непрерывному простою. Неисправный
модуль профилей может возвращать некорректные данные, что приведет к повреж
дению ваших онлайн-отчетов. Часто самым безопасным способом является полное
отключение приложения во избежание негативных последствий.
Браузер/Пользователь
Один сбой в монолите
Приложение версии
2
может вывести из строя
всю систему
Рис.
1.8.
Недостатки монолита: проблемы с доступностью/изоляцией сбоев
Даже в монолитах для решения задач серверной части иногда необходимо исполь
зование микросервисов. По сути, установка отдельных компонентов может упро
стить
развертывание,
в главе
6 «Принципы
если
они
правильно
спроектированы,
о
мы
чем
расскажем
надлежащего предоставления сервисов».
Помните, что монолиты
-
это не только серверные сервисы или полнофункцио
нальные приложения. Веб-сайты, ориентированные на клиента, и приложения, ори
ентированные на мобильные устройства, имеют схожие недостатки: одно большое
развертывание, сопряженное с риском существенной ошибки или простоя. К сча
стью, для интерфейсного кода существуют шаблоны, аналогичные микросервисам,
например микрофронтенд 13
13
Микрофронтенд (microfrontend) -
(Microfrontend).
архитектурный подход. в котором независимые приложения собраны
в одно большое приложение. Он дает возможность объединить в одном приложении различные виджеты
или страницы. написанные рюными командами с использованием разных фреймворков.
-
Пер.
40
■
Глава 1
Хотя подробное рассмотрение этого вопроса выходит за рамки данной книги, од
ним из примеров эффективного стека технологий для микрофронтенда является
объединение модулей
Webpack 14 (https://webpack.js.org/concepts/module-federation/)
Repack
(https://github.com/callstack/repack).
и решений с разделением кода для мобильных приложений, таких как
Несмотря на то что сложные развертывания представляют собой серьезный побоч
ный эффект, они являются частью более широкой проблемы
-
отсутствия ста
бильности, часто наблюдаемом в монолитах. Отсутствие стабильности, вызванное
сложными установками, является одним из ключевых факторов, который может
заставить бизнес в конце концов опустить руки и поддержать перемены.
Недостаточный уровень тестирования
Программное обеспечение может работать неправильно по многим причинам,
а учитывая высокую степень связности, неправильные абстракции и отсутствие
изоляции, тестирование монолита часто превращается в кошмар. Даже для внесе
ния простых изменений может потребоваться множество сценариев, которые необ
ходимо учитывать, чтобы действительно гарантировать отсутствие скрытых побоч
ных эффектов от любых изменений. Результирующие наборы тестов часто выпол
няются медленно и затрудняют отладку приложения.
Учитывая возраст монолита и присущую ему сложность, тестовая кодовая база са
ма по себе может стать такой же большой и запутщшой, как и сам монолит, и так
же плохо понимаемой. Поэтому большинству команд сложно полностью протести
ровать монолит, и они пропускают важные сценарии сбоев, которые возникают
только в самые неподходящие моменты.
Эффективное тестирование программного обеспечения
-
сложная задача. Тести
рование монолита еще больше усложняет задачу, учитывая наши дополнительные
ограничения, и результат обычно не соответствует ожиданиям.
Меньшие по размеру изолированные компоненты упрощают тестирование по раз
делам и ускоряют циклы тестирования. О том, какую важную роль играет тестиро
вание при выходе из монолита, мы расскажем позже в главе
7 «Надлежащее
тес
тирование сервисов».
Отсутствие владельца
Владение кодом
(ownership)
означает знание того, кто из сотрудников или какая
команда несет основную ответственность за определенный набор исходных кодов.
В хорошо спроектированных проектах по разработке программного обеспечения
владение
кодом
гарантирует,
что
код проверяется,
хорошо тестируется,
остается
стабильным и поддерживается в актуальном состоянии с учетом требований безо
пасности.
14
Webpack- это сборщик модулей, который позволяет объединить множество JavaScript-фaйлoв в один
JS к НТМL-странице, адаптировать код к старым версиям браузера, подго
большой, легко подюпочить код
товить файлы к размещению на сервере для их оптимизации, тестировать код с помощью локального серве
ра, выпоJПIЯть разнообразные преобразования кода и дополнительные действия.
-
Пер.
Что не так с монолитами?
■
41
Из-за недостаточной изолированности отсутствие четких границ, часто встречаю
щееся в монолитах, распространяется и на саму организацию. Может быть неясно,
где начинаются и заканчиваются границы владения любой команды. Просмотр ис
тории коммитов монолита, особенно часто используемого класса, может стать на
стоящим кошмаром. Эти важные элементы монолита становятся «общим кодом»,
который используется всеми, но никому конкретно не принадлежит, что в конеч
ном итоге приводит к трагедии общего доступа.
Не все монолиты одинаковы, и некоторые команды могут справиться с этим бреме
нем благодаря дисциплине и строго выстроенному процессу разработки и тестиро
вания. Но монолит сам по себе делает сложнее преодоление этих трудностей, в от
личие от использования других архитектурных стилей.
Мы подчеркнем важность владения в главе
5 «Оценки».
Медленное внедрение новых технологий
Когда все ваши решения объединены в единый модуль развертывания, обновление
одного технического компонента может означать изменение многих других компо
нентов. Обеспечение безопасности
-
одна из ключевых задач управления любым
монолитом.
Некоторые из этих обновлений связаны с появлением новых функций или исправ
лением ошибок. Но даже простые обновления библиотеки могут привести к пута
нице, с которой трудно совладать. Это называется бинарной связью (Binary
когда компоненты в вашей системе эффективно связаны бинарными 15
Coupling),
зависимостями. Давайте проиллюстрируем это простым примером.
Возьмем пример монолитного приложения, показанный на рис.
1.9. В вашем моду
JasperReports, и вы используете сервисы, которые предос
Hibemate 4 16, который сейчас является продуктом с истек
ле отчетов используется
тавляют данные через
шим сроком службы. В модуле отчетов все работает.
Теперь отдел продаж хочет перейти на
Hibemate 5.
Это может быть вызвано мно
гими причинами: команда столкнулась с критической ошибкой безопасности, ис
правленной в Hibemate 5, они хотят использовать новую версию ключевой функ- •
ции, или обновление
Spring Boot17
требует обновления
Hibemate.
А может быть,
они просто интересуются новыми технологиями!
Независимо от причины теперь у вас возникла проблема. Модуль развертывания
вашего монолитного приложения уже включает
зовать
15
Hibemate 4
и
Hibemate 5
Hibemate 4.
Вы не можете исполь
в рамках одного и того же класса/проекта. Отделу
Хотя не все языки используют общие зависимости с помощью двоичных файлов или других скомпилиро
ванных объектов, в этой книге основное внимание уделяется
Java.
Бинарная связь
-
полезное выражение,
и мы будем использовать его на протяжении всей книги.
16
Нibemate -
библиотека для языка программирования Java, предназначенная для решения задач объектно
реляционного отображения. Актуальная версия
Hibemate
ОRМ
5.0.2
выпущена в сентябре
2015
года.
-
Пер.
17
Обновление в Spring Boot -
жения.
-
Пер.
это возможность обновлять значения конфигурации без перезапуска прило
42
■
Глава 1
продаж запрещено обновлять
Hibemate
самостоятельно. Будут обновлены либо все
модули, отчеты, профили и продажи, либо ни один из них. Команды связаны не
напрямую своим кодом, а общими двоичными файлами.
Недостаток монолита:
бинарная связь ограничивает внедрение технологии
Браузер/Пользователь
Монолитное приложение
0-Ш П~м+-~
Использование
Рис.
1.9.
Hibernate 4
Недостаток монолита: бинарная связь ограничивает внедрение технологии
В этих обновлениях принцип «все или ничего» приобретает особое значение, по
скольку командам
сложно действовать
проактивно
и
выполнять
естественную
миграцию по собственному графику. Это создает больше точек координации для
руководства, и ситуация становится еще сложнее, когда несколько миграций про
исходят одновременно.
Напротив, когда сервис А обращается к другому сервису В, сервис А не имеет тес
ной связи с операционной системой, внутренними библиотеками и базой данных
сервиса В. Сервисы обеспечивают естественную развязку и разделение задач. Од
нако, когда внутренняя библиотека С вызывает другую библиотеку
D,
они оказы
ваются тесно связанными и ограниченными во многих аспектах. Они вынуждены
использовать один и тот же язык и разделять все графики зависимостей, что накла
дывает дополнительные связи и ограничения.
Что касается отдела продаж, то результат этого сценария расстраивает техническую
команду до такой степени, что некоторые люди просто сдаются. Вносить улучше
ния
становится
слишком
сложно,
и
это
негативно
сказывается
на
моральном
со
стоянии разработчиков. Как следствие, в коллективе формируются нездоровая
культура и антипаттерны. Команда, отвечающая за отчеты, довольна
Hibemate 4
и
не хочет отвлекаться от своих целей в спринте, выполняя миграцию, которая ниче
го им не дает. Для ясности:
Hibemate
здесь не является проблемой. Та же проблема
возникает и с другими библиотеками. Чем чаще вы пользуетесь библиотекой, тем
популярнее она становится и тем больше у вас шансов попасть в подобную ситуа
цию.
Как вы можете видеть, бинарная связь является большой проблемой для монолит
ных систем, где они запутаны, и ограничивает внедрение технологий и даже их из
менение. Бинарная связь создает сценарии «все или ничего», в которых постепен
ные изменения более сложны, а иногда и невозможны.
Что не так с монолитами?
■
43
Сервисы не защищены от бинарной связи; мы подробно рассмотрим это в главе
4
«Антипаттерн: внутренние общие библиотеки».
Бинарная связь
-
это один из четких и понятных способов, с помощью которого
изменения в команде могут затронуть всех остальных сотрудников, совместно ис
пользующих монолит или модуль развертывания. Общий вывод, который следует
сделать, заключается в том, что любое изменение, внесенное командой, влияет на
любую другую команду, что является следствием централизации, присущей моно
литным архитектурам. Независимо от того, идет ли речь о переименовании табли
цы, рефакторинге общего класса или просто добавлении библиотеки, которая пре
доставляет множество дополнительных зависимостей, безопасность практически
отсутствует из-за отсутствия границ. Обычные задачи, выполняемые инженерами,
сопряжены с рисками.
Вот почему мы возвращаемся к теме внедрения новых технологий. Если обычные
задачи сопряжены с рисками, как насчет агрессивного рефакторинга или модерни
зации? Если их приходится выполнять в рамках монолита, укореняется страх, а из
менения либо откладываются, либо не происходят вовсе.
В какой-то степени внедрение технологии все еще возможно с использованием
классического монолита
(classical monolith).
Например, вот несколько идей о том,
как команда может ограничить воздействие при создании новой функции.
♦ Разработать новую функцию:
.. .полностью
за пределами монолита. Возможно,
использовать другой инструмент для работы, например отчеты можно было бы
обрабатывать с помощью технологии
♦
Big Data за пределами
Создать функцию в монолите, но частично опереться на внешние сервисы:
например, вы могли бы использовать бессерверную
выделенный сервис, такой как АWS
♦
монолита.
(serverless)
функцию, а не
Lambda.
Не создавать новую функцию: использовать сторонний полнофункциональный
сервис, т. е. если вам нужно совершать платежи, то можно использовать
♦
Stripe 18 •
Уменьшить риск бинарной связи, рассмотрев:
•
Возможность использования более простых библиотек, например
JDBC Template.
Мы вернемся к этой теме в главе
4
MyBatis,
«Антипаттерны: Внут
ренние общие библиотеки».
•
Возможно ли скопировать код вместо загрузки новой библиотеки?
•
Возможно ли разработать такую функцию самостоятельно?
•
Нужна ли вам вообще эта библиотека? Не могли бы вы предложить другое
решение?
В разумных пределах и проявляя осторожность, вы определенно могли бы изучить
эти варианты. Однако будьте бдительны, т. к. в зависимости от выбора эти вариан-
18
Stripe -
это американская платформа ДJIЯ обработки онлайн-платежей, которая предлагает предпринима
телям и бизнесам инструменты для приема и управления платежами через Интернет. Сервис поддерживает
разнообразие платежных методов, включая кредитные карты, банковские переводы и -электронные кошель
ки, обеспечивая безопасность и удобство транзакuий.
-
Пер.
44
■
Глава 1
ты могут усугубить проблему. Например, представьте, что вы разрабатываете но
вую функцию за пределами монолита. Насколько изолированной будет эта функ
ция? Зависит ли она от каких-либо других функций моI-Jолита? Как насчет доступа
к базе данных? В классических монолитах
(classical monolith)
все еще возможно
внедрение технологий. Однако это палка о двух концах. Новые технологии имеют
свои преимущества, но их внедрение без тщательной оценки текущей ситуации
может стать источником множества ошибок и проблем. Более подробно об оценках
мы поговорим в главе
5 «Оценки».
Медленный цикл разработки
На сборку монолитов часто уходит больше времени, чем при использовании другой
архитектуры программного обеспечения (рис.
1.1 О).
Из-за большого объема кода и
количества тестов, которые необходимо выполнить, результат не удается получить
быстро. Тесты всегда можно оптимизировать, удалить и выполнять параллельно, но
чем больше у вас кода, тем медленнее он будет работать. Время цикла разработки
(Cycle time) -
это время, которое требуется разработчику от написания строки
кода до выполнения компиляции и начальных модульных тестов. Высокая продол
жительность цикла
-
одна из самых больших проблем для разработчиков моно
литных систем.
Браузер/Пользователь
Монолитное приложение
Разработчик
1:
изменил общее . . . . . • . • . . . ►
Разработчик
перечисление,
не работает
• •.
• • • • • • • •
Разработчик
4:
регрессионные тесты
не выявили ошибки
но все исправно
1.10.
3:
функция теперь
2:
использует то же
Рис.
Разработчик
.....
перечисление
Недостатки монолита: медленный цикл разработки (инженеры срывают работу друг друга)
При этом бизнес озабочен общим временем выпуска или выполнения заказа, вре
менем, затрачиваемым на переход от идеи к рабочему коду в процессе производст
ва. В целом продолжительность цикла влияет на сроки выполнения заказа. Мы уже
видели, как внедрение новых технологий сопряжено с дополнительными рисками
для монолитов. Исправления, оперативная установка или переход от одной ветви
к другой для развертывания в рабочей среде
-
все это возможно для монолитов.
Независимо от этого, сама по себе установка будет осуществляться по принципу
«все или ничего». Все компоненты будут развертываться одновременно, и их необ
ходимо будет протестировать одновременно, как мы уже обсуждали в случае слож
ных установок. Конечно, не все монолиты будут страдать от этой проблемы в рав
ной степени, но медленная сборка, скорее всего, неизбежна, и при любом размеще-
Что не так с монолитами?
■
45
нии нет возможности избежать риска попадания в радиус поражения. Все это от
нимает время на разработку.
Автоматизация и антипаперны
Автоматизация процессов производства лежит в основе движения
DevOps
и имеет
ряд преимуществ, таких как:
♦ сокращение времени выполнения заказа и времени цикла разработки;
♦
автоматизация способствует большей согласованности и предсказуемости про
цессов: снижение количества ошибок по сравнению с любым ручным процес
сом;
♦
~~томатизация упрощает масштабирование вашей технологической организа
ции, позволяя сотрудникам сосредоточиться на реальных бизнес-задачах вашей
компании и не тратить время на рутинную работу.
По нашему опыту, производство некоторых монолитов автоматизировано, но чаще
всего классические монолиты
(classical monolith)
не обладают достаточной степе
нью автоматизации производственных процессов. При рассмотрении вопроса о пе
реходе к распределенной архитектуре, такой как микросервисы или микрофронтен
ды, автоматизация процессов производства становится все более актуальной для
управления растущим
числом
модулей развертывания.
Облачные провайдеры,
такие как А WS, значительно упрощают работу команд по автоматизации их рабо
ты. Когда у вас есть возможность масштабирования, автоматизация процессов не
вызывает вопросов.
Что должно быть автоматизировано? Всё. Вот несколько примеров:
♦
развертывание кода (интерфейсного и серверного);
♦
изменение схемы базы данных;
♦
миграция данных;
♦
изменения инфраструктуры;
♦
обно1щение зависимостей;
♦
все формы тестирования (тестирование на наличие дыма, модульное, интегра
ционное, сквозное, хаотическое, мутационное, нагрузочное, стрессовое, А/В-тес
тирование, тестирование в производственных условиях).
Итак, давайте согласимся: мы стремимся к автоматизации наших производствен
ных процессов. Однако, возвращаясь к нашим целям, важно отметить, что бизнес
ожидает от нас масштабирования, чтобы мы могли быстро внедрять новые функ
ции. Один из способов масштабирования
пасно работать параллельно (рис.
1.11 ).
-
позволить нескольким командам безо
Позволяет ли автоматизация автоматически
развертывать и эксплуатировать все ваши компоненты независимо друг от друга?
Означает ли автоматизация, что ваши команды могут работать параллельно или без
координации?
Если говорить о классическом монолите
(classical monolith),
то ответ на вопрос
о независимом развертывании, скорее всего, будет отрицательным. Вам нужна ко-
46
■
Глава 1
ординация, которая замедляет работу, создает узкие места и сдерживает вас. Авто
матизация может снизить сложность развертываний, с которыми вы сталкиваетесь,
но она не может решить проблему, присущую централизации.
Можем ли мы выпустить продукт и работать независимо?
2 недели
Перенос в одну ветку
Синхронизация
Сервис отчетов
Сервис профилей
Сервис продаж
готов в 1-й день
готов на 3-й день
готов на 5-й день
Тестирование
Установка
Стабилизация
кода
Рис.
1.11.
Недостатки монолитов: автоматизация
Допустим, у вас есть
100
-
насколько вы независимы при развертывании?
микросервисов. Означает ли это автоматически, что вы
можете развертывать их все независимо друг от друга без согласования? Это зави
сит от степени скрытой взаимосвязи между микросервисами, измеряемой качест
вом их контрактов, независимо от того, используют ли они базы данных или биб
лиотеки совместно. В крайних случаях вы не сможете развернуть их самостоятель
но без тщательной координации. Мы вернемся к этим скрытым связям позже
в текущей главе, когда будем говорить о распределенных монолитах. А более под
робно обсудим, как избежать распространенных ошибок при разработке сервисов
в главе
6 «Принципы
надлежащего предоставления сервисов».
Итак, автоматизация процессов производства
использовать
DevOps, CI/CD,
-
это хорошо, организации хотят
и это имеет смысл. Но помните, что реальные узкие
места в бизнесе не всегда устраняются за счет улучшения конвейеров и применения
более современных инструментов.
Усилители
Из-за этих антипаттернов и побочных эффектов, влияющих на ваш монолит, серь
езные проблемы часто могут привести к еще более серьезным, со временем усугуб
ляя последствия. Мы называем эти эффекты усилителями
(amplifier).
Давайте рас
смотрим некоторые из них.
Разбитые окна
В
1982
/
копирование и вставка
году социологи Джеймс К. Уилсон и Джордж Л. Келлинг представили тео
рию разбитых окон
(Broken windows),
которая гласит, что видимые признаки пре-
Что не так с монолитами?
■
47
ступности, антиобщественного поведения и гражданских беспорядков способству
ют дальнейшему преступному поведению (рис.
1.12).
Другими словами, если у вас
есть разбитые окна, то со временем их количество увеличивается.
Рис.
1.12.
Stehli Silk Mill в городке Манхейм, округ Ланкастер, Пенсильвания.
https://en.wikipedia.org/wiki/File:Stelhi_Silk_Mill_Lanco_broken_windows.JPG
Разбитые окна фабрики
Источник:
Хотя теория разбитых окон вызывает споры в некоторых круrах 19 , она имеет боль
шой смысл в контексте разработки программного обеспечения для устаревших сис
тем. Монолитный код со временем приходит в упадок, а техническая задолжен
ность растет из-за антипаттернов и побочных эффектов, которые мы здесь описали.
Нулевой технический долг невозможен даже при самой лучшей архитектуре про
граммного обеспечения. Однако и в контексте монолита возможно поддерживать
его на управляемом уровне. Упадок можно ослабить с помощью дисциплины, по
следовательных и осознанных процессов работы
рое
отличается
от
компании
к
компании
и
-
от того,
культурного поведения, кото
как
ваша
команда
подходит
к решению проблем.
Например, неопытные разработчики могут неправильно копировать и вставлять код
(сору
and paste),
чтобы ускорить выполнение работы. Мы бы сказали, что в копиро
вании и вставке как таковой нет ничего плохого:
инженеры часто копируют и
вставляют, когда используют такие инструменты, как
StackOverflow, Reddit, CoPilot
и
ChatGPT.
При копировании и вставке возникают проблемы из-за того, что код
может быть правильным для определенного варианта использования, но для друго
го варианта использования он может оказаться неверным. Инженерам необходимо
глубоко разбираться в концепциях во время своей работы. Как правило, опытные
инженеры больше внимания уделяют изучению проблемного пространства и поис
ку компромиссов в решении или архитектуре, чем скорости выполнения задач. Вам
нужно следить за подобным поведением неопытных разработчиков и иметь время
для исправления ситуации. В противном случае возникнет техническая задолжен
ность.
19 На странице Википедии. посвяще11ной теории ра1битых око11, есть рюумное изложение проблем:
https:/len. wikiped ia.org/w iki/Rroken_ wi ndows_ theory.
48
■
Глава 1
Где копирование и вставка пересекаются с теорией разбитых окон? Если у вас есть
несколько плохо написанных или понятных фрагментов кода, существует высокая
вероятность того, что этот плохой код или некорректное поведение будут воспро
изведены повторно последующими инженерами.
Внезапно фрагмент кода, который, как вы знаете, является антипаттерном, стано
вится стандартом проекта, потому что команда изначально допустила существова
ние плохого кода. Вы бы удивились, узнав, как много людей считают свою кодо
вую базу «хорошей», когда в ней полно антипаттернов, технических ошибок и
очень плохих технических решений ... И поскольку неопытные инженеры склонны
копировать и считать, что если что-то существует, то оно должно быть хорошим и
правильным, ситуация усугубляется. Одно разбитое окно
-
и внезапно повсюду
появляются разбитые стекла.
Конечно, именно поэтому ревью кода
(code review)
и дизайна важно для снижения
сложности.
Монолиты
-
крупные и старые системы, которые могут иметь серьезные пробле
мы из-за высокой степени связанности, худших абстракций и отсутствия изоляции.
В результате эти системы могут быть заполнены антипаттернами и примерами пло
хого кода, которые инженеры продолжают тиражировать. Кроме того, все антипат
терны могут быть доступны в рамках вашей единой среды разработки, поскольку
весь плохой код находится в одном месте и одинаково доступен. Хотя все про
граммные проекты обременены техническими проблемами, монолит имеет уни
кальное расположение, позволяющее ускорить их распространение.
Что касается того, почему окна бьются, то это объясняется естественными стиму
лами: быстрее завершить работу над новой функцией, чтобы перейти к следующей
задаче, а копирование и вставка
-
это способ ускорить работу. Необходимы дру
гие мотивации, чтобы компенсировать эти естественные стимулы, поэтому важно
предпринять следующие шаги:
♦
измерьте, сколько времени потребовалось инженеру, чтобы прочитать код;
♦
измерьте, сколько раз был перенесен неработающий код;
♦
измерьте, сколько часов команда потратила на поиск призраков и неработающе
го кода при устранении неполадок;
♦
создайте цели и ключевые результаты
(Objectives and
Кеу
Resu\ts, OKR)
для
снижения сложности кода;
♦
создавайте
rate)
♦
OKR
для обеспечения 100-процентного прохождения тестов
(pass
в любое время;
планируйте время простоя в спринтах на
20 %
и более, чтобы снизить техниче-
скую задолженность;
♦
поощряйте инженеров за удаление кода.
Легко критиковать монолиты и их стиль архитектуры, но гораздо важнее разо
браться в реальных причинах возникновения антипаттернов и плохого кода. Это
поможет командам правильно мыслить при переходе на микросервисы. Ничто же
не может пойти не так, верно?
Что не так с монолитами?
■
49
Зависть к микросервисам
Другим источником риска и возможных сложностей является то, что инженеры
любят блестящие разработки: новые идеи, фреймворки и подходы. Проблема с по
добными разработками заключается в том, что мы также подходим к ним с учетом
их недостатков, ограничений, способов отказа и болевых точек. Многие команды
внедряют микросервисы, не понимая реальных проблем, которые они решают
с помощью своего монолита, и не замечая недостатков, присущих стилю архитек
туры микросервисов.
ThoughtWorks называет этот антипаттерн завистью к микро
(Microservice Envy, https://www.thoughtworks.com/en-us/radar/techniques/
microservice-envy).
сервисам
Микросервисы обладают множеством преимуществ, но они не являются пана
цеей от всех бед, и уж точно подходят не для всех компаний. Начиная с середины
20 l 0-х
гг. многие организации по всему миру пытались внедрить архитектуру мик
росервисов,
Spotify,
и некоторые компании, такие как
Amazon, Netflix, SoundCloud
и
добились значительных успехов. Однако многие другие компании пыта
лись это сделать, но потерпели неудачу.
Каждый сбой по-своему уникален, но существуют общие закономерности, которые
можно наблюдать из нашего опыта: от отсутствия должного понимания монолитов
и микросервисов до отсутствия надлежащей подготовки инженеров и нехватки ква
лифицированных специалистов, а также многих других
причин.
В
результате
у многих компаний по-прежнему есть свой монолит, а теперь и целый ряд микро
сервисов. И во многих случаях в результате возникает проблема еще более серьез
ная, чем бьmа вначале: распределенный монолит. Как описано в этой главе, распре
деление не является волшебным решением при чрезмерной централизации. Почему
увеличение количества компонентов не всегда является решением проблемы, если
компании не могут правильно настроить программное обеспечение при централи
зации? Скорее всего, сейчас у вас просто распределенные проблемы.
Мы рассмотрим их более подробно в главе
3
«Антипаттерны: распределенные мо
нолиты».
Нехватка квалифицированных специалистов
Компания
Netflix
хорошо известна благодаря уникальной культурной платформе,
которую они опубликовали в начале своего перехода на онлайн-сервисы и в кото
рой описывают свои цели для компании под названием «Свобода и ответствен
носты>
(Freedom and
1798664).
ResponsiЬility,
https://www.slideshare.net/reed2001/cu1ture-
В своей платформе
специалистов
Netflix представляет концепцию плотности квалифицированных
(Talent Density, рис. 1.13). Компании начинают с высокой плотности
талантов, поскольку они выходят на новые рубежи и добиваются успеха. По мере
роста компаний происходят две вещи: сложность бизнеса возрастает, а вместе с ней
и необходимость в найме персонала, что, естественно, снижает плотность талантов
в организации. Новый персонал не справляется со сложностями, и в результате
возникает хаос. Чтобы укротить хаос, компания внедряет процесс, который по сво-
50
■
Глава 1
ей сути ограничивает свободу передвижения для любого человека. Такое отсутст
вие свободы снижает влияние высокоэффективных талантов, которые устают и
уходят, что еще больше снижает концентрацию талантов, усугубляет проблему
и приводит к бюрократии.
Ключ к успеху:
увеличивайте количество квалифицированных
специалистов быстрее, чем растет сложность
NETFLIX
Рис.
1.13.
Платформа «Свобода и ответственность»
Источник:
Netflix - плотность талантов.
https://www.slideshare.net/reed2001/culture-1798664 (слайд 56)
Монолиты прекрасно отражают результат этого процесса. Поскольку монолиты
побуждают организации не спешить с внедрением новых технологий и, как следст
вие, замедляют процессы разработки, естественная бюрократия вытесняет талант
ливых специалистов. Это затрудняет внесение необходимых изменений для разви
тия и продвижения, бизнеса, усугубляя проблему.
Талант всегда имеет значение. Борьба за таланты есть и всегда будет. К сожалению,
мы не можем привлечь всех нужных нам ценных специалистов. Даже при наличии
всех талантов в мире случаются ошибки, и мы все равно можем столкнуться с тех
ническими трудностями. Но без таланта вы не сможете выйти или двигаться вперед
с той скоростью, которая вам нужна.
Инерция монолита проявляется, когда ваша организация осознает проблему, как
социологическую, так и архитектурную, но не может найти в себе волю или талант,
чтобы определить путь развития на будущее. Таким образом, несмотря на то, что
вы можете понять природу своего монолита, вам все равно нужны таланты, чтобы
преодолеть ее. Недостаточно признать проблему
-
вам нужна организация, общая
стратегия и финансирование, чтобы нанять квалифицированных специалистов и
восстановить их численность, достаточную для продвижения вперед.
Потребовалась бы еще одна книга, чтобы полностью охватить все темы, связанные
с построением эффективных организаций и заключением правильных соглашений
на всех уровнях компании для того, чтобы справиться с монолитом. На данный
момент помните, что плотность талантов важна, а нехватка квалифицированных
специалистов может привести к ухудшению положения в вашем монолите.
Что не так с монолитами?
■
51
Страх перемен
Страх перемен
(fear of change) -
главная проблема монолитов. Инженеры начина
ют бояться рефакторинга кода для улучшения структуры. Инженеры часто знают
об антипаттернах, таких как высокая степень связанности, неправильные абстрак
ции, отсутствие изоляции, отсутствие тестирования, отсутствие владения
sh ip)
(owner-
и техническая задолженность по монолиту. Некоторые инженеры пытаются
устранить проблемы или внедрить новые идеи и концепции с помощью рефакто
ринrа. Однако их попытки часто оказываются безуспешными из-за того, что они
сталкиваются со взломом кода других инженеров или даже с критическими ошиб
ками в самом продукте. Руководство пытается контролировать монолит, заморажи
вая его, заставляя инженеров не трогать код или делать «как можно меньше». Это
только еще больше усугубляет ситуацию (рис.
1. 14 ).
Страх перемен:
давайте скопируем и вставим то, что есть
Технический долг:
долг усиливается и становится больше
Рис.
1.14. Антипаттерны
и усилители подкрепляют друг друга
В то же время инженеры не боятся добавлять новые функции, но боятся рефакто
ринrа и улучшения существующего кода. Это любопытное социальное явление.
Добавление новых функций не означает простого написания кода в новых файлах.
В конечном итоге вам придется иметь дело с существующими структурами кода,
которые необходимо будет изменить и адаптировать. Инженеры, разрабатывающие
новые функции, могут скопировать и вставить код
полный анти
паттернов, усиливая разбитые окна
рассказывали
ранее в этой главе. Это иронично
-
( сору and paste ),
(Broken windows ), о которых мы
было бы намного безопаснее, если бы они со
временем сделали рефакторинr кода. Их страх перед переменами
(fear of change)
приводит к увеличению рисков, присущих кодированию новых функций, что при
водит к еще большему страху и меньшему количеству изменений.
Все ли монолиты плохие?
У монолитов есть много того, что мы называем «негативной кармой»: антипаттер
ны, сложные побочные эффекты, которые усугубляются усилителями
(amplifier).
Поскольку монолиты со временем разрушаются, путь к плохому исходу кажется
52
■
Глава 1
неизбежным. Итак, учитывая все, что вы только что прочитали, вы можете поду
мать, что существует простой ответ на вопрос: все ли монолиты плохие?
Но ответ: нет! Монолит
-
это не всегда плохо.
На самом деле иногда правильным решением является разработка чего-то центра
лизованного с самого начала. Это позволяет уменьшить количество модулей раз
вертывания независимо от размера кодовой базы, что особенно важно, учитывая
характер решаемой проблемы.
Архитектура и проектирование программного обеспечения, по сути, связаны с по
иском компромиссов. При моделировании чего-либо и принятии решения о том,
какие возможности следует использовать для каждого сервиса, мы часто сталкива
емся с большой дилеммой: вместе или по отдельности? Централизованно или рас
пределенно? Эта ситуация показана на рис.
, ...
Микросервисы
Монолиты
Распределенно
Централизованно
Отдельно
Вместе
Рис.
1.15.
1.15.
Большая дилемма проектирования
Проще говоря, решение о том, будет ли монолит плохим, зависит от архитектуры
программного обеспечения, а архитектура зависит от требований. Если при пра
вильном проектировании все элементы будут объединены, монолит будет хорош;
если нет, то он будет на пути к тому, чтобы стать плохим. Вы заплатите штраф,
если разделите то, что не должно быть разделено, или объедините то, что не долж
но быть объединено.
Монолиты-
это форма архитектуры программного обеспечения
Наша книга посвящена архитектуре программного обеспечения. На протяжении
всей книги мы говорим об этом и давайте уделим немного времени, чтобы дать
определение.
Архитектура программного обеспечения
(Software architecture) -
это прежде всего
структуры: классы, модули, библиотеки и прочие элементы вашей системы, а также
то, как они соединены друг с другом и взаимосвязаны. Разработка архитектуры
программного обеспечения
-
это прежде всего осуществление выбора: сложные
компромиссы, принимаемые при проектировании этих структур, позволяют решить
сразу несколько проблем. Проектирование этих сложных компромиссов необходи
мо на протяжении всего проекта для создания наилучшего программного обеспече
ния из возможных, учитывая требования и ограничения.
Скорее всего, данная тема ассоциируется у вас с нефункциональными требования
ми: масштабируемостью, стабильностью, отказоустойчивостью, производительно
стью, безопасностью и т. п. В этом нет ничего плохого, но архитектура программ-
Что не так с монолитами?
ного обеспечения
-
■
53
это нечто большее. Да, она является ключевым и критически
важным элементом, отвечающим за масштабирование: масштабирование пользова
телей,
масштабирование
аппаратного
обеспечения,
масштабирование запросов
в секунду. Но архитекrура программного обеспечения также связана с масштаби
рованием ваших сотрудников: команды разработчиков и инженерные практики по
своей сути реагируют на струкrуру проектирования. Решения, которые вы прини
маете, будут отвечать за то, как организация может масштабировать инженеров и
команды.
В архитекrуре программного обеспечения не так много абсолютно правильных или
абсолютно неправильных решений. Вместо этого все зависит от того, что имеет
наибольший смысл с учетом ваших вариантов использования
(use cases)
и компро
миссов. Иногда команды с самого начала разрабатывают правильную архитекrуру,
но со временем из-за неизбежности изменений и многих других факторов она пере
стает работать по назначению. Например, вы начали с проектирования лодки, но
потом оказалось, что вам нужен космический корабль.
Таким образом, архитекrура программного обеспечения должна быть чем-то жи
вым и естественным, а не дискретным. Это не то, что создается раз и навсегда, а
скорее практика, которая проходит через всю жизнь любой системы.
Преимущества монолитов
Монолиты
-
это очень старый, но распространенный стиль архитекrуры про
граммного обеспечения. Например, первым монолитом был мейнфрейм! Как и лю
бой архитекrурный стиль, монолиты полны компромиссов. В них есть как плюсы,
так и минусы, как удачные, так и неудачные элементы дизайна.
Короче говоря, у монолитов есть свои преимущества. Давайте рассмотрим их.
Влияние рефакторинга и изменений
Возможно, самым большим преимуществом монолитной архитекrуры является
простота рефакторинга кода, когда весь ваш код находится в одном месте. Боль
шинство современных интегрированных сред разработки
(lntegrated Development
IDEA, SuЬlime Text
IntelliJ
Eclipse,
Environment, IDE) и редакторов кода, таких как
и VSCode, обладают потрясающими возможностями
рефакторинга, а монолит по
зволяет легко применять их все.
Представьте, что вы хотите знать, используется ли класс, насколько широко он ис
пользуется, и связан ли он непосредственно с вашим кодом или находится глубоко
в графе зависимостей. Когда у вас есть весь код в одном месте, вы можете просто
удалить класс и позволить компилятору показать вам его влияние.
В отличие от этого, в случае микросервисов ваш код распространяется в разных
кодовых базах. Взаимосвязь выражается в том, что
сути. Расширенные возможности
IDE
сложнее оценить влияние изменений.
IDE
сложнее понять по своей
по рефакторингу теряются, и становится
54
■
Глава 1
Упрощение некоторых миграций
В какой-то степени монолиты упрощают миграцию, поскольку вся база кода нахо
дится в одном месте; требуется изменять меньше независимых репозиториев, и все
изменения могут содержаться в одном РR-файле. Когда у вас архитектура микро
сервисов
с
несколькими
репозиториями
кода,
вам
нужно
запустить
несколько
(classical monolith)
возникают
РR-файлов и выполнить гораздо большую координацию.
Конечно, при миграции классических монолитов
проблемы из-за таких факторов, как бинарная связь, которые обычно замедляют
внедрение новых технологий. Однако мы должны признать, что проще использо
вать один
PR для
объединять сотни
обновления одной библиотеки, чем фиксировать, просматривать и
PR с
микросервисами.
Хорошая отправная точка
Наличие всего в одном месте, одной базы кода и минимума модулей развертывания
означает меньшие организационные затраты. Монолиты упрощают работу с базой
кода. В какой-то степени при меньшем количестве движущихся элементов требует
ся меньшая координация, а ответственность может быть немного более определен
ной. Когда вы только начинаете свой путь, будь то создание предприятия или
запуск стартапа, может быть быстрее и зачастую лучше начать с меньшей структу
ры и позволить шаблонам развиваться по мере вашего продвижения.
Упрощенная инфраструктура
Чем больше машин вам нужно для запуска вашего программного обеспечения, чем
больше модулей развертывания, тем больше требуется координации. Еще раз: пе
реход от централизации к распределению не обязательно решит все ваши пробле
мы; распределенные системы могут иметь гораздо более высокие накладные расхо
ды. Если позволяет специфика программного обеспечения, монолитное решение
будет дешевле в эксплуатации, чем распределенное программное обеспечение.
Однако в больших масштабах сочетание распределенных и
централизованных
решений часто оказывается невозможным.
Типы монолитов
Давайте подробнее рассмотрим типы монолитов. Мы разделим монолиты на три
типа: классические
(classical),
распределенные и модульные монолиты.
Классические, распределенные и модульные
монолиты
Теперь, когда мы разобрались с особенностями монолитов, их недостатками и даже
потенциальными преимуществами, давайте поговорим о трех видах монолитов, ко
торые мы видели вживую: двух отрицательных и одном положительном (рис.
1.16).
Что не так с монолитами?
Классический
Серверная часть
Интерфейс
Интерфейс
Интерфейс
пользователя
пользователя
пользователя
Серверная
Серверная
Сер верная
часть
часть
часть
Интерфейс пользователя
Серверная часть
модуль
База данных
Рис.
♦
База данных
1:1
1.16.
55
Модульный
Распределенный
Интерфейс пользователя
■
модуль
модуль
База данных
1: 1
Типы монолитной архитектуры
Классический/устаревший монолит. Имеет большую кодовую базу, немного
модулей развертывания, полностью централизован и, как правило, довольно
старый. Представьте себе настольное приложение для
Windows,
МVС-приложе
ние старого образца или более старое приложение, созданное на мейнфреймах,
например банковское ядро 1980-х или 1999-х гг. Всякий раз, когда мы говорим о
монолите, по умолчанию мы имеем в виду этот стиль.
♦
Распределенный монолит. Архитектура микросервисов или
но там, где
SOA,
ошибки проектирования привели к высокой степени связности между компо
нентами, отсутствию изоляции, а на практике вся система должна развертывать
ся и эксплуатироваться как единое целое. Распределенный монолит сочетает
в себе все недостатки классических монолитов
(classical monolith)
и все недос
татки микросервисов; мы бы сказали, что это наихудший из всех вариантов. Мы
уже упоминали о таком плохом результате в этой главе и подробно остановимся
на нем в главе
♦
4 ((Антипаттерны:
внутренние общие библиотеки».
Модульный монолит. Монолит, который был специально разработан для раз
деления и изоляции функциональности через дискретные границы и в котором
эволюция и изменения системы могут быть безопасно смоделированы и выпол
нены благодаря применению правильных абстракций и модульности.
Для многих компаний можно считать, что существует определенная траектория
движения через все три монолита:
♦ Компания начинает с монолитной архитектуры, добивается успеха, но рост без
технической эволюции загоняет ее в тупик, неизбежно приводя к классическому
монолиту
♦
(classical monolith).
Испытывая зависть к микросервисам
преодоле
вает свой страх перед переменами
(Microservices Envy), компания
(fear of change) и решает заняться
распреде
лением и быстрым внедрением микросервисов. Но из-за нехватки квалифициро-
■
56
Глава 1
ванных специалистов
(lack of Talent Density)
или других факторов команда при
меняет неправильные абстракции и в итоге создает набор микросервисов, кото
рые страдают от антипатrернов, таких как совместное использование базы дан
ных или широко распространенная внутренняя библиотечная связь. Полученную
в результате систему так же трудно эволюционировать из-за скрытых взаимо
связей.
♦ Вооружившись уроками, извлеченными из неудачной миграции, компания обес
печивает правильный баланс между централизацией и распределением, исполь
зуя
сочетание микросервисов
и
классических централизованных компонентов,
которые выражают правильные абстракции благодаря надлежащему модульно
му дизайну.
Короче говоря, не все монолиты плохи. Хотя легко обвинять монолитные архитек
туры, не все они созданы одинаково. Реальная проблема имеет множество при
чин
-
будь то архитектура программного обеспечения, которая не развивалась
вместе с бизнесом, или техническая задолженность, накопившаяся из-за отсутствия
надлежащих инженерных принципов и практик.
Хотя можно легко понять, почему команды, естественно, отрицательно относятся
к идее использовать монолитную архитектуру, важно осознавать роль централиза
ции в программном обеспечении, как монолиты приводят к сбоям и где они дейст
вуют правильно.
В противном случае попытки вашей организации выйти из монолита только усугу
бят проблему.
Давайте подробнее рассмотрим хорошую монолитную архитектуру: модульные
монолиты.
Модульные монолиты: хороший вид монолита
Модульное программирование
-
это не новая концепция в разработке программ
ного обеспечения: это понятие разделения функциональности системы на отдель
ные блоки, называемые модулями. Каждый модуль содержит все необходимое для
выполнения конкретной задачи, входящей в общую функциональность системы.
Модульное программирование впервые бьmо определено Ларри Константайном
в
1968
году, а модули бьmи выпущены вместе с языком программирования
на платформе
Модульный монолит
-
это простая концепция: применяйте модульное програм
мирование для решения основной проблемы классических монолитов
monolith) -
ALGOL
ALGOL 68-R в 1970 rоду20 .
(classical
отсутствия изоляции. С помощью модульного подхода вы можете вос
пользоваться преимуществами монолитной разработки: небольшим количеством
модулей развертывания, более простыми принципами организации и меньшими
накладными расходами. Используя модульность с четкими контрактами и дискрет-
20
Отличный обзор истории модульности в разработке программного обеспечения можно найти в превос
ходно написанной статье в Википедии: https://en.wikipedia.org/wiki/Мodulaг_pгogгamming.
Что не так с монолитами?
■
57
ными границами, вы также снижаете риск влияния антипаттернов на общую произ
водительность.
Модульный монолит облегчает проблемы, связанные в основном со сложностью
микросервисов, таких как:
♦ Отладка и наблюдаемость 21 . Тут проще видеть, как компоненты соединяются
в архитектуре программного обеспечения, и отслеживать отдельные запросы
в процессе работы приложения.
♦ Повторное использование и рефакторинг. Благодаря преимуществам совре
менных
IDE
легко увидеть влияние однострочного рефакторинга на вашу кодо
вую базу.
♦ Перенос сложности в другое место. Поскольку микросервисы реализуют все
что угодно, при появлении новых требований повышенный акцент на распреде
лении иногда может привести к неприятным результатам, таким как неправиль
ное дробление сложности процесса по нескольким сервисам или внедрение
новых сервисов только для решения простых проблем с координацией.
♦
Управление зависимостями. Несмотря на то что система по-прежнему защи
щена за счет изоляции, огромное количество отдельных библиотек, используе
мых в более чем
100
сервисах, может усложнить общее управление зависи
мостями, исправления, обеспечивающие безопасность, и скоординированные
обновления.
Централизованно
Распределен но
...
...
Классические
Модульные
монолиты
монолиты
Рис.
Сервисы
1.17.
Микросервисы
Спепр решений
Модульные монолиты разрабатываются не только старыми компаниями, пытаю
щимися
преодолеть
ограничения
устаревшего
программного
обеспечения;
со
временные компании также используют модульные монолиты при проектировании.
Многие компании не смогли внедрить микросервисы, столкнувшись с недостатка
ми плохо спроектированных микросервисных архитектур, и при необходимости не
боятся применять монолитный дизайн. Вот несколько примеров компаний, исполь
зующих модульные монолиты:
♦ Сервисная сетка
Istio Service Mesh,
которую мы рассмотрим в качестве примера
хорошего модульного монолитного дизайна в этой главе.
♦
Shopify
начинала с монолита
дующим
на
своем
Ruby
оп
Rails
и сделала модульные монолиты сле
пути (https://shopify.engineering/
deconstructingmonolith-designing-software-maximizes-developer-productivity).
21
шагом
Наблюдаемость (observabllity) -
архитектурном
показатель того, насколько легко можно понять внуrреннее состояние
системы по её внешним проявлениям. Это общее определение, применимое к любой системе, не только
вИТ.-Пер.
♦
Глава 1
■
58
Segment
перешел на микросервисы, но из-за роста накладных расходов и узких
мест решил вернуться к монолитной архитектуре с внедрением
Centrifuge
(https://www.infoq.com/news/2020/04/microservices-back-again/;
https://segment.com/ Ыog/introducing-centrifuge/).
♦
Фреймворк
описывает себя как «создающий JаvаSсriрt-приложения моно
Inertia
литным способом»
♦
Фреймворк
(https://inertiajs.com/).
формально поддерживает модульные монолиты благодаря
Spring
экспериментальной поддержке
Spring Modulith
(https://spring.io/Ыog/2022/10/21/introd ucing-springmod ulith).
Модульные монолиты:
это платформа
Istio ходов,
с
lstio
Service Mesh,
которыми сталкиваются
разработанная для снижения накладных рас
микросервисов, за
распределенных
архитектуры
счет решения таких распространенных задач, как балансировка нагрузки, маршру
тизация, наблюдаемость и безопасность.
Istio
начала с микросервисной архитектуры, состоящей из четырех компонен
Со временем в него были
тов/сервисов :
(рис.
добавлены
результате чего их стало шесть. В про-
Mixer, Pilot, Galley и Citadel
микросервисы Policy и Injector, в
1.18).
ф СервисВ
ф СервисА
l
о
gRPS или ТСР с или без mTLS
о
Прокси
сервер
•'..
Проверка политик,
• - ····• •. телеметрия ..• •·····
... ..
Адаптер ◄ - • j~
rJ
--
Данные конфигурации ~
для прокси-серверов
..
'',, ,, ,,
Mixer
Данные
••
:
конфигурации
---
Pilot
◄ - • j~
--
~
:
Рис.
1.18.
•- ►
D
Адаптер
Сертификаты
TSL •
... .. .. .. .. :
j~
---
Citadel
Панель управления
lstio
lstio версии 1.1 с микросервисами.
https://istio.io/v1 .1/docs/concepts/what-is-istio/
Оригинальная архитектура
Источник:
..
,
,
для прокси-серверов :
Galley
Архитектура
.-
Прокси
сервер
,, ,,
1 .......
А
i
НТТР/1 . 1 . НТРР/2 ,
Что не так с монолитами?
цессе решения проблем
lstio
■
59
перешла от архитектуры микросервисов к единому
двоичному файлу под названием istiod, построенному в виде модульного моно
лита (рис.
1.19).
lstio Mesh
1Плоскость
данных
Входящий
1
---------------------~
•
i
СервисА
1
о
трафик
Прокси-
СервисВ
•
Трафик
Mesh
сервер
•
t
о
1
+
Проксисервер
Исходящий
t
трафик
Сертификаты
конфигурации
обнаружения
-,
Панель уп равления
1
Citadel
Pilot
Архитектура
Рис.
Источник:
1.19. Архитектура lstio -
Galley ]
lstio
монолитная архитектура.
https:1/istio.io/latest/docs/ops/deploymentlarchitecture/
Кристиан Поста является активным участником проекта
переход в своем благе:
«Istio
Istio
и кратко описывает
как пример того, когда не следует использовать мик
росервисы» 22 . Кристиан цитирует превосходный проектный документ2 3 от Луиса
Istio к монолиту, все
Райана, в котором излагаются аргументы в пользу перехода
обусловливается сложностью:
♦ упрощение процесса установки и обновления;
♦ снижение сложности конфигурации;
♦ упрощение настройки и эксплуатации
♦
lstio;
повышение эффективности и снижение накладных расходов, например за счет
совместного использования кешей;
♦ устранение ненужной связности за счет уменьшения потребности агентов
в доступе к привилегированной конфигурации.
22
https://Ыog.christianposta.com/microservices/istio-as-an-example-of-when-not-to-do-microservices/
23
https ://docs.google.com/document/d/1 v8Bxl07 u-mby5f5rC ruw F7 odSXgb9G8-C9W5hQtSIAg
lstio
60
■
Глава 1
Для Кристиана и других членов
сделала
Istio
Istio
общая сложность подхода к микросервисам
неоправданно трудоемким в использовании и эксплуатации. Еще не
сколько ключевых моментов, на которые стоит обратить внимание в замечательном
посте Кристиана:
♦
Микросервисы
-
не единственный подход. Проще говоря, в разработке про
граммного обеспечения нет единого правильного решения, а микросервисы
-
это не «идеальная архитектура приложений».
♦
На старте лучше всего держаться подальше от микросервисов. Как мы уже
говорили в разделе «Преимущества монолитов», когда компании только начи
нают
свою деятельность,
способом.
централизованная
архитектура
может
стать лучшим
Она позволяет сосредоточить внимание на создании продукта, отве
чающего требованиям рынка, а не на фиксированных технологиях.
♦
Честность в ситуации, когда что-то не получается. Даже если проект начи
нался с правильных намерений, признайте, что допускать ошибки и менять
архитектуру в рамках целенаправленной эволюции
-
это нормально.
Наличие монолита не означает автоматически, что у вас есть спагетти-кодовая база
практически без изоляции или модульности. И в некоторых случаях наличие не
большого количества модулей развертывания является неоспоримым преимущест
вом и может стать отличным техническим решением.
Модульные монолиты:
мобильные суперприложения
Да, мобильные приложения могут быть превосходно сконструированными модуль
ными монолитами. Независимо от того, написаны ли они на
Swift для IOS
или на гибридных платформах, таких как
Kotlin для Android,
React Native или Flutter, вы,
безусловно, можете соответствовать стандарту большой кодовой базы, и если вы не
хотите, чтобы вашим пользователям приходилось загружать несколько мобильных
приложений, то у вас будет мало модулей развертывания.
Для разработки мобильных приложений этот шаблон в настоящее время описыва
ется как суперприложение 24
(SuperApp).
Проекты
SuperApp
объединяют все функ
циональные возможности мобильных приложений организации в одно приложение.
Суперприложения имеют смысл по целому ряду причин:
♦
молодое поколение ожидает, что в первую очередь мобильные устройства обес
печат глубокую интеграцию и привлекательные впечатления;
♦
потребители получают консолидированные сервисы в рамках всего предприятия
в одном месте;
♦
♦
проще создавать и внедрять единый пользовательский опыт;
возможность перекрестных продаж продуктов в приложении с расширенным
функционалом.
24
Определение суперприложения от Gartner: bttps://www.gartner.com/en/articles/wbat-is-a-superapp.
Что не так с монолитами?
Gartner
ожидает, что к
активно пользоваться
2 приложения -
Uber
2027
году более
50 %
61
населения rmанеты будет ежедневно
несколькими суперприложениями.
для организации поездок и
перь оба решения доступны в едином
■
Раньше у
UberEats для
приложении (рис. 1.20).
Uber
было
доставки еды. Те
Uber
Get а ride
Orderfood
о
о
Goaqain
Рис.
1.20. Суперприложение Uber. Источник: https://www.forbes.com/sites/Ьizcarson/2019/09/26/
uber-overhauls-app-for-eats-rides/?sh=2133640045c8
Такие задачи неизбежно вынуждают компании использовать монолитную архитек
туру. При современных темпах развития больших технологий модульный монолит
является единственным практичным решением, позволяющим командам суперпри
ложений безопасно работать и выпускать приложения параллельно.
Можно ли избежать плохих монолитов?
Как мы уже говорили ранее в этой главе, в архитектуре программного обеспечения
не так много абсолютно правильных или абсолютно неправильных решений. Рас
смотрим еще раз траекторию между централизацией и распределенностью, пока
занную на рис.
1.2.
Не существует единого правильного выбора для проекта. На
самом деле правильный выбор имеет тенденцию меняться с течением времени,
учитывая присущую ему сложность, требования бизнеса, социальную среду и
аппаратные ограничения; то, что когда-то было правильным, позже становится
неправильным.
Монолиты
-
отличный пример того, как мы можем начать с очень позитивной и
эффективной архитектуры: они упрощают процессы и позволяют достичь большего
62
■
Глава 1
с меньшими затратами. Одна из распространенных историй возникновения моно
литов связана с компаниями-стартапами или компаниями на ранней стадии разви
тия; им рекомендуется сохранять свою техническую архитектуру простой и понят
ной, пока они добиваются соответствия продукта рынку, и сосредоточиться на
рефакторинге для обеспечения масштабируемости и отказоустойчивости после
достижения успеха. Нужно избегать потерь времени на преждевременную оптими
зацию технологии, которая не приносит существенной пользы бизнесу.
На противоположном конце спектра устоявшиеся компании могут прийти к такому
же результату, разрабатывая крупные проекты, находящиеся в центре внимания
(Big Designs Up Front, BDUF).
По мере добавления все новых требований конечный
продукт получается слишком сложным, реализованным в виде единой системы
или, что еще хуже, в виде распределенного монолита.
Независимо от того, создавался ли монолит с благими намерениями или в попытках
преодолеть обнаруженную сложность, монолиты в конечном итоге становятся бо
левой точкой, препятствующей эффективному масштабированию. Именно в этот
момент монолиты перестают обладать положительными характеристиками и пре
вращаются в кошмар (рис.
1.21).
Это может занять
10
лет или
l
год. Наступает мо
мент, когда антипаттерны укореняются, побочные эффекты начинают перевеши
вать любые преимущества, и все это усугубляется усилителями
(amplifier).
Именно
тогда растущее осознание изнурительного состояния монолита становится очевид
ным как для технических специалистов, так и для бизнес-команд.
Когда ценность превращается в долг
Долг/Боль
Рис.
1.21.
Ценность превращается в долг, и мы катимся под откос
Ключ к тому, чтобы избежать этого переломного момента,
-
вовремя распознать
закономерности и начать действовать. К сожалению, это сложнее, чем кажется. На
пример, когда мы говорим об антипаттерне высокой степени связанности, слож
ность заключается в том, что его не всегда легко обнаружить до тех пор, пока он не
станет очевидным. Для этого требуются время,
понимание бизнес-требований,
своевременный анализ проекта. Другими словами, чтобы выявить и устранить эти
проблемы, необходимо придерживаться дисциплинированной практики разработки
как в бизнесе, так и в инженерном деле. Необходимо постоянно контролировать
появление ненужных сложностей и бороться с ними.
Что не так с монолитами?
■
63
Короче говоря, если вы хотите избежать переломного момента в своей работе, вам
нужно культивировать хорошие практики и избегать плохих решений. Хотя это
легче сказать, чем сделать, помогите заинтересованным сторонам вашего бизнеса
избежать такого поведения, которое приводит к технической задолженности и пло
хому результату.
♦ Нереалистичные сроки. Легко попасть в ловушку с дизайном или программ
ным обеспечением, если работать надо быстрее, чем вы способны создавать
новые функции, и избегать технической задолженности. Помните, что лучшие
решения получаются в результате совместной работы специалистов по продук
там, дизайну, инженерии и бизнесу. Команды, которые отчаянно пытаются уло
житься в срок, пропускают этот первый шаг.
♦
Фокус на новых функциях. Каждое предприятие должно признать, что на тех
ническое обслуживание необходимо тратить время, чтобы избежать дополни
тельного упадка. Постоянное внедрение новых функций
-
верный способ соз
дать перегруженную команду, не имеющую достаточного времени для устране
ния технического долга и внедрения передовых практик.
♦
Отсутствие структуры. Переход от функции к функции без создания прототи
пов, тестирования
пользователями или предоставления идеям или дизайнам
возможности достичь зрелости
-
это идеальный способ растянуть команду и
увеличить техническую задолженность, особенно если это усугубляется нереа
листичными сроками.
♦ Направляйте решение, а не определяйте проблему. «Все, что нам нужно сде
лать, это изменить один экран, и все готово! Это должно быть просто!». Дове
ряйте своим инженерам и архитекторам, они должны знать свои системы, пре
имущества и последствия: говорите им, ЧТО, но не говорите, КАК. Сотрудни
чайте, а не диктуйте; и прислушивайтесь к их советам, но не отменяйте их.
♦ Сокращение затрат. Когда дело доходит до проектирования, вы часто получае
те то, за что платите. Квалифицированные инженеры стоят денег, а дешевые
подрядчики
-
нет, но в итоге вы все равно платите больше, поскольку нехватка
квалифицированных специалистов
(lack of Talent Density) приводит к еще худ
- это работа с талантливыми,
шим результатам. Правильный способ работы
должным образом подготовленными инженерами, которые получают соответст
вующие указания, независимо от того, работают ли они в вашей компании или
за ее пределами. Компании на свой страх и риск игнорируют этот момент.
Конечным результатом является то, что команда инженеров вынуждена следовать
плохим практикам. Лучшие команды инженеров применяют дисциплину и стро
гость для обеспечения хороших практик; плохие команды позволяют плохим прак
тикам процветать и усугубляться. Распространенные плохие практики включают:
♦ Отсутствие надлежащего код-ревью.
LGTM25
при каждом запросе на обновле
ние, никаких комментариев, никакого рефакторинга
25
LGTM (looks good to me -
-
нет более быстрого спо-
на мой взгляд, хорошо)- сокращение, которое часто встречается на гитхаб
в комментариях к подтверждению коммитов. Обычно его используют, когда не получается сказать ничего
конструктивного по поводу кода.
-
Пер.
64
■
Глава 1
соба реализовать ситуацию с разбитыми окнами
(Broken windows)
в рекордно
короткие сроки.
♦
Поверхностные ретроспективы.
15
минут не помогут. Вам нужно отмечать
прошлые успехи и перечислять распространенные неудачи, иначе вы повторите
ошибки прошлого и не сможете развить свои сильные стороны. Командам необ
ходимо изучить и пересмотреть свои убеждения. Вы не сможете достичь этого,
не углубившись в суть, а это требует времени.
♦
Отсутствие простоев. Всем командам требуется неструктурированное время
для проведения технического обслуживания и приведения в порядок своих ре
шений. В противном случае небольшие технические проблемы быстро перерас
тут в серьезные.
♦ Неумение наставлять и развивать команду. Разработка программного обес
печения
-
это бесконечно развивающаяся дисциплина. Чтобы преуспеть в ней,
члены команды должны осознанно работать над своим индивидуальным разви
тием. Разработка программного обеспечения
рываете благодаря стратегии
(strategy)
-
это спорт, а не война; вы выиг
и индивидуальному исполнению, а не
забрасывая проблему телами. Наставничество повышает способность членов
вашей команды к обучению, улучшает их практику и помогает им расти и рас
крывать свой индивидуальный потенциал
♦
-
как для вас, так и для них самих.
Отсутствие технического руководства. Кто-то должен встать и сказать «нет»
плохим решениям, независимо от давления, и поддержать все передовые мето
ды, ранее упомянутые в этом разделе.
Важно то, как мы разрабатываем программное обеспечение. Монолиты создаются
не
в
вакууме:
вы достигаете
переломного
момента
из-за неудачных
инженерных
решений, часто под влиянием бизнеса, стремящегося к непрактичным целям. Пере
ломный момент не является неизбежным
-
применяйте эти методы, и сможете из
бежать появления ужасного монолита в вашем будущем.
Что нужно запомнить
Поздравляем вас с завершением главы
1! Мы
рассказали вам о ключевых чертах и
характеристиках монолитов, о том, почему монолиты часто ассоциируются с про
блемами и как команды в конечном итоге их создают. Мы также узнали, что не все
монолиты одинаковы, не все обязательно плохи, и в некоторых сценариях моноли
ты могут быть подходящей архитектурой для решения поставленной задачи.
Далее мы подробно рассмотрим наиболее важные антипаттерны, которые влияют
на монолиты и архитектуру программного обеспечения в целом: отсутствие изоля
ции, распределенные монолиты и общие библиотеки. Только поняв, что такое ан
типаттерны, мы сможем правильно разработать решение. Давайте продолжим!
Кратко, вы изучили:
♦
Монолиты
-
это стиль архитектуры программного обеспечения, при котором
большой объем кода устанавливается с использованием небольшого числа мо-
Что не так с монолитами?
■
65
дулей развертывания. Монолиты имеют другие особенности кода, например
склонность к централизации или большой срок жизни.
♦ Монолиты
♦
-
это архитектурный стиль со значительными компромиссами.
Монолиты плохи не потому, что они большие.
♦ Монолиты плохи тем, что их архитектурный стиль поощряет использование не
стандартных решений и создает побочные эффекты, которые приводят к тех
нической задолженности. Результатом являются не·гативные последствия как
для бизнеса, так и для технологий, такие как высокие затраты на техническое
обслуживание и частые простои.
♦ Монолиты со временем разрушаются.
♦ Монолиты по своей сути способствуют появлению антипаттернов:
•
Высокая степень связности, когда программные компоненты излишне взаи
модействуют друг с другом.
•
Неправильные абстракции, когда вы используете неправильный шаблон для
решения проблемы.
•
Оrсутствие изоляции, которое из-за отсутствия границ ограничивает незави
симость программного обеспечения и его эволюцию.
♦ Из-за перечисленных антипаттернов монолиты испытывают побочные эффекты:
•
СлоЖJ!ые развертывания, затрудняющие выпуск программного обеспечения и
приводящие к простоям. Классические монолиты
(classical monolith)
не по
зволяют командам выполнять независимые развертывания.
•
Недостаточный уровень тестирования, когда комплексность, присущая моно
литу, очень затрудняет оценку всех возможных результатов.
•
Оrсутствие владельца при отсутствии границ приводит к тому, что команда
практически не владеет компонентами напрямую.
•
Медленное внедрение новых технологий в результате невозможности внести
изменения из-за таких явлений, как бинарная связь.
•
Медленный цикл разработки, что является конечным результатом всего вы
шеперечисленного.
♦ Эти изменения со временем усугубляют проблемы монолитов:
•
Разбитые окна, из-за чего техническая задолженность распространяется по
всей кодовой базе.
•
Зависть к микросервисам, когда команды, ненавидящие монолиты, бросаются
к плохо разработанному микросервисному решению, усугубляя проблему.
•
Нехватка квалифицированных специалистов в результате того, что бюрокра
тия монолитов отталкивает таланты и увеличивает текучесть кадров. Инже
неры часто не заинтересованы в работе с монолитами.
•
Боязнь перемен, которая мешает вам вносить необходимые изменения для
улучшения дизайна монолита и решения технических проблем.
■
66
♦
Глава 1
Не все монолиты плохи. Иногда они представляют собой правильный архитек
турный подход, при котором централизация является корректным решением.
♦
Правильно реализованные монолиты обладают следующими преимуществами:
•
Рефакторинг монолита проще, т. к., когда код находится в одном месте, легче
увидеть влияние определенных изменений.
•
Некоторые миграции упрощены, поскольку вы можете внести изменение
в одно место и обновить всё.
•
Благодаря меньшим организационным затратам и упрощенной инфраструк
туре вы можете быстро внедрять монолиты, что делает их отличным местом
для любого стартапа на ранней стадии.
♦
Существуют три вида монолитов, которые разделяют эти элементы: два плохих
и один хороший.
•
Классический/устаревший монолит, такой как настольное приложение
dows
•
или более старое приложение
Java
Win-
МУС.
Распределенный монолит, в котором группа микросервисов выглядит незави
симой, но на самом деле они имеют высокую степень связности и должны
рассматриваться как единое целое.
•
Модульный монолит, в котором вы правильно определили границы между
компонентами и решили разделить их на несколько модулей развертывания.
♦
Istio
и мобильные суперприложения
-
два отличных примера модульного мо
нолитного программного обеспечения. Модульные монолиты активно разраба
тываются многими компаниями, такими как
♦ Давление культуры или бизнеса
Shopify и Segment.
(business pressure)
может привести к созданию
плохих монолитов из-за требований нереалистичных сроков, стремления только
к функциональным
возможностям,
отказа от сотрудничества,
недопущения
инженеров к разработке технических решений и общего отсутствия дисциплины
и структуры.
♦
Плохих монолитов можно избежать, но в основном за счет соблюдения надле
жащих инженерных практик, таких как надлежащий код-ревью, хорошие ретро
спективы, поощрение простоя для погашения технической задолженности, по
ощрение наставничества и сильного технического руководства.
ГЛАВА
2
Антипаттерны:
отсутствие изоляции
Ваши личные границы защищают внутреннюю суть вашей идентичности и ваше право на выбор.
Джерард Мэнли Хопкинс
Разработка программного обеспечения
сложная задача. Еще сложнее создавать
-
системы, которые будут работать долго и качественно; многим это не удается. Как
часто вам хочется нажимать кнопку Перезагрузка
(Reset)
и начинать все сначала?
Как вы думаете, если просто начать все сначала, это в корне устранит все ваши
проблемы? Вы на
100 %
уверены, что знаете, в чем они заключаются? Как вы мо
жете предотвратить их повторение?
В этой главе мы откроем один из самых важных секретов успешной архитектуры
программного обеспечения, возможно, один из главных ключей вселенной
ляцию
(isolation).
-
изо
Изоляция освобождает, ее свобода волшебна; это все равно, что
взять торт и съесть его. Изоляция
-
это правильный путь при разработке архитек
туры программного обеспечения. Изоляция позволит вам допускать ошибки и ис
правлять их, не переписывая всю вселенную.
Структура главы
В этой главе мы рассмотрим следующие темы:
♦ Что такое изоляция?
•
Изоляция в программном обеспечении.
♦ Соблазны изоляции.
•
Внешнее воздействие.
0
Существующий компонент,
0
Существующий компонент, изменение существующей конечной точки.
0
Существующий сервис, добавление новой конечной точки.
0
Новый сервис, общий доступ к базе данных.
0
Что такое бэкенд для фронтенда
BFF.
(BFF)?
Глава 2
■
68
•
□
Новый сервис, общий доступ к данным.
□
Что такое обработка собьrrий?
□
Обработка событий в программном обеспечении.
□
CQRS
□
Новый сервис, общий доступ через
и ее связь с
ES.
API.
Централизация.
□
Преимущества централизации инженерных команд.
□
Проблемы, связанные с чрезмерной централизацией.
□
Проблемы с поставками и инновациями.
□
Централизация в сравнении со стандартизацией для обеспечения наблю
даемости и развертывания.
□
Плохие общие библиотеки.
♦ Разрушение изоляции.
•
•
Совместное использование баз данных.
□
Когда можно использовать базы данных совместно?
□
Базы данных приложений для совместного использования в
□
Скрьrrые контракты и сохранение изоляции.
□
Интеграция с устаревшими системами.
Big Data.
Общие библиотеки.
□
Бинарная связь.
•
Отсутствие стабильных контрактов.
•
Повышение сложности.
□
Детализация и распространение: побочные эффекты.
♦ Давайте изолируем всё.
•
Базы данных.
•
Общие библиотеки.
•
Стабильные контракты.
•
Насыщенные модули и философия проектирования программного обеспе
чения.
•
Операционные системы и инфраструктура.
•
Расширенная изоляция.
□
Сооружение переборок и изоляция сбоев.
□
Резервные варианты.
□
Изоляция пользовательского опыта: деградация и изыскания.
Антипаттерны: отсутствие изоляции
♦
69
Как предотвратить проблемы с изоляцией.
•
♦
■
Обзор конструкций и оснастки.
Что нужно запомнить.
Что такое изоляция?
Изоляция
(isolation) -
это часть природы; вы можете наблюдать ее в клетках жи
вых организмов или наблюдать, как она меняется из-за того, что вещества перехо
дят из газообразного состояния в жидкое и твердое. Изоляция
-
фундаментальная
концепция устройства вселенной. Она прекрасна. Прежде чем мы попытаемся дать
ей определение в программных терминах, давайте начнем с простой метафоры.
Представьте, что у вас есть два разных лотка для льда.
Лед
Пусто
Рис.
Апельсиновый сок
Лед
2.1.
Вода
Шоколад
Метафора лотка для льда, обозначающая изоляцию
Монолитный лоток для льда (рис.
2.1,
слева). Кубик льда не так-то просто выре
зать; это выбор «все или ничего». Либо у нас получится целая плитка льда, либо
в поддоне будет вода. Да, вы могли бы попытаться отколоть лед и вытащить кусок
Но удачи вам в том, чтобы собрать лед обратно в лоток! Давайте посмотрим правде
в глаза, лоток нам не поможет; нам нужно проделать большую работу со своей сто
роны, и есть большой шанс все испортить.
Лоток для льда с изоляцией (рис.
2.1,
справа). Лоток разделяет лед на более мел
кие кубики. Каждый кубик может находиться в разном состоянии; например, неко
торые кубики могут быть наполнены водой, в другом кубике может быть апельси
новый сок, в следующем кубике может быть шоколадное молоко, а некоторые мо
гут быть полностью пустыми. Одно из преимуществ заключается в том, что вы
можете взять небольшой кубик льда из лотка, не касаясь других кубиков. Лоток
изолирует каждый кубик от другого, что делает процесс приготовления более
удобным, безопасным и быстрым. Несмотря на то что кубики льда не полностью
изолированы друг от друга
-
они находятся в одном лотке и в одной морозильной
камере, а значит, подвергаются воздействию одинаковой температуры
-
разделе
ние дает нам некоторую свободу в работе с отдельными кубиками, защищает их от
смешивания друг с другом и в целом снижает общее воздействие.
70
■
Глава 2
Изоляция в программном обеспечении
Изоляция
-
это способ организации программных и аппаратных технологий, при
котором каждый компонент отделен от другого. Компонентом может быть что
v
угодно, например, процесс операционнои системы
б азы
з
данных ,
4
порт ,
s
ресурс ,
1
,
вкладка
би золяция
контеинер .
V
б
раузера
может
2
б ыть
,
транзакция
Ф изическои,
V
локальной или виртуальной. В этой главе будут рассмотрены и другие формы изо
ляции.
Изоляция
-
это основной принцип архитектуры программного обеспечения. Это
ключевой элемент успеха и крайне желательное свойство. Это настолько важно,
что мы посвящаем ему целую главу, чтобы вы знали, что происходит, когда изоля
ция отсутствует или применяется неправильно.
Мы бы не хотели вас обманывать: добиться правильного баланса изоляции непро
сто. Это требует большой дисциплины и постоянного внимания. К тому времени,
когда вы закончите читать эту главу, вы будете знать, что такое изоляция, какие
соблазны возникают на пути к достижению сбалансированной изоляции в вашей
архитектуре, что происходит не так,
когда вы нарушаете изоляцию, и как это ис
править.
Когда программное обеспечение изолировано надлежащим образом, это ЗОЛОТО.
У вас есть множество преимуществ. Когда что-то не изолировано должным обра
зом, вы в беде. Изоляция
-
это способ уменьшить радиус поражения и ограничить
потенциальное воздействие изменений. Изоляция помогает избежать глобального
воздействия, глобального состояния и глобальных побочных эффектов. В конце
концов, вы хотите изменить
Изоляция
-
I
строку кода и повлиять на все классы в кодовой базе?
это способ сделать код более независимым, точным, надежным, мас
штабируемым и безопасным для работы. Изоляция
ство, и изоляция
Изоляция
-
-
-
это очень желательное свой
это всегда хорошая идея.
это спектр (рис.
2.2),
не просто наличие или отсутствие. Однако это
свойство настолько важно, что вы хотите всегда стремиться к левому краю. Приме
нение надлежащего уровня изоляции обеспечивает множество преимуществ, таких
1 Изоляция
2
процессов операционной системы https://en.wikipedia.org/wiki/Process_isolation.
В современных браузерах, таких как Google Cl1ron1e, каждая вкладка, которую вы открываете для посеще
ния веб-сайта или плагина, запускается изо:шронанно
https://en. wikipedia.org/wiki/Google_ Chrome#Sta Ьility.
Реляционные базы данных часто реа.1изуют свойства ACID, где буква I означает изоляцию
https://en.wikipedia.org/wiki/ACID.
3
4
Существует концепция организации частной сети VLAN, также на·1ываемой технологией изоляции портов,
которая ограничивает возможность обмена сообщениями только по заданному uplink-пopтy
https://en.wikipedia.org/wiki/Private_\!LAN.
5
Ядро Linux использует груп11ы управления (cgroups) для ограничения ресурсов, таких как процессор,
https://en.wikipedia.org/wiki/Cgroups.
память и доступ к диску
6
FreeBSD jails -
это виртуа:1ьные среды для запуска программного обес11ечения, обеспечивающие допол
https://en.wikipedia.org/~·iki/FreeBSD_jail.
нительную защиту основной операционной системы
Антипаттерны: отсутствие изоляции
■
71
Отсутствие изоляции
Изоляция
+ Безопасно
+ Ограниченный радиус поражения
+ Скрытие информации
-
+ Инкапсуляция
+ Границы
Рис.
2.2.
Небезопасно
Большой радиус поражения
Высокая степень связности
Глобальное состояние
Отсутствие границ
Спектр изоляции
как безопасность, ограниченный радиус поражения, скрытие информации, инкап
суляция, четкие границы, надежность и многое другое.
Соблазны изоляции
Новые концепции подобны обоюдоострому мечу, это риск. Результат может быть
хорошим, но при неправильном применении
-
ужасным. Случиться может всё что
угодно. Поэтому у вас возникнет соблазн действовать быстро, но при этом нужно
постоянно быть начеку. Это как предупреждающий сигнал: «Внимание, будьте ос
торожны: впереди опасность» (рис.
изоляции
(proper isolation)
2.3).
На вашем пути к достижению надлежащей
вас ждет множество искушений. Искушения не обяза
тельно разрушают изоляцию, но они могут привести к нарушению изоляции, если
вы будете недостаточно осторожны. Различные технические решения лучше или
хуже, чем другие.
Рис.
Источник:
2.3.
Соблазны изоляции
-
будьте осторожны.
https://dmv-permit-test.com/road-signs/slippery-road-sign
Внешнее воздействие
Чтобы программное обеспечение имело ценность, мы должны уметь взаимодейст
вовать с ним. Существует несколько способов контактировать с программным
обеспечением. Эта связь может осуществляться как между человеком и машиной,
так и между машинами. Взаимодействие человека с машиной облегчается с помо
щью пользовательских интерфейсов. Чаще всего мы сталкиваемся с клиентскими
интерфейсами: для настольных компьютеров, в виде приложений для мобильных
телефонов, веб-приложений; интерфейсы могут быть текстовыми или разговорны-
72
■
Глава 2
ми, в виде терминала/СL1 7 или чат-бота, аудиоколонки типа Alexa интерфейсы
могут влючать AR VR или расширенную реальность (XR
Машины, взаимо
действуя с другими машинами, часто используют АР1 12 , который может быть в тек
8
;
10
9
11
,
) .
стовой форме, например в виде
форматы сериализации, такие
WebAssemЫy,
Thrift,
или многие другие двоичные форматы. Когда машина взаи
модействует с машиной,
вызвать (рис.
JSON или XML, или в двоичной, использующей
как Google Protocol Buffers, Google FlatBuffers,
API
должен быть доступен для того, чтобы мы могли его
2.4).
ReP.ct Web fJI
ReP.ct Web UI
Noa~f IBFf
Nod~f IBFf
Отчет пользователя
не отображается!
Сервис профилей
О"Nет
пользователя
DAtAbo.re
MySQL
Рис.
2.4.
Внешнее воздействие
Чтобы проиллюстрировать основные положения этой книги, мы рассмотрим кли
ентское веб-приложение, которое позволяет сотрудникам компании
продавать свои виджеты. Приложение написано на
Java
и
JavaScript
Acme Widget
и имеет четыре
ключевые функции:
7
CLI (Command Line Interface)- интерфейс командной строки, позволяющий управлять различными про
- Пер.
цессами в компьютере с помощью текстовых команд.
8
Arnazon А\еха -
в умных колонках
9
виртуальный ассистент, разработанный компанией Amazon и впервые появившийся
Amazon Echo
и
объекть1 к тому, что люди видят в реальности.
10
Пер.
Amazon Echo Dot. -
Дополненная реальность (augmented rea\ity, AR) -
-
Виртуальная реальность (virtual reality, VR) -
технология, которая позволяет добавлять виртуальные
Пер.
технология полного погружения в виртуальный мир за счет
иммерснвных устройсm, таких как знакомые всем VR-очки.
11
-
Пер.
Расширенная реальность (extended reality, XR)- обобщающий термин для обозначения дополненной
реальности, виртуальной реальности и смешанной реальности. Технология предназначена для объединения
или зеркального отображения физического мира с миром
-
цифровым двойником, способным взаимодей
ствовать с ним, предоставляя пользователям захватывающий опыт пребывания в виртуальной или допол
ненной среде.
12
-
Пер.
API (application programming interface, программный интерфейс приложения) -
это набор способов и
правил, по которым различные программы общаются между собой и обмениваются данными.
-
Пер.
Антипаттерны: отсутствие изоляции
♦
■
73
профили: функция отслеживает основную информацию о клиентах, такую как
имя, адрес или номер телефона; также известен как профиль пользователя;
♦
продажи: функция управляет процессом продаж, включая корзины покупок,
виджеты, суммы и общую стоимость;
♦
платежи: функция безопасно собирает наличные у клиентов и направляет их
в компанию;
♦ отчеты: функция предоставляет отчеты в формате
PDF
об использовании и про-
дажах по отдельным клиентам или за весь день.
Конечно, в реальном мире приложение
Acme Widget
имело бы гораздо больше
функций, таких как проверка подлинности, определение виджетов, инвентаризация
виджетов и другие требования. Но пока этого будет достаточно.
В нашем примере есть типичный стек веб-приложений. Чтобы увидеть его в действии,
рассмотрим простое требование- отображать имя клиента при входе в систему.
♦
Веб-интерфейс на основе
React
запускает вызов
BFF
(паттерн уровня
backend
для интерфейса, см. далее раздел «Что такое бэкенд для фронтенда?») для за
проса профиля пользователя, вошедшего в систему.
♦
реализованный на
BFF,
JavaScript,
аутентифицирует сеанс пользователя, прове
ряет вводимые данные на безопасность и вызывает сервис профилей через
REST,
запуская НТТР-запрос на /user/25.
♦
Сервис профилей на основе
Java
проверяет, является ли запрос действительным
и имеет ли пользователь право просматривать данные. Для выполнения этой
проверки он использует свою реализацию драйвера базы данных для создания
запроса к хранилищу данных, реализованному на системе управления баз дан
ных МуSQL.
♦
База данных
♦
Сервис
профилей
в формат
♦
BFF
MySQL
SQL и
надлежащим
возвращает имя пользователя.
образом
форматирует
возвращаемый
ответ
JSON.
удаляет любую несущественную информацию из этого
ее приложению
♦
вычисляет
Приложение
JSON
и возвращает
React.
React отображает имя
пользователя.
Предположим, что сервис профилей написан на
ность предоставлять отчет в формате
PDF
Java
и имеет внутреннюю возмож
о ежегодных покупках пользователя,
и у нас есть новое требование вернуть этот отчет нашему клиенту. Ни один объект
за пределами сервиса профилей не может использовать эту возможность, даже при
наличии кода, потому что он не доступен.
BFF
смог получить профиль пользовате
ля из сервиса профилей только потому, что сервис предоставил
вращает
JSON.
Таким образом, новый компонент
React UI
или
API; REST API воз
BFF не может полу
чить доступ к этой возможности из серверной части.
Необходимо изменить кое-что в архитектуре, чтобы удовлетворить это требование.
Есть варианть1, однако не все из них приведут к хорошим результатам с точки зре
ния архитектурного проектирования и технического прогресса.
■
74
Глава 2
Естественно, этот сценарий подводит нас к началу обсуждения изоляции. Каждый
вариант требует компромиссов, которые влияют на изоляцию отдельных компо
нентов в нашей архитектуре.
♦
Существующие компоненты
• BFF.
Переопределение функциональности на уровне
BFF
и обращение к той
же базе данных, которая вызывается сервисом профилей.
•
Изменение существующей конечной точки. Предоставление обеих функ
циональных возможностей из существующей конечной точки
врат большего количества данных в виде полезной нагрузки
•
(/user/25), воз
JSON.
Добавление новой конечной точки. Предоставление доступа к другой ко
нечной точке в сервисе профилей, например /user/report/25.
♦
Новый сервис
•
Общий доступ к базе данных. Перенос этой функциональности в другой
сервис (сервис отчетов) и предоставление ее там, но с использованием той же
базы данных, так называемое совместное использование базы данных;
•
Общий доступ к данным. Предоставление общего доступа к данным, но не
к базе данных; создание нового сервиса, для которого данные будут получе
ны косвенно из сервиса профилей через обработку событий;
•
Общий доступ через
API.
Создание нового сервиса, который будет получать
данные из сервиса профилей, вызывая его
Существующий компонент,
API.
BFF
Повторная реализация функциональности сервиса отчетов в
BFF
сопряжена с теми
же проблемами, что и в любой из новых опций сервиса. В некотором смысле это
немного лучше; меньше шансов, что у вас будет плохая общая библиотека между
реализациями, потому что код написан на другом языке
-
Java
или
JavaScript.
Но
у нас есть и другие проблемы, такие как ненужное дублирование кода, ошибки
в разных реализациях, и вам по-прежнему необходимо согласовывать изменение
базы данных или другие изменения в нескольких проектных командах. На самом
деле вы только увеличили сложность стека, а не устранили проблему.
Существующий компонент,
изменение существующей конечной точки
Добавление дополнительных данных в существующую конечную точку сервиса
профилей кажется привлекательным. Поскольку у нас есть два разных типа МIМЕ
данных: данные
JSON
для профиля пользователя и двоичный отчет в формате
теперь нам нужно объединить обычный текст и данные, закодированные в
в объект
JSON.
PDF,
base64,
Каждый раз, когда вы вызываете конечную точку для получения
имени пользователя
-
небольшого фрагмента данных,
-
вы получаете РDF-файл
со всеми его продажами за год. Что, если в будущем вы захотите запросить кон
кретные периоды времени для отображения в отчете в формате
PDF?
Результатом
Антипаттерны: отсутствие изоляции
здесь будет непонятный код и неестественный
API,
■
75
т. е. еще больше технических
проблем.
Так зачем вообще рассматривать этот вариант? В данном случае это может быть не
лучшим вариантом, но во многих других случаях добавление еще одной операции
в существующий код окажется более простым и, возможно, правильным решением.
Вам нужно учитывать все аспекты, в том числе такие, как:
♦ Есть ли подходящее место для этой функции/возможности?
♦
Насколько это изменение нарушает концептуальную целостность сервиса?
♦ Должны ли другие сервисы и пользовательские интерфейсы вызывать эту опе
рацию?
♦
Будут ли все функциональные возможности использовать одни и те же шаблоны
доступа?
Добавление новой конечной точки
-
это не обед за чужой счет. Вы можете увели
чить сложность, создать больше связей или разрушить изоляцию. Любой шаг тре
бует тщательного обдумывания и анализа возможных компромиссов.
Существующий сервис, добавление новой конечной точки
Добавление новой конечной точки в сервис профилей
-
это самое простое реше
ние, которое не создает проблем с изоляцией базы данных или скрытыми контрак
тами. Отдельная конечная точка без проблем вернет двоичный файл
PDF
и не уве
личит объем первоначального вызова сервиса профилей. Однако этот вариант так
же может привести к проблемам; если функция находится в неправильном сервисе,
у нас могут возникнуть проблемы с подключением, излишняя сложность и техни
ческие проблемы.
Прежде чем отказаться от этой опции, задумайтесь: возможно, это лучшая отправ
ная точка, чем вы думаете. Вы всегда можете отключить сервис и перенести код
в другое место.
Всякий раз, когда вам нужно представить информацию об операциях, функциях
или бизнес-возможностях, проводите этот анализ компромиссов. Подумайте о том,
что имеет больше смысла в краткосрочной и долгосрочной перспективе. Хотя это
может
показаться
слишком
сложным,
решения
часто
принимаются лучше,
когда
у вас есть представление о целом, а не только о том, что нужно сделать вашей
команде.
Главный риск здесь заключается в том, что мы ставим под угрозу контракт, а также
общее единство и цель сервиса. Это может быть неправильно, но, учитывая все об
стоятельства, данная беда может быть наименьшей из бед.
Новый сервис, общий доступ к базе данных
Мы можем создать выделенный сервис, поскольку у нас есть отдельный пользова
тельский интерфейс в
React
и отдельный
BFF
в
NodeJS.
Но этот сервис должен
иметь доступ к данным профиля; в этом варианте мы используем одну и ту же базу
данных.
76
■
Глава 2
Совместное использование базы данных создает очевидные проблемы с изоляцией
между сервисом профилей и сервисом отчетов (рис.
2.5).
Что произойдет, если дру
гая команда изменит функциональность профиля пользователя и переименует таб
лицу из user в profile? Итак, ваш пользовательский отчет теперь не работает. То же
самое может произойти и со стороны команды отчетов. Таким образом, оба сервиса
могут нарушить работу друг друга, если их команды внесут изменения в базу дан
ных.
Что
произойдет,
если
команда
сервиса
профилей
захочет
использовать
Cassandra 13 , а команда отчетов не захочет переходить на Cassandra? Мы объединили
эти два сервиса; они больше не являются полностью независимыми.
Новый сервис
Общий доступ
к базе данных
R.et).ct Web UI
R.et).Ct Web UI
Node}f I BFF
Node}f I BFF
/цrer/25
/цrer/re,m·t/25
Сервис профилей
Сервис отчетов
Что произойдет,
если изменить
таблицу
Рис.
2.5.
User?
Новый сервис, общий доступ к базе данных (плохая идея)
Возможно, вам будет интересно, но связан только уровень базы данных! Остальной
код изолирован и не имеет проблем! Ну, т. е. имеет или не имеет, зависит от нашей
реализации. Представьте, что у вас есть POJ0 14 для представления пользователя
в объекте profile. Вы дублируете имеющийся код в обоих сервисах или создаете
общую библиотеку с этими
POJO,
а затем оба сервиса используют эту библиотеку?
В любом случае это плохая идея, поскольку вы используете общую базу данных.
Теперь оба сервиса связаны, и у вас есть связь не только на уровне базы данных, но
и в основном домене каждого сервиса. Совместное использование базы данных
создает ситуации, которые приводят к нарушению изоляции. Мы рассмотрим этот
антипаттерн более подробно в главе
4
«Антипаттерн: внутренние общие библио
теки».
13
Apache Cassandra - Пер.
распределенная система управления базами данных, относящаяся к классу NoSQL-
cиcтeм.
14
POJO (Plain Old Java Object) - это простой Jаvа-объект, не унаследованный от какого-то специфического
объекта и не реализующий никаких служебных интерфейсов сверх тех, которые нужны для бизнес
модели.
-
Пер.
Антипаттерны: отсутствие изопяции
Что такое бэкенд для фронтенда
■
77
(BFF)?
SoundCloud впервые применила термин «бэкенд для фронтенда)) (Backend for
Frontend, BFF)1 5 еще в 2013 году. SoundCloud определяет BFF как «архитек,урный
шаблон, который предполагает создание нескольких выделенных шлюзов API (API
Gateway) для каждого устройства или типа интерфейса с целью оптимизации каж
дого API для его конкретного варианта использования)).
BFF
живет между фронтендом и бэкендом (рис.
2.6), являясь, как следует из назва
BFF часто пишутся на JavaScript
ния, серверной частью для внешнего интерфейса.
или
TypeScript, работающих на NodeJS, но они могут быть написаны на любом
BFF появляются там, где у вас есть код, специфичный для пользовательско
языке.
го интерфейса и недостаточно универсальный для использования в сервисе. Код
в
BPF,
как правило, должен использоваться повторно, иметь требования к произво
дительности или обрабатывать безопасность или другие важные функции, поэтому
его не следует реализовывать с помощью фронтенда. BFF часто является агрегато
ром вызовов
API
для одного пользовательского интерфейса или группы пользова
тельских интерфейсов.
GЕТ /users/123Лikes
~
+Б~лансировка
~+
нагрузки
.. .
а. ,
Q) '
,
:::;
Интернет
Рис.
~:
Зона доступности
Q) '
С •
2.6. BFF согласно SoundCloud:
https://developers.soundcloud.com/Ыog/service-architecture-1
Новый сервис, общий доступ к данным
Создайте новый сервис, но отделите сервис профилей от сервиса отчетов, создав
очередь обмена сообщениями. Сервис профилей записывает изменения данных
о профилях пользователей в эту очередь, а также в свою базу данных. Сервис отче
тов может считывать очередь и записывать необходимые данные в свою локальную
базу данных, используя их по мере поступления запросов. Это реализация шаблона
«обработка событий».
Что такое обработка событий?
Обработка событий (Event sourcing, ES) 16
-
это способ фиксировать изменения
в форме событий, а не в конечных значениях. Возможно, самый классический и
15
Вот отличная статья о путешествии SoundCloud с BFF:
bttps://developers.soundcloud.com/Ыog/service-aгchitectuгe-1.
16
Вот хорошая статья Мартина Фаулера про ES: https://maгtinfowleг.com/eaaDev/EventSouгcing.html.
78
■
Глава 2
старый пример
это финансовая книга, в которой хранятся не конечные значения,
-
а их изменения.
Обработка событий в программном обеспечении
Паттерн обработки событий связан не с технологией, а с моделированием данных.
Вы можете сохранять события в очередь сообщений, базу данных или даже добав
лять их в файл: важно вести неизменяемый журнал событий, а не просто корректи
ровать сами конечные значения. Конечно, некоторые технологии делают этот про
цесс проще, чем другие, например специализированное программное обеспечение,
такое как
Kafka.
Здесь, на рис.
2.7,
для простоты мы проиллюстрировали пример с одной записью
в бухгалтерской книге. На самом деле в бухгалтерском учете используется двnйная
бухгалтерская книга. Представьте, что для каждого перевода делается одна запись
в таблице для Диего, а другая запись в таблице для Сэма. Тогда вы можете сверять
вычеты. Это основа современного бухгалтерского учета, созданная Лукой Пачоли
в 1494 году 17 .
Когда?
Сколько
(USD)
Описан ие из менения
1 января 2010
600
Диего внес
1О декабря 2012
900
Сэм внес
16 фе в раля 2014
100
Сэм забрал
24 декабря 2015
60
Диего забрал
18 апреля 2020
200
Диего передал
24 сентября 2023
300
Сэм передал
Рис.
2.7.
Пример
ES
600
900
100
60
200 Сэму
300 Диего
в виде финансовой книги
Обработка событий в программном обеспечении означает, что помимо простого
хранения данных в базе данных мы также публикуем события в очереди сообще
ний, например в Kafka или RabЬitMQ (рис. 2.8). Моделирование событий отличает
ся от моделирования таблиц в реляционной базе данных.
В отличие от предыдущих вариантов, вы отделяете сервис профилей от сервиса от
четов, поскольку они не используют одну и ту же базу данных. Улучшена изоля
ция, и при внесении изменений в базу данных вы обеспечиваете некоторый уровень
косвенности, обеспечиваемый очередью сообщений . Этот уровень косвенности
может быть нарушен, если изменятся данные, опубликованные в очереди сообще
ний, но каждая база данных может развиваться независимо.
Сервис отчетов может выполнять чтение/запись непосредственно в очередь сооб
щений. В качестве альтернативы мы можем создать независимый процесс чте-
17 Лука Пачоли известен как создатель системы двойной записи в бухгалтерии:
https://en.wikipedia.org/wiki/Luca_Pacioli.
Антипаттерны: отсутствие изоляции
ния/записи в такой технологии, как
Spark Streaming.
■
79
Сама очередь сообщений мо
жет быть реализована с помощью разнообразных технологий:
Kafka,
RabЬitMQ или
JMS/ ActiveMQ.
Обработка
событий
R.e().ct Web
UI
R.e().ct Web
UI
!
Norle}f / BFF
Node}f / BFF
i
/цrer/25
ДокументJSON Т
в формате
Сервис профилей
публикует события
в
для раздела
Сервис профилей
Сервис отчетов
Kafka
Kafka.
l
База данных
Рис.
2.8.
Что произойдет ,
MySQL
если
Подход к обработке событий
-
База данных
JSON изменится?
обработка событий с помощью
MySQL
Kafka
Данные, публикуемые в очереди, могут быть представлены в промежуточном фор
мате, например
JSON,
что делает решение менее зависимым от конкретной техно
логии базы данных. Поэтому оно лучше, хотя и не идеально. Конечно, проблема
в том, что система более сложная, в ней больше точек сбоя и требуется больше
программного обеспечения и инфраструктуры для обслуживания. Однако этот ва
риант действующий.
Спросите себя: сколько контрактов сейчас у сервиса профилей? Вы сказали один?
На самом деле их два: общедоступная конечная точка в
REST+JSON (/user/{IDJ)
и
данные, которые она публикует в очереди обмена сообщениями.
Данные сами по себе являются контрактом; даже если они не имеют четкого опре
деления и не публикуются через АРI-шлюз (АР!
Gateway),
они не менее важны.
Часто эти нераспознанные контракты могут быть пропущены или проигнорирова
ны, и мы называем их скрытыми контрактами. Более подробно мы рассмотрим кон
тракты и скрытые контракты в г.1аве
6 «Принципы
надлежащего предоставления
сервисов».
Возвращаясь к обработке событий
(Event sourcing, ES), отметим, что это отличный
ES создает другие проблемы,
архитектурный шаблон, но не панацея от всех бед.
поскольку, в конце концов, это не база данных. В зависимости от технологии, у вас
будет больше или меньше проблем.
■
80
♦
Глава 2
Упорядочивание. Некоторые бизнес-процессы требуют, чтобы события были
строго упорядочены при обработке, например транзакции по банковским сче
там.
♦
Согласованность. Системы
ES
часто предоставляют гарантии согласованности
доставки, например ровно один раз, минимум один раз, максимум один раз. Они
не являются традиционными реляционными базами данных, и в них могут от
сутствовать конструкции для обеспечения согласованности данных, например,
позволяющие двум пользователям получать один и тот же адрес электронной
почты с помощью ограничений реляционной базы данных, таких как первичный
ключ.
также обеспечивает конечную согласованность, что характерно для больших
ES
систем в широком масштабе. Но вы должны учитывать это в своем пользователь
ском опыте, а иногда и в работе с бизнесом.
CQRS
и ее связь с
ES
Созданная Грегом Янгом система разделения ответственности за выполнение ко
мандных запросов
(Command Query Responsibllity Segregation, CQRS)
представляет
собой программную архитектуру, в которой команды и запросы имеют разные мо
дели и разные хранилища данных. Архитектуры, управляемые событиями, такие
как
ES,
обычно используются для синхронизации двух хранилищ данных. Структу
ра данных событий по своей природе менее ограничена, чем набор SQL-команд для
конкретной технологии баз данных.
таких решений, как
Поскольку
CQRS
Apache Kafka,
ES
часто предоставляется с использованием
RabЬitMQ,
Apache ActiveMQ,
А WS
Kinesis
и др.
разделяет команды и запросы, необходимы различные структуры,
классы и, возможно, базы кода. Этот шаблон обеспечивает лучшую масштабируе
мость системы, поскольку разные модели могут работать на разном оборудовании,
например можно по-разному масштабировать операции чтения и записи.
CQRS
можно комбинировать с технологиями кеширования, системами очередей и посто
янным хранилищем. Также возможно использовать одну и ту же технологию
в смысле хранения, но на разных узлах или серверах, чтобы избежать влияния друг
на друга операций записи и чтения.
Новый сервис, общий доступ через
API
Наконец, мы можем создать новый сервис для отчетов и вызывать сервис профилей
с
помощью
его
открытого
API. Этот подход является классической
(Service Oriented Architecture, SOA). Связь
ориентированной архитектурой
чена опубликованным
API,
сервис
ограни
а не опосредованно через структуры данных или на
прямую через совместное использование одних и тех же баз данных.
Общий доступ через
API
может показаться очевидным выбором, но у каждого ре
шения есть свои компромиссы. Как мы уже говорили ранее в этой главе, наличие
нового сервиса влечет за собой накладные расходы и нагрузку на обслуживание,
устаревшие библиотеки могут стать причиной уязвимости в системе безопасности,
Антипаттерны: отсутствие изоляции
■
81
а члены команды, освоившие кодовую базу, могут покинуrь вашу компанию, что
приведет к размыванию команды
(team erosion)
и отсутствию владельца
(owner-
ship).
Однако с точки зрения изолированности в этом примере у нас есть отличный ком
промисс. Для удовлетворения требований необходимо раскрытие информации, но
разрыв изоляции связан с понятной большинству инженеров концепцией: опубли
кованным
API,
использующим хорошо известный подход.
Как бы то ни было, сложность возросла; только время покажет, стоит ли идти на
компромисс.
Централизация
Мы рассмотрели централизацию в главе
1
«Что не так с монолитами?», где мы
сосредоточились на том, как централизация
(centralization)
играет ключевую роль
в монолитах, и на ее недостатках. Централизованные решения по своей сути со
держат компоненты, которые не изолированы друг от друга. Для развертывания
или выпуска программного обеспечения, контроля времени безотказной работы
или доступа к базам данных, системам кеширования очередей сообщений или хра
нилищам
данных
NoSQL
требуется
только
одно
решение.
Централизованные
решения могут позволить командам работать быстро. Но команды не изолированы,
и если одна из команд нарушит доступ к базе данных, то доступ к базе данных все
го монолита, скорее всего, будет нарушен.
Централизация по своей сути поощряет решения, которые не являются изолиро
ванными. Это не означает, что централизованные решения по своей сути непра
вильны; если вы правильно сгруппируете то, что должно быть сгруппировано,
вы получите преимущества в скорости и сроках вывода на рынок. Но централизо
ванные архитектуры могут способствовать группированию объектов, которые не
должны быть сгруппированы, тем самым нарушая изоляцию ненадлежащим об
разом.
Давайте посмотрим на централизацию и изоляцию с другой стороны: что происхо
дит, когда вы объединяете команды инженеров. Как это влияет на создаваемое ими
программное обеспечение?
Преимущества централизации инженерных команд
Централизация инженерных команд
(centralizing engineering teams) имеет ряд пре
имуществ. Эти команды часто называют командами DevOps (DevOps team), коман
дами разработчиков платформ (Platform team), командами ядра (Core Team), архи
текторами (Architect) и многими другими именами. Такие команды, которые часто
присутствуют в организациях, занимающихся разработкой программного обеспе
чения, имеют:
♦ устав;
♦ бюджет;
♦ персонал;
82
■
Глава 2
♦
опыт;
♦
цели.
Сервисные команды выигрывают от наличия централизованных групп, которые
помогают с развертыванием, инструментами, базами данных, производительно
стью, безопасностью и многими другими вопросами, что позволяет им сосредото
читься и приносить больше пользы бизнесу с меньшим количеством отвлекающих
факторов (рис.
2.9).
Фокус
Команда продаж
•••
<о
•••••••••••••••••
Команда
Команда профилей
••••••••
2.9.
•••••••••••••••••••••••••••••
Команда разработчиков платформы
DevOps
Тестирование/развертывание
Рис.
•••
Команда отчетов
+ стенды
Централизация
-
Общие библиотеки
+ сервисы
на потребностях
бизнеса
•
'
•••••••••
•
Техническая
подцержка
Управление/
Абстрагирование
команды DеvОрs/раэработчиков платформы
Когда мы используем монолитный архитектурный стиль, такие команды могут и не
понадобиться, потому что, как только кто-то приступает к работе, это делается для
всех. Даже в случае с монолитами вам может потребоваться опыт, и у вас могут
быть причины для подобного деления. Но когда мы переходим к распространению
и у нас появляется много масштабируемых команд, то нам действительно нужны
такие специализированные команды. Микросервисный стиль архитектуры
services Style of Architecture, MSA)
(Micro-
вынуждает их создавать. Это не обязательно
плохо. Однако бывают ситуации, когда роли, которые играют эти команды, дово
дятся до крайности, и в итоге мы сталкиваемся с еще большими проблемами.
Проблемы, связанные с чрезмерной централизацией
Централизация (over-centralization) может быть палкой о двух концах, потому что
без тщательного управления мы можем столкнуться с двумя большими пробле
мами:
1.
Проблемы с поставками и инновациями.
2.
Плохие общие библиотеки.
Проблемы с поставками и инновациями
DevOps -
это движение, в котором команды разработчиков и операторов объеди
няются и совместно создают и работают над улучшением написания , сопровожде
ния и эксплуатации программного обеспечения. По определению иметь только
одну команду, занимающуюся
DevOps,
неправильно. Представьте, что в компании
Антипаттерны: отсутствие изоляции
■
83
есть одна команда тестирования, Аgilе-команда или (что хуже всего) команда ин
новаций. Такие понятия, как тестирование,
Agile
и инновации, являются сквозными
и должны быть заложены в ДНК компании. Все команды должны практиковать эти
дисциплины. Имея единую команду, вы говорите, что это концентрированная про
блема, и ни к кому другому она не относится.
Хорошим примером узкого места является ситуация, когда команда
DevOps
стано
вится единственной командой, которой разрешено использовать облачные серви
сы/ А WS, и все сервисные команды зависят от команды
любых изменений (рис.
движения
DevOps -
2.1 О.)
команда
DevOps
при внесении
Это противоречит первоначальному определению
DevOps
должна предоставлять инженерным коман
дам хорошие инструменты и шаблоны, а не блокировать их способность изменять
инфраструктуру. Команда
DevOps должна
обучать, наставлять и направлять другие
команды, она не должна быть центром контроля, который ограничивает возможно
сти и замедляет работу.
Еще один антипаттерн
-
когда команды
DevOps
создают свои собственные кли
ентские оболочки или слои. Это типичный, но плохой шаблон, потому что в А WS
уже есть
API
для всего, и разработчики знают, как его использовать! Требовать от
DevOps,
чтобы они использовали только А WS или ставили оболочку перед всем,
необязательно, т. к. это создает узкие места. Во времена центров обработки данных
и физического оборудования мы понимали, насколько разумно централизовать дос
туп и иметь специализированную команду. Однако в эпоху облаков нам нужно
мыслить по-другому; мы не можем работать, используя те же принципы физиче
ского центра обработки данных. Проблема узких мест в поставках усугубляется
тем, что часто сервисные команды на порядок превосходят команды
размеру
неров
- мы наблюдаем соотношение разработчиков
DevOps в соотношении 50: 1 и даже 100: 1.
по
1
1
Команды сервисов
DevOps
сервисных команд и инже
...
Команды сервисов
Фокус
Сотни
на потребностях
разрабо~иков ...
бизнеса
Команда
DevOps (горстка людей)
Тестирование/развертывание
Рис.
2.10.
Техническая поддержка
Управление/Абстрагирование
+ стенды
Узкое место
DevOps для
инноваций
Как мы можем устранить узкие места:
♦
Внутренние источники: используйте модель совместной работы с внутренними
источниками на
GitHub
и позвольте инженерам отправлять РR-файлы в репози-
■
84
Глава 2
тории
OevOps git.
Предоставьте им возможность самообслуживания и создания
собственной системы автоматизации.
♦ Обеспечьте прямой доступ к облаку: не создавайте оболочки поверх сервисов
АWS, используйте их напрямую или через такие известные проекты, как
Terrafoпn, чтобы разработчики могли полагаться на Интернет, документацию и
Stack Overflow.
♦ Документируйте и обучайте: если вам необходимо создавать инфраструктур
ные решения
собственными силами,
подготовьте отличную документацию,
ресурсы и видеоролики и обучите людей пользоваться вашими решениями.
♦ Встраивайте DеvОрs-инженеров в процесс разработки: включайте ОеvОрs
инженеров в Sсrum-команды или в идеале проводите перекрестное обучение
разработчиков, чтобы они сами овладели навыками
OevOps.
♦ Позвольте разработчикам создавать инфраструктуру в виде кода: исполь
зуйте СОК, такие как
Pulumi,
Terrafoпn СОК или А WS CloudFoпnation СОК,
чтобы инженеры могли использовать свои родные языки, а не специфичные для
Ops инструменты
или диалекть1.
Централизация в сравнении со стандартизацией
для обеспечения наблюдаемости и развертывания
Хорошая форма централизации
(centralization),
которой должны придерживаться
команды
OevOps,
dization).
Вам не нужно стандартизировать все, но, когда дело доходит до обеспе
это не столько общий код, сколько стандартизация
(standar-
чения наблюдаемости или развертывания, вы не хотите, чтобы каждый использовал
v
свои со
v
б ственныи
инструмент
snowfl аkе 18 .
Хотя МSА-сервисы хороши тем, что позволяют использовать различные языки и
детали
инфраструктуры,
микросервисы должны
использовать общие
подходы
к публикации метрик, логгированию, оповещениям и развертыванию. Регистрируй
те события с использованием разных библиотек, но публикуйте их в общем форма
те; создавайте метрики, используя стандартную семантику; или проводите провер
ки работоспособности по общему URL-aдpecy. Команды
OevOps
могут поддержи
вать общий синтаксис для создания и запуска вашего программного обеспечения
в контейнерах без чрезмерных ограничений или позволить командам определять
конвейеры
CI/CO
в У АМL, которые поддерживают произвольные действия и обес
печивают безопасность. Все эти стандартизации
(standardization)
помогают вне
дрять и отлаживать программное обеспечение в процессе производства, не ограни
чивая при этом инновации.
Мы бы сказали, что ни один из таких подходов сам по себе не является централизо
ванным, а скорее стандартизированным. В этом случае команды
OevOps
могут
сосредоточиться на разработке инструментов, которые поддерживают стандарт и
18
Snowflake -
современный SSН-клиент со встроенными инструментами графического интерфейса для
Linux. - Пер.
легкого управления серверами
Антипаттерны: отсутствие изоляции
соответствуют
ему,
не
ограничивая
при
этом
инженерные
инновации;
■
85
команды
разработчиков могут создавать новые функции, причем безопасно и без ущерба для
фундаментальных принципов.
Плохие общие библиотеки
Мы подробно рассмотрим эту тему в главе
4
«Антипаттерн: внутренние общие
библиотеки» и неоднократно в нашей книге. Централизованные команды могут
оказать непропорционально большое влияние на работу с плохо спроектированны
ми библиотеками. Когда у вас есть общий сервис, вам нужно позаботиться о дос
тупности. Вы можете несколько ослабить опасения по поводу доступности библио
тек. Но когда вы предоставляете глобальные библиотеки всей компании, у вас воз
никают разные проблемы, но с одинаковым эффектом: раздутые решения, которые
приводят к бинарной связности; принудительная каскадная миграция разработчи
ков; люди избегают библиотек и, как следствие, дублируют код, а также множество
других проблем.
Плохие библиотеки
по определению
не изолированы:
команда разработчиков
платформы, поставляющая плохие и ненужные общие библиотеки всей компании,
объединяет их в единое целое.
Разрушение изоляции
Мы осмеливаемся утверждать, что изоляция
(isolation) -
это важнейший принцип,
если не самый главный. Мы с самого начала не все понимаем в программном обес
печении. Возможно, мы изучаем бизнес или какую-то новую технологию, и допус
кать ошибки
-
это нормально. Нам нужно максимально использовать изоляцию,
потому что только так мы сможем пережить эти ошибки, восстановиться и улуч
шить ситуацию, даже если на каком-то этапе примем неверное решение.
Давайте систематизируем способы, с помощью которых команды обычно разру
шают изоляцию.
Совместное использование баз данных
Оrсутствие изоляции может проявляться и часто проявляется в нескольких различ
ных формах; наиболее распространенной является отсутствие изоляции при совме
стном использовании баз данных.
Не предоставляйте общий доступ к базам данных! Совместное использование баз
данных в разных сервисах
-
это зло, равносильное первородному греху. Базы дан
ных должны быть изолированы. Если вы можете усвоить только один урок из этой
книги, то не предоставляйте общий доступ к базам данных.
Под базами данных мы подразумеваем любой способ, которым приложение коди
рует свои данные, метаданные и базовую схему в определенной технологии/инфра
структуре.
Для
большинства
приложений
данные
являются
самым
медленно
меняющимся элементом инфраструктуры и наиболее опасными для изменения;
86
■
Глава 2
сколько страшных историй вы слышали о младшем инженере, который удалил базу
данных в процессе работы и вызвал многодневный сбой в работе?
Как только какая-либо технология соединяется с базой данных, она меняется мед
ленно, если меняется вообще. Со временем размывание команды
(team erosion)
приводит к тому, что никто не помнит, зачем нужен этот индекс или столбец и ка
кую функцию он поддерживает.
Проблемы усугубляются тем, что несколько независимых команд и кодовых баз
совместно используют одну и ту же базу данных. Благодаря совместному исполь
зованию базы данных эти команды теперь связаны; модель данных базы данных
представляет собой скрытый контракт. И теперь ваш и без того медленный процесс
обременен необходимостью согласовывать изменения между несколькими коман
дами (рис.
2.11 ).
/urer/2.S
/цr:er/repr,rt/2.5
Сервис профилей
Сервис отчетов
/urer/2.S
Сервис профилей
!
---
База данных
MySQL
__,
...._
2.11.
__,
~
~
База данных
MySQL
__,
Правильно
Неправильно
Рис.
i'
----
......
MySQL
Сервис отчетов
......
,,...
База данных
/ur:er/repr,rt/2.5
Отсутствие изоляции. Антипаттерн №
1:
общие базы данных
Какие мотивы побуждают команды к совместному использованию баз данных?
♦
Нереалистичные бизнес-ожидания. Давление со стороны сроков выпуска ре
лиза в конечном итоге приводит к компромиссам и плохому дизайну.
♦
Неправильное решение. Иногда люди хотят исправить монолит и разделить
его на части, но база данных не входит в их планы. Не существует хорошо про
думанных, надлежащих шаблонов сервисов, а плохие шаблоны многократно по
вторяются, например игнорируются базы данных и фокусируются на коде.
♦
Отсутствие проверок дизайна. Возможно, в вашей команде регулярно прово
дятся проверки кода код-ревью
(Pull Requests, PR).
(code reviews)
Однако проверки дизайна
в форме запросов на доработку
(Design Reviews)
не проводятся
или проводятся в начале задачи/заявки, а не на протяжении всего проекта.
♦
Отсутствие надлежащих технических ретроспективных обзоров. За преде
лами 15-минутных совещаний нет самоанализа, времени подумать о неудачах
в разработке или улучшить техническое состояние.
Антипаттерны: отсутствие изоляции
■
87
♦ Нехватка свободного времени. У инженеров мало стимулов совершенствовать
процесс проектирования, продукт, архитектуру, устранять технический долг и
выполнять работу, выходящую за рамки новых функций.
Если быть точным, можно совместно использовать сервер базы данных, но избегать
совместного использования схемы и данных (рис.
2.12).
Практически во всех хра
нилищах данных есть способы такой организации работы. Иногда в низкооплачи
ваемых/непроизводственных средах вам, вероятно, захочется совместно использо
вать один и тот же сервер базы данных с группой приложений, чтобы снизить
затраты . Возможно даже совместно использовать один и тот же сервер базы данных
и при этом сохранять изоляцию с помощью схем в рабочей среде . Однако мы бы не
советовали использовать это в рабочей среде из соображений доступности и отка
зоустойчивости. Вы уменьшаете изоляцию, увеличивая радиус поражения сбоя
базы данных.
Совместное использование баз данных: сервер против схем/данных
Общий кластер баз данных/Сервер
Сервис платежей
1 (не продуктив)
Схема матежей
Сервис отчетов
Схема отчетов
......................... ,•
Рис.
2.12.
Общий сервер баз данных
-
изолированные схемы/данные
В нашем примере сервис платежей является критически важным сервисом. Если
сервис платежей не работает, компания не может получать деньги и сталкивается
с серьезными сбоями в бизнесе. В свою очередь, сервис отчетов не так важен, при
этом они используют одно и то же аппаратное обеспечение базы данных, но, по
крайней мере, данные и схемы изолированы друг от друга. Однако риск здесь за
ключается в том, что физическое оборудование не изолировано. Запросы сервиса
отчетов потребляют общие аппаратные ресурсы, и если эти запросы начинают
использовать
100 %
ресурсов центрального процессора сервера баз данных, то это
негативно сказывается на работе сервиса платежей (рис.
2.13).
Вот почему мы ре
комендуем избегать такой схемы при промышленной эксплуатации .
Как вы можете видеть, изоляция применяется не только к данным/схемам базы
данных, но и к серверам. Отсутствие изоляции создает много проблем.
Поэтому не используйте совместно базы данных! Вы усугубляете и без того серь
езную проблему.
88
■
Глава 2
Совместное использование баз данных: сервер против схем/данных
Общий кластер баз данных/Сервер
Сервис платежей
1 (не продуктив)
Сервис отчетов
Схема платежей
Схема отчетов
Рис.
2.13.
Общий сервер баз данных
-
влияние на доступность/отказоустойчивость
Когда можно использовать базы данных совместно?
В контексте сервисов онлайн-обработки транзакций (Online Transaction Processing,
OLTP 19 ) совместное использование баз данных является антипаттерном. Тем не ме
нее
существуют
другие
контексты,
в
которых
совместное
использование
может
иметь место и быть приемлемым, если оно ограничено конкретными вариантами
использования
( use cases)
и существует осведомленность и некоторая степень кон
троля над общим доступом.
Базы данных приложений
для совместного использования в
Big Data
Одно из преимуществ монолитов заключается в том, что, как правило, все решение
использует одну базу данных. Когда все данные собраны в одном месте, можно от
ветить на любой вопрос с помощью SQL-зaпpoca.
Когда мы переходим к распространению и внедряем сервисы
сы
(MSA),
(SOA)
и микросерви
у нас появляется больше реляционных баз данных и различных техноло
гий сохранения данных, таких как базы данных документов, графические базы дан
ных, столбчатые базы данных, хранилища КN и многие другие в области
NewSQL.
NoSQL
и
Теперь ни один SQL-зaпpoc не сможет ответить на все ваши вопросы.
Именно здесь на помощь приходит технология Big Data2°, создавая среду, в которой
можно одновременно обрабатывать, обогащать и получать доступ ко всем источни
кам данных. В некотором смысле
Big Data
может показаться большой объединяю
щей машиной.
19
Определение OL ТР взято из Википедии: https://eo.wikipedia.org/wiki/Online_transactioo_processing.
20
Big Data -
это структурированные, частично структурированные или неструктурированные большие
массивы данных. Также под этим термином понимают обработку, хранение и анализ огромных объемов
данных.
-
Пер.
Антипаттерны: отсутствие изоляции
■
89
это доступ к постоянно увеличивающимся огромным объемам данных.
Big Oata -
Мы уже установили, что онлайн-сервисы должны скрывать свои хранилища дан
ных и предоставлять общедоступные интерфейсы. Однако в мире
оборот: вы должны видеть все и подключаться ко всему. Стеки
Big Oata все на
Big Oata должны
обеспечивать доступ к данным из некоторых или всех хранилищ данных компании,
а также из сторонних источников. Часто оперативные данные передаются в среду
Big Oata
путем считывания данных из реплики базы данных с использованием
методов захвата изменения данных
средника, такого как
Apache Kafka
(Change Oata Capture, СОС)
Kinesis (рис. 2.14).
или с помощью по
или А WS
Big Data
БД профилей
Более
100 сервисов
Сервис платежей
Сервис профилей
Вышестоящие
онлайн-сервисы
сос
Нижестоящие
аналитические сервисы
Унаследованная копия
Система/задания
дл>\борьбы
с мошенничеством
Рис.
В случае с
Big Oata
2.14.
Пример использования
Big Data
это не проблема, это желательно. Нам нужно иметь возмож
ность обмениваться данными.
На рис.
2.15
мы показываем три различных варианта, которые следует учитывать
при захватывании данных.
♦ Прямая репликация базы данных: команда, занимающаяся
Big Oata,
считыва
ет данные непосредственно из баз данных приложений и может преобразовать
их во временный формат, а может и не преобразовать. В результате среда
Oata
Big
напрямую подключается к онлайн-среде, а данные, скорее всего, не подхо
дят для анализа и потребуют дорогостоящих преобразований.
♦ Использование обработки
СОС в
Kafka.
работающие с
Big Data:
базы данных публикуют события через
Используя корпоративную информационную модель, команды,
Big Oata,
разрабатывают формат СОС и структуру событий для
преобразования данных и их использования в среде
ботчиков приложений и
Big Oata
Big Data.
Команды разра
должны полностью понимать модель базы
данных приложения и координировать изменения, чтобы избежать сбоев.
90
■
Глава 2
Контракт профипей
0
Корпоративная
информационная
модель (контракт)
Сервис профилей
Обработка
Big Data
Корпоративная
информационная
модель (контракт)
База данных
MySQL
Рис.
♦
2.15.
Варианты наполнения
Big Data
Сервисы публикуют события: команда разработчиков сервисов преобразует и
публикует данные в
Kafka,
используя корпоративную информационную модель.
Только команда разработчиков должна понимать формат своих внутренних баз
данных.
Скрытые контракты и сохранение изоляции
В сфере
Big Data
мы видели, как команды стремятся получить доступ к изолиро
ванным базам данных и моделям данных онлайн-сервисов, рассматривая это как
необходимый и желанный способ получить доступ к критически важным данным.
Это также может показаться вполне логичным: как среда
Big Data
может получить
доступ ко всем данным, если они не могут получить доступ к базам данных? Но это
не
означает,
что
разработчики
приложений
должны
отказаться
от
ключевых
средств защиты своих онлайн-систем или переложить ненужную работу на среду
Big Data.
Все это основано на ключевой дисциплине лучших специалистов по работе с
Data -
основной информационной модели
(master information model),
Big
которая
управляет данными, используемыми в их средах и процессах. Основная информа
ционная модель не зависит от онлайн-сервисов, она основана на жизненном цикле
предприятия и становится основой всех будущих преобразований для поддержки
аналитики и других вариантов использования.
Разработчики приложений могут преобразовывать свои данные в основную инфор
мационную модель, в идеале публикуя события с использованием посредника, та
кого как
Kafka,
и формата, такого как
JSON,
или двоичного формата, такого как
А vro, в соответствии с шаблоном обработки событий. Вместо того чтобы предоста
вить специалистам по работе с
Big Data
разбираться в том, как устроен каждый
микросервис, лучшие прикладные команды публикуют свои данные в основной
информационной модели, соблюдая ту же дисциплину, что и при поддержке любо-
Антипаттерны: отсутствие изоляции
■
91
го контракта с данными, поддерживая его и избегая обратной совместимости, вме
сто того, чтобы выбрасывать свои схемы баз данных команде обработки данных и
желать им удачи. Такой подход в конечном счете способствует надлежащей изоля
ции, гарантируя, что команды разработчиков приложений смогут избежать совме
стного использования внутренних компонентов базы данных из сервиса .
Интеграция с устаревшими системами
Другой вариант
-
когда общий доступ к базам данных используется в устаревших
системах, а наиболее практичным способом взаимодействия двух систем является
обмен данными через общую базу данных (рис.
2.16).
Такая схема интеграции яв
ляется хрупкой и создает много проблем. Тем не менее есть веские причины при
менять ее, но с осторожностью:
♦
в одной или обеих системах используются устаревшие технологии, с которыми
ваша команда не знакома;
♦
в краткосрочной или среднесрочной перспективе системы будут выведены из
эксплуатации;
♦
вы не полностью контролируете системы; например, требуется сторонняя инте
грация с внешней компанией или поставщиком , и вы не можете использовать
API
или другой разумный метод.
Сторонний
Сервис платежей
или устаревший
вендор
* Будет выведен
из эксплуатации
База данных
пользователей
Рис .
2.16.
Совместное использование баз данных
-
интеграция или пластырь
Как вы можете видеть, существует несколько ограниченных вариантов использова
ния, в которых совместное использование баз данных может быть необходимым и
приемлемым для облегчения взаимодействия между машинами . Однако мы наде
емся, что такие ситуации будут возникать редко и будут находиться под строгим
контролем. В противном случае вы рискуете попасть в гораздо большую и мрачную
ловушку: распределенный монолит, который будет подробно рассмотрен в главе
3
«Антипаттерн: распределенные монолиты».
Общие библиотеки
Вы можете воспринимать программные библиотеки как полезные и безобидные
объекты. Независимо от вашей архитектуры
микросервисы , сервисы
ленные сторонними
-
-
монолит, распределенный монолит,
вы , скорее всего, используете библиотеки, предостав
поставщиками , с открытым
внутренними поставщиками .
исходным кодом,
или созданные
92
■
Глава 2
Библиотеки помогают вам заменить код, который вы сами написали бы, сэконо
мить время и быстрее вывести программный продукт на рынок. Отчасти это верно,
но в обмен на эти преимущества вы напрямую используете код, созданный сторон
ними разработчиками, который имеет как прямые, так и косвенные связи. Сопря
жение иногда необходимо, но по своей сути опасно, и при неправильном обраще
нии оно полностью нарушает изоляцию вашего кода.
Библиотеки
-
это не так уж плохо. Но именно то, как индустрия работает с внут
ренними библиотеками, представляет собой серьезную проблему, которая создает
большие неприятности для сервисов по двум причинам: из-за бинарной связности и
нестабильных контрактов. Нестабильные контракты могут влиять как на библиоте
ки, так и на сервисы, о которых мы расскажем в следующем разделе. Давайте про
должим.
Бинарная связь
Мы рассматривали этот вопрос в главе
связь
(Binary coupling) -
1
«Что не так с монолита.ми?». Бинарная
это явление, при котором ваше программное обеспече
ние, его зависимости и зависимости от этих зависимостей могут быть перепутаны
таким образом, что попытка обновить компонент или зависимость может привести
к неизбежному конфликту. Вы не можете перейти на
Hibemate 5,
пример, половина вашего программного обеспечения подключена к
потому что, на
Hibemate 4.
Внутренние общие библиотеки еще больше усугубляют эту проблему.
Сервис платежей
Сервис отчетов
Сервис профилей
... +
100 сервисов
Внутренняя библиотека
дпя логирования
Рис.
2.17.
Отсутствие изоляции. Антипаперн
No 2:
общие библиотеки
Ваша компания могла бы создать простую библиотеку для логирования; вы могли
бы отправлять свои журналы в А WS SЗ, потому что позже вы сможете выполнять
запросы с помощью А WS
Athena
для обеспечения различных вариантов использо
вания, таких как наблюдаемость, обнаружение мошенничества, аудит и многое
другое. Команда сервиса платежей первой отправила логи в SЗ из соображений на
блюдаемости; они подумали, а давайте создадим библиотеку, которой смогут поль
зоваться и другие пользователи. В этом нет ничего плохого, не так ли?
Антипаттерны: отсутствие изопяции
■
93
Итак, команда сервиса платежей создает простую оболочку для SЗ, используя
популярную
библиотеку на Java для сериализации/десериализации
JSON или ХМL, а также применяет клиент aws-java-sdk-sЗ для
отправки файлов JSON в SЗ. Однако эта команда предпочитает не использовать
методы получения getters/setters в Java. Поэтому они также решили использовать
Lombok, чтобы устранить шаблонную многословность Java (рис. 2.17).
Jackson-
объектов в формате
Теперь командам сервиса отчетов и сервиса профилей также необходимо отправ
лять журналы в SЗ, но по другим причинам
- в целях защиты от мошенничества.
Они видят библиотеку ведения журнала логов, которую создала команда по оплате,
и думают: «Что ж, мы можем ее использовать, она подходит для нашего варианта
использования, и нам не нужно ничего дополнительно кодировать». Повторяйте
этот процесс снова и снова, и вы не заметите, как в вашей компании появятся сотни
сервисов, использующих эту общую библиотеку.
Возьмем саму внутреннюю библиотеку ведения журнала логов в отдельности. Мы
могли бы подумать, что все это хорошо и проблем нет. Что произойдет, если один
или несколько других сервисов также захотят использовать
Jackson,
но по какой-то
причине у них разные версии? Если
Jackson
вместимость
и/или вы не пьпаетесь стандартизировать всех
(backward compatibility)
Jackson,
на одной и той же версии
Jackson,
не реализует прямую и обратную со
у вас уже есть проблемы. И это только для
не говоря уже обо всех других библиотеках в клиенте awsjava-sdk-s3 или
даже обо всех общих библиотеках в вашей компании.
Результатом является отсутствие изоляции, поскольку теперь все сервисы имеют
бинарную связность с внутренними библиотеками ведения журнала и всеми зави
симыми библиотеками, которые могут быть у них во всем графе зависимостей;
например, сам Jackson также используется А WS SDK. Здесь есть и другие послед
ствия. Что, если другие команды не захотят использовать
использовать это решение, хотят они того или нет (рис.
Общие библиотеки и отсутствие изоляции
Lombok?
2.18).
Им придется
Могу ли я использовать
другую версию
Jackson
здесь?
Сервис платежей
Сервис отчетов
Сервис профилей
... + 100 сер висов
Мы не хотим
$
Мы не хотим
поддерживать
10 веток
использовать LomЬor
Внутренняя библиотека
для логrирования
разработки
Рис.
2.18.
Отсутствие изоляции. Антилаттерн
No 2:
общие библиотеки
-
лроблемы
94
■
Глава 2
В итоге мы также сталкиваемся с плохим сценарием для команд сервисов. Теперь
им, возможно, придется иметь дело с миграциями
-
обновлениями, исправления
ми безопасности, критическими изменениями, которые потребуют проведения ре
факторинга. Это задачи, которых они не хотят, которые их не заботят и на которые
у них нет времени. Но выполнить их все равно придется. Подождите секунду!
Теперь сделайте шаг назад и подумайте о том, что здесь происходит. Большинство
решений, которые мы предложили, имеют серьезные последствия. Предполагается,
что микросервисы и архитектура сервисов защищают нас от этих проблем и обес
печивают изоляцию. У нас должна быть независимость, поскольку у каждого сер
виса есть свои серверы, модули развертывания и даже разные команды. Некоторые
преимущества сервисов были утрачены из-за отсутствия изоляции в общих библио
теках. Однако это не то, что мы здесь получаем.
Общие библиотеки часто могут быть серьезным источником технических сложно
стей и технической задолженности. Библиотеками необходимо управлять тщатель
но. Но зачастую этого не происходит, поскольку библиотеки, как правило, скрыты
и неуправляемы. У них часто нет устава или владельца продукта, отсутствует над
лежащий жизненный цикл и существует множество других проблем. В главе
4
«Антипаттерн: внутренние общие библиотеки» мы обсудим проблему отсутствия
изоляции в общих библиотеках. Мы рассмотрим эту тему гораздо глубже и пред
ставим другие решения.
Отсутствие стабильных контрактов
Контракты
(Contracts) -
это интерфейсы, публикуемые сервисами или библиоте
ками для демонстрации своих возможностей. Контракты создают у потребителей
ожидания
(expectations),
которые поставщик контракта должен оправдывать. Соз
дание и выполнение выгодных контрактов лежит в основе создания удобных про
граммных решений, а удовлетворение ожиданий потребителей
-
в основе созда
ния стабильных программных решений.
Плохие контракты могут проявляться по-разному. Давайте взглянем на следующий
Jаvа-код.
1.
2.
iшport
java.math.BigDecimal;
java.util.Calendar;
puЫic
class TaxProcessor {
iшport
3.
4.
5.
6.
puЬlic
BigDecimal computeSalesTax(Long salesID,BigDecimal value,String state) {
7.
//
используйте идентификатор продажи,
8.
9.
//
//
из базы данных ...
чтобы получить конкретную продажу
фильтруйте по регионам и учитывайте разные тарифы для ка)l(Цого региона
11. // допустим, по умолчанию это 30 %
12. return BigDecimal.valueOf(value.longValue() * 1.3);
13. )
14.
. ..
Антипаттерны: отсутствие изоляции
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
■
95
String getDayOfTheWeek(int year,int month,int day) {
Calendar cal = getCalendar();
cal.set(year, month - 1, day, О, О);
return switch(cal.get(Calendar.DAY_OF_WEEK)) {
case 1 -> "Воскресенье";
case 2 -> "Понедельник";
case 3 -> "Вторник";
case 4 -> "Среда";
case 5 -> "Четверг";
case 6 -> "Пятница";
puЬlic
Наш Jаvа-класс представляет собой наиболее распространенную форму контракта,
открытый метод в открытом классе. Нам нужно многое здесь рассмотреть внима
тельнее. Давайте начнем.
♦
Метод расчета налога с продаж computeSalesтax является частью контракта, по
скольку является общедоступным.
♦
Метод получения дня недели
getDayOfTheWeek также является частью контракта,
поскольку является общедоступным. Однако этот метод не должен быть обще
доступным. Какое отношение getDayOfTheWeek имеет к обработке налогов? Воз
можно, он должен находиться в каком-то классе
util,
хотя это не имеет значе
ния, потому что он общедоступен; это часть контракта.
♦ Метод getCalendar не является частью контракта, даже находясь в общедоступ
ном классе с общедоступными методами. Этот метод помечен private, т. е.
является частным, поэтому не является частью контракта.
♦
Внутренние методы
internalMethodHardToTest и anotherMethodHardToTest также не яв
ляются частью контракта, поскольку они не являются общедоступными. Эти ме
тоды трудно протестировать, потому что они не получают параметров и возвра
щают значение void. Их следует удалить, но что касается нашего обсуждения
-
они не являются частью контракта.
Итак, что же такое контракт? Это любой публичный документ, состоящий из сле
дующих частей.
♦
Имя метода
♦
Сигнатура метода. Параметры, входные данные и выходные данные
(Name ).
(parameters,
input, output).
♦
Формат данных.
Например,
строка,
в
причем
формате
в
getDayOfTheWeek выходными данными является
"Понедельник".
Если
эта
строка
изменится
на
"ПОНЕДЕЛЬНИК", это может нарушить работу пользователей.
♦
Здесь у нас есть код на
Java,
который будет использоваться через
JAR
в виде ме
тода класса. Это может быть как внутренний модуль, так и библиотека. Если бы
вместо этого мы раскрыли его с помощью REST + JSON, эти элементы тоже бы
ли бы частью контракта.
Другими словами, контракты касаются данных.
■
96
Глава 2
Какие проб,1емы с текущим определением контракта можно выявить на основе вы
шеизложенного?
♦ Контракт не является явным. Контракт смешан с реализацией, и, таким обра
зом, нет ощущения, что им должным образом управляют, владеют им и поддер
живают его.
♦ Контракт не разделен. Опять же, контракт смешан с реализацией. По мере из
менения реализации контракт может быть легко разорван. В идеале контракт не
должен нарушаться при каких-либо изменениях реализации.
Мы можем улучшить этот контракт, выделив контракт для реализации и перемес
тив общедоступные части контракта в интерфейс. Давайте рассмотрим еще один
фрагмент кода на
1.
2.
3.
4.
5.
i.шport
Java.
java.math.BigDecimal;
interfaoe TaxProcessorV2
BigDecimal computeSalesTax(Long salesID, BigDecimal value, String state);
puЫic
Теперь это намного лучше. Контракт стал явным, и в результате стал намного по
нятнее. Мы можем свободно изменять реализацию этого метода расчета налога
с продаж computeSalesтax, если только не нарушаем ожидания потребителей относи
тельно поведения и типов данных, как входных, так и выходных. Однако все еще
остаются вопросы, требующие рассмотрения.
Совместимость. Рассмотрите возможность предоставления этого последнего кон
тракта по сети, через
REST + JSON
или двоичный файл, такой как
gRPC;
имеют значения. Теперь у нас есть еще одна проблема: BigDecimal Как насчет ваших потребительских сервисов или он написан не на
рассматриваем
возможность
распространения
контракта
по
сети,
детали не
это тип
Java?
Java.
Когда мы
использование
примитивных типов может оказаться лучшей идеей с точки зрения совместимости.
Высокая согласованность и слабая взаимосвязь. Что произойдет, если налог бу
дет постоянно меняться? Что делать, если ваша компания работает по всему ми
ру
-
в каждой стране существуют разные способы расчета налогов, может ли этот
интерфейс работать в штатном режиме? Наш контракт посвящен налогу с продаж,
и, как вы можете видеть из определения, напрямую связан с идентификатором про
дажи
SalesID. Контракт ориентирован не только на расчет налогов; в нем также
должен учитываться жизненный цикл продаж. Это хорошо изолировано?
Контракт не устойчив к изменениям. Неясно, является ли этот контракт стабиль
ным; могут не только измениться требования, но и, скорее всего, он неправильно
составлен. С точки зрения детализации
(granularity)
было бы лучше взглянуть на
жизненный цикл налогообложения шире, а не ограничиваться только налогами
с продаж. Из-за высокого риска неправильной детализации бизнеса кардинальные
изменения кажутся неизбежными.
Антипаттерны: отсутствие изоляции
Давайте рассмотрим другой пример контракта на
■
97
Java.
1. puЫic interface ProfileService {
2. UserOutput retrieveByID(Userinput userinput);
3. }
4.
Пока что у нас есть чистый контракт. В том смысле, что он является явным, у кон
тракта также есть четко определенные входные и выходные данные, что имеет не
которые ключевые преимущества. Как мы видели в предыдущем коде, мы хотим
отделить контракт от реализации. Давайте рассмотрим определение входного объ
екта.
1.
2.
3.
4.
5.
6.
7.
iшport
java.util.Objects;
puЬlic
class Userinput
private Long id;
puЬlic
Userinput(){}
8.
9.
puЬlic Userinput(Long id) {
this.id = id;
10.
11.
12.
13.
puЬlic Long getid()
return id;
14.
15.
16. puЬlic void setid(Long id) (
17.
this.id = id;
18.
19.
20. @Override
21. puЬlic Вoolean equals(Object о) {
if (this == о) return true;
22.
23.
if (о== null 11 getClass() 1 = o.getClass()) return false;
24.
Userinput user = (Userinput) о;
return Objects.equals(id, user.id);
25.
26 .
.27.
28. @Override
29. puЫic int hashCode()
return Objects.hash(id);
30.
31. }
98
■
Глава 2
32.
33. @Override
34. puЫic String toString()
return "Userinput{" +
35.
"id=" + id +
36.
37.
1 )
1 ;
38.
39.
40.
И определение выходного объекта сервиса профилей (листинг
2.5).
ЛиcтиlJl\1111:in на сервис n~ProfileService -~Ol:l"Wft .-.мные
1. illlport java.util.Objects;
2.
3.
puЬlic
class UserOutput
4.
5. private Long id;
6. private String name;
7. private String email;
8.
9. puЬlic UserOutput() {)
10.
11. puЬlic UserOutput(Long id, String name, String email) {
12. this.id = id;
13. this.name = name;
14. this.email = email;
15.
16.
17. puЬlic Long getid()
18. return id;
19.
20. puЬlic void setid(Long id) {
21. this.id = id;
22.
23.
24. puЬlic String getName()
25. return name;
26.
27. puЬlic void setName(String name)
28. this.name = name;
29.
30.
31. puЬlic String getEmail()
32. return email;
33.
Антипаттерны: отсутствие изоляции
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
■
99
void setEmail(String email) {
this.email = email;
puЫic
@Override
equals(Object о)
if (this == о) return true;
if (о== null 11 getClass() != o.getClass()) return false;
UserOutput user = (UserOutput) о;
return Objects.equals(id, user.id);
puЫic Ьoolean
@Override
int hashCode()
return Objects.hash(id);
1
puЬlic
@Override
String toString()
return "UserOutput{" +
"id=" + id +
", name=' " + name + '\ ' ' +
", email='" + email + '\'' +
1 1 1;
puЬlic
Глядя на контракт, можно предположить, что в процессе реализации у нас будет
таблица с именем users, а также пользовательский
POJO
в нашем основном домене.
Так почему бы не вернуть тот же класс в наш контракт и повторно не использовать
код? Что ж, если мы поступим таким образом, то свяжем внутреннюю реализацию
с явным контрактом. А мы не хотим этого, потому что стремимся к стабильности
наших контрактов (рис.
2.19).
Когда вы имеете дело с общими библиотеками, нужно быть в
lО
раз более осто
рожным, чем с сервисами. Мы уже рассмотрели риски, связанные с бинарной связ
ностью, и вам также следует внимательно относиться к перечислениям, общим
POJO
и другим тонким формам скрытых контрактов. Стабильные контракты могут
и должны применяться как на макро-, так и на микроуровне, как для сервисов, так и
для библиотек.
Таким образом, контракты необходимы для обеспечения надлежащих сервисов,
поскольку отсутствие стабильных контрактов нарушает изоляцию (рис.
2.20).
Мы
не должны излишне заботиться о частных или внутренних операциях; наибольшее
значение имеют общедоступные операции. Избегайте неявных и скрытых контрак-
100
■
Глава 2
тов. Контракты определяются не только входными и выходными данными, но и
протоколами и форматами. Следует помнить, что в конечном счете все зависит от
данных.
Контракт профилей
Сервис профилей
Сервис профилей
Основной домен
--
't
База данных
профилей
.........
Рис.
2.19.
База данных
профилей
(Правильно}
(Неправильно}
-_,
"--
-
Отсутствие изоляции : отсутствие стабильных контрактов
Что такое контракты?
о
Общедосм_уnные оnераци.и
Входные и. 6t>1ходнt:>1е объекмы
о
Ожи.даемое nобедени.е
о
□
промокал (НТГР,
о
Данные
9RPC, SOAP)
и. формамt>t
(Strin&, JSON , Binar_y)
Сtпабu.А..ьн.ые коюпракты
о
Я6нt>1е (не неzласнt>1е , не скрt>1мt:>1е)
о
Не сбязанt:>1 с бн_умренней реали.зацией
Усмойчи.бы к и.зменени.ям (неболt>щое коли.чесмбо кри.ми.чески.х
и.зменени.ц , nраби.лt>ная смеnенt> демали.зации.)
о
Рис.
2.20.
Краткое описание контрактов
Повышение сложности
До сих пор мы видели все проблемы и побочные эффекты, которые влечет за собой
отсутствие изоляции. Изоляция необходима на всех уровнях: от стабильных кон
тактов до общих библиотек, баз данных, процессов и отдельных серверов.
Основные проблемы, нарушающие изоляцию в таких случаях, в значительной сте
пени обусловлены технологиями; однако отсутствие понимания предметной облас
ти может привести к тем же последствиям.
Микросервисы обеспечивают детализацию (granularity) на микроуровне. Иногда вы
не можете сопоставить функцию или код с бизнес-областью сервиса. Или вы про
сто не хотите этого сопоставления, потому что оно делает сервис слишком боль
шим; вы хотите сохранить микроуровень. Итак, что вы делаете?
Один из антипаттернов : вы игнорируете бизнес-область, относитесь к ней как
к проблеме потребителя, а не к своей, и позволяете увеличивать сложность. Иногда
Антипаттерны: отсутствие изоляции
■
101
это оправданно, однако зачастую все не так, и побочные эффекты таких сложных
проектов нарушают изоляцию.
Детализация и распространение: побочные эффекты
Когда мы используем монолитный стиль архитектуры, мы объединяем все бизнес
области в нашем монолите. Наличие всех бизнес-областей в одном бэкенде имеет
преимущества, поскольку мы объединяем всю сложность в одном месте. Следова
тельно, клиенты/потребители, браузеры и внешние
API,
как правило, становятся
проще. Скорее всего, потребителю потребуется меньшая агрегация, поскольку сер
верная часть является глубокой, с большим количеством кода, модулей и бизнес
областей, по сравнению с мелкими одноцелевыми микросервисами в распределен
ных архитектурах.
Монолиты имеют тенденцию к централизации
нию; и, как мы видели в главе
1 « Что
(centralization),
а не к распределе
не так с монолитами?», существует множе
ство проблем, связанных с классическими монолитами. Дr~я сравнения: архитектуры
микросервисов стремятся к большему распределению, а не централизации (рис.
-------б-и-те-пь
____
2.21 ).
Кто сейчас
собирает
Потребитель
--~~~;-----,----,--)
(попьзоватепьский интерфейс ипи API)
данные
о профилях/
продажах?
Профили
Продажи
База данных
Профили
Продажи
База данных
База данных
База данных
профилей
продаж
отчетов
монолита
Рис.
2.21.
Монолит против микросервисов (централизация против распределения)
По мере того как сервисы становятся более сфокусированными, они, как правило,
становятся более компактными. Это создает проблему, когда необходимо удовле
творить требования, охватывающие широкий спектр функциональных возможно
стей вашего приложения. Какому-то компоненту, вероятно, требуется вызывать
несколько
сервисов,
и
эта
сложность,
присущая
распределенным
архитектурам,
часто перекладывается на вызывающего. Вызов нескольких сервисов или агреги
рование их выходных данных сами по себе не являются чем-то неправильным, но
могут вызвать трудности.
102
■
Глава 2
Давайте рассмотрим несколько вариантов решения этой проблемы.
♦ Переход к сервису. Мы можем создать агрегацию или функцию в рамках одно
го из имеющихся у нас сервисов (Профиль/Продажи).
♦ Сервис агрегации. Мы можем создать специальный сервис согласования/агре
гации, чтобы собирать данные для этой функции.
♦
BFF. Мы можем перенести
как BFF или даже UI.
агрегацию на верхние уровни нашего стека, такие
♦ GraphQL. Аналогично сервису агрегации мы можем использовать GraphQL 21
для создания решения по агрегации.
♦ АРI-шлюз. У нас мог бы быть АРI-шлюз 22 (API Gateway) в качестве шлюза для
бизнес-области.
♦
Реорганизация сервисов по бизнес-областям. Мы можем перегруппировать
сервисы и сгруппировать их по бизнес-областям, а не по функциям/возмож
ностям.
Давайте проанализируем каждый вариант с точки зрения архитектурных компро
миссов.
♦ Переход к сервису. Мы можем объединить всю оркестрацию или агрегацию
в одном из наших сервисов (Профили, Продажи). Возможно, не имеет значения,
доступна ли функция только в одной или нескольких бизнес-областях. В качест
ве альтернативы, что более вероятно, вы можете связать две бизнес-области,
которые не должны быть разделены. В результате сервису теперь не хватает со
гласованности, что не является идеальным вариантом.
♦
Сервис агрегации. Мы можем создать сервис согласования/агрегации, чтобы
управлять агрегацией/функцией. Мы не связываем продажи и профили и, по
скольку у нас есть новый сервис, можем легко использовать его для разных
потребителей и удовлетворения будущих потребностей. Однако если только
пользовательский интерфейс будет отвечать за эту агрегацию, то эти усилия
могут быть напрасны. Было бы лучше реализовать
BFF,
чтобы разработчики ин
терфейса могли делать свою работу быстрее и с меньшим количеством зависи
мостей.
♦
BFF.
Как мы упоминали ранее, наиболее распространенный способ повысить
сложность
-
это перенести бизнес-логику и агрегацию в
BFF. На самом деле
JavaScript/TypeScript предпочитают ис
являются большими поклонниками Java. Бла
это замечательно, потому что инженеры
пользовать идиоматику и часто не
годаря этому они могут быстро реализовывать свои идеи, не требуя от руко
водства координации в спринте и взаимодействия с серверными инженерами.
GraphQL- это язык запросов для АРI-интерфейсов и среда, в которой они выполняются. С помощью
GraphQL можно получить данные из АР! и передать их в приложение (от сервера к клиенту). -Пер.
21
22
АРI-шmоз находится между клиентами и сервисами. Он выполняет роль обратного прокси-сервера, кото
рый перенаправляет запросы от клиентов к сервисам. Он также может выполнять такие специализирован
ные задачи, как аутентификация, завершение SSL-запросов и ограничение частоты. Если этот шлюз не раз
вернут, клиенты должны отправлять запросы непосредственно к внешним сервисам.
-
Пер.
Антипаттерны: отсутствие изоляции
■
103
Основная проблема этого подхода заключается в том, что если другим сервисам
или АРI-интерфейсам также требуется такая агрегация, вы оказываетесь в слож
ном положении. Кроме того, вам всегда нужно все кодировать с нуля, по срав
нению с
GraphQL,
где можно повторно использовать одни и те же
API
и изме
нять разные запросы. Штрафы за агрегацию часто можно компенсировать с по
мощью систем кеширования.
♦
GraphQL. Мы можем использовать GraphQL в качестве решения для агрегации.
GraphQL является популярным и зачастую оказывается удачной идеей, посколь
ку позволяет интерфейсу (веб-сайту и/или мобильному устройству) самостоя
тельно выбирать, какие именно точки данных ему нужны, выполнять один вы
зов и сокращать время ожидания. Это перспективное решение, поскольку вы
можете добавлять бизнес-области и данные по мере необходимости. Запросы
GraphQL,
как правило, выполняются синхронно. Для веб-приложений использо
вание исключительно
GraphQL
может привести к потере гибкости в применении
асинхронных шаблонов, что ограничит вашу способность выполнять запросы
раньше пользователя или в фоновом режиме.
♦
АРI-шлюз. Мы можем использовать АРI-шлюз
(API Gateway)
в качестве шлюза
для бизнес-области. АРI-шлюзы обеспечивают косвенную связь между потреби
телями и сервисами. Агрегации, оркестровки, преобразования, обогащение дан
ных,
ние
-
проверки достоверности,
мультиплексирование
или демультиплексирова
все это может происходить на уровне АРI-шлюза. АРI-шлюз
старый шаблон, который появился еще до
серверную часть.
GraphQL
-
более
и больше ориентирован на
Это похожие решения, но АРI-шлюзы могут потребовать
больше усилий от ваших инфраструктурных команд.
♦
Реорганизация сервисов по бизнес-областям. Мы можем перегруппировать
сервисы и сгруппировать их по бизнес-областям, а не по функциям/возмож
ностям. Часто инженеры разбивают свои сервисы по уровням или возможностям,
а не по бизнес-областям. Если вы практикуете предметно-ориентированное про
ектирование
(Domain Driven Design, DDD),
то это элегантное решение, которое
снижает частоту или эффект увеличения сложности. Однако оно не может
уменьшить его на
100 %.
Проблема с таким подходом заключается в том, что вы
не всегда следуете ему, поскольку это требует значительных усилий по рефак
торингу/миграции для внесения подобных изменений.
Как можно заметить, многие из распространенных методов, направленных на сни
жение сложности микросервисной архитектуры, включают в себя повышение этой
сложности. Команды могут решить эту проблему на месте, используя сервис агре
гации или подход в стиле
BFF.
Если вы часто оказываетесь в подобной ситуации,
рассмотрите вариант «под ключ», например обычное решение
GraphQL
или АРI
шлюз. Однако ни один из этих ответов не может быть по-настоящему подходящим
для вашей архитектуры и может иметь побочные эффекты, нарушающие изоляцию.
В этом случае проведите анализ проекта, оцените свои бизнес-области и рассмот
рите возможность реорганизации своих сервисов по бизнес-областям.
104
■
Глава 2
Давайте изолируем всё
Изоляция
(isolation) -
ключевой принцип правильной архитектуры программного
обеспечения. Суть в следующем: давайте изолируем всё.
Базы данных
Базы данных являются одним из наиболее важных элементов, которые необходимо
изолировать. Приложению не следует предоставлять общий доступ к базам данных.
Когда приложению требуется общий доступ, оно должно поместить контракт на
обслуживание в начало базы данных, разделив основные варианты сохранения. При
совместном использовании баз данных возникает каскадный эффект, который мо
жет быть таким же общим, как простое объединение данных, или более распро
страненным, как совместное использование объектов сохранения и библиотек.
Классический монолитный и распределенный стиль архитектуры монолитов ис
пользует общие базы данных, и если вы можете запомнить из главы только одно: не
используйте общие базы данных.
Сервисы должны иметь специализированные базы данных, и каждый сервис дол
жен иметь свою собственную базу данных. При необходимости совместного ис
пользования учитывайте вызовы
API
или расширенные шаблоны, такие как обра
ботка событий.
Общие библиотеки
Общие библиотеки также должны быть изолированы, но для этого требуются под
ходы, отличные от баз данных или сервисов. Например, из-за бинарной связности
лучше использовать меньшее количество библиотек или убедиться, что они не со
держат зависимостей. Мы подробно рассмотрим это в главе
4
«Антипаттерны:
внутренние общие библиотеки». На данный момент помните, что изоляция также
должна применяться к библиотекам, и внутренние общие библиотеки могут стать
отличным способом нарушить изоляцию. Следите за своими библиотеками.
Стабильные контракты
Контракты должны быть четкими и не должны смешиваться с их реализацией.
Когда вы объединяете свой публичный контракт (puЫic
ренними классами, вы теряете преимущества
contracts) с вашими внут
MSA или SOA, потому что любое
внутреннее изменение может привести к взаимодействию с вашим публичным кон
трактом, нарушению стабильности контракта и в конечном счете к нарушению
изоляции. Стабильные контракты (staЫe
contracts) -
это публичные, четко сфор
мулированные контракты, которые устойчивы к изменениям и редко нарушаются
потребителями.
Критические изменения в публичных контрактах могут вызвать каскадный эффект.
Например,
если
100 внутренними
АРI-интерфейсы
сервиса
сервисами и более чем
50
профилей
используются
более
чем
внешними партнерами через АРI-ин-
Антипаттерны: отсутствие изоляции
■
105
терфейсы взаимодействия с клиентами, критические изменения означают, что каж
дый пользователь должен изменить свой код. Радикальные изменения замедляют
общий цикл разработки, снижают эффективность бизнеса и сокращают сроки вы
полнения заказов.
Если бы нам пришлось выбирать между исправлением плохой реализации с помо
щью отличного контракта и отличной реализации, но с плохим контрактом, мы бы
каждый раз выбирали отличный контракт. Отличные контракты позволяют вам
реорганизовывать код, перепроектировать реализацию и изменять практически все,
что находится под контролем, с минимальными потерями для потребителей или
вообще без них
-
и это довольно эффективно.
Насыщенные модули и философия проектирования
программного обеспечения
В своей основополагающей работе «Философия проектирования программного
обеспечения» 23 Джон Остерхаут дает определение сложности в программных сис
темах, показывает, как идентифицировать сложность и ее признаки.
В главе
«Антишаблон: внутренние общие библиотеки» Джон утверждает, что
4
модули должны быть насыщенными. Насыщенные модули, как правило, содержат
больше кода и, следовательно, содержат сложность, в то время как интерфейсы
модулей должны быть простыми в использовании и понимании. Мы не можем не
согласиться с ним. Если мы возьмем принципы Джона и применим их к архитекту
ре программного обеспечения и дизайну сервисов (рис.
2.22),
то, по нашему мне
нию, они идеально согласуются с концепциями, рассмотренными в этой книге, где:
♦
Интерфейсы
♦
Модули
== Стабильные сервисные контракты;
== Реализации сервисов.
Контракт
Реализация сервиса
Простой контракт, легко использовать, легко понимать
Насыщенная реализация, ориентированная на бизнес-область,
сложность сосредоточена здесь
База данных
профилей
Рис.
2.22.
Применение философии проектирования программного обеспечения
к сервисам
23
(MSA
и
SOA)
«Философия разработки программного обеспечения» опубликована в 2018 году уже во втором издании:
https://web.stanford.edu/-ouster/cgi-Ьin/Ьook.php.
106
■
Глава 2
Операционные системы и инфраструктура
Инфраструктура программного обеспечения
(Software infrastructure) -
это одна из
самых важных вещей, которые вы можете изолировать.
Выполнение рабочих нагрузок на виртуальном оборудовании является одной из
наиболее распространенных задач для компаний, работающих в облаке, таких как
развертывание на инстансах ЕС2 в А WS. На инстансах ЕС2 работает операционная
система (ОС), и во всех ОС есть ошибки, требующие исправления.
Чем компактнее ваша ОС
-
чем меньше в ней пакетов,
-
тем меньше элементов
требуется поддерживать, исправлять и переносить. Например, не стоит устанавли
вать
Python
без необходимости, если это не требуется вашему программному обес
печению, или не стоит использовать компиляторы, такие как
GCC
или
Clang.
В конце концов, многие библиотеки ОС не являются компактными и страдают от
раздутых зависимостей. Даже одна небольшая установка может привести к кон
фликтам при управлении несколькими конфликтующими пакетами. Хотя разработ
чики пакетов делают. все возможное, они тоже могут случайно или иным образом
нарушить контракты; и чем большему количеству контрактов вы подвержены, тем
выше риск того, что нестабильный контракт нарушит вашу среду.
Контракт
Сервис профилей
Контра кт
Сервис продаж
Теперь нужно установить патч
на все ОС
База данных
профилей
Рис.
2.23.
Изоляция операционной системы
-
пример исправления HeartЫeed
Любой, кто сталкивался с ошибкой HeartЫeed 2 4, критической ошибкой TLS
в
OpenSSL,
помнит о необходимости срочного обновления
ленной на всех их дистрибутивах
Linux
(рис.
2.23).
OpenSSL 1.0.1, установ
Многим командам приходилось
отлаживать неисправную среду из-за неправильного управления конфигурацией
OpenSSL
или необходимости перекомпилировать множество зависимостей.
Использование более компактной операционной системы, в идеале с использовани
ем контейнерной рабочей нагрузки, делает процесс внесения исправлений более
24
Обзор ошибки HeartЫeed в Википедии: https://en.wikipedia.org/wiki/HeartЫeed.
Антипаттерны: отсутствие изоляции
■
107
упорядоченным и плавным, снижая влияние изменений операционной системы и
повышая изоляцию любого развернутого решения.
Расширенная изоляция
Для улучшения изоляции ваших программных архитектур можно применить мно
жество методов, и этой теме можно бьmо бы посвятить отдельную книгу. Давайте
рассмотрим три передовые концепции изоляции: переборки
ные варианты и ухудшение
(bulkheading),
резерв
UX.
Сооружение переборок и изоляция сбоев
В военно-морской инженерии есть концепция, называемая переборкой
тельный инженерный принцип, существующий с
V
-
увлека
века. Идея проста: внутри кор
пуса корабля должны быть вертикальные стены, разделяющие судно на отсеки
таким образом, чтобы в случае затопления одной зоны она бьmа изолирована от
других (рис.
2.24).
Переборка предохраняет все судно от затопления, если повреж
дена только одна небольшая часть судна.
Рис.
Источник:
2.24. Концепция переборок в Википедии.
ttps://en.wikipedla.org/wiki/Bulkhead_(partltlon)
В области разработки программного обеспечения аналогичным образом программ
ные сбои имеют тенденцию к каскадированию: сбой не локализуется, переходит
к следующему элементу в стеке и в конечном итоге приводит к сбою всего стека
или, в крайнем случае, к полному отказу. Здесь мы снова видим последствия отсут
ствия изоляции, теперь уже в виде изоляции от сбоев.
Шаблон переборки (Bulkhead Pattem)2 5
-
это шаблон проектирования, который
делает приложение устойчивым к сбоям.
Netflix был пионером в разработке этой
концепции благодаря своей библиотеке Hystrix26 . С помощью Hystrix исходящие
вызовы сервисов могут быть сгруппированы и привязаны к пулам потоков или
Определение шаблона переборки от помощью Microsoft:
https://learn.microsoft.com/en-us/azure/architecture/patterns/bulkhead.
25
26
Hystrix от Netflix: https://github.com/Netflix/Нystrix. Сегодня Hystrix находится в режиме технического
обслуживания, и сообщество разработчиков с открытым исходным кодом создало альтернативу под назва
нием
Resilience4J: https://resilience4j.readme.io/docs.
108
■
Глава 2
семафорам. Если одна группа начинает сбоить, она может полностью использовать
только один пул потоков или не сможет освободить свой семафор, что не повлияет
на другие группы вызова сервисов.
Одним из серьезных недостатков монолитов является их низкая доступность и от
казоустойчивость. Отказ одного модуля может повлиять на работу всего приложе
ния (рис.
2.25).
Микросервисная архитектура устраняет эти проблемы, потому что,
когда у вас есть сервисы, сбой в работе одного сервиса не обязательно означает
сбой в работе других. Хотя микросервисы все еще могут вызывать каскадные сбои,
как мы проиллюстрировали выше.
• •• • • • •
Профили
Отчеты
Продажи
...__ _ _.__ __.__ _ ___.
Это классический или модульный монолит
Сервис отчетов вызвал сбой
JVM,
все приложение будет отключено,
.......
причем независимо от того,
есть у нас модули или нет
БД
Рис.
Сбой JVM 27
2.25.
-
Отсутствие изоляции сбоев
-
классические модульные монолиты
не единственная возможная причина, приводящая к катастрофиче
скому сбою всего вашего приложения. Поскольку мы используем монолитную
архитектуру, любое исчерпание общих ресурсов может привести к той же проб
леме, например:
♦
нехватка памяти
♦
нехватка ресурсов процессора
♦
нехватка ресурсов ввода-вывода диска
♦
нехватка пропускной способности сети
♦
нехватка централизованных или совместно используемых баз данных;
♦
( memory );
(CPU);
(Disk/IO);
(Network bandwidth);
нехватка централизованных или совместно используемых сервисов или любая
отдельная точка отказа
(Single Point of Failure, SPOF).
Даже если у вас нет простоев, нехватка ресурсов все равно может сказаться на
работе пользователей. Кто-то может запросить затратный и громоздкий отчет,
в результате остальные
пользователи
Отсутствие изоляции сбоев
с трудом отправляют запросы
(failure isolation)
на
продажу.
может не только повлиять на доступ-
27 Java Virtual Machine (Java VM, JVM)- виртуальная машина Java, основная часть исполняющей системы
Java - Java Runtime Environment (JRE). - Пер.
Антипаттерны: отсутствие изоляции
■
109
ность, но и привести к проблемам с производительностью. Проблемы с производи
тельностью мoryr быть устранены путем надлежащего планирования производи
тельности, стресс-тестов и перегрузки оборудования, но проблемы доступности
и отказоустойчивости не всегда решаются так просто.
На рис.
2.26
показано, как архитектура в стиле микросервисов может обеспечить
лучшую изоляцию, поскольку весьма вероятно, что возможности создания отчетов
не повлияют на продажи и операции с профилями. Микросервисы позволяют это,
поскольку у них изолированы:
♦
кодовая база -
как контрактов, так и реализации;
♦
инфраструктура, где каждый сервис выполняется на независимых серверах ЕС2;
♦
fia:5ы данных с выделенными кластерами для каждого сервиса.
Профили
Продажи
О"Nеты
Модуль о"Nетов привел к сбою
• •.
JVM,
весь сервис о"Nетов будет недоступен .
Продажи и профили продолжают
работать нормально.
Рис.
2.26.
Изоляция сбоев в микросервисной архитектуре
К недостаткам стиля архитектуры микросервисов в данном случае относятся:
♦
стоимость
-
больше ресурсов, следовательно, еще больше затрат;
♦
сложность
-
сложнее отлаживать и поддерживать.
На самом деле эта проблема более запутанная, чем кажется. В нашем примере ви
зуализированы отчеты, работающие в отрыве от продаж. Однако возьмем платеж
ный сервис. Если платежный сервис не работает, это может легко сказаться на про
дажах, даже если они не связаны между собой и полностью изолированы, посколь
ку они сцеплены друг с другом в рамках общего бизнес-процесса для потребителей.
Тестирование-ключ к оценке возможных сценариев каскадных сбоев, таких как:
♦ Хаотическое тестирование (Chaos engineering)2 8 . Заблаговременное отключе
ние ваших приложений и инфраструктуры и проверка возможности их восста
новления после сбоя.
28
Chaos Engineering -
это дисциплина, направленная на тестирование и повышение отказоустойчивосm
сложных распределенных систем путем проведения контролируемых экспериментов, имитирующих реаль
ные сценарии отказов. Такой подход помогает выявить и устранить потенциальные проблемы до того, как
они появились и могли бы привести к значительным сбоям, сократить время простоя и повысить общую
доступность систем.
-
Пер.
110
♦
■
Глава 2
Стресс-тестирование. В сложных условиях вы можете увидеть, где ваше при
ложение выходит из строя, и обнаружить узкие места. Это чрезвычайно полезно
для планирования производственных мощностей.
Хаотическое тестирование, тестирование в производственных условиях и другие
аспекты тестирования будут подробно рассмотрены в главе
7
«Надлежащее тес
тирование сервисов». Как вы можете видеть, всё это формы изоляции, и здесь изо
ляция становится чрезвычайно важной для обеспечения доступности и отказо
устойчивости.
Резервные варианты
Помимо простого решения проблем масштабирования и обеспечения отказоустой
чивости, разработка резервных вариантов
(fallback)
является эффективным спосо
бом смягчения последствий сбоев. Например, если сервис платежей не работает,
можем ли мы поставить сообщение в очередь в
Kafka,
буферизовать и возобновить
обработку платежа после восстановления сервиса? Если сбой произошел в сторон
нем платежном сервисе, можем ли мы привлечь резервного поставщика на случай
сбоя в работе основного? Не во всех сценариях возможен резервный вариант или
частичный успех, но там, где это возможно, это мощные инструменты.
Резервные варианты могут быть реализованы самыми разнообразными способами.
♦
Повторная попытка. Если пользовательский вызов завершается ошибкой, мо
жем ли мы просто повторить попытку?
♦
Обработка отказа. Если зависимость от сервиса не работает, можем ли мы
попробовать запустить экземпляр в другом экземпляре зоны доступности
lability Zone, AZ)
♦
(Avai-
в А WS?
Кеmирование. Можем ли мы извлечь из кеша меньше текущих данных? Этот
метод применим ко всем формам кеширования: статическому, динамическому,
внутреннему, внешнему, локальному или удаленному. Можно начать с удален
ного кеша и вернуться к локальному.
♦
Буферизация. Можем ли мы сохранить запрос в
Kafka
или в постоянной очере-
ди для последующей обработки?
Однако для каждого из этих вариантов есть свои подводные камни.
Повторные попытки следует использовать с осторожностью, в противном случае
они могут создать дополнительные проблемы с доступностью и привести к каскад
ным сбоям. Если группа сервисов не работает, может произойти множество по
вторных попыток,
из-за которых сервис может отключиться, а затем снова вклю
читься. Это называется проблемой «грозового стада». Алгоритмы безопасных по
вторных попыток обычно вводят колебание, случайное время между несколькими
попытками, и экспоненциальное замедление,
когда мы экспоненциально увеличи
ваем время ожидания между повторными попытками. Марк Брукер делится опытом
AWS в области повторных попыток, колебаний и экспоненциального замедления:
https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-withjitter/.
Антипаттерны: отсутствие изоляции
■
111
Интересным фактом является то, что повторные попытки, колебания и экспоненци
альное замедление являются встроенными функциями А WS
SDK,
но их необходи
мо настроить.
Что касается обработки отказа, то сбой может произойти за пределами любой зоны
доступа и охватить весь регион А WS. Для восстановления после сбоя может потре
боваться повторная попытка в совершенно другом регионе. Региональная обработ
ка отказа более сложна и обходится дороже. Вашему бизнесу это может и не пона
добиться
-
возможно, достаточно просто смириться с последствиями простоя.
В кешах могут быть ошибки, их необходимо тщательно протестировать, и они по
своей сути являются частью процесса повышения надежности. Как и любой про
граммный компонент, кеши также могут давать сбои и создавать свои собственные
проблемы. Независимо от того, есть ли у вас резервный код или кеш-память,
вы должны протестировать их, что может оказаться непрактичным или непростым
делом.
Буферы могут быть переполнены. Что произойдет, если очередь никогда не будет
очищена? Это может привести к проблеме отказа в обслуживании
(Denial of
Service, DoS). Безопасное использование буферов требует времени жизни (Тime То
Live, TTL) и дополнительных компенсирующих механизмов, таких как обеспече
ние наблюдаемости (мониторинг и оповещение), и, возможно, людям необходимо
время от времени просматривать очередь.
Мы считаем, что резервные варианты
-
это здорово, однако ими можно злоупот
реблять и использовать их неправильно. У
Amazon Web Services
в библиотеке раз
работчика есть отличная серия статей, в которых рассказывается об уроках, извле
ченных из создания А WS. Джейкоб Габриэльсон объясняет проблемы с резервны
ми вариантами в одной из них:
https://aws.amazon.com/builderslibrary/avoiding-
fallback-in-distributed-systems/.
Изоляция пользовательского опыта: деградация и изыскания
Еще один доступный резервный вариант
(fallback) -
улучшить взаимодействие
с пользователем, избегая полного простоя приложения. Изоляция пользовательско
го опыта
(UX isolation) -
это высшая форма изоляции: теперь изоляция распро
страняется не только на программное обеспечение, базы данных и инфраструктуру,
но и на UХ-дизайн самого приложения. Микросервисы не решают всех наших про
блем с отказоустойчивостью. Они хороши в плане изоляции сбоев
(failure isolation),
но нам нужно разработать интерфейс нашего приложения, чтобы безопасно справ
ляться с частичными сбоями и продолжать обслуживать клиентов.
Когда вы видите сбой в работе
Twitter29 (рис. 2.27),
это означает, что
Twitter полно
стью не работает. Частичного снижения качества обслуживания нет. Если ваш биз
нес не работает, это напрямую сказывается на клиентах и может привести к потере
доходов. А если такие простои будут частыми, то у вас могут возникнуть серьезные
29
Запрещен на территории РФ. -
Ред.
112
■
Глава 2
Home,
Twitter is over cap....a...c_ity
~ . -:""""---:"""':'"--::--~-P!e.se w.,1 .-. momtnt .nd try ,19.,
Источник:
or more 1nform.i1on. <h«k ou\
Twiнe,
Sta1u, •
Рис. 2.27. Знаменитый неудачник Twitter.
https:/ltechcrunch.com/2010/06/18/twitter-fail-whale-3/
проблемы с брендом и клиенты могут потерять доверие к вашему цифровому про
дукту.
Нам необходимо разработать систему с учетом отказоустойчивости и доступности.
Вернемся к нашему примеру. Рассмотрим ситуацию, если сервис отчетов не рабо
тает или его нижестоящие зависимости
(downstream dependencies)
не работают. Ка
ковы будут последствия? Будет ли это частичным сбоем или это будет означать,
что весь бизнес не работает? Если это частичный сбой, есть тактика, которую мы
можем применить на стороне бизнеса, сервиса и инфраструктуры. Например, мо
жет ли бизнес согласиться на ухудшение качества обслуживания пользователей?
Netflix
известен тем, что сохраняет доступность основных потоковых приложений
за счет снижения качества обслуживания клиентов30 . Например, Netflix предостав
ляет рекомендации по просмотру следующего фильма с помощью машинного обу
чения. Если этот сервис недоступен, может ли приложение предоставить список из
1О
лучших фильмов по всему миру или просто список всех фильмов? В любом
приложении некоторые сервисы будут более важными, чем другие; например, если
основная потоковая передача
Netflix
не работает, бизнес
Netflix
фактически пре
кращается. Но не все программные сбои на сложном предприятии одинаково влия
ют на бизнес
(business impact).
зо Пример того, как Nettlix применяет ухудшение функциональности в действии:
https://netflixtech Ыog.com/Ьгingingrich-experiences-to-memoгy-constгained-tv-devices-6de771 еаЬЬ 16.
Антипаттерны: отсутствие изоляции
■
11 З
Как предотвратить проблемы с изоляцией
Лучший способ создать и сохранить изоляцию
-
это усвоить хорошие принципы
разработки программного обеспечения и обеспечить информированность ваших
разработчиков об этих принципах и знания, как применять их в своих повседнев
ных проектах. Обучение важно для обмена знаниями.
Обзор конструкций и оснастки
На сессиях по обзору архитектуры программного обеспечения разработчики и ар
хитекторы представляют свои предложения по инженерному проектированию для
экспертной оценки и получения отзывов перед началом проектирования. Обзоры
дизайна должны охватывать новые функции, исправление значимых ошибок или
проекты по устранению технической задолженности, а также предоставлять пре
красную возможность проанализировать ключевые элементы дизайна программно
го обеспечения:
♦ архитектурная целостность: также известная как концептуальная целостность,
в любом месте вашего кода, куда бы вы ни заглянули, вы можете сказать, что
дизайн является частью одного и того же общего проекта и всегда согласован;
♦
согласованность дизайна: является ли дизайн отдельных компонентов согласо
ванным и правильным;
♦
ясность: учитывая присущую ему сложность, дизайн хорошо документирован
и прост для понимания;
♦ экономичность: дизайн решает проблему и не требует дополнительных дейст
вий, а также не смешивает области без необходимости;
♦
применение основных принципов: таких как изоляция, высокая согласован
ность, слабая связность, и применение правильных абстракций;
♦
избегание антипаттернов: таких как недостаточная изоляция, высокая степень
связанности или неправильные абстракции;
♦ избегание нарушения изоляции: как обсуждалось в этой главе, избегайте со
вместного использования баз данных, подключения к плохим библиотекам и
применяйте стабильные контракты.
Код-ревью тоже может быть полезен, но, на наш взгляд, он часто фокусируется на
недостатках кода и небольших изменениях и, как правило, упускает из виду важ
ные вопросы архитектуры. Применение строгого подхода к проектированию во
время жизненного цикла обзора кода также может быть одним из вариантов.
Ваша практика проверки дизайна должна быть постоянной. Архитекторы про
граммного обеспечения и инженеры-проектировщики должны время от времени
анализировать программную архитектуру сервисов и кода. Они должны оценивать
всю систему, чтобы убедиться, что всё сделано так, как должно быть реализовано.
Как мы упоминали ранее, если у вас стабильный контракт и надлежащая изоляция,
то даже если у вас возникнут другие проблемы, неверные решения, ошибки и зна-
114
■
Глава 2
чительная техническая задолженность, у вас будет четкий путь к исправлению си
туации.
При масштабировании у вас никогда не будет достаточного количества разработ
чиков программного обеспечения. Обзоры проектов
-
но,
и
вам
придется
инвестировать
в
автоматизацию
хорошая идея, но, возмож
инструменты
для
создания,
которые помоrут вам выявить недостатки в разработке, такие как:
♦ Имеет ли мой сервис доступ более чем к одной базе данных?
♦ Как часто меняется мой проектный контракт в течение
♦ Как выглядят мои зависимости? Дrrя
теки в моем
Maven:
3 месяцев?
есть ли какие-либо общие библио
pom.xml?
Что нужно запомнить
Поздравляем, мы подошли к концу главы
2!
В этой главе рассказывается о том, как
изоляция играет ключевую роль в архитектуре программного обеспечения и как
отсутствие изоляции создает множество серьезных проблем. Подведем итоги наше
го изучения.
♦ Надлежащая изоляция
-
ключ к эффективной архитектуре программного обес
печения.
♦ В процессе создания реального программного обеспечения вы столкнетесь с на
рушением изоляции. Избегайте соблазна нарушить надлежащую изоляцию.
♦
Открытость
-
необходимый элемент любой современной архитектуры про
граммного обеспечения. Правильное отображение элементов вашей архитекту
ры требует правильного и сложного компромисса.
♦
CQRS
и обработка событий моrут быть мощными методами управления распре
деленными системами, но также сопряжены со сложностями.
♦
Централизация может быть эффективной, если она выполняется правильно,
с
использованием
сервисов надлежащего размера и модульных монолитов,
но
также может привести к нарушению изоляции из-за неправильной группировки
элементов.
♦
Централизованные команды, такие как
DevOps,
команда платформы, моrут
стать узким местом для инноваций и предоставления сервисов, а также создать
средства
для
преодоления
изоляции,
например
путем
предоставления
плохо
спроектированных внутренних библиотек или сервисов. Они также могут быть
существенным преимуществом; управляйте ими тщательно.
♦
Для сохранения изоляции следует по возможности избегать совместного ис
пользования баз данных. В идеале каждый сервис должен иметь свое собствен
ное изолированное хранилище данных.
♦ В общих библиотеках моrут возникнуть проблемы с изоляцией: следите за биб
лиотеками сторонних производителей и внутренними общими библиотеками.
Антипаттерны: отсутствие изоляции
■
115
♦ Внутренние общие библиотеки могут стать огромной скрытой нагрузкой на
вашу организацию из-за бинарной связности, каскадной миграции и создания
антипаттерна «Распределенный монолит».
♦
Контракты
-
это общедоступные операции с четко определенными объектами
ввода и вывода с четкими ожиданиями поведения. Контракты включают в себя
как протокол вызова, так и форматы данных. В конечном счете контракты
-
это
данные.
♦
Стабильные контракты являются важным элементом хорошо изолированного
программного обеспечения. Стабильный контракт, поддерживаемый качествен
ным тестированием, может позволить вам легко обновлять свои реализации, не
влияя на потребителей. Ключ к стабильным контрактам
-
это:
•
явные контракты;
•
интерфейс, четко отделенный от реализации;
•
устойчивость к изменениям, но при этом обеспечение глубокого понимания
бизнес-области и требований.
♦
Сложность должна где-то присутствовать. Более масштабные сервисы, возмож
но, не так уж плохи; будьте осторожны, чтобы не увеличивать сложность и не
создавать беспорядок в
BFF
и пользовательских интерфейсах.
♦ Вы должны стремиться изолировать все элементы вашей программной архитек
туры: базы данных, контракты, библиотеки, серверы, операционные системы и
инфраструктуры.
♦ Шаблон переборки
-
отличный способ изолировать базовые ресурсы, исполь
зуемые вашими сервисами, и ограничить каскадные сбои.
♦ Резервные варианты могут эффективно противостоять сбоям в режиме снижения
производительности, включая повторные попытки, отработку отказа, буфериза
цию и кеширование.
♦ Разработка
UX
таким образом, чтобы он адаптировался к снижению производи
тельности, является отличным способом защиты пользовательского опыта.
♦ Активный анализ проекта и эффективное оснащение
-
это два отличных спосо
ба предотвратить проблемы изоляции в вашей организации.
ГЛАВА
3
Антипаттерны:
распределенные монолиты
Здесь нет больших проблем, есть только множеС1110 мелких.
Генри Форд
«Наконец-то руководство одобрило наш план рефакторинга. Этот огромный фраг
мент С# отправляется в мусорную корзину! Компания
Acme Widget
переходит на
микросервисы! У нашего проекта отличное новое название (проект «Новые гори
зонты») и 12-месячный план действий по обновлению и созданию совершенно но
вого стека приложений. Наши возможности безграничны!».
«Что ж, нам пришлось пойти на некоторые компромиссы, но спустя
24
месяца мы
здесь. Первые сервисы запущены в производство! Они функционируют хорошо,
и всё замечательно. У нас большой долг по новым функциям, но это не должно
стать проблемой для нашей удивительной распределенной системы».
«Что вы имеете в виду, говоря, что команда отчетов нарушила работу сервиса пла
тежей, изменив схему? Разве мы не использовали
что нам нужно обновить
50
Liquibase?»,
«Вы хотите сказать,
сервисов, потому что команда продаж изменила способ
расчета налога с продаж в Бразилии?», «Послушайте, эта ошибка критична ... Поче
му мы должны ждать выхода ежемесячного релиза?».
Что-нибудь из этого вам знакомо? Если да, то добро пожаловать в распределенный
монолит.
Структура главы
В этой главе мы рассмотрим следующие темы.
♦
Что такое распределенный монолит?
•
♦
Особенности распределенных монолитов.
Как создаются распределенные монолить1?
•
Совместное использование баз данных разными сервисами.
•
Общие библиотеки доступа к данным.
•
Общие контракть1.
Антипаттерны: распределенные монолиты
■
♦ Проблемы с распределенными монолитами.
•
Бинарная связь.
•
Временная взаимосвязь.
□
Повышение сложности.
□
Внедрение асинхронности с архитектурой, управляемой событиями.
•
Уязвимости и исправления в системе безопасности.
•
Тестирование.
•
Проблемы с управлением.
•
Проблемы с логикой.
♦ Усилители.
•
Размывание команды.
□
Владелец программного обеспечения.
•
Антинаучное мышление.
•
Новые функции и исправление багов.
□
•
Мины.
Плохая среда.
♦ Типы распределенных монолитов.
•
Серверная часть.
• BFF
•
и интерфейс.
Бессерверная архитектура.
□
Сложность бессерверных архитектур.
♦ Обратный эффект: снова хуже!
•
Архитекторы как контролеры не масштабируются.
•
Новые возможности/функции.
•
Новая таблица.
•
У старевшая технология.
♦ Предотвращение дальнейших повреждений.
•
Подумайте о возвращении к монолиту.
□
Советы по команде и процессу.
□
Советы по технологиям и архитектуре программного обеспечения.
♦ Что нужно запомнить.
117
118
■
Глава З
Что такое распределенный монолит?
Классические монолиты сложны в обслуживании и не обладают достаточной гиб
костью. Антипаттерн распределенного монолита
(Distributed Monolith)
обладает
этими же проблемами, а также всеми проблемами, присущими микросервисам.
Создание распределенной системы означает, что ваши проблемы с обслуживанием
и гибкостью распространяются на сотни кодовых баз и сервисов, а не только на
один из них. И теперь команды могут легко отрицать их, восхваляя свою новую
архитектуру микросервисов, в то время как скорость изменений сейчас хуже, чем
когда-либо.
Суть антипаттерна «Распределенный монолит» заключается в отсутствии изоляции:
когда сервисы или компоненты распределенной системы глубоко переплетены и
тесно взаимосвязаны, независимо от того, явные эти связи или скрытые. Степень
этой взаимосвязи показывает, насколько сильно вы скомпрометированы антипат
терном. Представьте себе это как спектр зависимости от степени ненужной связи
(рис.
3.1), с распределенным монолитом
SOA или MSA на другом.
на одном конце и правильно спроектиро
ванным
Распределенный монолит
Рис.
3.1.
Правильные сервисы
(SOA, MSA)
Спектр от распределенного монолита до правильных сервисов
(SOA, MSA)
Ответив на следующие три ключевых вопроса, вы сможете определить, в какой
части спектра находится ваша команда.
♦
Можете ли вы выполнять развертывание самостоятельно или вам нужны все
команды (например, последовательный выпуск релиза)?
♦ Можете ли вы безопасно обновить любую библиотеку или фреймворк, не раз
рушая при этом мир?
♦
Можете ли вы изменить свои хранилища данных, не консультируясь с другими
командами?
Если все ответы на эти вопросы «нет», то вы, вероятно, далеко продвинулись в сто
рону «распределенного монолита». Мы надеемся, что для читателей этой книги
правильный ответ заключается в более тонком «иногда». На вопрос о том, страдаете
ли вы от антипаттерна «распределенный монолит», нельзя ответить «да» или «нет»,
это скорее набор степеней, диапазон спектра, как на рис.
3 .1.
То, где именно вы
находитесь, описывает уровень сложности исправления ситуации, но не теряйте
надежды и не допускайте, чтобы ситуация ухудшилась. Проблема со временем
может усугубиться.
Особенности распределенных монолитов
Распределенные монолиты только на первый взгляд выглядят распределенными,
но на практике они обладают худшими чертами централизованных архитектур
(рис.
3.2).
Тремя ключевыми чертами распределенных монолитов являются:
Антипаттерны: распределенные монолиты
■
119
..о
.;,с
~
отсутс тв ие
~6>~
Общая
стабильных контрактов
'S:s-~
база данных
Распределенный монолит
~Q
'ts,
ОС),
~
Общие библиотеки
Рис.
3.2.
Особенности распределенных монолитов
♦ Отсутствие изоляции. Как было рассмотрено в главе
2
«Антипаттерны: от
сутствие изоляции», изоляция является ключом к архитектурам
обеспечения;
распределенные
программного
монолиты нарушают изоляцию,
как
правило,
в общей базе данных, внутренних общих библиотеках и отсутствии стабильн:,1 х
контрактов (staЫe
♦
contracts).
Отсутствие независимости. Хотя может показаться, что их сервисы или микро
сервисы
устанавливаются
независимыми
модулями,
на
практике
высокая
сте
пень связности означает, что ни один компонент не может изменятся в одиноч
ку, и требует от команд частой синхронизации работ.
♦
Распределенная сложность. Поскольку распределенные монолиты имеют тен
денцию к распределению, они становятся гораздо более сложными в операцион
ном
и
организационном
плане,
что затрудняет понимание определенных про
блем и требует гораздо больших затрат на их решение.
Как создаются распределенные монолиты?
Компании, стремящиеся к внедрению архитектуры в стиле микросервисов, зачас
тую сталкиваются с проблемой формирования распределенных монолитов. Это
может происходить по одной или нескольким из следующих причин:
♦ сосредоточиваются только на коде и неправильно разделяют базу данных;
♦ заканчиваются деньги, и компании сокращают расходы;
♦ не знают или не понимают принципы правильной архитектуры программного
обеспечения, такие как изоляция, стабильные контракты и экономичные биб
лиотеки;
♦ отсутствует архитектурный анализ или рекомендации (что можно и чего нельзя);
♦ разрабатывают программное обеспечение в стиле культа карго 1 (Cargo Cult), что
встречается чуть ли не во всех компаниях
и
Google),
1 Cargo
MAANG (Meta, Apple, Amazon, Netflix
и, возможно, всем им не нужно использовать микросервисы.
cult programming -
стиль компьютерного программирования, характеризующийся ритуальным
вкmочением кода или программных структур, которые не служат никакой реальной цели. Программирова-
Глава 3
■
120
Использование общедоступного облака
сов
-
это хорошо, архитектура микросерви
-
это здорово, а отказ от старых технологий в пользу новых
-
это замеча
тельно. Все благие намерения могут привести к созданию распределенного моно
лита (рис .
3.3).
Давайте порежем
Классический
МОНОЛИТ
на кусочки монолит,
0000
примем микросервисы!
Но ...
Отсутствие
Бинарная связь
Отсутствие
Временная
изоляции
с внутренними
стабильных
взаимосвязь
базы ~анных
общими
библиотеками
контрактов
j
'
.
'
Распределенный монолит
'
ОбщаяБД
Рис.
3.3.
Как мы в итоге получаем распределенные монолиты
Чем крупнее ваша компания, тем сложнее добиться симметричной согласованности
действий во всех командах. С большой долей вероятности дела пойдут не так, как
планировалось. Обычно компании постоянно переписывают системы и время от
времени выводят их из эксплуатации.
Использование архитектуры в стиле микросервисов может быть отличным решени
ем. Тем не менее их следует использовать с осторожностью, поскольку в конечном
итоге очень легко получить распределенный монолит. Как показано на рис.
3.3,
мы
можем получить распределенные монолиты четырьмя возможными способами. За
дачу нарезания монолита ломтиками и кубиками необходимо выполнять с особой
осторожностью; в противном случае вы можете усугубить ситуацию. Ремонт рас
пределенных монолитов является более сложным процессом и стоит дорого.
Теперь, когда мы знаем, что такое распределенный монолит, давайте разберемся,
как они на самом деле создаются.
Совместное использование баз данных
разными сервисами
На рис.
3.4 мы
видим три микросервиса. У каждого из них может быть:
♦ отдельная кодовая база на
git;
♦ отдельный конвейер развертывания
CVCD (Jenkins);
ние культа карго является симптомом того, что программист не понимает ни ошибки, которую он пытался,
устранить, ни очевидного решения . Термин «программист культа карго» может применяться, когда любой
человек, не имеющий опыта работы с рассматриваемой проблемой, копирует некоторый программный код
из одного места в другое, слабо понимая, как это работает и требуется ли это. - Пер.
Антипаттерны: распределенные монолиты
Распределенные монолиты №
1-
■
121
совместное использование баз данных
Сервис
Сервис
Сервис
профилей
продаж
отчетов
Три сервиса
Общая БД
Рис.
3.4.
Раслределенный монолит №
1.
используют
одну и ту же БД
Совместное использование таблиц
♦
выделенная команда инженеров;
♦
выделенный устав, владелец продукта и дорожная карта;
♦
выделенный сервер А WS ЕС2.
На первый взгляд, эти сервисы выглядят великолепно. Однако такого разделения
недостаточно, и существует одна большая проблема: общая база данных. Наличие
общих баз данных показывает, как отсутствие изоляции может создать множество
следующих проблем.
♦ Доступность. Если общая база данных не работает, пострадают все три сервиса.
♦
Проблема с ресурсами. Сервис отчетов может запустить массивный запрос, что
приведет к истощению ресурсов базы данных и повлияет на все остальные сер
висы.
♦
Эволюция схемы БД. Сервис продаж может вносить серьезные изменения
в схему/таблицы, нарушая рабоrу всех сервисов. Любые изменения струкrуры
данных должны быть синхронизированы и требуют особой осторожности.
♦ Координация разработки. Все три сервиса должны быть синхронизированы на
протяжении всей разработки, чтобы команды могли поддерживать связь на вы
соком уровне, чтобы не наносить ущерб друг другу.
♦ Независимость развертывания. При любых критических изменениях вы не
сможете развернуть эти сервисы изолированно. Их необходимо объединить. Не
нарушая изменений, вы можете выполнить независимое развертывание, но хо
тите ли вы рисковать?
♦ Нарушение изоляции. Как мы объясняли в главе
2
«Антипаттерны: отсутст-
вие изоляции», мы также нарушаем изоляцию, не изолируя базу данных.
Как видите, архитекrура микросервисов должна обеспечивать независимость, но
если в итоге вы создадите распределенный монолит, то не получите независимости.
Вы столкнетесь с необходимостью постоянной синхронизации.
Совместное использование баз данных
-
самый распространенный способ нару
шить изоляцию и в конечном итоге создать распределенный монолит. К сожале-
122
■
Глава З
нию, это не единственный путь; существуют и другие пути, ведущие в столь ковар
ную ловушку.
Общие библиотеки доступа к данным
Наш второй пример похож на пример №
1с
одним ключевым отличием: сервисы
больше не имеют доступа непосредственно к общей БД (рис.
3.5).
Вместо этого все
они используют одну и ту же общую библиотеку доступа к БД с общими
POJO.
На
первый взгляд, это выглядит хорошей идеей, поскольку мы больше не дублируем
код доступа к БД в каждом сервисе; кому не нравится повторное использование?
Если есть ошибки, мы можем устранить их все в одном месте. Однако в долгосроч
ной перспективе общие библиотеки доступа к данным могут легко превратиться
в кошмар, который можно описать следующим образом.
♦ Выбор по собственному усмотрению. У команды, которой принадлежит биб
лиотека, может быть одно предпочтение, но что, если сервис отчетов не хочет
напрямую
использовать
Hibemate
и
предпочитает
Spring Data
или
просто
JDBC/SQL?
Сервис
Сервис
Сервис
профилей
продаж
отчетов
Три сервиса используют
одну и ту же общую библиотеку
для доступа к общей БД
Общая библиотека
Общая БД
Рис.
♦
3.5.
Распределенный монолит №
2-
совместное использование библиотек доступа к данным
Миграция «все или ничего». Команды должны координировать свои действия,
что приводит к длительным каскадным миграциям и/или взрыву веток. Что про
исходит, когда сервис профилей хочет перейти с
Hibemate 4
на
5,
но у сервиса
отчетов недостаточно пропускной способности или требуется обновление? Мно
го головной боли.
♦
Синхронизация данных. Все три сервиса должны использовать одну и ту же
версию библиотеки и постоянно поддерживать тесную связь, иначе они могут
нарушить работу друг друга. Такая тесная синхронизация является болезненной
и требует эффективной автоматизации работы нескольких команд.
♦
Хрупкость. Наличие общей библиотеки не предотвращает проблем с доступно
стью; если база данных не работает, это затрагивает все сервисы.
Антипаттерны: распределенные монолиты
♦
■
123
Нарушение изоляции. Контрактом общей библиотеки, скорее всего, будут
классы ОАО, интерфейсы репозитория или другие объекты, тесно связанные
с базой данных и/или платформами сохранения. Таким образом, у нас не будет
стабильных контрактов; еще один антипаттерн, нарушающий изоляцию.
Внутренние общие библиотеки доступа к БД не устраняют проблемы с распреде
ленным монолитом. Они усугубляют их или даже вызывают проблему в первую
очередь. Давайте рассмотрим наш последний пример.
Общие контракты
3.6)?
Некоторые команды решают, что совместное использование кода
это здорово.
Так почему бы не поделиться и определениями контрактов (рис.
В конце кон
цов, контракты могут ссылаться на общие концепции; вы же не хотите, чтобы один
сервис называл поле
FirstName,
Если контракт написан на
Java,
а другая команда использовала вместо него
то любой контракт
Java JAR
fname.
будет зависеть от биб
лиотеки базовых контрактов. Команды получают централизованное место для хра
нения общих
POJO
и сокращают дублирование кода за счет повторного использо
вания.
Контракт
Контракт
Контракт
Сервис
профилей
Сервис
Сервис
продаж
отчетов
Контракт
профилей
Общая БД
Рис.
3.6.
Распределенный монолит № З
-
общие контракты
Библиотеки базовых контрактов могут легко выйти из строя. Представьте, что биб
лиотека базовых контрактов, от которой зависят все контракты, получает свои соб
ственные зависимости, такие как
Spring, Hibemate, Log4J
и др. Теперь у нас есть
негативные побочные эффекты, аналогичные нашему предыдущему примеру.
♦ Выбор по собственному усмотрению. Как и в примере
команда создания отчетов не хочет использовать
или
Jakarta ЕЕ
(прежний
Spring
2,
что делать, если
и предпочитает
Guice
Java ЕЕ)?
♦ Миграция «все или ничего». Как и в примере
2,
что делать, если команда по
базовому контракту хочет перейти на новую версию валидаторов
Hibemate,
но
сервис отчетов не может или не будет этого делать? Нам нужно перенести их
все одновременно.
124
■
Глава 3
♦ Пахнет синхронизацией. Ядро
Spring
хорошо тем, что поддерживает обратную
совместимость, но большинство библиотек несовместимы. Во всех ли контрак
тах есть критические изменения? Поэтому при реализации сервисов необходимо
будет использовать одну и ту же версию библиотек.
♦ Нарушение изоляции. Как мы объясняли в главе
2 «Антипаттерны:
отсутст-
вие изоляции», мы также нарушаем изоляцию, не изолируя контракты.
Код контракта должен быть максимально простым, в идеале с нулевыми фреймвор~
ками и зависимостями. Старайтесь избегать экзотических типов данных, зависящих
от языка. Сторонние фреймворки и библиотеки с открытым исходным кодом
хороши для реализации сервиса, но они категорически не подходят для сервисного
контракта.
Проблемы с распределенными монолитами
У распределенного монолита много недостатков и нет преимуществ, следователь
но, он является антипаттерном. Давайте немного подробнее разберемся в этих не
достатках.
Бинарная связь
Мы обсуждали бинарную связь в главе
1 « Что
не так с монолитами?» и главе
«Антипаттерны: отсутствие изоляции». Бинарная связь
(Binary Coupling)
2
в рас
пределенных монолитах влияет на вашу способность понимать свои системы. Каж
дый микросервис имеет свой проект и свой собственный путь к классу и может
использоваться различными внутренними и внешними библиотеками с широким
разнообразием версий. Выяснение того, кто какую библиотеку/версию использует
на протяжении всего графика зависимостей, может стать непреодолимой задачей.
И каждое принудительное обновление библиотеки может привести к множеству
неожиданностей при сборке или во время выполнения. Такая непредсказуемость
затрудняет планирование.
Чем больше бинарных связей в вашем сервисе, тем меньше у вас возможностей для
продвижения вперед и развития. Если ваш сервис имеет стабильные контракты,
у вас есть надежный способ реорганизовать и устранить проблемы с бинарными
связями. Благодаря стабильным контрактам вы можете многое изменить, не затра
гивая другие команды или бизнес, например:
♦ свободно поменять базовую бизнес-логику;
♦ обновить весь свой технологический стек работы с данными и модель данных;
♦ заменить все сервисы, языки и библиотеки, которые вы используете;
♦ проводить технические эксперименты более свободно, используя более простые
стратегии отката.
Антипаттерны: распределенные монолиты
■
125
Временная взаимосвязь
Временная взаимосвязь 2 (Temporal coupling) характеризует сmуацию, когда между
одной или несколькими системами существуют зависимости, связанные со време
нем, что часто наблюдается при синхронном программировании. Временная взаи
мосвязь похожа на любую другую форму связи. В некоторых сценариях от нее
трудно избавиться, но необходимо это сделать, поскольку она влияет на доступ
ность.
Вот один из примеров временной взаимосвязи между четко определенными серви
сами.
BFF планирования
впечатлений
!0
@
Контракт
--
Сервис
--.....
0_
-
Контракт
Контракт
бронирования
Сервис
бронирования
проката
отелей
авиабилетов
автомобилей
~
База данных
отелей
Рис.
-
---
.....
--
3.7.
t
База данных
авиабилетов
Распределенные монолиты
-
Сервис
---
----
_,,,,,
....._
't'
-
~
База данных
автомобилей
для проката
временная взаимосвязь
--
Представьте, что имеется простое приложение для бронирования поездок, позво
ляющее найти и приобрести идеальный вариант для отпуска или медового месяца.
У нас есть мобильное приложение, написанное на
React Native, которое подключа
(API Gateway) в А WS, который, в свою оче
впечатлений, написанный на NodeJS. BFF пере
ется к общедоступному АРI-шлюзу
редь, вызывает
BFF
планирования
дает запросы сервисам на
базы данных (рис.
Java,
которые имеют свои собственные изолированные
3. 7).
Общий бизнес-процесс приложения выглядит следующим образом.
1. BFF
обращается в сервис бронирования отелей, чтобы забронировать отель для
пользователя.
2.
После бронирования отеля сервис бронирования отелей обращается в сервис
бронирования авиабилетов, чтобы приобрести билеты на самолет.
Объяснение временной взаимосвязи:
bttps://www.d.umn.edu/-gsbute/softeng/presentations/temporalcoupling.xbtml.
2
126
3.
■
Глава З
После получения авиабилетов сервис бронирования билетов на самолет обра
щается в сервис проката автомобилей для оформления дополнительной аренды
автомобиля.
Вы можете заметить много хорошего в этой архитектуре, например:
♦
все три сервиса имеют изолированные базы данных;
♦
выделенные контракты для каждого сервиса (стабильные контракты);
♦ у каждого сервиса есть своя собственная кодовая база.
Вы можете подумать, что у нас здесь нет распределенного монолита, но, к сожале
нию, это не так, потому что сервисы имеют высокую временную связность. Спро
сите себя:
♦
Что произойдет, если какой-либо сервис выйдет из строя?
♦
Есть ли у вас какой-либо резервный вариант
(fallback)?
♦ Что делать, если пользователь не хочет арендовать автомобиль? Или ему нужен
только номер в отеле?
Действительно ли у вас есть три независимые системы? В смысле контрактов, баз
данных и кодовых баз
-
да, это так. Но с точки зрения обслуживания, тестирова
ния и надежности возникает проблема.
Итак, как мы можем улучшить эту архитектуру?
Повышение сложности
Возможно устранить некоторые проблемы (и создать новые), переместив оркест
ровку на верхний уровень, который может быть либо другим сервисом, либо про
сто частью
BFF,
как в примере на рис.
3.8.
Преимущество этого решения заключается в том, что теперь
BFF
может организо
вывать вызов сервисов:
BFF планирования впечатлений
Контракт
Контракт
Контракт
Сервис
бронирования
отелей
Сервис
бронирования
проката
авиабилетов
автомобилей
База данных
отелей
База данных
авиабилетов
Рис.
3.8.
Распределенные монолиты
Сервис
База данных
автомобилей
-
повышение сложности
Антипаттерны: распределенные монолиты
♦
BFF
■
127
может сам выбрать, в какой сервис он будет вызывать, и даже делать это
в любом порядке;
♦
BFF
может пропустить сервисы и даже безопасно повторить попытку, используя
экспоненциальное замедление3 и колебания4.
Поскольку архитектура программного обеспечения основана на компромиссах, за
всё приходится платить, и с этим подходом у нас также есть проблемы. Вот недос
татки:
♦ Все еще возникают проблемы, когда
BFF
не работает.
♦ Допустим, обращения в сервис бронирования отелей начинают сбоить. Как дол
го мы будем повторять попытки? Что, если потребуется
2
часа, чтобы снова
подключиться к сети?
♦ Большая часть сложности теперь сосредоточена на уровне
BFF.
Некоторые из этих проблем могут быть устранены с помощью улучшенной инфра
структуры и резервных методов
(fallback), например:
♦ Убедитесь, что вы правильно реализовали переход на другой ресурс на стороне
клиента; рассмотрите возможность внедрения подсистемы балансировки на
грузки на стороне клиента.
♦ Повысьте доступность за счет наличия нескольких экземпляров всех сервисов
и резервных копий
BFF;
рекомендуется иметь по крайней мере три копии, по
одной на каждую зону доступности
(AZ).
♦ Используйте несколько регионов, что позволит вам выполнять переход на другой регион.
Основная проблема, связанная с этими исправлениями, заключается в увеличении
стоимости. Для некоторых крупных компаний это нормально, но, возможно, в ва
шей компании всё не так. В целом такой подход хорошо работает с общедоступным
облаком, поскольку мы можем использовать группы автоматического масштабиро
вания для предоставления большего количества ресурсов и обработки большего
количества запросов по требованию вместо предоставления ресурсов с избытком.
Внедрение асинхронности с архитектурой,
управляемой событиями
Теперь рассмотрим внедрение паттерна проектирования
Event Bus в виде классиче
RabbltMQ, или более
как Apache Katka. Рассмот
ской технологии обмена сообщениями, такой как JМS или
современной формы распределенного журнала, такой
рим решение, представленное на рис.
3 Концепция
3.9.
экспоненциального замедления в Википедии:
bttps://en.wikipedia.oгg/wiki/Exponential_backoff.
4 Колебания
вводят случайное время ожидания перед следующей повторной попыткой, более подробная
информация здесь: https://en.wikipedia.oгg/wiki/Jitteг.
128
Глава 3
■
Асин хронн ый подход , основанный на событиях
BFF планирования
впечатлений
0
Apach Kafka (... или другая шина передачи сообщений)
0
Контракт
Контракт
Контракт
Сервис
Сервис
бронирования
авиабилетов
Сервис
бронирования
отелей
База данных
База данных
отелей
авиабилетов
Рис.
3.9.
проката
автомобилей
База данных
автомобилей
Асинхронный подход, основанный на событиях
Это решение может показаться похожим на предыдущее, но оно значительно
улучшено за счет перехода от синхронных вызовов к асинхронным. У нас нет
временной взаимосвязи, и система переходит в окончательное, полностью заброни
рованное состояние по мере того, как каждый сервис обрабатывает свои запросы,
что также называется архитектурой, управляемой событиями.
Все сервисы являются производителями и потребителями событий из шины .
Давайте разберемся, как работает этот асинхронный подход, основанный на собы
тиях, шаг за шагом:
♦ Нулевой
шаг.
bookHote\Event,
BFF
запускает три
события:
событие
бронирования
отеля
bookPlaneEvent и событие бро
bookRentalCarEvent, отправляя их в очередь со
событие бронирования самолета
нирования проката автомобиля
общений .
♦
Шаги
1..3
сервисов. Каждый сервис постоянно ищет соответствующее событие
бронирования в очереди сообщений. По мере поступления каждого сообщения
в очередь сообщений сервис получает его и выполняет действие бронирова
ния.
Система функционирует иначе, чем в предыдущих двух примерах . Сервисы могут
получать сообщения в любое время и в любом порядке. Ранее гарантировалось, что
система будет работать в фиксированном, последовательном порядке (отель, само
лет, арендованный автомобиль). Теперь порядок не гарантирован. Сервис брониро
вания автомобилей может сначала забронировать автомобиль, арендовав его до по
купки билетов на самолет. Если сервис бронирования билетов на самолет не рабо
тает, сервис бронирования автомобилей полностью изолирован и по-прежнему
будет успешно работать.
Антипаттерны: распределенные монолиты
■
129
Основными преимуществами такой архитектуры являются
♦
Антихрупкость. Теперь не страшно, если все сервисы отключены. Когда они
заработают, сообщения будут обработаны, а заказы завершены.
♦
Масштабируемость. Система хорошо масштабируется, потому что мы можем
добавить больше экземпляров пользователей сообщений, например сервисов,
и ускорить обработку.
♦
Мы
исключили
временную
связность.
Благодаря
отказу
от
синхронных
НТТР-вызовов и использованию асинхронной обработки с использованием ши
ны сообщений системы больше не связаны друг с другом во времени.
Но этот подход также имеет некоторые недостатки. Во-первых, шина сообщений не
может быть отключена и не должна терять сообщения, т. к. это становится критич
ным для обеспечения надежности. Во-вторых, шина сообщений на самом деле не
является базой данных; некоторые могут возразить, что
Kafka -
это база данных,
но это не так. Вы не получите консистенцию бесплатно. Вам нужно будет следить
за следующим:
♦
События поступают с опозданием или никогда не обрабатываются. Что де
лать, если какой-либо сервис не работает в течение нескольких часов, а обработ
ка сообщений сильно задерживается? Что делать, если ошибка приводит к исте
чению срока действия сообщений? Что делать, если ваша система испытывает
нехватку ресурсов и сообщения переполняют ваши очереди?
♦ Дублирование. Не все системы обмена сообщениями гарантируют, что сообще
ния будут обработаны только один раз; или же событие может появиться не
сколько раз.
♦ Порядок. Если у вас нет строгого порядка, то как ваша система ведет себя,
когда сообщения поступают в разном порядке? Можете ли вы определить, какое
событие является первым или последним?
♦
UI/UX.
В асинхронных системах ваш пользовательский интерфейс больше не
получает простой обратный вызов при обработке всех транзакций. Как будет
вести себя пользовательский интерфейс и осуществлять взаимодействие с поль
зователем? Будет ли он обновляться по мере обработки сообщений? Как отреа
гирует пользовательский интерфейс, если сообщения так и не будут обработа
ны,
-
нужно ли вам просить своих клиентов позвонить вам, если бронирование
не будет выполнено в течение
24
часов?
При должном внимании все эти проблемы можно решить. Например, в некоторых
системах, таких как
Kafka,
упорядочение может быть достигнуто за счет использо
вания одной и той же темы и группы потребителей. С дублированием можно спра
виться, написав идемпотентные системы, способные безопасно обрабатывать по
вторяющиеся сообщения, которые готовы безопасно обрабатывать дублирование.
Несмотря на то что асинхронные системы более сложны, лучшим решением для
решения проблем временной связности является использование асинхронных ре
шений. Бесплатного обеда не предусмотрено.
130
■
Глава 3
Уязвимости и исправления в системе безопасности
Все компании технологические, и все технологические компании должны вести
эффективную стратегию
пасности
(strategy) и процессы обеспечения информационной безо
(Information Security, InfoSec), чтобы оставаться на плаву и вести бизнес.
В любой компании приличного размера или с жестким регулированием есть специ
альные команды по информационной безопасности.
В некотором смысле информационная безопасность может быть хорошим источни
ком и стимулом для внедрения модернизации:
♦ обеспечение постоянной актуальности внутренних и внешних библиотек;
♦
защита критически важных данных (таких как личные данные) в любое время:
в режиме ожидания, при передаче;
♦
высокая наблюдаемость для обнаружения угроз (журналы, оповещения и метрики).
Побочным эффектом этого является постоянная миграция. Правильная миграция
может быть полезной. Но реальность такова, что бизнес-команды всегда будут от
казываться от любой работы, которая мешает им получать непосредственную отда
чу. Миграция систем безопасности приносит пользу: ущерб бренду, который может
нанести нарушение безопасности, представляет собой огромный риск и может по
дорвать доверие ваших клиентов к вашему продукту.
Из-за высокой степени связности в распределенных монолитах миграция всегда
сопряжена с трудностями. Болезненная миграция означает, что всем становится
сложнее удовлетворять потребности вашей команды информационной безопасно
сти. Применять надлежащие принципы безопасности в правильно спроектирован
ных и архитектурных сервисах намного проще, поскольку вы можете легко реорга
низовать их реализацию, не затрагивая потребителей.
Тестирование
Тестирование
-
важнейший этап производства любого программного обеспечения.
Без тестирования как мы можем быть уверены, что все работает так, как должно?
В распределенных системах тестирование становится сложным и дорогостоящим,
потому что вы не можете просто протестировать сервисы изолированно. Высокая
степень связности означает, что вы не можете предполагать, как они будут работать
вместе, на основании того, как они работают изолированно. В результате команды
распределенных монолитов, как правило, тестируют все сервисы вместе. Одним из
побочных эффектов является то, что это может создать ощущение, что сквозные
и интеграционные тесты важнее модульных тестов и их необходимо проводить
в большем объеме.
Майк Чон в своей книге «Успех с помощью
Agile»
представил концепцию пирами
ды тестирования, которая представляет собой метафору, описывающую тестирова
ние на разных уровнях, где каждый уровень требует постоянно растущего количе
ства времени и денег (рис.
3 .1 О).
Антипаттерны: распределенные монолиты
■
131
Что касается серверной части, то у нас всегда должно быть больше модульных тес
тов, чем Е2Е 5 и интеграционных тестов. Модульные тесты дешевле создавать
и поддерживать, и они могут выполняться намного быстрее. Для сравнения: Е2Е и
интеграционные тесты более сложны и требуют данных и подготовки. Из-за этого
они могут быть ненадежными, полными ложных срабатываний и случайных не
ожиданных сбоев.
В распределенном монолите модульные тесты не могут дать вам всей необходимой
уверенности. Как бы то ни было, решение состоит не в том, чтобы полностью
посвятить себя Е2Е и интеграционным тестам, а в том, чтобы сосредоточиться и
внедрить другие формы тестирования, такие как мутационное тестирование6 (Muta-
tion), тестирование свойств (Property), фаззинг7 (Fuzzy), конфигурационное тести
рование (Configuration), нагрузочное тестирование (Stress), хаотическое тестирова
ние 8 (Chaos) и тестирование в производственных условиях (Testing in production).
Распределенные монолиты также создают проблемы с данными для тестирования;
часто вам нужно будет вставить данные в несколько чужих таблиц, чтобы получить
зависимости, необходимые для вашего конкретного теста.
Медпеннее
Пирамида тестирования
Дороже
Интеграционное
Модульное тестирование
Быстрее
Дешевле
Рис.
5
3.1 О.
Сквозное тестирование (End-to-end, Е2Е) -
Пирамида тестирования
это вид тестирования, используемый для проверки программ
- Пер.
ного обеспечения от начала до конца, а также его интеграцию с внешними интерфейсами.
6
Мутационное тестирование -
это метод тестирования ПО, основанный на всевозможных изменениях
исходного кода и проверке реакции на эти изменения набора автоматических тестов. Если тесты после из
менения кода успешно выполняются, значит, либо код не покрыт тестами, либо написанные тесты неэффек
тивны.
7
-
Пер.
Фаззинr (также тестирование мусорными данными) -
техника тестирования программного обеспечения,
часто автоматическая или полуавтоматическая, заключающаяся в передаче приложению на вход неправиль
ных, неожиданных или случайных данных.
8
Тестирование хаоса -
-
Пер.
зто метод, используемый для проверки устойчивости программных систем путём
внесения непредвиденных сбоев. С помощью тестирования хаоса можно смоделировать реальные сценарии,
такие как сбои сервера, задержка сети или нехватка ресурсов. Имитация этого поведения помогает в выяв
лении скрытых проблем и слабых мест. которые могут быть неочевидны в обычных условиях тестирова
ния. -Пер.
132
■
Глава 3
Проблемы с управлением
Как и все монолиты, распределенные монолиты создают массу проблем для руко
водства. Давайте начнем с общих вопросов.
♦
Почему на выполнение задач уходит так много времени?
♦
Почему мы снова и снова сталкиваемся с одними и теми же проблемами?
♦ Почему разработчики часто недовольны и так трудно удержать талантливых
специалистов?
♦ Почему у нас так много споров по поводу технических функций? Почему все
должно быть таким сложным?
♦
Почему мы продолжаем вкладывать деньги, время и усилия в программное
обеспечение, но чувствуем, что получаем мало взамен?
Распределенные монолиты не позволяют командам работать быстрее; вместо этого
командам требуется больше координации, и в конечном итоге они работают мед
леннее. У любого программного обеспечения есть «неизвестные переменные»,
непредвиденные проблемы, которые мы обнаруживаем в процессе работы. Но из-за
высокой
степени
связности
распределенные
монолиты
всегда
сталкиваются
с большим количеством таких переменных.
Помимо этих представлений, реальность, скорее всего, остается прежней: команды
сталкиваются с реальными проблемами в своей повседневной работе над распреде
ленным монолитом, еще более сложными, чем в случае классического монолита:
♦ больше ошибок;
♦
больше координации между командами;
♦
больше неприятных сюрпризов и неожиданных неудач на пути;
♦ больше буферизации оценок, когда команды дают все более консервативные
оценки;
♦
больше компромиссов в техн~ческом проектировании и наборе функций;
♦
в целом достигается меньшая ценность для бизнеса.
В конце главы
1
«Что не так с монолитами?» мы обсудили роль хороших инже
нерных практик, помогающих справляться с монолитами: надлежащий код-ревью,
полные ретроспективы, финансирование времени простоя, техническое наставни
чество и сильное руководство. Время простоя
-
один из ключевых элементов,
в котором команды нуждаются больше, чем когда-либо, в распределенных моноли
тах, поскольку они предоставляют свободную возможность для внесения улучше
ний, рефакторинга, дополнительного тестирования, перепроектирования и обеспе
чения того, чтобы один и тот же инцидент не повторился. Но бизнес уже испыты
вает трудности из-за пропущенных сроков и меньшей стоимости, чем ожидалось.
Это мешает последовательным инвестициям.
Антипаттерны: распределенные монолиты
■
133
Проблемы с логикой
Программное обеспечение требует осмысления. Если вы не можете разобраться
в том, что делает код, вы возвращаетесь к методу проб и ошибок; вы становитесь
неэффективными, вам не хватает точности, и это сокращает время выполнения за
каза. К программному обеспечению следует подходить с научной точки зрения.
Рассуждения позволяют нам установить причину и следствие, а также быть в со
стоянии предсказать неудачу и последствия.
Распределенные монолиты сильно усложняют логику из-за перечисленных далее
факторов.
♦
Множество движущихся частей. У вас есть десятки или сотни сервисов, кото
рые на первый взгляд выглядят независимыми, но на самом деле являются од
ним приложением. Теперь вам нужно просмотреть сотни отдельных баз кода и
угадать, в какой из них проблема.
♦ Недостаточная изоляция. В распределенных монолитах недостаточно изоли
рованы базы данных, внутренние общие библиотеки и контракты, что приводит
к побочным эффектам
-
ошибкам, нестабильности, сбоям и трудностям для
инженеров. Отсутствие изоляции затрудняет точное определение основной при
чины любой проблемы.
♦ Кто это нарушил? Или что это нарушило? Многие команды могут изменять
общую базу данных и внутренние общие библиотеки в любое время, взламывая
код друг друга в течение всего дня. Ошибка может быть вызвана кодом вашей
или любой другой команды. Радиус поражения большинства изменений стано
вится огромным.
♦
Недостаточное разнообразие тестирования. Из-за разрозненности тестов и
отсутствия важных проверок в ключевых местах крайне сложно проверять тео
рии до их внедрения в производство и/или до того, как они повлияют на клиен
тов.
Чтобы разобраться в происходящем, вам нужна определенная степень контроля.
Трудно контролировать сотни людей, поэтому в больших масштабах распределен
ный монолит становится очень и очень непонятным, сложным и полным противо
речий, как и классический монолит, но намного хуже, потому что он распределен
ный.
Наиболее существенным последствием отсутствия должного обоснования является
низкая производительность и трудности с устранением неполадок. Вы потратите
недели или месяцы на борьбу с проблемами. Это плохо как для бизнеса, так и для
инженеров, поскольку создает впечатление, что разработка ведется медленно и не
приносит результатов. Представители бизнеса мало что знают о трудностях, свя
занных с распределенными монолитами.
134
■
Глава 3
Усилители
Распределенные
(amplifier)
монолиты
также
подвержены
явлениям,
которые
усиливают
все их проблемы, заставляя их становиться еще хуже и со временем раз
рушаться.
Размывание команды
Размывание команд
(team erosion)- интересный
эффект в разработке программно
го обеспечения. Диего Пачеко, автор этой книги, написал в блоге об эффекте раз
мывания
команд
erosion.html).
в
году
2021
(bttp://diego-pacheco.Ыogspot.com/2021/01/team
Со временем инженеры приходят и уходят из компаний, команды
создаются и распадаются, а программное обеспечение создается и выводится из
эксплуатации. Это часто приводит к ситуации, когда программные продукты ока
зываются бесхозными и у них нет владельца или даже сопровождающего. Со вре
менем команды разработчиков программного обеспечения подвергаются размыва
нию по многим причинам.
♦
Эволюция бизнеса. Мир меняется. Меняются клиенты. В мире существует
множество факторов, которые заставляют бизнес менять направление. Напри
мер, новые поколения, новые технологии, изменения законодательства и многое
другое.
♦ Приобретения. Ваша компания может время от времени приобретать и прода
вать
другие
компании,
создавая
напряженность
и
меняя
приоритеты
и
права
собственности.
♦
Повороты стартапа. В стартапе постоянно меняются идеи в поисках продукта,
соответствующего рынку
(Product Market Fit, PMF).
♦ Макросреда. Из-за макросреды
ской реальности и политики
-
-
экономики, войн, пандемий, потребитель
могут произойти увольнения, и программное
обеспечение может остаться без первоначальных создателей.
♦ Напряженность в кадрах. Люди могут захотеть решать разные задачи. Инже
неры, желающие работать в других областях или решать другие задачи, покида
ют вашу компанию.
♦
Горячие технолоrические рынки. Кремниевая долина и некоторые европей
ские страны, такие как Великобритания, Германия, Нидерланды, могут предос
тавить лучшие возможности и привлекать людей и команды переходить в дру
гие компании.
♦
Жизненный цикл проrраммноrо обеспечения. Программное обеспечение ста
реет, и срок его службы заканчивается
(End of Life, EOL);
поставщик, который
раньше его поддерживал, больше не существует или не хочет инвестировать
в него. Ценный опыт может быть утрачен.
♦
Реорrанизации и смена руководства. Смена руководства может заставить
компанию двигаться в другом направлении.
Антипаттерны: распределенные монолиты
■
135
Существует множество причин, по которым может произойти размывание команды
(team erosion},
и классические монолиты тоже могут пострадать от этого. Однако
микросервисы и распределенные монолиты больше всего страдают от размывания
команды. Чем больше у вас программного обеспечения, тем больше шансов, что
у вас возникнут проблемы с владельцем
(ownership)
(рис.
3 .11 ).
В любой организации размывание команды оказывает реальное и долговременное
воздействие на вашу способность к быстрому продвижению.
♦
Кто будет исправлять ошибки или заниматься миграциями, если у вас нет вла
дельцев?
♦
Кто будет тестировать исправления безопасности и миграцию, если они понадо
бятся?
♦ Как правильно оценить влияние изменений на объекты, не имеющие официаль
ных владельцев?
♦
Как предотвратить ухудшение технического состояния программного обеспече
ния, у которого нет владельца?
♦
В случае изменений в дизайне, кто решает, что дизайн правильный или непра
вильный? Кто следит за целостностью дизайна и кодовой базы?
♦
♦
Кто будет заниматься оперативной и производственной поддержкой?
Вы новый сотрудник или подрядчик и хотите поработать с этим программным
обеспечением. К кому обратиться за помощью? Кто может научить вас, как это
работает?
Чем ближе команды взаимодействуют с бизнесом, тем меньше шансов, что у какой
то команды не будет устава. Но все же это возможно. По мере того, как вы удаляе-
**
Размывание команды
Сервис
Сервис
Сервис
... + сотни
профилей
авторизации
генерации
сервисов
отчетов
Рис.
3.11.
Размывание команды и общие библиотеки
Есть владелец
Нет владельца
136
■
Глава 3
тесь от пользовательского интерфейса, бизнесу становится все труднее понимать и,
следовательно, расставлять приоритеты. Конечно, размывание происходит даже
в бизнес-командах. Но чаще всего это происходит с техническими или платфор
менными сервисами. Они находятся глубоко в стеке и являются более технически
ми по своей природе. Эти сервисы связаны скрытыми зависимостями, которые
трудно объяснить бизнесу.
Самая большая проблема, связанная с размыванием команды, часто связана с об
щими библиотеками. Часто компании не придерживаются строгой политики в от
ношении библиотек, скорее наоборот. Даже компании, у которых есть «владельцы»
всех общих библиотек, не обязательно подразумевают, что они действительно
знают библиотеку.
Размывание создает напряженность между существующими бизнес-командами и
командами ядра/платформы (рис.
3.11).
Нередко команды отказываются от владе
ния тем, чего не создавали и что может иметь технические проблемы. Вам не нуж
но стремиться к идеальному владению, но лучше владеть чем-то, чем вообще
ничем.
Кто борется с отсутствием сопричастности? Как справиться с размыванием команды?
Владелец программного обеспечения
У всего должен быть владелец
(ownership).
В идеале команда создала сервис или
библиотеку, и она же владеет этим артефактом. К сожалению, такое не всегда воз
можно из-за размывания команды
(team erosion),
и иногда нам приходится прини
мать сложные решения. Вот несколько критериев, которые помогут вам решить,
какая команда должна владеть тем или иным сервисом/библиотекой.
♦ Близость к предметной области. Относится ли это к той же бизнес-области?
Кто или какая команда ближе к этой области?
♦ Частота коммитов. Кто или какая команда чаще всего запрашивала изменение
кода
(Pull Request, PR) за последние 12 месяцев?
♦ Доступные возможности. У какой команды в настоящий момент больше воз
можностей для выполнения этой работы?
♦
Сочувствие и забота. Какая команда больше всего заботится о данном серви
се/библиотеке или, возможно, захочет поддерживать их в рабочем состоянии?
Спросите своих сотрудников; возможно, вы найдете добровольцев.
♦
Технологическая близость. У какой команды есть стек, который ближе или
совпадает с тем, что использует этот сервис/библиотека?
Владение
-
это то, что нужно время от времени пересматривать. Важно сохранить
информацию о владельце где-нибудь, например на вики-странице, или некоторые
метаданные в файле в вашем git-репозитории, например CODEOWNERS в GitHub
(https://docs.github.com/en/repositories/managing-your-repositorys-settingsandfeatures/customizing-your-repository/about-code-owners).
Размывание команды также может быть признаком того, что у вас слишком много
сервисов и/или общих библиотек. Если вы не справляетесь с количеством про-
Антипаттерны: распределенные монолиты
■
137
граммных ресурсов, рассмотрите возможность упрощения своих библиотек и даже
объединения некоторых сервисов для упрощения владения и поддержки.
Антинаучное мышление
Научный подход имеет решающее значение для устранения сложных проблем. Ру
ководство часто испытывает сильное давление и не хочет тратить время впустую,
поэтому в ход идут всевозможные сокращения и обходные пути. В сочетании
с плохим окружением
(bad environment)
такое краткосрочное мышление приводит
к тому, что проблемы со временем становятся все хуже и хуже. Если вы не устра
няете проблемы в первоисточнике, вы просто обманываете себя.
Логика, здравый смысл и применение научных методов имеют решающее значение
для устранения сложных проблем. Четкое рассуждение
-
единственный способ
разобраться в сути проблемы. Чем быстрее вы разберетесь в вопросе, тем лучше
будет результат для ваших клиентов. Этот подход применим к разработке про
граммного обеспечения. Но, как мы уже показали, он еще больше необходим при
работе с распределенными монолитами: из-за их сложности особенно трудно рас
суждать о последствиях своих действий или безопасно тестировать теории.
К сожалению, как мы уже говорили, в таких условиях возрастает давление со сто
роны руководства: действуйте быстро, просто наложите пластырь, просто устрани
те симптом, не устраняя первопричину. В ход идет множество коротких и обход
ных путей. Вы не можете игнорировать науку: если вы не рассуждаете и не устра
няете проблемы на месте ее возникновения, вы просто обманываете себя.
Из-за отсутствия прикладных научных обоснований проблемы распределенного
монолита усугубляются. Происходит следующее.
♦ Технический долг растет. Если вы не будете стремиться должным образом
устранятъ проблемы и инвестировать в серьезный рефакторинг и постоянное со
вершенствование, как в случае с классическими монолитами, антипаттерны рас
пространятся по всему коду с помощью теории разбитых окон
(Broken windows ).
(fear of
Когда антипаттерны проникают в вашу кодовую базу, боязнь перемен
change) становится
нормой.
♦ Остаточные явления. Если бизнес не дает командам возможности рассуждать,
понимать и устранять первопричину, предпочитая обходные пути, миграция
начнется, но часто будет «приостановлена» или «остановлена» при первом же
обходном решении. Это делает распределенные монолиты плодородной почвой
для мин
(landmine)
и ведет к еще более медленному устранению неполадок;
многочисленные обходные пути создают дополнительные сложности и долги.
♦
Переделки. Вернемся к основной проблеме: если вы не понимаете, какой код
используется вашим приложением, вы перенесете неработающий код, исправите
ошибки в неработающем коде и будете беспокоиться о пути к коду или рабочем
процессе, которые могут никогда не запуститься. Вы будете выполнять больше
работы, чем необходимо для обеспечения безопасности.
♦ Неверные решения. Руководство часто настаивает на выполнении работ и по
лучении быстрых результатов, не желая вкладывать средства в рефакторинг,
■
138
Глава 3
улучшения и модернизацию. Однако это окупит все затраты времени, медлен
ную разработку, ошибки и инциденты.
Со временем распределенные монолиты становятся слишком большими, сложными
и безумными, что затрудняет их исправление. Для их правильного решения требу
ется научная строгость, но правильное обоснование может занять много времени и
быть дорогостоящим. Без финансирования люди опускают руки и отвергают необ
ходимость научного мышления, предпочитая игнорировать эти проблемы. В какой
то момент технический долг становится вашим королем, потому что он диктует
все, что вы делаете. Расходы слишком высоки, программного обеспечения слиш
ком много, и вы продолжаете усложнять ситуацию.
Проблемы, порожденные антинаучным мышлением, только усугубляются, когда вы
добавляете новые функции и исправляете ошибки.
Новые функции и исправление багов
Независимо от того, какой у вас архитектурный стиль программного обеспече
ния
-
классический монолит, микросервисы или даже антипаттерн, подобный рас
пределенному монолиту,
-
вам нужно будет разрабатывать новые функции и
исправлять обнаруженные баги
(features and bugs).
При правильном подходе вы
можете предотвратить дальнейшие повреждения и избежать дополнительных тех
нических проблем, а при неправильном можете усугубить ситуацию. Реальность
такова, что часто это не является бинарным результатом для всей вашей архитекту
ры, а скорее решается постепенно: команда за командой, сервис за сервисом и об
щая библиотека за общей библиотекой.
Распределенные монолиты усложняют работу с новыми функциями и исправление
багов из-за их особенностей, затрудняющих правильное понимание. Давайте про
иллюстрируем это на примере. Предположим, у вас есть два разных сервиса, ис
пользующих одну и ту же таблицу в общей базе данных (рис.
Сервис продаж
Сервис профипей
3.12).
Сервис продаж
Продажи замедnяются,
с профиnями все в порядке ...
Общая БД
Рис.
3.12.
Ошибки в распределенных монолитах
Антипаттерны: распределенные монолиты
■
139
работает медленно. Причем проблема может быть связана не только самим этим
сервисом, но и с другим сервисом профилей, поскольку они используют одну и ту
же базу данных.
Поскольку у нас сервисы должным образом не изолированы, не исключено, что
сервис профилей может создать проблемы для сервиса продаж. Это явный негатив
ный побочный эффект отсутствия изоляции, присущей распределенным моноли
там. Сервис профилей может по-разному влиять на сервис продаж.
♦
Сервис профилей использует больше ресурсов процессора, чем ожидалось,
и средняя нагрузка на процессор базы данных высока.
♦ Сервис профилей начинает вставлять огромный объем ненужных данных из-за
ошибки.
♦
Команда сервиса профилей случайно удалила индекс таблицы во время недавне
го изменения базы данных.
♦ Команда сервиса профилей запустила стресс-тест, не связываясь с командой
сервиса продаж.
♦ Команда сервиса профилей запустила новый А/В-тест, который привел к увели
чению количества запросов на обслуживание, потребляя больше общих ре
сурсов.
♦
Прилетел «черный лебедь» в виде мероприятия типа «черная пятница» или «киберпонедельник», и все приложение завалено новыми заказами.
Это небольшое взаимодействие между сервисами, созданное за счет совместного
использования таблицы базы данных, усложнило поиск и отладку неисправностей,
поскольку теперь проблема распределена. Теперь представьте себе это в масштабе,
когда сотни сервисов имеют уникальные комбинаторные побочные эффекты. Воз
можно, в прошлом у команды сервиса профилей были проблемы с производитель
ностью, и команда сервиса продаж сразу же указывает на них и делает неверный
вывод. Внезапно между командами возникает напряженность. Теперь у вас возни
кают трудности с рассуждениями и проблемы с персоналом.
Исправление ошибки в этом случае может привести к еще большей сложности и
техническим трудозатратам. Представьте, что замедление продаж на самом деле
было вызвано некачественным отображением в объектах
Hibemate/JPA,
и анало
гичным образом команда сервиса профилей проводит расследование и сообщает
о такой же медлительности. Сервисы профилей и продаж используют общую базу
данных, но не кодовую базу. Для обеих команд не составит большого труда создать
общую библиотеку, перенести туда общий код и исправить его в одном месте.
Ознакомьтесь с нашим комментарием о совместно используемых внутренних биб
лиотеках ранее в этой главе; проблема начинается именно с благих намерений.
Новые функции имеют тот же эффект: представьте, что команда сервиса профиля
решает внедрить функцию ведения журнала аудита с использованием
JPA,
сохра
няя журналы в новой таблице в общей базе данных. Сотрудникам команды сервиса
продаж нравится эта функция, и они хотят ее использовать (рис.
3 .13).
■
140
Глава 3
Сервис профилей
Сервис продаж
Аудит
Общая БД
Рис.
3.13.
Функции в распределенных монолитах
Поскольку функция ведения журнала аудита обеспечивает постоянство, она ис
пользует фреймворки и библиотеки с их собственными зависимостями, и у нас есть
бинарная связь. Как владелец библиотеки команда сервиса профилей решила заме
нить
JPA
на
Spring Data.
Теперь у нас могут возникнуть трения между командами.
♦ Команда сервиса продаж использует старую версию
Spring data,
в то время как
команда сервиса профилей, хочет внедрить более новую. Кто понизит или обно
вит версию? Кто будет заниматься рефакторингом? Скорее всего, это сделает
команда-владелец, что может вызвать недовольство других команд.
♦
Возможно, руководству придется вмешаться и решить, что будет происходить.
♦
Время тратится на чтение кода, анализ, обсуждения, встречи и т. д.
Соблазны распределенного монолита заставили команды внедрить раздутую биб
лиотеку с внутренним разделением. Этот подход нельзя назвать экономичным, по
скольку он использует тяжелые фреймворки и библиотеки, что приводит к усиле
нию координации, усложнению аргументации, снижению гибкости, напряжению
персонала и отвлечению внимания от создания реальной ценности для бизнеса. Для
чего? Пара объектов
Java и универсальный
ОАО для проведения аудита
-
стоит ли
оно того? Ответ отрицательный.
Основная причина заключается в том, что в распределенном монолите команды
часто просто смотрят только на преимущества, такие как:
♦
Кто-то уже создал это, и моей команде придется меньше работать. Давайте ис
пользуем готовое решение.
♦ У нашей команды больше свободного времени, поскольку проект уже завершен.
♦
Моя команда может сосредоточиться на чем-то другом или повысить эффектив
ность бизнеса.
♦
Владельцы библиотек исправят любые обнаруженные ошибки, что позволит нам
выполнять меньше работы по обслуживанию.
♦
Владельцы библиотек добавят функции для нас, если нам что-то понадобится.
Антипаттерны: распределенные монолиты
■
141
Все это может быть правдой. Часто команды не обращают внимания на недостатки,
а ведь они неизбежны. У всего есть свои минусы, и вот некоторые из них:
♦
Бинарная связь; существуют ли сторонние зависимости, которые могут созда
вать проблемы во время миграции?
♦
Что, если владелец библиотеки не хочет вносить необходимые нам изменения,
не уделяет приоритетного внимания нашим функциям или у него никогда не
было возможности исправить ошибки?
♦
Что, если они всегда думают, что ошибки на нашей стороне, и просят нас разобраться?
♦
Какой степени координации управления это потребует?
♦
Деtiствительно ли эта библиотека стабильна и хорошо написана?
♦
Насколько нам нужна эта функция? Не могли бы мы сделать что-нибудь более
простое?
♦
Владельцы библиотек решают, что происходит с библиотекой. Насколько гиб
кой она становится? Каковы компромиссы?
♦
Насколько мы будем зависеть от библиотеки, принадлежащей другой команде?
В чем выгода? Стоит ли оно того?
У команд благие намерения, но распределенные монолиты разрушают благие на
мерения и создают взаимосвязь и негативные последствия. Объединение сотен сер
висов и библиотек приводит к хаосу. Сценарии, которые мы здесь проиллюстриро
вали, являются обычными и происходят в нашей отрасли каждый день; они проис
ходят потому,
что люди
принимают повторное
использование
как должное и
не
рассматривают потенциальные недостатки. Мы подробно обсудим недостатки по
вторного использования в главе
4
«Антипаттерны: внутренние общие библиоте
ки»; а пока помните, что слепое повторное использование никогда не бывает более
рискованным, чем в распределенной, тесно связанной системе, такой как распреде
ленный монолит.
Мины
Мина
(landmine) -
это ловушка, которая может стать проблемой или багом, из-за
которой инженер или группа инженеров потратят дни и часы на отладку и попытки
разобраться (рис.
3.14 ).
Проблема с миной усугубляется тем, что часто кто-то уже
знал о проблеме и ее решении, но не задокументировал его; это превращается
в своего рода технический долг. Мины часто группируются в распределенных мо
нолитах,
возникают снова и
снова,
независимо от того,
управляется ли
монолит
первоначальной командой или новой командой инженеров. Хорошие инженеры со
временем создают в своей голове карту известных им минных полей; великие ин
женеры делятся этой картой с другими.
Как мы можем лучше бороться с минами?
Лучше всего поделиться знаниями: на внутренней вики-странице или в какой
нибудь внутренней технической
презентации.
Еще лучше,
напишите тестовый
пример, который выявит проблему и начнет сбоить, если кто-то активирует мину.
142
■
Глава З
Карта мин
-
Q
Пожалуйста, поделитесь ею!
Мина
Часы/дни отладки,
головные боли
из-за повторяющейся проблемы ...
кто-то знает решение
...
и это повторится снова
Рис.
3.14.
Мины
-
...
повторяющаяся форма проблемы технического долга,
которая продолжает возникать
Как мы уже объясняли, тестирование в распределенных монолитах затруднено, по
скольку система излишне взаимосвязана. Если у вас есть общая библиотека, вы
можете протестировать ее централизованно и изолированно. В других сценариях
создание надлежащего изолированного тестового примера может быть дорого
стоящим, но даже в этом случае мы считаем, что его следует использовать, чтобы
помочь полностью обезвредить мину или, по крайней мере, разместить очевидные
предупреждающие знаки.
Поскольку в разных командах постоянно возникают одни и те же ошибки, может
возникнуть соблазн создать больше общих внутренних библиотек, чтобы решить
проблему раз и навсегда. Библиотеки могут показаться естественным решением, но
мы считаем, что к ним следует подходить с большой осторожностью. Мины
-
это
признак, который может означать, что у вас слишком много программного обеспе
чения и вам требуется некоторая консолидация: меньше сервисов, меньше библио
тек и меньше компонентов программного обеспечения для обслуживания.
Плохая среда
Плохая программная инфраструктура
(bad environment)
негативно воздействует на
распределенные монолиты.
Можно ли запустить распределенный монолит на локальном компьютере? Нет. Он
слишком большой или, возможно, в нем есть база данных и отсутствует автомати
зация баз данных. Таким образом, вам приходится полагаться на общую инфра
структуру, а не на изолированную среду. Если вы работаете в облаке, возможно,
вам
удастся
создать
изолированную
среду,
решив
проблему
автоматизации
баз данных. Но, если вы используете локальные ресурсы компании
(on premises),
с ограниченными возможностями и сотнями разработчиков, у вас возникнут про
блемы.
Антипаттерны: распределенные монолиты
■
143
Среды также должны быть изолированы. Когда разработчиков больше, чем машин,
ситуация становится непредсказуемой. Конечно, есть мнение, что сегодня не стоит
запускать всю инфраструктуру на компьютере, потому что это плохая замена
реальной облачной среде. Конечно, мы можем протестировать и в непроизводст
венных условиях, но вернемся к нашему ключевому тезису: у вас плохая среда.
В вашей организации это не работает. Лучшим решением, скорее всего, будет тес
тирование в производственных условиях
смотрим в главе
7 «Надлежащее
-
отличный подход, который мы рас
тестирование сервисов».
Итак, что же делает среду плохой? Она плохая только потому, что она общая? Нет;
обычно серверы
-
не самый большой недостаток, но база данных
-
да. Если
команда удаляет данные, это затрагивает всех, кто использует базу данных. Если
кто-то изменяет таблицу, это может повлиять на других, выполняющих тесты и ис
следования. И если одному инженеру удается отключить базу данных, это касается
всех.
Плохая среда опасна, потому что приводит к другим очень неприятным и усугуб
ляющим последствиям, таким как:
♦
Плохое дублирование. Чтобы быть более независимыми, избежать миграций и
повысить отказоустойчивость, пользователи начинают дублировать бизнес-код
и код доступа к Бд, чтобы изолировать свой конкретный сервис в плохой среде.
К сожалению, это приводит к серьезным последствиям.
♦
Отсутствие
непрерывной
интеграции.
Программное
обеспечение
должно
быть интегрировано постоянно. Из-за нестабильности, которую создают плохие
среды с распределенными монолитами, люди будут делать все возможное, что
бы обеспечить изоляцию и стабильность, а также заблаговременно и часто вно
сить изменения в код. Это приводит к взрыву веток, и команды сдерживают все,
что связано с функциональными ветками. И вы получаете обратную связь толь
ко в процессе разработки. Это плохо, потому что задерживает циклы обратной
связи и делает весь процесс разработки дорогостоящим и неэффективным.
♦
Пустая трата времени. Поскольку среда непредсказуема и ненадежна, вы те
ряете время, гоняясь за призраками, думая, что это реальные ошибки. На самом
деле это результат отсутствия синхронизации во внутренних общих библиоте
ках, объектах базы данных и недокументированных минах
(landmine ),
которые
вы устраняете только через несколько дней или недель. Это сокращает время
продуктивной работы и подрывает моральный дух инженеров.
Типы распределенных монолитов
В этой главе мы обсуждали влияние распределенных монолитов на серверные сер
висы. К сожалению, существует не только один тип антипаттерна в виде распреде
ленного монолита. Распределенные монолиты могут быть созданы на многих уров
нях и компонентах.
144
■
Глава 3
Серверная часть
Это переплетение сотен микросервисов, библиотек и баз данных, предоставляющих
общий доступ, и множества нестабильных контрактов. Надеемся, что вы уже поня
ли эту закономерность.
BFF
BFF
и интерфейс
может стать распределенным монолитом, что происходит из-за внутренних
общих библиотек на
JavaScript/TypeScript
или из-за того, что команды часто повы
шают сложность за счет временной связи с сервисами.
Давайте рассмотрим пример на рис.
3.15; как вы можете видеть, наш BFF большой
(Single Point of Failure, SPOF). Хотя проблему
3 экземпляра в трех разных зонах доступа. Еди
и действует как единая точка отказа
доступности можно решить, создав
ный
BFF,
естественно, является узким местом для нескольких инженерных групп,
поддерживающих этот монолитный
BFF.
Возможно, команды будут недовольны.
Таким образом, естественное решение состоит в том, чтобы разделить это на не
сколько
BFF,
может быть, по
1 или
BFF (бэкенд для фронтенда) -
более на каждую бизнес-область, верно?
классический монолит
BFF
Контракт
Контракт
Контракт
Сервис профилей
Сервис продаж
Сервис отчетов
БД
БД
Рис.
3.15. BFF
БД
в классическом монолите
В случае с несколькими приложениями мы решили проблему доступности, убрали
SPOF.
Разработчики теперь довольны, им нужно меньше объединять и у них боль
ше гибкости ... за исключением небольшого поля под названием «Внутренние об
щие библиотеки» внутри каждого
Подобно тому как
Maven
BFF (рис. 3.16).
использует pom.xrnl,
NodeJS
имеет зависимости, которые
могут быть указаны в файле package. j son. Представьте себе, что у нас есть несколь
ко пакетов
NodeJS,
которые имеют
Express Framework
в качестве зависимости.
Антипаттерны: распределенные монолиты
Даже при наличии трех разных кодовых баз для
BFF
■
145
и достаточной досrупности
у нас есть бинарная связь. Мы больше не можем обновлять что-либо изолированно.
Выпустить новую версию внутренней общей библиотеки легко, но перенести все
ваши
100+ BFF
может оказаться непросто. Поздравляем: теперь у вас есть распре
деленный монолит на слое
BFF.
BFF (бэкенд для фронтенда) -
распределенный монолит
BFF для профилей
BFF для продаж
BFF для отчетов
Внутренние
Внутренние
Внутренние
общие библиотеки
общие библиотеки
общие библиотеки
'
'~
(
Контракт
Контракт
Контракт
Сервис профилей
Сервис продаж
Сервис отчетов
t
L
БД
Рис.
3.16. BFF
~
J
БД
[
t
БД
~
J
в распределенном монолите
К сожалению, тот же самый антипаттерн может быть применен и к интерфейсу,
даже если ваша команда использует архитекrуру в стиле микрофронтендов. Во
внешнем интерфейсе используется
React
от
Facebook, с несколькими микрофрон
React? Допустим, вы исполь
тендами и отдельными базами кода. Что вы делаете с
зуете одну и
ry
же версию
React
во всех интерфейсах/страницах/компонентах. Если
одной из страниц потребуется изменить версию, вам придется изменить все стра
ницы. Теперь давайте перейдем к противоположному компромиссу: вы разрешаете
разные версии
React
для каждой страницы. Что теперь происходит с внутренними
общими библиотеками? У вас должно быть несколько версий библиотеки для каж
дой версии
сию
React,
React?
Кроме того, каждая страница загружает свою собственную вер
что негативно сказывается на времени загрузки первой страницы, т. е.
пользователь получает негативный опыт. У нас есть внутренние общие библиотеки,
и есть риск получить распределенный монолит.
Бессерверная архитектура
По сравнению с микросервисами архитекrура без сервера, функционирующая как
услуга
(Functions as
а
Service, FaaS),
имеет тенденцию к использованию еще более
компактных сервисов и компонентов (рис.
3 .18).
Вспомните концепцию централи
зации по сравнению с распределением, которую мы представили в главе
1 « Что
не
■
146
Глава З
так с монолитами». Бессерверность
(serverless) -
это самый экстремальный вари
ант распределения, где единицей развертывания могут быть отдельные функции
(рис.
3.17.)
Микросервисы
1
Бессерверная архитектура
Классический монолит
Распределение
Централизация
Рис.
3.17.
Спектр от монолитов до бессерверной архитектуры
Бессерверный подход может быть хорошим решением, если учесть следующие его
характеристики:
♦
среда выполнения на абстрактном языке (но вам все равно нужно работать
с библиотеками);
♦ управляемый событиями;
♦
по требованию;
♦
оплата по мере поступления;
♦ эфемерный.
Бессерверная архитектура
(FaaS)
Контракт
API GAtew"-y
K;,,.er;~
rз
!
Триггер + Ввод данных
ra.r
fNf
CfJ/ eve"fr
IoT
Функция отчета
Контракт
о продажах
Вывод данных
D
Внутренние
общие библиотеки
Реализация
Внутренние
общие
библиотеки
~ База
L_Jданных
БДпродаж
Рис.
3.18.
Бессерверная архитектура
(FaaS)
Да, большинство из этих проблем являются общими для микросервисов и бессер
верных систем, но из-за возможности экстремального распространения вам нужно
подходить к этому стилю архитектуры с осторожностью, т. к. легче потерять кон
троль и создать распределенный монолит, попав в те же ловушки:
Антипаттерны: распределенные монолиты
♦
♦
■
147
отсутствие изоляции базы данных;
отсутствие экономичных внутренних общих библиотек, т. е. наличие бинарной
связи;
♦
отсутствие стабильных контрактов;
♦
временная связность.
Чтобы проиллюстрировать это, на рис.
3 .19
показан пример бессерверной архитек
туры, в которой функции выполняются с использованием великолепной, эфемер
ной, абстрактной языковой среды выполнения. Но, по сути, у нас есть междомен
ные функции продаж и отчетности, использующие одну и ту же общую базу дан
ных, что снижает риск создания распределенного монолита. Для удобства все
функции используют одни и те же внутренние общие библиотеки. Представьте, что
некоторые библиотеки имеют общую бизнес-логику и общий сохраняемый код
через
Hibernate
и
Spring Boot;
это бинарная связь.
Функция продажи
Функция отчета
компьютеров
о продажах
Внутренние общие
Внутренние общие
библиотеки
библиотеки
Функция
БДпродаж
Рис.
3.19.
Бессерверная архитектура
(FaaS) -
распределенный монолит
Сложность бессерверных архитектур
При использовании бессерверного интерфейса потребность вашего приложения
в оркестровке никуда не денется. Как мы объясняли в главе
2
«Антипаттерны:
отсутствие изоляции», сложность должна где-то присутствовать, и часто в конеч
ном итоге вы переносите все за пределы сервиса
-
либо вверх, либо вниз. Пред
ставьте, что у вас есть стандартный стек сервисов, и вы хотите преобразовать его
в бессерверные функции (рис.
3.20).
Сервис отвечал за обеспечение последователь
ного выполнения трех методов. Можно усложнить задачу и поручить уровню
BFF
организовать вызов трех отдельных функций; или, как представлено в нижней час
ти рисунка, организовать асинхронное выполнение этих трех функций с помощью
шины сообщений, общего состояния в базе данных (не рекомендуется!) или с ис
пользованием общей функции в качестве координатора.
Ключевой вопрос такого сценария: кто управляет выполнением этих функций? Нам
нужно где-то повысить сложность, и, скорее всего, это будет еще одна функция или
148
■
Глава З
совершенно другой уровень. Экстремальный подход бессерверной архитектуры
к распределению заключается в том, чтобы переместить команды из сервисного
подразделения в функциональное, но не останавливаться на достигнутом. А WS
Step Functions
предлагает вам комплексный уровень оркестрации, который включа
ет в себя базовые конструкции, такие как условия
фильтры
(switche),
(filter)
и средства конвертации
(it), циклы (for), переключатели
(mappers). Каков же результат?
Теперь вы тесно связаны с облаком и отказались от правильного языка программи
рования. По крайней мере,
BFF был настоящим кодом. Мы виде
ли эту ошибку в прошлом, она называлась BPEL9 ; сегодня она называется А WS
Step Functions 10 .
NodeJS
на уровне
UI
UI
BFF
BFF
Сложность
Контракт
повышается
Сервис
профилей
.._...,_...,.
Б
Сложность
понижается
шина
Стек сервисов
Рис.
3.20.
сообщений
Компромиссы в отношении сложности при использовании бессерверной архитектуры
Когда ваша архитектура требует наличия состояния для нескольких функций, бес
серверное управление вынуждает вас иметь внешнее состояние; таким образом, вы
можете легко использовать общие базы данных. С ростом количества отдельных
«сервисов» или функций, которые необходимо объединить в цепочки, бессерверное
управление может легко привести к временной связности. И, конечно, бессервер
ные системы опять же могут страдать от бинарной связи, поскольку вы по
прежнему используете все свои внутренние общие библиотеки с бессерверными
системами. Да, мы рассматриваем совершенно другую технологическую архитек
туру, сравнивая бессерверную с А WS ЕС2 или даже с контейнерами, такими как
Docker.
Однако, несмотря на различия, мы сталкиваемся с теми же проблемами,
Язык выполнения бизнес-процессов (Business Process Execution Language, BPEL):
https://en. wikipedia.org/wiki/Вusiness_ Process_ Execution_ Language
9
10
А WS Step Functions https://aws.amazon.com/step-functions/ и Amazon States Language
https://docs.aws.amazon.com/step-functionsЛatest/dg/concepts-amazon-states-language.html
Антипаттерны: распределенные монолиты
■
149
недостатками и болевыми точками. Кроме того, у каждой из этих архитектур есть
свои уникальные особенности.
Бессерверность
-
это зло? Нет. Бессерверность
-
это здорово. Но бессерверные
функции не панацея от бед, они не решат всех ваших проблем, и бессерверность
отнюдь не является защитой от распределенных монолитов. Распределенные моно
литы могут быть созданы на любом языке и на любой платформе распределенных
технологий. Распределенные монолиты
это антипаттерн и проблема дизай
-
на/архитектуры, а не технологии. Тщательно выбирайте варианты использования
(use cases),
в которых вы будете применять бессерверный интерфейс, и избегайте
рассматривать
его
как универсальное
решение
для
всех
ваших
сервисных
архи
тектур.
Обратный эффект: снова хуже!
Нет ничего настолько плохого, что не могло бы стать еще хуже. Люди пытаются
«починить» распределенный монолит, используя неправильные решения, и угадай
те, что происходит? Проблема становится глобальнее. И что еще хуже, бездействие
еще больше усугубляет проблему!
Инженеры и менеджеры часто хотят что-то сделать и улучшить. У команд могут
время от времени появляться благоприятные возможности для улучшения, напри
мер:
♦
Нам нужно создать новую возможность/функцию.
♦
Нам нужно создать новую таблицу.
♦
Используется технология, срок службы которой подходит к концу
EOL),
(End of Life,
и нам необходимо внедрить новую.
В разумных пределах, после тщательного анализа и обдумывания, эта возможность
может оказаться полезной; команды принесут пользу бизнесу и в конечном итоге
разработают более качественное программное обеспечение. Однако давайте под
робнее остановимся на том, как такая возможность может привести к обратному
эффекту и создать больше проблем, чем решений.
Архитекторы как контролеры не масштабируются
Один из способов решения этой проблемы
-
привлечь архитекторов решений/про
граммного обеспечения в качестве ответственных за качество и дизайн. Этот метод
может работать в небольшой/средней компании. В крупной организации невоз
можно заранее проверить и устранить все проблемы. Контроль за работой отдель
ных архитекторов или команд архитекторов не масштабируется и создает напря
женность в отношениях с инженерами.
Проведение регулярных обзоров архитектуры/дизайна
-
хорошая и полезная прак
тика. Обзорные сессии могут помочь выявить недостатки дизайна до того, как они
станут слишком серьезными, чтобы их можно было исправить.
150
■
Глава 3
Мы бы сказали, что самый большой пробел связан с образованием. Компании
предполагают, что команды знают хороший дизайн, передовые практики и как соз
давать отличные архитектуры программного обеспечения. Гораздо важнее, чтобы
ваши инженеры были обучены правильным принципам. Такой подход распреде
ленный и масштабируется естественным образом.
Стабильные контракты, небольшое количество экономичных внутренних общих
библиотек и изолированных баз данных
это всегда отличное начало и имеет
-
много преимуществ, о которых мы расскажем в этой главе.
Новые возможности/функции
Давайте поместим новую функциональность в новый сервис. Мы получаем новую
кодовую базу, новый модуль развертывания и, что более важно, новое начало, из
бавленное от технических проблем. Проблема в том, что возможности/функции
может потребоваться взаимодействовать с остальным кодом. Скорее всего, вам
удастся изолировать код нового сервиса, но можете ли вы изолировать базу дан
ных? Допустим, вам нужны данные из существующей таблицы: что вы делаете?
Просто получите доступ к таблице из старой базы данных. Если ответ положитель
ный, что ж, теперь у нас есть зачатки распределенного монолита (рис.
3.21 ).
Изолированная
Профили
Продажи
Новый сервис
Отчеты
. . . . ..... кодовая база
Этого достаточно? ... НЕТ!
БД
Рис.
3.21.
Обратный эффект
-
новая возможность/функция
В качестве альтернативы представьте, что вам удалось еще больше изолировать
новую функциональность. Вам не нужны старые таблицы, и новая возможность
может быть реализована полностью изолированно. Пока все хорошо! Но у вас нет
времени писать все с нуля, верно? У вас есть бизнес-ценность, которую нужно реа
лизовать, и ОКR, которые нужно выполнить. Таким образом, вы повторно исполь
зуете как можно больше кода, применяя внутренние общие библиотеки. Является
ли эта библиотека экономичной, с небольшим количеством зависимостей и без
бизнес-логики? Если нет, поздравляю, вы снова идете по пути к распределенному
монолиту (рис.
3.22).
Антипаттерны: распределенные монолиты
Профили
Продажи
Отчеты
■
151
Изолированная кодовая база
Новый сервис
Изолированная БД
Но ...
Внутренние общие библиотеки
Общие внутренн ие библиотеки
Внутренние
общие библиотеки
со множеством зависимостей
и бизнес-логикой
БД
Рис.
3.22.
Обратный эффект
-
новая возможность/функция
-
внутренние общие библиотеки
Теперь представьте, что на основе вашего нового сервиса работает другой сервис.
Независимо от причины новая функция перестает работать, потому что бизнес от
казывается от нее. Теперь у вас есть «фантомный» сервис, который напрямую не
нужен бизнесу, но все же необходим в качестве косвенной зависимости от чего-то
другого. Где владелец
(ownership)?
С благими намерениями и реальными возможностями мы можем легко ухудшить
ситуацию. А при наличии нескольких команд легко ухудшить ситуацию масштабно
и одновременно.
Новая таблица
Внедрение новой таблицы сопряжено с тем же риском, даже если речь не идет
о новой функции; это может расширить существующую функциональность. Та же
возможность может привести к ловушкам, описанным ранее.
Устаревшая технология
Время от времени технологии устаревают. Это может произойти из-за отсутствия
поддержки, банкротства компании или утраты актуальности. В других случаях
просто возникает так много проблем, что ваша компания решает отказаться от тех
нологии; или, возможно, это просто слишком дорого. Теперь у нас есть возмож
ность измениться и внедрить новую захватывающую технологию. Как это может
привести к обратному эффекту? Опять же, внутренние общие библиотеки.
Ранее в классическом монолите повсеместно использовался один и тот же фрейм
ворк доступа к данным,
TopLink.
нологии и решила перейти на
Hibernate
Допустим, ваша команда потеряла интерес к тех
Hibemate.
Однако для упрощения миграции на
была создана общая внутренняя библиотека доступа к данным. Миграция
152
■
Глава 3
Общая
Профили
Продажи
Профили
Отчеты
Продажи
Отчеты
библиотека
достуnа к БД
использовала
• • , Oracle Topllnk,
а теперь
,
,,,"'--БД
Рис.
3.23.
Обратный эффект
-
--
БД
---
мы перешли
на HIЬemate
устаревшая технология
в целом стала проще, но, как можно видеть из рис.
3.23,
вы создали распределен
ный монолит.
Предотвращение дальнейших повреждений
Эта глава была полна болезненных и сложных сценариев реального мира с распре
деленными монолитами. Вы можете задаться вопросом, как можно эффективно
предотвратить дальнейшие повреждения?
К сожалению, распределенные монолиты
-
это реальность, и мы должны научить
ся эффективно с ними обращаться. В некоторых случаях лучше отказаться от этой
системы. В больших масштабах вы не сможете просто переписать все свое про
граммное обеспечение за раз; это непрактично и нецелесообразно.
Подумайте о возвращении к монолиту
Распределенные монолиты гораздо сложнее исправить, чем классические. В случае
с монолитами, по крайней мере, кодовая база находится в одном месте, и вы може
те использовать свою идею для удаления кода и увидеть результат за считанные
секунды. Когда у вас распределенный монолит, понять влияние изменений и даже
применить рефакторинг гораздо сложнее, поскольку у вас нет всего кода в
IDE
и,
конечно же, вы не можете запускать сотни сервисов.
Мы подробно и в красках рассмотрим эту тему в следующих главах: глава
ка», глава
6
«Принципы надлежащего предоставления сервисов» и глава
5 «Оцен
7 «Над
лежащее тестирование сервисов», но пока мы дадим вам несколько советов.
Советы по команде и процессу
♦
Улучшите свое понимание. Изучите дизайн вашего программного обеспе
чения, проведите исследования, отладку и тестирование, чтобы улучшить свои
знания.
Антипаттерны: распределенные монолиты
♦ Прочитайте код. Прочитайте его
100
■
153
раз, проанализируйте зависимости и хо
рошенько подумайте.
♦
Создайте документацию. На страницах
wiki
или даже запишите видеоролики,
объясняющие ваши выводы. Создайте раздел часто задаваемых вопросов с об
щими проблемами и решениями.
♦ Делитесь. У становите распорядок дня внутри вашей команды и за ее пределами,
используя такие методы, как еженедельные встречи, обеды и тренинги, внут
ренние инженерные совещания, а также создавайте сообщества практиков, гиль
дии и отделения.
♦
Общайтесь. Поговорите с другими командами и выясните, где и как лучше все
го решить вашу проблему. Создайте канал
Slack для
публикации своих выводов
и документации. Не страдайте в одиночку, другие команды могут рассказать
о прошлых минах
(landmine) и
о том, как решить вашу проблему.
♦ Привлекайте своих подрядчиков. Обучайте их, наставляйте и инвестируйте
в них, потому что, в конце концов, они также создают функции и исправляют
ошибки.
♦ Тщательно планируйте. Прежде чем приступить к работе, подумайте, сколько
времени, энергии и денег ваша команда действительно может вложить. Не мог
ли бы вы потерять популярность в течение нескольких спринтов и создать не
нужные ресурсы?
♦ Быстрый выигрыш. Подумайте о небольших улучшениях, прежде чем вне
дрять новые библиотеки и сервисы.
♦ Наставничество, лидерство и расширение орав и возможностей. Для техни
ческих менеджеров и директоров важно расширить возможности команд и раз
веять
страх, дать
инженерам
понять,
что
они
могут и
должны улучшать код
и дизайн.
Советы по технологиям и архитектуре
программного обеспечения
♦ Всегда применяйте научное мышление. Четкая логика и рассуждения
-
един
ственный способ решить сложные проблемы, а распределенные монолиты стал
киваются с самыми сложными и трудноразрешимыми проблемами.
♦
Осваивайте свои инструменты. Ошибки могут возникать из-за того, что люди
не знают, как пользоваться имеющимися у них инструментами. Например, у вас
медленно получается создавать сопоставление
Hibernate/JPA?
Пройдите онлайн
курс по конвертации или найдите бесплатного эксперта для обучения вашей
команды. Инвестируйте в обучение.
♦
Будьте подозрительны. Действительно ли нам нужен этот фрагмент кода, нуж
на ли эта функция? Не принимайте все как должное. Могли бы мы упростить
это? Есть ли способ уменьшить сложность?
♦ Будьте осторожны. Если, в конце концов, вы не уверены, оставьте все как есть.
154
■
Глава 3
♦ Настоящая изоляция. Сначала подумайте о том, чтобы вернуться к своей тех
нологии и повторно объединить ее в единую архитектуру. По возможности из
бегайте зависимостей между бизнес-областями.
♦ Учитывайте обратные эффекты. Всегда учитывайте возможность того, что
ваши новые архитектуры и проекты могут привести к негативным последстви
ям, и помните о мерах предосторожности, описанных в этой главе.
♦
Создавайте экономичные библиотеки. Избегайте больших внутренних общих
библиотек и создавайте новые внутренние общие библиотеки с осторожностью.
♦ Не создавайте дополнительные сервисы. Рассмотрите возможность добавле
ния кода к существующим сервисам. По возможности избегайте зависимостей
между бизнес-областями.
♦
Стандартов не существует. Инженеры часто называют технический долг и ан
типаттерны «стандартом» проекта. Не думайте, что то, что существует, является
правильным; оспаривайте существующие идеи и решения.
♦
Пишите больше тестов. Тесты придают нам уверенности и позволяют прово
дить рефакторинг, но они также являются отличной формой документации.
♦ РОС. Проверяйте свои теории и эксперименты с технологиями с помощью про
верки концепции
(Proof of Concept, РОС),
а не в реальных сервисах.
Что нужно запомнить
Поздравляем, мы подошли к концу главы
3!
Давайте подытожим полученные знания.
♦ Суть антипаттерна распределенного монолита заключается в отсутствии изоля
ции.
♦ Распределенные монолиты
-
это не технологическая проблема, а проблема
проектирования программного обеспечения и архитектуры и в конечном счете
антипаттерн.
♦ Распределенные монолиты могут быть созданы на любом языке и с использова
нием любой технологии.
♦
♦
Три ключевые черты распределенных монолитов:
•
Отсутствие изоляции;
•
Отсутствие независимости;
•
Распределение сложности.
К числу основных причин появления распределенных монолитов относятся:
•
совместное использование баз данных в разных сервисах. Не используйте
базы данных совместно;
•
общие библиотеки доступа к данным;
•
общие библиотеки контрактов. Делайте контракты максимально простыми.
Антипаттерны: распределенные монолиты
■
155
♦ В конечном итоге легко создать распределенный монолит.
♦ Соблюдение правильных принципов, таких как стабильные контракты, изолиро
ванность баз данных и наличие небольшого количества экономичных внутрен
них общих библиотек, все еще может позволить вам многого добиться.
♦ Бинарная связь является серьезной проблемой для монолитов.
•
Ненужное повторное использование может привести к бинарной связи. Не
принимайте повторное использование как должное, оно может привести
к ограничениям и потенциальным проблемам, таким как лишняя связность,
может нарушить изоляцию, уничтожить свойство независимости, которое
требуется в соответствующих сервисах и микросервисах. Всегда нужно ду
мать о компромиссах.
•
Тщательно выбирайте свои библиотеки. Во всех случаях будьте осторожны
с внутренними общими библиотеками.
♦
Временная связность может привести к распределенным монолитам.
•
Чтобы справиться с временной связностью, рассмотрите возможность повы
шения сложности до уровня оркестровки или
BFF
и используйте облако для
обеспечения гибкости.
•
Лучшим способом избежать временной связности является переход на асин
хронную обработку с использованием архитектуры, управляемой событиями,
например с использованием
Kafka.
♦ Е2Е и интеграционные тесты не могут быть единственным способом тестирова
ния распределенных монолитов. Внедрите другие формы тестирования, которые
могут быть дешевле, но выполняются быстрее и при этом покрывают функцио
нальность монолита.
♦
В распределенных монолитах очень часто возникают проблемы с управлением,
такие как необходимость большей координации, большего количества резервов
в оценках, большего количества компромиссов, большего количества неожидан
ностей и меньшего времени для создания ценности для бизнеса.
♦ Рассуждать о проблемах с распределенными монолитами и их побочных эффек
тах очень нелегко, учитывая их сложность.
♦ Антинаучное мышление может оказать реальное воздействие на распределенные
системы. Непонимание проблемы, поиск коротких и обходных путей под давле
нием бизнеса со временем приведут к снижению производительности. Всегда
старайтесь решить реальную проблему.
♦ Размывание программного обеспечения и команды
•
-
это реальные явления.
Резкое увеличение числа сервисов в распределенных монолитах может при
вести к размыванию команды.
•
Поддержание программного обеспечения очень сложно из-за размывания
команды. Необходимы владельцы.
156
•
■
Глава 3
Общие библиотеки и сервисы, расположенные в глубине стека, чаще всего
подвергаются размыванию команды, но это может произойти как с ядром/плат
формой, так и с бизнес-сервисами.
•
Владение программным обеспечением
-
один из ключей к решению про
блем, связанных с размыванием команды.
•
Критерии владения включают близость к бизнес-области, частоту коммитов,
доступные возможности, сочувствие и заботу, а также близость к техноло
гиям.
♦
Новые функции и ошибки могут стать источником разногласий между команда
ми и усугубить проблемы вашего распределенного монолита.
♦
Мины
-
это сложные, постоянные и неустранимые проблемы, с которыми
можно столкнуться в распределенных монолитах. Определите и поделитесь сво
им пониманием ваших мин с другими пользователями.
♦
Плохая среда усугубляет проблему с распределенными монолитами.
♦
Типы распределенных монолитов не ограничиваются только серверным слоем,
и их можно создавать в
♦
BFF,
интерфейсах и бессерверных стеках.
Архитекторы в качестве контролеров могут работать в небольших компаниях
среднего размера, но такой подход не масштабируется.
♦
При попытке исправить распределенные монолиты возникают сбои. Даже если
у вас благие намерения, будьте осторожны. Следите за возможными сбоями при
создании новых возможностей, функций, таблиц и замене устаревших техно
логий.
♦
Чтобы предотвратить дальнейшие повреждения:
•
убедитесь, что ваша команда понимает, документирует и делится своими
знаниями о распределенном монолите;
•
предоставьте своей команде возможность вносить ключевые исправления и
добиваться ключевых результатов. Тщательно планируйте и всегда приме
няйте научное мышление;
•
если вы не уверены, всегда можно оставаться на прежнем уровне, не созда
вать дополнительные сервисы или даже выборочно создавать классические
или (в идеале) модульные монолиты;
•
всегда стремитесь по-настоящему изолировать технологии.
ГЛАВА
4
Антипаттерны:
внутренние общие библиотеки
Не позволяйте своему счастью зависеть от того, что вы можете потерять.
К С. Льюис
В современной разработке программного обеспечения библиотеки используются
повсеместно. Причем некоторые из проблем, с которыми мы сталкиваемся, пол
ностью связаны с библиотеками.
В этой главе мы рассмотрим библиотеки со всех сторон: хорошие, плохие и урод
ливые. Мы подробно объясним и раскрасим антипаттерны в библиотеках и расска
жем, как избежать этих ошибок в вашем программном обеспечении. Вы узнаете,
когда следует создавать библиотеки, а когда нет, а также об альтернативных под
ходах, таких как сервисы и
sidecar.
И наконец, при полном понимании проблем мы
дадим вам ключевые советы по правильному оформлению библиотек, ~побы вы
могли устранить недостатки, следуя правильным прmщипам.
Структура главы
В этой главе мы рассмотрим следующие темы.
♦ Что такое библиотека?
♦ Типы библиотек.
•
Библиотеки и фреймворки.
♦ Проблемы с библиотеками.
•
Постоянные миграции.
•
Оrсутствие стабильных контрактов.
•
Бинарная связь
•
Стимулы для создания библиотек.
•
Антипаттерн: фреймворк.
/ сломанная
♦ В защиту библиотек.
•
Производительность.
•
Путь к надежности.
изоляция.
■
158
Глава 4
•
Языковые идиомы.
•
Централизация кода.
•
Перестаньте заново изобретать велосипед.
♦ Подводные камни
-
неправильные методы, которых следует избегать.
•
Внутренние общие библиотеки.
•
Эффект короткого одеяла.
•
Большие фреймворки.
•
Раздутые библиотеки.
•
Очень популярные библиотеки.
•
Библиотеки доставки конфигурации.
•
Размывание команды в общих библиотеках.
0
Драйверы сервисов.
•
Утилиты.
•
Обёртки.
•
0
Расширение.
0
Новые абстракции.
Отсутствие управления.
♦ Улучшенные возможности.
•
Когда нам следует создавать библиотеку?
•
Когда нам не следует создавать библиотеку?
•
Использование сервисов.
•
•
0
Отсутствие бинарной связи.
0
Значительно улучшенная гибкость.
0
Простая миграция или отсутствие миграции.
0
Критический уровень надежности.
0
В некоторых случаях производительность.
Паттерн
Sidecar.
0
Современный
0
Sidecar и
0
Sidecar и Kubemetes.
0
Как можно построить
0
Сетки сервисов.
Sidecar.
прокси.
Sidecar? Типы Sidecar.
Простые альтернативы.
0
Использовать существующие пакеты
0
Сделать это самостоятельно.
SDK
и библиотеки.
Антипаттерны: внутренние общие библиотеки
0
Скопировать и вставить код.
0
Внести свой вклад в работу с открытым исходным кодом.
■
159
♦ Правильная конструкция библиотеки.
•
•
•
Дублирование против повторного использования.
0
Плохое дублирование: бизнес-код.
0
Плохое дублирование: выполнение.
0
Хорошее дублирование: миграция.
0
Хорошее дублирование: конфигурация и код установки.
0
Повторное использование: палка о двух концах.
Грамотное управление зависимостями.
0
Сливки зависимостей.
0
Избегайте использования родительского РОМ.
0
Объявляйте зависимости явно.
Экономичные библиотеки.
♦ Спектр возможностей.
♦
Что нужно запомнить.
Что такое библиотека?
Согласно Википедии библиотека
(library) -
это совокупность ресурсов, исполь
зуемых компьютерными программами. Чаще всего библиотеки содержат общий
код, но они могут включать документацию, данные конфигурации, изображения
или любой другой общий ресурс 1 . Идея программных библиотек не нова; она вос
ходит к самым первым компьютерам, о которых говорил Чарльз Бэббидж2 в своей
статье
1888
года об аналитической машине. Библиотеки повышают производитель
ность и являются наиболее распространенной формой повторного использования.
Библиотеки кода могут быть связаны статически: на них можно ссылаться во время
компиляции, или динамически: они будут загружаться во время выполнения.
Библиотека может представлять собой двоичный файл, предоставляющий
пользователей,
доступных
-
API
в
Java
это часто
JAR.
API
для
Библиотеки могут иметь множество обще
и множество внутренних классов, методов и пакетов (рис.
4.1).
Надлежащие библиотеки должны иметь публичный явный контракт и соответст
вующую реализацию, как и сервисы. Разные языки программирования имеют мно
жество разных способов использования библиотек. И не все библиотеки являются
двоичными. В
JavaScript
или РНР вы можете напрямую обмениваться кодом и дру
гими ресурсами, без использования двоичного файла.
1 Определение
2
компьютерной библиотеки в Википедии: https://en.wikipedia.org/wiki/Library_(computing).
О Чарльзе Бэббидже: https://en.wikipedia.org/wiki/Charles_Babbage.
160
■
Глава 4
Что такс~ библиотека?
Контракт
Реализация
...
Метод
простой библиотеки
зависимость
...
Граф зависимостей
зависимость
Рис.
4.1.
Что такое библиотека
Типы библиотек
Для нашей '- ' lиги давайте разделим библиотеки на два класса в зависимости от их
происхождевия: внутренние
(internal) и
внешние
(external),
как показано на рис .
4.2.
Практически все компании создают внутренние библиотеки. Некоторые из них де
лают это очень хорошо или, по крайней мере, делают это хорошо какое-то время,
пока их поддержка не сойдет на нет. Что касается внешних или сторонних биб
лиотек, то они имеют множество источников, таких как коммерческие библиотеки
Intel DPC++3, оптимизированные для высокопроизводительных вычислений, или
множество библиотек с открытым исходным кодом в Интернете.
В компаниях внутренние библиотеки не всегда называются библиотеками; иногда
они называются другими именами, такими как:
например, ядро платформы
♦
Core,
♦
Base (базовый)
♦
Common
♦
Shared (общий), такой
♦
Framework (фреймворк).
♦
Standards
или
(Core Platform);
Bootstrap (загрузочный);
(совместный), например
как
Common Stock или Common Libraries;
Shared Layer или Shared Library;
(стандарт) компании в области разработки программного обеспече
ния.
3
Оптимизированные библиотеки lntel С++:
bttps://www.intel.com/content/www/us/en/developer/tools/oneapi/dpclibrary.Ыml.
Антипаттерны: внутренние общие библиотеки
■
161
Типы библиотек
Внешние
Внутренние
<;:fri1,.g Fr()..,..,ework
<;:fri1,.g Bor,t
I"terмl Utik ...
r"ter"AI Perrir:te"ce...
r,,,ter'1AI Vм·,l().f;r,,,r.. .
r,,,ter,,,AI Mi,ldlewAre .. .
I,,,ter,,,AI <;:ecurify ...
r,,,ter,,,AI UI k.it...
Рис.
Н;Ьеrм,..t.е
GuAvA
Netty
ReAct
4.2.
Типы библиотек
Внутренние библиотеки часто рассматриваются в компаниях как основа, обеспечи
вающая эффективную и масштабируемую разработку программного обеспечения.
Это исключительно полезные вещи, поскольку они способствуют повторному ис
пользованию, стандартизации
(standardization)
и созданию единого шаблона для
сотен команд. Все инженеры любят повторное использование! Инженеры и менед
жеры часто приходят в ужас от того, что обнаруживают одну и ту же ошибку
в двух или трех местах, а иногда и в сотнях или тысячах сервисов и не имеют про
стого способа ее исправить. Инженеры, стремящиеся стать ведущими инженерами
или архитекторами, часто видят в библиотеках путь для дальнейшего роста в своей
технической карьере, повышения своего авторитета и привлечения внимания со
стороны разработчиков платформ, где их карьера может быть чисто технической, а
не подчиняться бизнес-требованиям.
Библиотеки и фреймворки
Основное различие между библиотеками и фреймворками заключается в их отно
сительном размере и форме. Часто фреймворки делают больше и они крупнее, что
означает больше строк кода, больше зависимостей и больше возможностей для ин
женеров. Библиотеки часто меньше по размеру, более понятны, их проще исполь
зовать изолированно, и они не навязывают определенного образа мышления, на
пример какие объекты вы создаете и как вы их создаете. Как следует из названия,
фреймворки
(framework)
предназначены для того, чтобы «обрамлять» то, как вы
«работаете»; влиять на то, как вы мыслите, и подталкивать вас в определенном на
правлении.
Для данной книги не имеет значения, библиотека это или фреймворк. Все пробле
мы, связанные с библиотеками, описанные в этой главе и предыдущих, такие как
бинарная связь и/или распределенные монолиты, применимы и к тем и к другим.
Проблемы одни и те же. Для удобства чтения вы просто увидите, что мы называем
все это библиотеками или, более конкретно, внутренними общими библиотеками
(intemal shared libraries),
когда речь идет об основном классе библиотечных про
блем, обсуждаемых в текущей главе.
162
■
Глава 4
Проблемы с библиотеками
Библиотеки, и особенно внутренние общие библиотеки, могут быть полезны и по
могать компаниям работать продуктивно. Однако ничто не бывает бесплатным,
и библиотеки имеют свои недостатки. Важно знать о проблемах, чтобы их из
бежать.
Некоторые из вопросов, представленных в этом разделе, могут относиться как
к внешним, так и к внутренним библиотекам. Используйте этот раздел в качестве
критериев для оценки библиотек OSS4, когда ваша команда решает, какую библио
теку добавить в ваши проекты.
Постоянные миграции
Библиотеки требуют постоянной миграции. Возможно, произошла ошибка, и вам
срочно требуется ее исправить, или библиотека выпустила новую основную версию
с новыми функциями, которые принесут пользу вашему бизнесу или повысят про
изводительность.
Конечно, библиотеки также имеют уязвимости и нуждаются в исправлении. Ин
формационная безопасность важна, и поддерживать ее в актуальном состоянии мо
жет быть очень сложно. Например, в статье АСМ: «О возможности обнаружения
уязвимостей npm в Node.js»5, авторы проанализировали 6546 Node.js приложений и
обнаружили, что
Уязвимости
99,42 % приложений зависят от нераскрытых уязвимостей пакета.
(Vulnerabilities) - это веская причина для постоянного обновления
ваших библиотек.
Отсутствие стабильных контрактов
В
Java
все библиотеки представлены в описании пути к классам. Инженеры могут
легко получить к ним доступ через свою среду
IDE.
Однако инженеры могут также
легко допускать ошибки:
♦
Использовать внутренние реализации. Напрямую использовать внутренние
объекты и функции, которые, по замыслу авторов библиотеки, не предназначе
ны для совместного использования.
♦
Реализовывать
интерфейсы.
Реализовывать
интерфейсы
и/или
расширять
классы, расширение которых запрещено.
В
Java
есть несколько решений, которые мы можем применять для устранения этих
ошибок. В классах можно использовать уровни видимости final и package для защи-
4
Программное обеспечение с открытым исходным кодом (open source software, OSS)- это программное
обеспечение, которое предоставляется бесIUiатно для публичного использования, позволяя любому полу
чить доступ, изменять и распространять его исходный код. Фундаментальный принцип
OSS
заключается в
идее сотрудничества между многочисленными разработчиками и участниками, стимулировании инноваций
и обеспечении постоянного улучшения программного обеспечения.
5
-
Пер.
Статья АСМ об уязвимостях в Node.JS: https://dl.acm.org/doi/pdf/10.114S/3S71848.
Антипаттерны: внутренние общие библиотеки
■
163
ты внутренней реализации библиотек. Тем не менее часто внутренние общие биб
лиотеки подвергаются меньшему контролю, чем внешние пакеты. Вместо примене
ния строгих методов их разработчики объявляют все классы общедоступными ...
Это позволяет инженерам свободно использовать все компоненты библиотеки,
включая перечисления, аннотации,
POJO
и многое другое. По своей сути, библио
теки более уязвимы по сравнению с сервисами.
Как мы неоднократно отмечали, библиотеки часто воспринимаются как нечто само
собой разумеющееся. Например, при создании или использовании библиотек ин
женеры часто не задумываются о следующих рисках и недостатках библиотек.
♦
Отсутствие владельца. Что делать, если больше нет сопровождающих? Мы
рассмотрели
в главе
последствия
отсутствия
владельца
программного
обеспечения
3 «Антипаттерны: распределенные монолиты».
♦ Изменение направления. Что, если владелец выберет совершенно иной путь
развития, чем тот, от которого вы зависите сейчас?
♦
Медленное реагирование. Разработчики могут быть медлительными, не при
нимать много запросов или просто игнорировать вас. Что тогда? Вы постоянно
переделываете код?
♦
Ошибки. Что, если библиотека изначально выглядит великолепно, но на прак
тике оказывается полна ошибок?
♦
Огромный график зависимостей. Что, если библиотека имеет множество зави
симостей, и только позже вы понимаете, что это создает множество бинарных
связей?
♦ У язвим ости в системе безопасности. Что, если библиотека изначально небезопасна или полна уязвимостей в системе безопасности?
Как обсуждалось в предыдущих главах, в компаниях часто существуют команды
разработчиков продуктов или платформ. Команды разработчиков продукта могут
создавать внутренние библиотеки, но их редко обучают сопровождению, т. к. оно
не входит в их уставы/ОКR. Вместо этого они вынуждены постоянно повышать
ценность для бизнеса. Инженеры-разработчики платформ
-
типичные владельцы
внутренних библиотек. Из-за предыдущего пункта они также вынуждены брать на
себя обслуживание заброшенных библиотек у разработчиков и в конечном итоге
выполнять бесчисленные миграции снова и снова для одних и тех же библиотек.
Владение
(ownership) -
это одна из проблем, но она усугубляется бинарной свя
зью, которая вынуждает всех к каскадной миграции.
Бинарная связь/ сломанная изоляция
Как мы уже говорили в предыдущих главах, бинарная связь
(Binary Coupling) -
это когда программное обеспечение имеет множество отдельных зависимостей от
библиотеки, прямо или косвенно. Не осознавая этого, ваша команда больше не мо
жет легко обновлять программное обеспечение, использующее библиотеки или да
же сами библиотки, не нарушая работу всего вашего приложения. Допустим, одной
164 ■
Глава 4
из ваших зависимостей теперь требуется
Hibernate 4. Вы не
приложения на Hibernate 5.
пользуют
Бинарная связь
-
Hibernate 5,
но ваши сервисы в целом ис
сможете выполнить это обновление без перехода всего
одна из главных скрытых проблем при работе с библиотеками,
особенно в устаревших проектах, таких как монолиты. Со временем накапливаются
несовпадающие элементы: старые библиотеки с устаревшими зависимостями и но
вые с актуальными. Необходимость предоставления единого модуля развертывания
только усложняет ситуацию, смешивая все в один клубок.
Как мы уже говорили в главе
1 « Что
не так с монолитами?», монолиты страдают
от недостаточного тестирования и общего медленного цикла разработки; а в главе
3
«Антипаттерны: распределенные монолиты» мы показали вам, что распределен
ные монолиты могут бьпь еще хуже. Обновление может оказаться болезненным.
Одной из основных причин является наличие внутренних общих библиотек, кото
рые не обращали внимания на свои зависимости и допускали бинарную связь.
Мы утверждаем, что неспособность должным образом изолировать программное
обеспечение
-
это проблема номер один в современной разработке программного
обеспечения, особенно для монолитов. Бинарная связь
-
один из основных спосо
бов, с помощью которых библиотеки могут нарушить изоляцию программного
обеспечения. Хуже того, бинарная связь имеет тенденцию оставаться бездейст
вующей и скрытой до тех пор, пока команды не поймут, что оказались в сложной
ситуации, а масштабный и опасный рефакторинг -
единственный выход.
Стимулы для создания библиотек
Компании создают библиотеки по целому ряду причин; мы не утверждаем, что все
эти причины веские, и мы не утверждаем, что согласны с ними, но в реальности это
происходит исходя из следующих соображений.
♦ Избегание дублирования. Избегание написания одного и того же кода в не
скольких местах.
♦ Работа на резюме. Главный инженер или архитектор стремится к карьерному
росту, создавая общую библиотеку или фреймворк для организации.
♦
Абстрагирование от будущего. Стремление
в будущем, которого никогда не будет,
-
к повторному
использованию
это антипаттерн. Повторное исполь
зование кода случайно, а не задумано. Оно может возникнуть, когда какой-то
разработчик работает в другой команде и хочет сэкономить свое время.
♦ Конфликт интересов. Размещение кода в одном месте и передача права владе
ния другой команде, избегая бремени обслуживания. Такое явление часто встре
чается в проектах с открытым исходным кодом.
♦ Предпочтения разработчиков. Некоторым людям нравятся аннотации или
аспекты, поэтому они создают библиотеки для них.
♦
Одержимость производительностью. Мы тоже любим производительность, но
гибкость всегда важнее!
Антипаттерны: внутренние общие библиотеки
♦
■
165
Недоверие. Исходя из прошлого опыта, библиотечные обёртки могут быть спо-
собом «оградить» себя от плохих библиотек, навязываемых вашей команде.
В большинстве организаций инженеры практически не сталкиваются с препятст
виями при создании библиотек, а правила, касающиеся библиотек, могут быть
очень мягкими. Кроме того, люди гордятся тем, что создают библиотеки и видят,
как ими пользуются другие команды. В конечном итоге могут поверить, что это
важная часть их работы.
В индустрии программного обеспечения в целом существует банальность:
♦
младшие инженеры создают код, поэтому в их
PR много
зеленого или много до
полнений;
♦
ведущие инженеры удаляют код, поэтому в их
PR
много красного или много
удалений.
Следуя этому принципу, ведущие инженеры не только удаляют код, но и решают
проблемы, делая всё более компактным: меньше кода, меньше сервисов и никаких
ненужных библиотек. Ведущие инженеры являются отличными учителями и рас
пространяют правильную культуру, которая в данном случае заключается в эконо
мичном подходе. Руководство часто не следит за удалением кода. Вместо этого они
отслеживают
предоставление
функций
новых
или
исправление
ошибок,
в большинстве случаев и происходит. Конечно, если ваша библиотека
-
что
это путь
к большему количеству функций, вы защищены. Но что делать, если это не так?
Великие организации не просто уделяют приоритетное внимание расширению
и созданию, но и имеют
OKR,
которые охватывают удаление: вывод систем из экс
плуатации и снижение сложности организации в целом.
Антипаперн: фреймворк
Компании создают внутренние фреймворки
(framework)
не беспокоясь об их техно
логии или языке. Это может иметь как положительные, так и отрицательные по
следствия. Но, по нашим наблюдениям, иногда это делается просто ради ощущения
собственной значимости.
В
Java
они часто называются в компании сокращенно, например «фреймворк».
Возможно, фреймворк использует
Spring и Hibemate,
и все ваши сервисы вынужде
ны использовать эту базовую библиотеку.
На рис.
4.3
показано, почему фреймворк является антипаттерном.
Фреймворк на
Java
представляет собой бинарную группу из одного или нескольких
JАR-файлов. Допустим, у вас есть сотни или тысячи сервисов/микросервисов, ис
пользующих этот фреймворк. Одна из ваших команд говорит, что мы хотим ис
пользовать
Spring
6.х. Но подождите
-
фреймворк использует
Spring
4.х. Может
ли команда выполнить переход на новую версию изолированно?
Нет! Команде нужно будет сначала дождаться миграции фреймворка или выпуска
новой версии, поддерживающей
Spring
6.х тоже. Это означает не только взаимо
связь между командами, но и приводит к другим серьезным побочным эффектам.
166
■
Глава 4
Сервис
Сервис
Сервис
профилей
платежей
отчетов
Сотни/тысячи
других сервисов
«Фреймворю)
Hiberi,,.д.te
Рис.
♦
4.3.
Антипаттерн: фреймворк
Напряженность в связи с миграцией. Инженеры по продукту должны прино
сить пользу бизнесу, прилагая усилия к приоритетным функциям, а не к мигра
ции.
♦
Нехватка персонала
/
пропускной способности. Команды разработчиков плат
форм, архитекторы и DеvОрs-инженеры часто значительно меньше по числен
ности, чем команды разработчиков продуктов. Поэтому они с трудом справля
ются с огромной нагрузкой, связанной с миграциями.
♦ Приоритетные задачи. Всегда существуют конкурирующие задачи. Миграция
может вообще не быть приоритетной.
♦ Проблемы с владельцами. Если у вас
1О
команд, использующих
Spring 4,
и
50
1О
команд, использующих
команд, использующих
Spring 3,
Spring 5, сколь
ко версий фреймворка вы будете поддерживать? На практике внутренним разра
ботчикам это не нравится, и они могут избегать выполнения базового обслужи
вания в таком количестве версий.
Умножьте эту проблему на количество совместно используемых внутренних биб
лиотек, имеющихся в вашей компании, и вы получите верный путь к неприят
ностям. В рамках платформы был внедрен антипаттерн распределенный монолит,
который не только сводит на нет все преимущества микросервисов, но и увеличи
вает технические затраты и сложность. Для чего? В чем заключаются эти преиму
щества? Фреймворковый антипаттерн создает распределенные монолиты, но он
также присутствует и в классических монолитах.
Фреймворк часто не добавляет никакой ценности. Это стена между разработчиками
и фреймворками с открытым исходным кодом. Такая ситуация часто происходит
из-за того, что менеджеры и архитекторы не доверяют инженерам и считают, что те
не могут решить проблему самостоятельно; поэтому они создают библиотеки. Биб
лиотеки не подходят в качестве решения из-за нехватки квалифицированных спе
циалистов
(lack ofTalent Density) и/или доверия.
Антипаттерны: внутренние общие библиотеки
Фреймворк
-
■
167
это старый антипаттерн, основанный на ложном обещании повыше
ния производительности. Все начинается с внутренних общих библиотек и внут
ренних фреймворков, цель которых
-
создать «стандартный подход» для всех раз
работчиков, что упрощает переход инженеров между командами. В конечном счете
менеджеры считают, что повсеместное использование одних и тех же библиотек и
АРl-интерфейсов ускоряет выполнение задач. Ведь код в большинстве случаев по
хож, а проблемы и их решения
-
общие. Нам не нужно говорить, что часто эти
идеи со временем оказываются абсурдно ошибочными, создавая множество далее
перечисленных проблем.
♦
Проблемы с производительностью. Инженеры не могут найти решения в Ин
тернете:
♦
StackOvertlow, Reddit, YouTube.
Проблемы с моральным состоянием разработчиков. Инженеры не хотят ра
ботать
над
фирменным
решением,
которым
больше
никто
не
пользуется.
Фреймворк лишает их видимости своей работы, возможности гордиться своей
работой и отдавать должное своему коду по сравнению с общедоступной биб
лиотекой с открытым исходным кодом на
♦
GitHub.
Решения с низкой планкой. Мы никогда не видели внутреннего фреймворка
взаимодействия с Бд, который был бы лучше, чем
JDBC
или
Hibemate;
на самом
деле, всё наоборот.
Самое забавное, что фреймворк
-
это попытка сделать что-то лучше, но по срав
нению с решениями с открытым исходным кодом почти всегда получается что-то
хуже. У нас уже есть достаточно отличных решений с открытым исходным кодом.
Так что нет! Не изобретайте велосипед, используйте фреймворки и библиотеки
с открытым исходным кодом, такие как
Spring
и
Hibemate. Spring
и
Hibemate -
отличные решения для своей цели. Не возводите стену между вашими разработчи
ками и их фреймворками.
Теперь вы, должно быть, задумались. Понятно! Все проблемы из-за того, что ком
пании создают свои собственные фреймворки; это просто культ карго
(Cargo Cult).
К сожалению, нет. Могут возникнуть и другие подводные камни по разным причи
нам. В этой главе мы рассмотрим разнообразные проблемы, связанные с внутрен
ними общими библиотеками.
В защиту библиотек
Давайте внесем полную ясность: библиотеки невероятно важны для современной
разработки. Большая часть программного обеспечения, с которым мы ежедневно
взаимодействуем, в значительной степени зависит от библиотек и не функциониро
вала бы без них. Библиотеки с открытым исходным кодом
пользуйте их! Пополняйте их репозитории на
GitHub
-
это потрясающе, ис
и пишите свои собственные!
Да, вы должны использовать библиотеки с открытым исходным кодом, как и любая
компания в отрасли. Библиотеки, находящиеся в надлежащем владении и управле
нии, предоставляют функции, которые нам не нужно писать, что сокращает время
разработки, а также помогает исправлять ошибки и патчи безопасности по мере
необходимости.
■
168
Глава 4
Производительность
Некоторые операции имеет смысл выполнять локально только из соображений по
вышения производительности. Удаленное выполнение таких задач было бы аб
сурдным, т. к. потребовало бы большого объема данных для передачи. Библиотеки
могут сэкономить вам массу времени. Сервисы по своей природе являются удален
ными, если только вы не используете
решения. Библиотека
-
Kubemetes
или другие инфраструктурные
это оптимальный способ выполнения определенных задач,
требующих повторного использования кода и/или высокой производительности.
Путь к надежности
По сравнению с написанием сервиса для всех ваших задач библиотеки могут упро
стить процесс обеспечения надежности вашего программного обеспечения. Когда
у вас есть работающий сервис, он потребляет ресурсы и требует большего внима
ния к целевым показателям уровня обслуживания
соглашению об уровне обслуживания
(Service Level Objectives, SLO) и
(Service Level Agreements, SLA). Также есть
множество других рисков. Например, может произойти сбой в работе базы данных,
пользователи могут исчерпать ресурсы сервиса, сервис может работать медленно.
Библиотеки подвержены меньшим рискам. Благодаря внедрению библиотек они, по
сути, становятся частью вашего сервиса и могут привести к снижению сложности и
повышению надежности.
Конечно, бесплатный сыр бывает только в мышеловке. Это относится и к чужому
программному обеспечению, работающему внутри вашего кода. Библиотека по
прежнему должна быть доступной для наблюдения и стабильной, иначе вы впусти
те троянского коня в свою кодовую базу, что может привести к ужасным последст
виям.
Языковые идиомы
Достаточно простая истина: инженеры хотят писать код на своих родных языках и
так, чтобы эти языки функционировали. В конце концов, хотите ли вы писать на
Rust
так же, как вы пишете на
т. е. так, как
Rust
Scala?
Нет, вы хотите писать идиоматический
Rust,
работает лучше всего. Инженеры не хотят изучать новые ненуж
ные фреймворки, конфигурационные файлы. Им не хочется писать сценарии кон
фигурации
Terraform, они предпочитают Java SDK, который позволяет работать на
Java с использованием Jаvа-идиом, чтобы добиться того же результата.
Библиотеки могут это обеспечить, а сервисы - нет. Библиотеки также могут рас
родном
ширяться, просто чтобы соответствовать идиоматике языка, что может быть как
плюсом, так и минусом. Пакет Goog\e Cloud SDK для Go6 позволяет инженерам
программировать на идиоматическом языке. В целом такие библиотеки больше по
хожи на сервис драйвер/клиент
(Service Driver/Client),
о котором мы поговорим
позже в этой главе.
6
Google Cloud SDK является языковым идиоматическим пакетом: https://cloud.google.com/go.
Антипаттерны: внутренние общие библиотеки
■
169
Централизация кода
Использование библиотеки также гарантирует централизованное выполнение. Как
мы уже объясняли, централизация
(centralization)- это
мощная концепция; иногда
проще устранять проблемы централизованно, чем повторять одно и то же в не
скольких местах. Эта особенность библиотек часто полезна для устранения ошибок
или внесения изменений. Однако таких же результатов можно достичь с помощью
других методов, таких как рефакторинг,
Библиотеки
-
Deep Modules,
агенты и другие методы.
один из самых простых способов добиться такой централизации.
Перестаньте заново изобретать велосипед
В статье Дэна Макфанли «Выбери скучную технологию» 7 Дэн просит компании и
команды представить, что у каждой из них есть по
бы у вас было только
3
3
инновационных токена. Если
токена, вы бы вложили их в переписывание
SSH?
В созда
ние своей собственной базы данных с нуля? Если вы занимаетесь инфраструктурой,
конечно, но для большинства компаний ответ прост: нет. Ваши сотрудники и их
блестящие умы
-
ограниченный ресурс, поэтому тратьте их там, где это необхо
димо.
Библиотеки позволяют вам сосредоточиться на основной сфере деятельности, по
вторно используя существующие решения. Нет смысла выделять ресурсы для ре
шения проблем, которые уже решены в технологической отрасли в целом. Зачем
создавать собственную шину сообщений? Вы можете использовать
чем создавать свой собственный фреймворк доступа к БД на
Java?
Зачем изобретать свой собственный фреймворк тестирования,
ActiveMQ. За
Spring Data.
если есть JUnit?
Есть
В этом мало смысла.
Конечно, все такие идеи с чего-то начинались. Если у вас, как у человека, есть от
личная идея для совершенно нового подхода, вы должны развивать ее, воплощать
в жизнь и делать то, что вам нравится. Просто осознайте, что вы тратите впустую
свое время и внимание.
Подведем итог: библиотеки удивительны и являются одним из ключевых нововве
дений, лежащих в основе современной разработки программного обеспечения.
Проблема не в самих библиотеках, а в том, где их используют, как создают и кто их
контролирует, распоряжается ими и поддерживает их (или нет). Чтобы лучше по
нять эту концепцию, давайте продолжим анализировать распространенные ошибки
библиотек, особенно внутренних общих библиотек.
7 Простой
и эффективный ответ на культ карго, о котором мы упоминали в предыдущих главах:
bttps:// boringtechnology.cluЫ и https://mcfunley.com/choose-boring-technology.
170
■
Глава 4
Подводные камни
-
неправильные методы,
которых следует избегать
Библиотеки могут иметь неприятные последствия во многих отношениях. Вам не
обходимо правильно применять внутренние общие библиотеки, иначе вы рискуете
увеличить размер вашего распределенного монолита.
Иногда можно создавать
внутренние общие библиотеки, но даже в этом случае необходимо придерживаться
правильных принципов.
Вот несколько подводных камней, которых следует избегать при работе с библио
теками.
Внутренние общие библиотеки
Простое создание внутренней общей библиотеки
ности, открытый исходный код
-
-
рискованное действие. Для яс
это здорово, и мы не против библиотек с откры
тым исходным кодом. Но снова и снова мы видим, как внутренние общие библио
теки нарушают изоляцию или даже создают распределенный монолит. Поэтому вам
нужно хорошо подумать, действительно ли необходимо их создавать.
Внутренние общие библиотеки часто представляют собой серьезные скрытые про
блемы. Они есть в каждой компании, и в большинстве случаев инженеры ими не
довольны. Создавать библиотеки очень просто; создавать надлежащие внутренние
общие библиотеки намного сложнее, чем думают люди. Правильное обслуживание
библиотеки еще сложнее! Внутренние общие библиотеки могут создаваться с бла
гими намерениями, но результаты могут оказаться совсем неожиданными.
Правильное создание внутренних общих библиотек требует осторожности и пра
вильного мышления. В вашем распоряжении все библиотеки с открытым исходным
кодом в мире; зачем вам, например, создавать более пяти библиотек? Пять
произвольное число, но выслушайте нас. Спросите себя в зеркале
3
-
это
раза: «Действи
тельно ли мне нужно создавать эту внутреннюю общую библиотеку?». Применяйте
тот же подход, когда команда хочет создать
1О
сервисов одновременно.
Эффект короткого одеяла
В Бразилии есть метафора, называемая
ла (рис.
4.4).
Cobertor Curto,
или эффект короткого одея
Это означает, что, когда вы пытаетесь решить одну проблему, вы соз
даете другую, устраняете новую проблему и возвращаетесь к предыдущей.
В Jаvа-приложениях у нас есть названия для таких ловушек:
classpath hell
(ад путей к классам) или
dependency hell
JAR hell
(ад
JAR),
(ад зависимостей). В вашем
приложении нарушен граф зависимостей. Библиотеки зависят от зависимостей
с внутренним конфликтом; вы исправляете одну библиотеку, объявляя фиксиро
ванную зависимость, что приводит к серьезным нарушениям в другой библиотеке.
Это эффект короткого одеяла, наблюдаемый в программном обеспечении, вызван
ный библиотечными зависимостями. Это еще один способ описания бинарной
связи, и наиболее экстремальные эффекты короткого одеяла наблюдаются в рас-
Антипаттерны: внутренние общие библиотеки
■
171
Эффект короткого одеяла
Ты укрыл свою грудь .
Ты укрыл свои ноги.
Открыл свои ноги.
Открыл свою грудь .
Рис.
4.4.
Эффект короткого одеяла.
Источник: https://www.freepik.com/icon/Ыanket_6629167 (изображение одеяла)
пределенных монолитах. Эффект короткого одеяла сильно усложняет работу с биб
лиотеками.
Большие фреймворки
Внутренним общим библиотекам следует избегать больших фреймворков. Когда
внутренние общие библиотеки зависят от больших фреймворков, это влечет за со
бой множество последствий для пользователей библиотек, таких как:
♦ Непредвзятый выбор. Что, если разработчик библиотеки использовал
или
Spring,
Hibemate
а ваша команда не хочет их использовать?
♦ Большой график зависимостей. Большие фреймворки, как правило, имеют
множество
зависимостей
Commons, Guava, Jackson
от
сторонних
разработчиков,
таких
как
Apache
и многие другие распространенные библиотеки с от
крытым исходным кодом, а также все их графики зависимостей.
♦ Размер пакета. Размер существенно влияет на интерфейс. Он определяет время
загрузки приложения при первом запуске
/
общее время загрузки приложения,
что напрямую сказывается на удобстве работы пользователей.
♦ Миграция: все или ничего. Часто возникает необходимость переместить всех
потребителей или никого. Сервисы не могут мигрировать до тех пор, пока вла
делец библиотеки не обновит ее; они ждут открытия ворот.
♦ Холодная загрузка оказывает реальное влияние на бессерверные среды. Чем
больше зависимостей, тем дольше запускается приложение,
-
медленная хо
лодная загрузка может быть затруднена.
Нет, большие фреймворки не обязательно плохи. Их можно и нужно использовать
в своем сервисе. Вы можете найти документацию, официальные руководства и
специальную поддержку на
StackOvertlow
и других сайтах. Кроме того, гораздо
проще найти квалифицированных специалистов. Однако использование больших
фреймворков во внутренних общих библиотеках
-
рия. Здесь высок риск возникновения бинарной связи.
это совершенно другая исто
172
■
Глава 4
Раздутые библиотеки
Библиотеки могут раздуваться несколькими способами. Одним из способов являет
ся увеличение функциональности. Представьте себе библиотеку, которая обеспечи
вает сохранение данных, настройку в формате
JSON,
объединение потоков и про
верку в зависимости от бизнес-области. Слишком много смешанных функций для
одной библиотеки!
Вторая форма раздутости связана с зависимостями; библиотеки должны иметь
очень мало зависимостей. Любая библиотека с множеством зависимостей и боль
шим графом зависимостей может считаться раздутой. Часто библиотеки, которые
перегружены зависимостями, раздуты и в плане функций, поскольку им приходит
ся обращаться к функциям в разных бизнес-областях. Кроме того, раздутые биб
лиотеки часто содержат множество ненужных зависимостей.
Всестороннее исследование зависимостей библиотеки
в экосистеме
Maven»,
Java
«Раздутые зависимости
проведенное Сезаром Сото-Валера, Николасом Харраном,
Мартином Монперрусом и Бенуа Боди в 2020 году8, после анализа 9639 артефактов
Maven,
показало, что
75, 1 % зависимостей являются
раздутыми.
Очень популярные библиотеки
Очень популярные библиотеки часто становятся жертвами своего успеха. Здорово
иметь библиотеки, проверенные на практике, которыми все пользуются в больших
масштабах и которые всегда содержат полезные функции. Однако очень популяр
ные библиотеки, как правило, используются другими библиотеками, что создает
сложные конфликты.
Иногда обновление популярных библиотек, таких как
Guava или Jackson, может
Jackson; это отличная библиотека сериализации
XML. Пакет А WS Java SDK использует Jackson, как и Spring Boot. Если
быть довольно сложным. Возьмите
для
JSON
и
ваши внутренние общие библиотеки также используют его и ваши сервисы исполь
зуют его, то нетрудно догадаться, что его обновление будет очень сложным и вызо
вет кратковременный общий эффект
(Short Blanket Effects).
Совет здесь тот же, что
и для больших фреймворков: их можно использовать в ваших сервисах, но избегай
те их использования в ваших внутренних общих библиотеках.
Библиотеки доставки конфигурации
Рассматривая фреймворк
Spring,
предположим, что вы хотите использовать управ
ление зависимостями и инверсию управления
используете
Spring
в библиотеках
-
(lnversion of Control, IoC).
Если вы
будьте осторожны с большими фреймворка
ми естественно подумать о том, чтобы поместить ваши конфигурации Spring
Beans в библиотеки. Звучит как хорошая идея, не так ли? Точно нет.
8
Статья «Раздутые зависимости в экосистеме Maven»: https://arxiv.org/pdf/2001.07808.pdf.
Антипаттерны: внутренние общие библиотеки
Компоненты
Spring являются
■
173
общедоступными, и, как мы объясняли в предыдущих
главах, общедоступные объекты неявно являются частью библиотечных контрак
тов. Из-за этого вам необходимо поддерживать их вместе со всеми вашими обще
доступными
API,
поскольку любой может подключиться к ним напрямую. Теперь
предположим, что это делают многие библиотеки. У вас сложная ситуация, потому
что сервисы больше не владеют своей конфигурацией: удалите компонент
Spring,
и вы нарушите работу сервисов.
Библиотеки могут доставлять конфигурации, если они статичны и редко или нико
гда не меняются. Если они меняются часто, это плохая идея. Тот же принцип при
меним к сервисам; однако сервисам должны принадлежать9 все их конфигурации.
Конфигурации должны быть внешними 10 .
Лучшйй подход: не используйте
ваших внутренних общих библиотеках.
Не отправляйте компоненты
Spring в
Spring в виде
конфигураций. Вместо этого используй
те разумные значения по умолчанию в своем коде. Это упростит использование
библиотеки и позволит пользователям настраивать нужные параметры.
Размывание команды в общих библиотеках
В главе
3
«Антипаттерны: распределенные монолиты» мы рассмотрели социаль
ный феномен размывания команд
(team erosion).
4.5).
Размывание команд сильно влияет
на внутренние общие библиотеки (рис.
Что касается инженеров, то, как мы обсуждали в разделе «Стимулы для создания
библиотек», в большинстве организаций очень легко создать внутреннюю общую
Размывание команд в библиотеках
Разработчик
1:
Я хочу добавить метод
в
StringUtils, но тесты
не проходят .
Разработчик
Разработчик
2:
Нужно исправить уязвимость
в
log4j -
как мне опубликовать
эту библиотеку?
Разработчик
3:
Хочу обновить
бизнес-перечисление
4:
Хочу выполнить
миграцию
Spring.
в этой библиотеке ...
Разработчик
Контракт
Новая версия
Контракт
сломала мой сервис!
Сервис
Сервис
бронирования
бронирования
мам уrмли
1
1
1
авиабилетов
-.
База данных
База данных
авиабилетов
отелей
Рис.
9
4.5.
1
.
..
100 других сер висов
1Мом у,млмты
Размывание команд в библиотеках
Сообщение Диего Пачеко о владении конфигурацией:
configuration-ownersbip.btml.
bttp://diego-pacbeco.Ыogspot.com/2022/06/
10
5:
Spring
12 принципов приложения Factor- о конфигурациях: bttps://12factor.net/config.
174
■
Глава 4
библиотеку и в конечном итоге отказаться от ее обслуживания. Люди самоуверен
ны, и часто хотят использовать определенные подходы, библиотеки и фреймворки.
Они могут создать внутреннюю общую библиотеку с наилучшими намерениями.
Однако библиотеки могут использоваться только для проектов, над которыми
работал конкретный человек. В компаниях легко найти подпольные рынки внут
ренних общих библиотек, поскольку часто нет ни перечня, ни устава, ни бизнес
обоснования. Код необходимо поддерживать, поскольку необходимо исправлять
ошибки, выполнять миграцию и вносить исправления в систему безопасности. За
частую эти библиотеки мешают работе, не принося пользы и вызывая больше про
блем, чем решений.
Очень часто у внутренних общих библиотек нет владельцев. По этой причине
внутренние общие библиотеки часто не проходят достаточно тестов или не к·леют
исчерпывающей документации для инженеров, выполняющих миграцию. В резуль
тате всегда обнаруживаются неприятные сюрпризы, связанные с этими библиоте
ками.
Размывание команды означает, что у внутренних общих библиотек нет владельцев.
Это также влечет за собой частые проблемы, такие как отсутствие тестирования,
низкий или неравномерный уровень прохождения
(pass rate)
и, что более важно,
абсолютный хаос, когда дело доходит до утверждения изменений или консультиро
вания об их потенциальном влиянии. Происходит одновременное выполнение не
скольких миграций, команды присоединяются к миграциям без согласования, их
работа разрушается другими командами, ошибками, изменениями в бизнесе. Опять
же, размывание командной структуры значительно усиливает проблемы работы
с внутренними общими библиотеками.
Драйверысервисов
Драйвер
(driver) -
это программное обеспечение, предоставляющее
API
для
управления низкоуровневым интерфейсом, часто связанным с аппаратным обеспе
чением 11.
У сервисов могут быть драйверы, также известные как клиенты. Клиентов сервисов
можно считать одним из видов драйверов, поскольку они управляют прямым ин
терфейсом сервиса для программного обеспечения, вызывающего его. Драйверы
сервисов могут быть еще одним источником проблем, и нам лично многие из них
нравятся. Однако мы должны иметь в виду, что драйверы
-
это внутренние общие
библиотеки. Они могут иметь зависимости и, следовательно, все проблемы, о кото
рых мы говорили ранее.
Рассмотрим следующий пример двух сервисов, в котором сервису бронирования
отелей необходимо связаться с сервисом бронирования авиабилетов. Разработка
была бы проще, если бы сервис бронирования авиабилетов предоставлял драйвер.
В противном случае команде, работающей над сервисом бронирования отелей,
и всем остальным потребителям пришлось бы:
11
Определение драйвера из Википедии: https://en.wikipedia.org/wiki/Driver_(software).
■
Антипаттерны: внутренние общие библиотеки
♦
создать все
Java POJO для
175
операций, которые они должны вызывать;
♦ сопоставить все конечные точки
REST
с нужными параметрами и
POJO;
♦
выполнить сериализацию/ десериализацию объектов/JSОN;
♦
запустить и при необходимости произвести логирование;
♦
применить базовые проверки для обязательных полей и основные преобразования типов.
Теперь представьте, что нам нужно вызвать сервис бронирования авиабилетов еще
из
30
сервисов. Всем сервисам нужно будет ввести один и тот же код. Таким обра
зом, смысл заключается в создании сервисного клиента или драйвера (рис.
4.6)
или
в совместном использовании объектов контракта, чтобы пользователям не прихо
дилось определять их снова и снова.
Сервисные драйверы/клиенты
Сервис бронирования
авиабилетов
Контракт
Драйвер сервиса
бронирования
авиабилетов
База данных
авиабилетов
База данных
отелей
Рис.
Драйвер/клиент
-
4.6.
Сервисные драйверы/клиенты
это здорово. Владельцам сервисов следует создавать драйверы.
это библиотеки, а библиотеки должны быть компактными.
Драйвер должен очень тщательно выбирать зависимости, поскольку это источник
бинарной связи. В противном случае драйверы могут столкнуться со всеми про
Однако драйверы
-
блемами, упомянутыми в нашей главе.
При изменении контракта на обслуживание, конечно, необходимо обновить и драй
веры. В противном случае пользователи могут не получить все изменения или, что
еще хуже, их работа может быть нарушена. Если вы используете драйверы, побоч
ным эффектом может быть постоянная миграция для всех пользователей, чтобы
они оставались на последних версиях драйверов.
Драйверы интересны тем, что они предоставляют еще один уровень косвенной
поддержки для разработчиков сервисов. Возможно реализовать механизм обратной
совместимости
(backward
compatiЬility) на стороне драйвера. Однако мы рекомен
дуем всегда выполнять это на стороне реализации сервиса.
Для большинства сервисов клиентский драйвер не нужен. Если вы возьмете на себя
работу, связанную с вызовом этого сервиса, это не принесет реальной пользы. Но
176
■
Глава 4
если вы хотите использовать клиентский драйвер и сделать его более экономич
ным, а также иметь четкое представление о владельце и приверженности к мигра
ции, это может хорошо сработать.
Утилиты
Утилиты
(Utils) -
это библиотеки, которые выполняют буквально всё (рис.
4.7).
Общий код для строк, чисел, дат, обработки ошибок, проверок, исключений, веде
ния журнала и нескольких частей и функций, специфичных для бизнеса вашей
компании. Утилиты также могут иметь зависимости.
Утилиты
Сервис авиабилетов хочет использовать
утилиту работы с датами, но ...
Моя библиотека утилит
Контракт
Утилиты работы
Все виды
со строками
бизнес-леречислений
Вот что они
получают
Утилиты работы
Пользовательские
с датами
аннотации
Исключения
Пользовательская
и проверки
бизнес-логика
...
с
•_
Мои_
утилиты
__
ервис
брон1jрования
ааи!lбилетов
БД авиабилетов
... другие зависимые библиотеки
от стооонних оазоаботчиков ...
Рис.
4.7.
Внутренние общие библиотеки утилит
Концепция класса utils сама по себе неплоха и может стать хорошим примером для
повторного использования кода. К сожалению, в большинстве компаний мы редко
видим Utils с хорошим кодом и достойной модульностью. Утилиты имеют огром
ную область применения, и почти все классы Utils являются частью контракта.
Часто можно увидеть, как бизнес-правила просачиваются из самого сервиса и про
никают в код утилит. Хотя утилиты существуют повсеместно, наличие внутренних
общих библиотек с утилитами может стать огромной проблемой.
Лучшим решением было бы использовать модульные библиотеки для утилит. Тем
не менее в нашей отрасли мы часто видим, что компании используют единую биб
лиотеку утилит, а также утилиты для каждой бизнес-области компании или даже
для каждого сервиса.
Одна из главных проблем библиотек утилит заключается в том, что они использу
ются многими разработчиками и командами совместно. Отсутствие единого вла
дельца приводит к хаотичному и бесконтрольному росту библиотек. Они часто
имеют множество сторонних зависимостей от других библиотек и легко заражают
все ваши внутренние библиотеки и бизнес-сервисы.
Антипаттерны: внутренние общие библиотеки
■
177
В Интернете есть много отличных библиотек. Вам нужно создать свою собствен
ную? Конечно, можно создать библиотеку утилит должным образом. Вот несколько
практических советов.
♦
Будьте сфокусированы. Сделайте класс Utils ориентированным на что-то одно.
Например, если это работа со строками, то сосредоточьтесь исключительно на
строках. Избегайте включения других задач, таких как обработка чисел или про
верка файлов.
♦
Будьте скромны. Не создавайте большие JАR-файлы с утилитами, в противном
случае
они,
как
правило,
становятся
мешками
для
мусора
и
могут
привести
к высокой степени связности.
♦
Стабильные контракты. Сделайте ваши контракты простыми и стабильными.
Убедитесь, что у вас не слишком много вариантов и не сотни АРI-интерфейсов.
Убедитесь, что степень детализации
(granularity)
правильная, а ваши открытые
методы действительно универсальны.
Обёртки
Разработчики программного обеспечения решают, что лучший способ предоставить
библиотеку или фреймворк
API
это «обернуть» их в свой код, предоставив новые
-
или применив новую абстракцию, специфичную для конкретной компании.
Как правило, обёртки
(wrappers)
работают поверх внешних библиотек с открытым
исходным кодом. Обёртки создаются потому, что инженеры и архитекторы чувст
вуют необходимость «изолировать» определенную библиотеку от своего бизнес
кода. Хотя обёртки могут быть предоставлены несколькими способами, мы часто
видим две формы:
♦ расширение: расширение некоторых или всех
♦
новая абстракция: замена
API
API
из целевой библиотеки;
библиотеки своими собственными под видом
защиты вашей компании или ее «стандартизации».
Расширение
Расширение
тором
вы
(Extension) -
пытаетесь
это реализация шаблона проектирования адаптера, в ко
создать
новое
или
пользовательское
поведение
лизации библиотеки. Хотя в некоторых вариантах использования
поверх
(use cases)
реа
это
может быть допустимым, у него есть явные недостатки.
♦
Переопределение некоторых или всех АРI-интерфейсов из библиотеки, которую
вы хотите обернуть, требует глубокого понимания того, как работает библиоте
ка для вашей модификации. Также важно провести пользовательские тесты,
которые гарантируют, что ничего не нарушено.
♦ Постоянное
обслуживание
вашей
обёртки
требует дополнительной
работы.
Каждый раз, когда целевая библиотека обновляется, вам необходимо проверять
и запускать тесты, чтобы убедиться, что изменения в поведении или сломанные
API
не повлияют на вашу обёртку.
178
♦
■
Глава 4
Если вы решите не поддерживать все
API,
вы удалите функции из библиотек,
которые могут понадобиться другим инженерам. Мы неоднократно сталкива
лись с таким явлением в отрасли, иногда оно происходило случайно, а иногда
-
из-за плохой организации взаимодействия. Инженерам это не нравится, и они
либо находят обходные пути, либо просто полностью прекращают использовать
обёртку.
Предположим, по какой-то причине ваши инженеры решили обернуть
Apache POI.
Теперь у вас, как у пользователя, есть как минимум две зависимости: обёртка и це
левая библиотека. Кроме того, вы также зависите от всех внешних зависимостей
обёртки и самой целевой библиотеки (рис.
4.8).
Ваша обёртка создана на заказ,
и создание обёртки для новой библиотеки должно быть выполнено на заказ; этот
подход не масштабируется.
Использование обёртки
и ее зависимостей ...
Моя обёртка
(расширяет контракты и предоставляет API)
Контракт
Сервис
Моя обёртка
,__ _ _.,.
бронирования
.
Делегирование в целевую библиотеку
авиабилетов
БД авиабилетов
Целевая библиотека
(Apache POI)
Рис.
4.8.
Обёртки
-
расширение
Обёртки могут быть эффективным инструментом, если их использовать разумно и
учитывать соответствующие компромиссы. В противном случае это может оказать
ся неоправданно дорогостоящим и сложным способом настройки. Рассмотрите аль
тернативные методы, такие как составной шаблон, агенты
прокси
серверы, шаблоны прокси-серверов, включая
простой
JDK Proxy
и
Java, сетевые
cglib, ASM или
рефакторинг кода.
Новые абстракции
Другой способ реализовать обёртку
-
создать совершенно новый интерфейс/ биб
лиотечный контракт, заменив все методы и делегировав их целевой библиотеке по
мере необходимости (рис.
4.9).
Обёртку можно использовать для полной защиты
приложений от библиотечного кода с какой-либо целью, например для:
♦
избегания распространения устаревших контрактов, возможно, некоторые уста
ревшие системы прекратят свое существование;
Антипаттерны: внутренние общие библиотеки
♦
абстрагирования от плохо спроектированного или сложного
API
■
179
во время созда-
ния новой системы.
Хотя может быть несколько ситуаций, где такой подход уместен, мы видели слу
чаи, когда этот шаблон применялся к библиотекам с открытым исходным кодом и
фреймворкам, где он вообще не нужен, таким как
Spring
или
Hibernate.
Бессмыс
ленно пытаться абстрагироваться от общей популярной библиотеки, т. к.
Community Process
печивая
их
Java
уже предоставляет спецификации для этих фреймворков, обес
совместимость.
В
таких
случаях
подобный
подход
ограничивает
использование инженерами функций, что, опять же, является плохой формой конт
роля.
Использование обёртки
и ее зависимостей ...
Моя обёртка
(совершенно новый интерфейс/АР!)
• • •• Контракт
Моя обёртка
Сервис ----◄
брон~рования
а~иабилетов
Делегирование в целевую библиотеку
t
Целевая библиотека
БД авиабилетов
(Apache POI)
Рис.
4.9.
Обёртки
-
новые абстракции
При правильном использовании шаблон оборачивания может оказаться полезным.
Однако важно не превращать обёртки в сторожевые устройства, которые излишне
ограничивают возможности отличных и мощных решений с открытым исходным
кодом.
Отсутствие управления
В чем причина всех этих проблем с внутренними общими библиотеками? Одной из
основных причин является отсутствие управления и прозрачности. Взгляните прав
де в глаза: по мере того как ваша работа становится менее заметной для продукта и
бизнеса, менеджеры все меньше заботятся о пользовательском интерфейсе. Внут
ренние общие библиотеки, как и любые другие технологические активы, требуют
управления, которое в настоящее время является лишь менее популярным названи
ем для владения.
Надлежащее управление библиотекой означает следующее.
♦
Однозначное владение. Вы знаете, кому принадлежит библиотека
ному лицу, команде или даже организации.
-
отдель
180
■
Глава 4
♦ Активное сопровождение. Внутренние общие библиотеки активно обслужива
ются, в них внедряются исправления безопасности и постоянно проводятся об
новления.
♦ Документация. Вики-страницы, диаграммы, часто задаваемые вопросы
(F AQ)
и
видеоролики, объясняющие распространенные проблемы и пути их решения.
♦
Строгая стабильность. Сборки
уровнем прохождения
CI, тестовые прогоны с постоянным 100%-ным
(pass rate ), достойным охватом и достаточным разнообра
зием тестов.
♦ Наблюдаемость. Ваша библиотека должна публиковать показатели, счетчики
успешности и ошибок, статистику производительности и счетчики доступа.
Ориентируйтесь на потребителя: показатели использования полезны как для
ваших пользователей, так и для вас, позволяя узнавать о проблемах до их воз
никновения. Показатели могут помочь вам понять, какие функции активно ис
пользуются в вашей библиотеке, спланировать будущие миграции и очистить/
вывести из эксплуатации старый код.
♦ Целостность дизайна. Владельцы должны убедиться, что сохранен единый
стиль проекта. Инженеры и менеджеры не должны вносить изменения без согла
сования.
PR не должны
получать моментальное одобрение.
Нередко мы наблюдаем обратное тому, что должно быть при эффективном управ
лении: боль и борьба команд с плохими внутренними общими библиотеками.
Улучшенные возможности
Как мы видели, при проектировании библиотек существует множество подводных
камней и плохих практик. Теперь мы рассмотрим соображения и лучшие альтерна
тивы для того, как вы можете использовать внутренние общие библиотеки.
Когда нам следует создавать библиотеку?
К созданию библиотеки следует подходить с осторожностью. Помните, что вам
нужно будет поддерживать ее на протяжении всего жизненного цикла. По своей
природе библиотеки ограничены своими языками. Если мы создаем библиотеку на
Java,
мы не сможем легко использовать ее повторно в
TypeScript
или
Go.
Таким
образом, библиотеки имеют больше ограничений, чем сервисы, которые можно вы
зывать и использовать на любом языке. Сервис обладает свойством совместимости,
которого часто нет у библиотек.
Перечислим веские причины для создания библиотеки.
♦ Вы делаете что-то действительно лучше. Например, повышаете производи
тельность, создаете более быстрый синтаксический анализатор для
улучшаете рендеринг
React.
JSON
или
Ваша библиотека явно улучшает существующие
возможности.
♦ В существующей библиотеке есть фундаментальный недостаток. «Текущая»
библиотека работает медленно, неэффективно или имеет неправильную мен-
Антипаттерны: внутренние общие библиотеки
■
181
тальную модель. Возможно, вам нужно создать новую, потому что вы не кон
тролируете существующую библиотеку или они не принимают ваши предложе
ния по улучшению.
♦
Вы столкнулись с пользовательской проблемой, которую никто не решил.
Представьте, что вы разрабатываете библиотеку для создания диаграмм в
Zig,
но
такой библиотеки пока нет. Библиотека для построения графиков достаточно
универсальна и не существует. Имеет смысл ее создать.
♦
Сервис не будет простым. Сервис будет работать слишком медленно или по
совершенно неправильной модели, т. е. вы не сможете абстрагировать
Spring
IоС/фрейморк базовой платформы от удаленного сервиса, это добавит сложно
сти и накладных расходов без каких-либо преимуществ. Некоторые понятия не
могут быть разделены и должны сосуществовать.
♦ Хорошее повторное использование. У вас есть код или бизнес-логика, которые
необходимо использовать повторно, например в модульном монолите, а сервис
ная модель неестественна. Рассмотрим наш пример istioct; вам нужна логика,
которая обращается к защищенному локальному конфигурационному файлу из
нескольких модулей монолита, и вместо того, чтобы дублировать этот код в ка
ждом большом модуле, вы создаете библиотеку. Для эффективного повторного
использования выбирайте действия или методы, которые должны широко ис
пользоваться вашей организацией и которые нельзя найти в открытом исходном
коде, например для анализа проприетарного двоичного формата файла; против
плохого повторного использования, такого как пользовательские rеst-клиенты,
JSОN-ридеры и т. д.
Когда нам не следует создавать библиотеку?
♦
Вы не доверяете инженерам. Вы думаете, что инженеры будут совершать
ошибки, и это вызывает у вас сомнения. Очень вероятно, что ваша проблема за
ключается в недостатке квалифицированных специалистов и/или архитекторы
используются в качестве контролеров, а не настоящих наставников.
♦
Это решение основано исключительно на предпочтениях. Вы предпочитаете
аннотации методам. Некоторые люди любят аннотации, другие их ненавидят.
Оба подхода хороши, но библиотеки не следует создавать только потому, что
вам удобнее работать по-другому.
♦ Противоречит определению экономичных библиотек. Независимо от потреб
ностей, созданная вами библиотека была бы раздутой, сложной, ее было бы
трудно поддерживать или она создавала бы негативные побочные эффекты для
потребителей.
♦
Плохое повторное использование. Вы одержимы идеей повторного использо
вания и не хотите допускать дублирования ни одной строки. Не всякое дублиро
вание плохо, но некоторые случаи дублирования могут быть очень опасными,
например для сохранения кода в одной и той же таблице. Конечно, в таких сце
нариях у вас возникают более серьезные проблемы, такие как классический или
распределенный монолит.
■
182
Глава 4
Наша рекомендация заключается в том, чтобы вы не рассматривали библиотеки как
выбор по умолчанию. По умолчанию должны быть выбраны сервисы. Этот совет
особенно важен для разработчиков платформ и
DevOps,
которые, как правило, соз
дают больше библиотек, чем сервисов.
Использованиесервисов
SOA расшифровывается как сервис-ориентированная архитектура (Service Oriented
Architecture, SOA). В SOA сервисы занимают центральное место. Конечно, вы мо
жете использовать внутренние общие библиотеки в любом архитектурном стиле.
Но
SOA
подчеркивает важность создания сервисов, а не библиотек. Сервисы обла
дают несколькими ключевыми преимуществами по сравнению с внутренними об
щими библиотеками, такими как:
♦ отсутствие бинарной связи, зависимости сервисов не влияют на их пользовате
лей;
♦
значительно повышенная гибкость, поскольку вы можете свободно изменять
структуру сервиса, не влияя на другие сервисы;
♦
упрощение миграции или полное ее отсутствие благодаря четкой изоляции.
Давайте рассмотрим каждый пункт и разберемся в нем более подробно.
Отсутствие бинарной связи
Сервисы не создают рисков бинарной связи для своих пользователей, если все вы
полнено правильно. Это означает, что если у вас есть драйвер сервиса, то это про
стая библиотека с почти нулевыми зависимостями и, следовательно, практически
без бинарной связи. Отсутствие бинарной связи окупится во многих отношениях,
например, нашими следующими двумя преимуществами: гибкостью и упрощением
миграции.
Значительно улучшенная гибкость
Без бинарной связи мы можем сосредоточиться на сервисном контракте. До тех
пор, пока мы не нарушим этот публичный контракт (puЫic
contracts),
мы можем
изменить буквально всё, что происходит под капотом, не нарушая интересы потре
бителей:
♦ масштабные контролируемые миграции: обновляем основные версии фрейм
ворков и библиотек внутри сервиса без ущерба для потребителей или других
сервисов;
♦
модернизация: меняем весь технологический стек, т. е. можно перейти с
на
♦
эволюция персистентности: радикально меняем хранилище персистентности,
например с
♦
Java 8
Rust;
Oracle на Cassandra;
переписывание: полностью переписываем реализацию, меняем весь код, пока
контракт остается в силе.
Антипаттерны: внутренние общие библиотеки
♦
■
183
повышение степени детализации: делим сервис на более мелкие модули или
даже на большее количество сервисов.
Возможности безграничны. Сервисы обеспечивают большую гибкость не только
для тех, кто занимается сопровождением, но и значительно облегчают повседнев
ную жизнь наших потребителей.
Простая миграция или отсутствие миграции
При использовании сервиса вместо внутренней общей библиотеки до тех пор, пока
мы не нарушаем публичный контракт, любая внутренняя миграция, которая может
потребоваться, останется в рамках сервиса. Например, мы можем выполнить сле
дующее без ущерба для пользователей.
♦ Миграция
JDK.
Изменить
Java с
8-й на 17-ю.
♦ Масштабная модернизация фреймворка. Обновите крупные фреймворки, та
кие как
Spring, Spring Boot и Hibemate, даже
основные версии.
♦ Масштабная миграция базы данных. Увеличьте версии вашей базы данных,
такие как
Postgres, MySQL
и т. д.
Ни один из них не требует миграции кода
(code migrations)
на стороне потребите
лей; возможности беспредельны.
Теперь предположим, что мы разрываем контракт. Если сервисный контракт стаби
лен и написан надлежащим образом, то в нашем публичном контракте нет зависи
мостей от фреймворков и библиотек.
Потребителям нужно только иметь дело с изменениями в бизнесе. Это намного
проще, чем иметь дело с большими фреймворками и библиотеками по всей вашей
кодовой базе!
Однако сервисы тоже не даются бесплатно. Зачастую это лучше, чем библиотеки,
но, как и во всем, что связано с архитектурой программного обеспечения, есть свои
компромиссы и недостатки, такие как:
♦
критический уровень надежности: теперь сервис находится на критической
линии огня для своих потребителей и не может быть отключен, иначе это по
влияет на потребителей;
♦ в некоторых случаях производительность: пользователям необходимо обра
щаться к сервису, обмениваться данными с сервисом и осуществлять обмен дан
ными по сети в обе стороны, что в некоторых случаях может быть хуже, чем
в библиотеках.
Давайте разберемся с каждым недостатком более подробно.
Критический уровень надежности
В книге «В защиту библиотек» рассказывается об этом преимуществе внутренних
общих библиотек: когда вы предоставляете одну или несколько внутренних общих
библиотек бизнес-сервисам, эти библиотеки по своей природе встроены в сами
бизнес-сервисы. Для сравнения: сервисы более непосредственно влияют на надеж-
184
■
Глава 4
ность пользователей. Любая внугренняя общая библиотека должна быть надежной
и хорошо протестированной. Тот факт, что она оказывает меньшее влияние на на
дежность пользователя, не является оправданием. Но по сравнению с сервисами на
практике мы видели, что многим командам не удается напрямую отслеживать об
щие библиотеки, но большинство отслеживают сервисы и замечают, когда они не
работают!
В некоторых случаях производительность
Конечно, вызов сервиса сопряжен с дополнительными издержками по сравнению
с использованием внугренней общей библиотеки. Однако архитектурные приемы,
такие как пакетные операции, кеширование, предварительная загрузка, обработка
данных, асинхронная обработка и многие другие шаблоны, позволяют нам преодо
левать эти проблемы в большинстве случаев.
Давайте рассмотрим пример. Представьте, что у вас есть большой файл, который
вам нужно загрузить на конечную точку сети, и этот файл необходимо предвари
тельно обработать перед отправкой. Давайте сравним два подхода: использование
сервиса и внугренней общей библиотеки. В случае использования сервиса нам
нужно было бы отправить файл в сервис, где он выполнял бы обработку, выгружал
результаты, а затем загрузить обработанные результаты к себе. Во втором случае
библиотека могла бы взять файл, выполнить внугреннюю обработку и затем загру
зить результат.
Реализация библиотеки требует меньшего количества перемещений файлов, и если
узким местом является сеть, то при использовании библиотеки процесс должен ид
ти быстрее. Но что делать, если обработка файлов интенсивна и требует больших
ресурсов
-
процессора, памяти, диска, которых у вас нет локально? Что, если мы
описываем алгоритм машинного обучения
(machine learning, ML),
которому тре
буются сотни серверов, работающих согласованно? В таком случае сервис будет
работать быстрее.
Мы всегда можем спроектировать что-то по-другому. Например, представьте, что
мы меняем порядок операций на обратный; сначала мы загружаем файл, а затем
обработка происходит после загрузки на удаленной сетевой конечной точке; это
может снизить влияние на производительность. Однако, как бы то ни бьmо, мы
хотим, чтобы вы поняли нашу позицию: в одних случаях библиотеки работают эф
фективнее, в других- сервисы.
Сервисы являются удаленными по своей природе, а внутренние общие библиоте
- локальными и встроенными (рис. 4.1 О). Сервисы не обязательно являются
продуктом или бизнес-сервисами, они могут быть техническими или общими сер
висами, обеспечивающими сквозные или общие задачи для организации, такие как:
ки
♦
безопасность: аутентификация, авторизация, права доступа, шифрование;
♦ конфигурации: настройка кода, флаги функций, эксперименты;
♦ общие бизнес-возможности: профили пользователей, учетные записи пользова
телей, глобальные настройки и многие другие возможности, специфичные для
бизнеса, которые имеют сквозное значение.
Антипаттерны: внутренние общие библиотеки
■
185
Сервисы вместо внутренних общих библиотек
Ваш сервис
Сетевой ВЫЗОВ
Ваш сервис
Вызов метода
Драйвер
Контракт
Контракт
локальной сети
Реализация
Реализация
библиотеки
сервиса
Хранилище сервисов
Сервис вызывает другой сервис,
Вызов библиотеки внутри сервиса :
выполняет дополнительные сетевые
без сетевых запросов , но с бинарной связью ...
запросы , но не устанавливает
бинарную связь ...
Рис.
4.1 О.
Сервисы, вызывающие сервисы, вместо сервисов,
вызывающих внутренние общие библиотеки
Хотя мы считаем, что лучше использовать дополнительные сервисы, но вот не
сколько общих компромиссов.
Сервисы, вызывающие внутренние общие библиотеки:
♦
(+)
путь к надежности намного проще, библиотека не может быть «отключена»;
♦
(+)
вы можете получить некоторый прирост производительности за счет вызова
метода встроенной библиотеки;
♦
(-)
бинарная связь: сложность обслуживания, сложные миграции, постоянное
воздействие на потребителей;
♦
(-)
гораздо меньшая гибкость для владельцев библиотек и пользователей биб-
лиотек.
Сервисы, вызывающие сервисы:
♦
♦
(+) отсутствие бинарной связи:
(+)
лучше поддерживать и проще переносить;
гораздо больше гибкости: используйте и изменяйте все, что хотите, при
условии, что вы не нарушаете публичный контракт;
♦
(-)
необходимо управлять уровнем надежности; сервис может работать с пере
боями;
♦
(+/-)
в некоторых случаях может быть снижена производительность, но в других
случаях она может возрасти.
Создание и поддержка сервиса могут показаться сложной задачей. Нужно иметь
собственную кодовую базу и конвейер развертывания
Jenkins,
предоставить пуб
личный контракт, внутреннюю реализацию, добавить надлежащую наблюдаемость,
а также тестировать
и управлять
всем
процессом.
Библиотеки,
по-видимому,
требуют гораздо меньше усилий, и создание сервиса для двух-трех классов может
186
■
Глава 4
оказаться излишним. Если бы речь шла всего о двух-трех классах, вы бы тоже за
думались: вы уверены, что вам нужна библиотека? Действительно ли это полезно
для всей организации? Действительно ли код имеет смысл? Возможно, но необяза
тельно, и вам следует просто смириться с дублированием в разных сервисах.
Паперн
Sidecar
Sidecar - это
Sidecar -
ми.
нечто среднее между сервисами и внутренними общими библиотека
это фоновый, длительный процесс, выполняющийся вне вашего про
граммного обеспечения. Можно рассматривать
Sidecar как особую форму сервиса.
Sidecar - это новая модель, но основная идея, лежащая
в ее основе, довольно старая. В Unix/Linux эта концепция называется Daemon 12 .
Daemon - это служебный процесс, который выполняется в фоновом режиме и
Вы можете подумать, что
предоставляет функциональность другому процессу, т. е. самой операционной сис
теме.
Каждый
Daemon (Sidecar)
в
Linux
имеет свое уникальное назначение. Вот несколь
ко примеров:
♦
Daemon
печати: отслеживает печать и заботится о ней;
♦
сетевой
Daemon:
♦
Daemon Cron:
управляет сетевым стеком;
известная служба запланированных заданий, широко используе
мая во многих программных решениях;
♦
распространенные приложения:
каться как
Docker, OpenVPN
и
Redis
также могут запус-
Daemon.
Daemon являются неотъемлемой частью операционных систем Unix/Linux. Управ
Daemon осуществляется активно; вы можете перечислить всех своих
Daemon, выполнив следующую команду в DeЬian Linux: service --status-all, полу
чив пример вывода, как показано на рис. 4.11.
ление
Daemon
в
Unix/Linux
присутствуют повсюду. Это не разовый шаблон, это неотъем
лемая часть операционной системы. То, что достаточно хорошо для
Linux,
безус
ловно, достаточно хорошо и для нашего собственного программного обеспечения!
Современный
Sidecar
Как видно из нашего примера с
Daemon,
современный шаблон
Sidecar -
это когда
вы запускаете другое приложение параллельно с вашим приложением.
требуют какой-либо конкретной технологии или стека. Например, у
несколько
Sidecar,
для
написанных на
Java, таких
Sidecar не
Nettlix есть
как:
♦
Priam
♦
Dynomite Manager для Dynomite (https://github.com/Netflix/dynomite-manager);
♦
Raigad для ElasticSearch (https://github.com/Netflix/Raigad).
Cassandra (https://github.com/Netflix/Priam);
12 На странице руководства по Liпux более подробно описаны Daemon:
https://man 7.oгg/lin ux/man-pages/ma n7/daemon. 7.html.
Антипаттерны: внутренние общие библиотеки
■
187
> service --status-all
acpid
+
alsa-utils
апасгоп
+
apparmor
apport
atop
atopacct
avahi-daemon
+
+
Ыuetooth
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
?
+
+
+
Ьinfmt-support
cgroupfs-mount
ciscod
console-setup.sh
cron
cups
cups-browsed
dbus
dns-clean
docker
gdrnЗ
grub-cornmon
hddtemp
hwclock.sh
irqbalance
kerneloops
keyboard-setup.sh
kmod
lm-sensors
logmein-hamachi
networking
openvpn
plymouth
plyrnouth-log
procps
pulseaudio-enaЫe-autospawn
+
+
+
+
+
redis-server
rsync
saned
speech-dispatcher
spice-vdagent
sssd
udev
ufw
unattended-upgrades
uuidd
vpnagentd
warsaw
whoopsie
xll-common
Рис.
Эти примеры
Sidecar от Nettlix
4.11.
Список
Daemon
в
Linux
представляют собой Jаvа-приложения, которые пре
доставляют общие возможности для баз данных
NoSQL,
такие как резервное копи
рование, восстановление, управление кластерами и многое другое. В случае ис
пользования
Netflix Sidecar
запускаются на компьютерах ЕС2 в А WS вместе с про
граммным обеспечением для работы с базами данных, точно так же как
Daemon
188
■
Глава 4
в Linux запускаются в
Linux. Принцип тот же.
Например,
пользовательском
пространстве операционной системы
находит применение не только в базах данных. Вот несколько
Sidecar
примеров его использования в бизнесе.
♦ Безопасность: сертификаты,
mTLS,
аутентификация, авторизация, права досту-
па, шифрование.
♦ Конфигурации: конфигурация, флаги функций, эксперименты.
♦
Наблюдаемость: журналы, метрики, оповещения и маршрутизация данных.
♦
Некоторые варианты использования в вашем бизнесе, в которых вы могли бы
применять библиотеки.
Sidecar обладают рядом
♦
преимуществ, таких как:
Отсутствие бинарной связи. Подобно сервисам, поскольку
Sidecar
представ
ляют собой разные приложения, они не могут конфликтовать с библиотеками
ваших приложений;
♦ Миграция упрощается. Поскольку вам не нужно прикасаться к своему прило
жению/сервисам;
♦ Прозрачность. Часто потребителям не нужно напрямую управлять своими
Sidecar.
Однако у
Sidecar,
как и у других решений в программной архитектуре, есть свои
недостатки. Давайте разберемся в минусах современных
♦
Обеспечение надежности. В некоторых случаях
Sidecar.
Sidecar
должны работать не
прерывно, в противном случае они могут привести к сбоям в работе, например
к шифрованию личных данных. В других системах, таких как
Sidecar,
если
Prime
выйдет из строя после загрузки
Netflix Priam
Cassandra, Cassandra продол
жит функционировать, хотя и потеряет часть возможностей.
♦
Развертывание. Развертывание
Sidecar
требует изменений в инфраструктуре,
которые можно сделать стандартным способом, но это все равно работа.
упрощает развертывание Sidесаr,.используя всего несколько строк
♦
Сложность.
SIDECAR
K8s
YAML.
более сложны, чем внутренние общие библиотеки, и их
отладка может быть сложнее, чем отладка библиотек или даже сервисов.
Sidecar Netflix -
самое современное решение. Они прозрачны, и даже если не
работают, это не обязательно приводит к сбою в работе соответствующей базы
данных
NoSQL (Cassandra, Dynomite
или
Elasticsearch). Sidecar Netflix
также не
требуют специальных клиентов/драйверов. Удивительно, но они работают как на
стоящие прозрачные
знать! Однако не все
Daemon, о которых некоторым пользователям даже не
Sidecar созданы одинаково, и у некоторых могут быть
нужно
клиен
ты/драйверы. Вот на что вам нужно обратить особое внимание. Если драйвер
Sidecar недостаточно
прост, у вас возникнут те же проблемы, что и с библиотеками,
но с гораздо более сложной нагрузкой.
Антипаттерны: внутренние общие библиотеки
Sidecar
■
189
и прокси
Прокси-сервер Envoy 13 также является важным дополнением и отличным инстру
ментом для создания сетевых архитектур сервисов.
Распределенные системы сталкиваются со многими проблемами, особенно в мас
штабе.
Envoy
фокусируется на решении проблем сетевого взаимодействия, безо
пасности и наблюдаемости в распределенных коммуникационных системах. При
развертывании
Envoy весь трафик передается через Envoy. Envoy был разработан
Lyft на С++ на основе опыта использования прокси-серверов и решений
балансировки нагрузки, таких как Nginx, НАРrоху и аппаратных балансиров
компанией
для
щиков нагрузки.
Ключевыми особенностями
♦ шаблон
Sidecar:
Envoy являются:
архитектура «вне процесса», которая может работать с любым
языком или приложением;
♦ высокая производительность и малый объем памяти;
♦ расширенная балансировка нагрузки: автоматические повторные попытки, ав
томатические выключатели, глобальное ограничение скорости, отслеживание
запросов, балансировщик локальной нагрузки в зоне;
♦ поддержка протоколов НТТР/2 и
gRPC
как для входящих, так и для исходящих
подключений, прозрачное проксирование НТТР
протоколу
TLS,
♦ расширенные
1.1/2,
завершение работы по
проверка работоспособности и поддержка
API для динамического управления
Edge;
конфигурацией;
♦ расширенная наблюдаемость: полная проверка трафика
L7,
встроенная под
держка распределенной трассировки, возможность наблюдения за несколькими
базами данных на низком уровне.
Sidecar, прошедшй испытания во многих компа
ниях Кремниевой долины, таких как Lyft, Google, Netflix, Airbnb, еВау, Microsoft,
Stripe, Pinterest, Twilio, Salesforce, А WS и многих других. Вы можете настроить
Envoy в различных сетевых топологиях, таких как внутренние балансировщики на
Envoy -
это хорошо известный
грузки, входящие или исходящие прокси-серверы на границе сети, а также много
уровневые топологии для обеспечения масштабируемости и надежности.
На рис.
4.12
вы можете видеть, что сервисы не связываются друг с другом напря
мую. Например, Сервис А хочет отправить запрос в Сервис В. Сервис А связывает
ся со своим локальным экземпляром
Сервиса А связывается с
Envoy
Envoy,
развернутым по схеме
Sidecar; Envoy
Сервиса В, который передает запрос в Сервис В.
Envoy также может использоваться совместно со сервисом mesh Istio 14 .
В отличие от внутренних общих библиотек,
бинарной связи с приложением/сервисом.
Sidecar хороши тем, что не создают
Sidecar предоставляют возможности, ко-
13
Envoy можно найти по адресу https://www.envoyproxy.io/.
14
bttps://istio.io/latest/, и см. главу I «Что не так с монолитами?))
190
■
Глава 4
торые могут быть прямыми или прозрачными; в случае
Envoy -
Envoy
в своих решениях.
,,,._____
-1/ @);;;,, ,
'---
/-
\
/
Сервис С
'\_
~envoy
модель
/
/
,___
/
4.12. Envoy,
l
/
/
\
~
Сервис В
Сервис А
Рис.
они прозрачны.
это отличное решение и опция, которую вам следует изучить и учитывать
,r
/
"'
Сервис
'i.
D
.1
~envoy
/
j/
Sidecar для обеспечения сетевого взаимодействия/наблюдаемости
https://www.envoyproxy.io/docs/envoy/latest/intro/life_of_a_request
между сервисами. Источник:
Как вы можете видеть,
Sidecar, тогда
Ribbon
для Netflix (https://github.com/Netflix/ribbon), использующий Java, и Finagle
(https://twitter.github.io/finagle/) для Twitter, написанный на Scala, используют
Envoy
решает проблемы с помощью шаблона
как другие подходы часто решают те же проблемы с помощью библиотек. И
библиотеки для достижения схожих целей.
Использование шаблона
Sidecar,
который, следовательно, находится за пределами
двоичного пути к приложениям/сервисам, позволяет
Envoy
не зависеть от языка
программирования и работать с широким спектром языков. Это существенное пре
имущество
Sidecar
и
Sidecar перед общими
библиотеками, внутренними или внешними.
Kubernetes
Kubemetes (https://kubernetes.io/, он же k8s) K8s занимается
с открытым исходным кодом.
это контейнерный инструментарий
автоматизацией развертывания, мас
штабированием и управлением контейнеризованными приложениями. Kнbernetes
был создан
Google
с использованием тех же принципов, которые на протяжении
многих лет позволяли
Google
масштабировать рабочие нагрузки в контейнерах.
можно запускать где угодно: в обычных облаках, таких как А WS и
GCP,
K8s
локально и
даже на периферии.
В
♦
Kubernetes
Автоматические откаты и развертывания. Если что-то пойдет не так,
netes
♦
есть множество функций и возможностей, таких как:
Kuber-
может автоматически отменить изменения.
Обнаружение сервисов и балансировка нагрузки. Модули
k8s, каждый из которых может
K8s может распределять нагрузку
-
это модуль раз
вертывания
иметь свой собственный IР-адрес и
DNS-имя.
между объектами.
Антипаттерны: внутренние общие библиотеки
■
191
♦ Самовосстановление. Перезапускайте контейнеры, которые выходят из строя,
заменяйте и перепланируйте контейнеры при отказе узла, отключайте контейне
ры, которые не отвечают, и избегайте рекламы контейнеров потребителям до
того, как они будут готовы к вызову, используя тесты готовности.
♦
Управление хранилищем. Автоматическое подключение системы хранения,
поддерживается множество решений для хранения, таких как локальное, облач
ное хранилище,
♦
NFS, Ceph
и
Cinder.
Управление секретами и конфигурацией. Развертывание и обновление секре
тов и конфигурации приложений без перестройки образов контейнеров;
♦ Автоматическая упаковка контейнеров. Размещайте контейнеры в соответст
вии с потребностями в ресурсах и другими ограничениями и требованиями, не
жертвуя при этом доступностью. Вы можете сочетать критические рабочие
нагрузки с нагрузками, требующими максимальных усилий, для оптимального
использования и экономии еще большего количества ресурсов.
♦
Пакетное выполнение.
но и
рабочими нагрузками
Kubemetes может управлять не только сервисами,
CI/CD и пакетными рабочими нагрузками, заменяя
кон
тейнеры в случае их сбоя.
♦
масштабирование. Масштабируйте по вертикали, горизонтали; масштабируйте
блоки, заметки, весь кластер; используйте простые команды, пользовательский
интерфейс или автоматически масштабируйте на основе стандартных показате
лей, таких как
CPU
или пользовательские показатели.
♦ Дизайн с учетом расширяемости. Добавляйте функции, не затрагивая приложения/сервисы.
Kubemetes хорошо зарекомендовал себя, присоединившись в 2016 году к Cloud
Native Computing Foundation (CNCF) https://www.cncf.io/projects/kubernetes/.
Kubemetes используется многими компаниями, такими как Вох, Capita!One,
Booking.com, The New York Times, Nokia, Pinterest, Sling, Spotify, Zalando, OpenAI,
ING, Викимедиа, Yahoo Japan, Pearson, IВМ, Buffer, Bose, BlackRock, Adidas,
Walmart, Airbnb, Yelp, Reddit, Tinder, Intuit, Slack, Zendesk, NuBank, Vodafone,
Ericsson, T-MoЬile, Comcast, Bloomberg и многими другими по всему миру.
Kubemetes
обладает многими преимуществами, но одно из самых важных заключа
ется в том, что он, по сути, предоставляет спецификацию для облачных вычисле
ний
(cloud computing),
обеспечивая в некоторой степени переносимость между об
лачными провайдерами и предоставляя широкую экосистему решений с открытым
исходным кодом, готовых к развертыванию на нем. С помощью
очень легко создавать и развертывать
Sidecar.
В частности, в
Kubemetes можно
Kubernetes есть декла
ративный формат файла У AML для описания желаемого состояния кластера и при
ложений.
Листинг
4.1.
Спецификация развертывания
для двух контейнеров, один из них
1. apiVersion: apps/vl
2. kind: Deployment
Sidecar
Kubernetes
на
YAML
192
■
Глава 4
3. metadata:
name: profile-service-deployment
4.
labels:
5.
арр: profile-service
6.
7. spec:
replicas: 1
8.
selector:
9.
matchLabels:
10.
арр: profile-service
11.
12. template:
metadata:
13.
labels:
14.
арр: profile-service
15.
spec:
16.
containers:
17.
- name: profile-service
18.
image: profileservice:2.0.5
19.
ports:
20.
- containerPort: 8080
21.
- name: security-sidecar
22.
image: security-sidecar:1.0.1
23.
ports:
24.
- containerPort: 9090
25.
Давайте разберемся с инструкциями в листинге
4.1.
В
Kubemetes Pod
является
стандартной единицей развертывания; вы можете развернуть несколько контейне
ров в одном
развертываются на узлах; кластеры содержат несколько узлов.
Pod. Pod
На предоставленном нами примере развертывания вы можете видеть, что мы раз
(Profile Service), но также в том же Pod
Security Sidecar. Возможно, Security Sidecar
протоколами mTLS, шифрованием или любыми други
вертываем контейнер с сервисом профилей
мы развертываем
Sidecar под
занимается сертификатами,
названием
ми проблемами безопасности.
Kubemetes
Sidecar, потому что с помо
Sidecar практически бесплат
действительно удобен для использования с
щью пары строк в У АМL-файле мы можем получать
но; благодаря
Kubemetes
нам не нужно вносить никаких особых изменений в нашу
инфраструктуру развертывания. Если бы мы создавали
Sidecar в ЕС2,
то, возможно,
нам пришлось бы самим решать все проблемы с развертыванием.
Kubemetes
позволяет добавлять несколько контейнеров в один и тот же
практике у нас может быть более одной
Sidecar
Pod.
На
рядом с нашим приложением/
сервисом. Такая конфигурируемость действительно великолепна, поскольку позво
ляет нам создавать модульные
решения, как
На рис.
4.13
Envoy,
Sidecar вместо монолитных и
Sidecar вашей компании.
комбинировать такие
с внутренними
описана архитектура кластера
вертывания. В самом
Kubemetes
Kubemetes
с применением нашего раз
есть уровень управления, где он выполняет управ
ление кластером совместно с АРl-сервером
kube,
планированием кластера, который
Антипаттерны: внутренние общие библиотеки
■
193
управляет состоянием, контроллером-диспетчером и т. д. для конфигураций. Уро
вень управления
Kubemetes
взаимодействует с рабочими узлами через
Kubelet
на
каждом узле. Внутри узлов на уровне данных у нас также есть прокси-сервер и
контейнерная среда выполнения, которая может быть
нерной средой выполнения. Внутри рабочих узлов
Docker или другой контей
(обозначенных синим прямо
угольником) у нас есть
рассматривать
по шаблону
Архитектура
Kubelet
Sidecar, но
Pod; внутри Pod находятся наши контейнеры. Мы можем
Sidecar. Таким образом, Kubemetes не только построен
и позволяет легко развертывать Sidecar.
как
Node
Kubernetes с Sidecar
11 Графический UI 1
1Kиbectl
1Сервис профилей 1 1 Контейнер
~✓
1АРl-сервер
~ 1Security Sidecar
1 Контейнер
1
POD
POD
1
1Ппанировщик
1
1Контейнер
o etcd
.., ,
Панель уГl)авления
Рис.
шаблон
4.13. Envoy,
11 Kиbekt 1
~
Node
1
1 Управляющий
1 1прокtц 1
Sidecar для
1
Контейнер
POD
1
1 Контейнер
1 Контейнер
POD
1 1nроксц 1
11 Kиbelef 1
~
обеспечения сетевого взаимодействия/наблюдаемости
между сервисами
Как можно построить
Прелесть шаблона
Sidecar?
Sidecar в том,
Типы
Sidecar
что мы можем создавать
Sidecar,
используя любую
технологию. Это позволяет нам использовать такие мощные языки, как С++,
V lang
или
Sidecar
Rust,
Zig.
необязательно требуют системных языков программирования и могут быть
созданы с использованием языков высокого уровня, таких как
или даже
Python.
Java, Scala, Kotlin
Однако мы хотим заметить, что, имея бинарную свободу, вы не
обязаны использовать тот же язык, который используется вашими микросерви
сами/сервисами.
При создании собственной внутренней платформы
Sidecar
анты использования. Давайте определим два типа систем
важно учитывать вари
Sidecar.
Первый тип
-
прозрачные, такие как прокси-сервер или вспомогательный сервер базы данных.
Второй тип
-
клиент-серверные, например в нашем случае с шифрованием лич
ных данных (рис.
Sidecar
4.14).
В зависимости от стиля архитектуры клиент-серверной
вам может понадобиться драйвер. Здесь важно быть осторожным, потому
194
■
Глава 4
что можно потерять большую часть преимуществ от шаблона
Sidecar,
поскольку
драйвер представляет собой просто внутреннюю общую библиотеку и, следова
тельно, имеет двоичную связь. Следите за своими зависимостями!
EJB
Узел
K8s
Сервис
Узел
или компьютер ЕС2
K8s
или компьютер ЕС2
Сервисы не взаимодействуют
Сервис напрямую вызывает
напрямую с
Sidecar.
Sidecar.
(А) Прозрачный
(В) Клиент-серверный
Sidecar
Рис.
4.14.
Типы
Sidecar
Sidecar
Прозрачный
Прозрачный
Sidecar
Sidecar - это
наиболее желаемая и идеальная форма шаблона
Sidecar.
Мы называем ее прозрачной, потому что сервисный/бизнес-код не выполняет ника
ких явных вызовов
Sidecar
и между
Sidecar и сервисами нет бинарной
Netflix Dynomite Manager.
связи. Это
относится и к прокси-серверам, таким как
Клиент-серверный
Sidecar
Для использования клиент-серверных
Sidecar (Client/Server sidecars)
сервису необ
ходимо использовать драйвер. Из бизнес-кода в сервисе будет один или несколько
явных прямых вызовов к драйверу
Sidecar,
как в наших предыдущих примерах для
шифрования личных данных.
Предположим, мы выполняем все операции шифрования в
Sidecar.
Следовательно,
сервису не требуется доступ к материалам ключа. Приложению/сервису необходи
мо вызвать драйвер, чтобы выполнить операции шифрования и дешифрования. Это
нельзя сделать прозрачно.
Все риски связаны с драйверами
Sidecar.
Если драйвер является экономичным и
имеет меньше зависимостей, то все в порядке. Для клиент-серверных
Sidecar
учи
тывайте следующие ограничения и недостатки.
♦
Могут потребоваться драйверы. Возможно, потребуется написать драйверы
для нескольких языков.
♦
Уровень надежности.
Sidecar
должна быть всегда в рабочем состоянии, в про
тивном случае это повлияет на уровень надежности сервиса.
♦
Сложность. Некоторая дополнительная
сложность, аналогичная сервисному
подходу. Возможно, вы все же сможете выполнить некоторые оптимизации,
Антипаттерны: внутренние общие библиотеки
■
195
но это будет не так эффективно, как вызов методов из внутренней общей биб
лиотеки.
Сетки сервисов
Сетка сервисов
это еще одна альтернатива внутренним общим
(Service Mesh) -
библиотекам. Наиболее известной из них является
Sitio.
Архитектура сетки серви
сов переносит сложность и абстракции распределенной системы на уровень инфра
структуры, например
Шаблон сетки сервисов решает такие проблемы,
Kubernetes.
как безопасность, наблюдаемость и сетевое взаимодействие, которые часто реша
ются с помощью внутренних общих библиотек (рис.
Сертификаты
4.15).
Сертификаты
конфигурации
конфигурации
обнаружения
обнаружения
метрики
метрики
После использования
Рис.
4.15.
lstio
Архитектура сетки сервисов
lstio
Сетки сервисов также могут решать те же задачи, что и
K8s,
такие как А/В-тес
тирование, обнаружение, балансировка нагрузки, развертывание саnаrу-релиза, ог
раничение скорости, контроль доступа, шифрование и аутентификация Е2Е.
Istio
использует Envoy. lstio используется такими компаниями, как AutoTrader, Airbnb,
Splunk, Salesforce, Rappi, T-MoЬile, еВау, Atlassian, HSBC, HelloFresh, Gov.UK,
Lowe's, Postman, SAP, Under Armour, Trulia и многими другими.
В
Istio
также есть уровень управления и уровень данных. В плане данных
пользует
Envoy.
Istio
ис
Как и в любой архитектуре программного обеспечения, здесь есть
свои недостатки:
♦
отсутствие поддержки асинхронных шаблонов:
практически
все сводится
к синхронным вызовам, поддерживаются только автоматические выключатели и
повторные попытки;
196
■
Глава 4
♦ накладные расходы: чем больше уровней мы накладываем на инфраструкrуру,
тем больше переходов, следовательно, теряем производительность и усложняем
систему. Однако со временем
Istio
улучшает свою внутреннюю производитель
ность.
Простые альтернативы
Простые альтернативы применимы не для всех возможных вариантов использова
ния. В некоторых случаях эти подходы могут сработать, но вряд ли они стануr
лучшим выбором, например для сервисов или экономичных библиотек. Тем не
менее такие тактические возможности необходимо учитывать. При этом ваше
обоснование должно быть таким же, как и при любом компромиссе в архитектуре,
дизайне и коде. Что вы получаете, но каковы болевые точки?
Вот несколько простых альтернатив для рассмотрения (рис.
Использовать
SDK
Рис.
4.16.
4.16).
Сделать
Скопировать
Поправить открытый
самостоятельно
и вставить
ИСХОДНЫЙ КОД
Простые альтернативы для внутренних общих библиотек
Использовать существующие пакеты
SDK
и библиотеки
Возможно, вы удивитесь, насколько полезными могут быть уже имеющиеся у вас
инструменты. В
Java Development Kit
(ШК) есть множество функций для повсе
дневных нужд. Конечно, это может быть не самый крутой или современный под
ход. Но может ли этого быть достаточно для вашего случая? Иногда решением
может быть создание простой и подходящей утилиты или класса-обёртки поверх
существующего
JDK,
чтобы добавить необходимое поведение.
Аналогично с библиотеками с открытым исходным кодом, которые вы уже исполь
зуете в своем classpath. Почему бы не использовать то, что у вас уже есть? Часто
мы замечаем, как разработчики добавляют библиотеки из личных предпочтений
или любопытства, даже если они не особо важны для вашего случая или дают не
существенные преимущества. Нередко можно увидеть
Jackson, Gson
и
json-simple
в одном проекте. Зачем нам нужны три разные библиотеки для синтаксического
анализа
JSON?
Сделать это самостоятельно
Иногда то, что вам нужно, не так уж и сложно. Это может быть простой алгоритм,
который меняется не так часто, возможно, несколько строк кода или пара файлов.
Почему бы просто не написать его самому и не использовать еще одну библиотеку?
Если вы придерживаетесь такого подхода, всегда старайтесь быть как можно более
минималистичным, особенно при создании внутренних общих библиотек.
Антипаттерны: внутренние общие библиотеки
■
197
Разработка чего-то самостоятельно может показаться пугающим и неправильным
решением. Оrбросьте скептицизм, проанализируйте компромиссы и свои потреб
ности в библиотеке. Хорошо, если вы используете
80 %
функций данной библиоте
ки. Но включать библиотеку, полную сложных зависимостей, когда вам нужен
только один метод
-
действительно ли оно того стоит? Взвесьте все за и против,
чтобы принять правильное решение.
Скопировать и вставить код
Другим тактическим подходом может быть простое копирование и вставка
and paste)
(сору
нужного вам кода из библиотеки с открытым исходным кодом. Иногда он
достаточно изолирован и переносим, вы можете легко скопировать пару классов и
добавить их в свое решение. Конечно, при соблюдении всех лицензий и кредитов!
Если код не изолирован на
факторинг и извлечь код
-
100 %,
возможно, вам удастся провести некоторый ре
даже частичного повторного использования может
быть достаточно.
Внести свой вклад в работу с открытым исходным кодом
В конечном счете вы могли бы помочь сообществу разработчиков с открытым
исходным кодом в создании лучшей библиотеки. Такой, которая поддерживается,
использует мало других зависимостей или вообще не использует их и помогает ре
шать реальные задачи как вам, так и другим.
Правильная конструкция библиотеки
Давайте рассмотрим некоторые ключевые идеи, которые следует учитывать при
разработке подходящей библиотеки.
Дублирование против повторного использования
Большинство людей придерживаются мнения, что повторное использование
всегда хорошо, а дублирование
-
версальная истина; напротив, она имеет ряд спорных моментов (рис.
самом деле иногда дублирование
-
это
это всегда плохо. Мы не считаем, что это уни
-
4.17).
это хорошо, а повторное использование
На
-
плохо! Нам нужно определить, что является хорошим дублированием, а что плохим
повторным использованием.
Дублирование
Рис.
4.17.
Повторное использование
Спектр компромиссов между дублированием и повторным использованием
Плохое дублирование: бизнес-код
Бизнес-код
-
это элементарно: не дублируйте его. Любой код, который определяет
повседневные бизнес-решения вашей компании, является хорошим кандидатом для
198
■
Глава 4
рисков дублирования. В идеале у вас не должно быть внутренних общих библиотек
с бизнес-кодом, только сервисы. Худший аспект дублирования
-
это ошибки. Вы
же не хотите исправлять одну и ту же ошибку бизнес-логики в более чем
100
сер
висах. Отсутствие централизации бизнес-правил может иметь серьезные последст
вия и напрямую влиять на прибыль и репутацию компании.
Плохое дублирование: выполнение
Когда вашей компании необходимо соблюдать отраслевые нормативы или гаранти
ровать информационную безопасность, дублирование является опасным и, следо
вательно, нежелательным. Однако не все варианты использования
и сценарии
основаны на соблюдении требований.
Естественным решением было бы использование сервисов. Они позволили бы нам
иметь решение в одном месте и не дублировать код. Библиотеки могут обеспечить
те же преимущества, однако, как мы пишем в этой главе, у библиотек есть много
подводных камней и проблем, таких как бинарная связь.
Хорошее дублирование: миграция
Дублирующийся код изолирован. Дублирующийся код можно использовать как
инструмент для уменьшения радиуса действия
API.
Представьте, что у вас есть три
разных сервиса, использующих одну и ту же внутреннюю общую библиотеку. Если
вы хотите закрыть библиотеку, вам нужно перенести три проекта на новое реше
ние. Но что, если один сервис также будет выведен из эксплуатации в ближайшее
время, через
6 месяцев?
Перенос всех трех проектов выглядит как расточительство,
и это действительно так. Вместо этого вы можете сократить радиус распростране
ния, скопировав части кода библиотеки непосредственно в выводимый из эксплуа
тации сервис. Вы устраняете неполадки, увеличивая дублирование и сокращая об
щие затраты на миграцию.
Повторюсь: дублирование
-
это зло, когда мы говорим о бизнес-коде, бизнес
правилах или даже коде сохранения для распределенного монолита. Лучшее, что
вы можете сделать,
-
это не создавать распределенный монолит, не разделяя хра
нилища данных и не используя сервисы. Однако, если по какой-то причине у вас
уже есть распределенный монолит и общая библиотека доступа к данным, все рав
но лучше использовать ее в этом наихудшем случае. Лучше иметь один централи
зованный репозиторий, а не несколько репозиториев кода, дублирующих сохраняе
мый КОД.
Хорошее дублирование: конфигурация и код установки
Проблема не в нажатии клавиш, а в быстром вводе текста. В какой-то момент
функция может перестать работать, но пока существует часть программного обес
печения, обслуживание в виде миграции может длиться вечно. Зачем оптимизиро
вать работу на короткий срок вместо оптимизации для долгосрочной миграции?
Можно дублировать конфигурацию или стандартный код, если мы не касаемся
бизнес-правил или бизнес-кода. Если вам нужно написать
1О
строк кода для от-
Антипаттерны: внутренние общие библиотеки
правки электронного письма на
Java,
■
199
естественно было бы создать библиотеку, ко
торая сократила бы его до одной строки. Если ваши
1О
строк являются просто шаб
лонными, так ли это важно, чтобы рисковать бинарной связью? Было бы неплохо
продублировать такой код во всех ваших сервисах.
Дублирование кода здесь подразумевает меньшее количество повторных использо
ваний, но на самом деле происходит следующее:
♦
смена владельца: поскольку код находится в сервисе, и команде обслуживания
необходимо его поддерживать;
♦
упрощение миrрации: наличие нескольких внутренних общих библиотек по
зволяет нам выполнять несколько миграций параллельно, без централизованного
«узкого места».
Давайте будем честны.
Какова вероятность того, что вы обнаружите ошибку
в стандартном коде? Хорошая новость заключается в том, что, если вы ошибаетесь,
вы можете создать библиотеку позже; вам не нужно начинать с библиотеки. Но как
только вы создаете библиотеку и у вас появляются сотни или тысячи потребителей,
вам уже не так-то просто загнать джинна обратно в бутылку.
Повторное использование: палка о двух концах
Инженеры бывают одержимы идеей повторного использования. Повторное исполь
зование часто переоценивается и может принести больше проблем, чем пользы,
если оно выполнено неправильно. Повторное использование не всегда полезно и
особенно сложно, когда речь идет о внутренних общих библиотеках вашей компа
нии. Также у повторного использования есть следующие недостатки:
♦
отсутствие контроля: вы можете не контролировать направление и приоритеты
команды, которая разрабатывает программное обеспечение;
♦ отсутствие решения: у вас может быть недостаточно влияния на дизайнерские
решения и направление;
♦ бинарная связь и раздутые зависимости: вы не можете управлять зависимо
стями сторонних разработчиков в этих библиотеках, что приводит к бинарной
связи;
♦ ошибки: ваши ошибки могут не быть приоритетными, а
PR
могут не прини-
маться;
♦ связь: вы создаете связь, используя любую библиотеку.
При повторном использовании кода вы получаете удовлетворение от работы:
♦ экономите время: вы становитесь более продуктивным, выполняете больше
задач;
♦ добиваетесь большеrо с меньшими затратами: не надо беспокоиться, кто
нибудь решит проблему за вас;
♦ ускоряете процесс разработки: теперь вы сможете получать в
1О
раз больше
задач и проектов;
♦ фокусируетесь на бизнесе: появляется время для других важных дел.
200
■
Глава 4
Однако подобное может быть верно не во всех случаях. Если программное обеспе
чение активно не поддерживается и не имеет хорошей репутации, у вас могут воз
никнуть проблемы с повторным использованием внутренних общих библиотек.
В контексте распределенных монолитов необходимо учитывать бинарную связь
в уравнении.
Все дело в дисциплине. Если у вас есть небольшой набор внутренних общих биб
лиотек, которые активно поддерживаются в рабочем состоянии, а потребители
(сервисы и библиотеки) всегда в курсе последних событий, то ваши внутренние
библиотеки хороши. Все зависит от качества вашего внутреннего стека и уровня
накопленной технической задолженности, а также от того, имеется ли у вас распре
деленный монолит
-
большой или маленький.
Повторное использование имеет свои плюсы и минусы (рис.
4.18).
Не принимайте
это как должное. Чем чаще вы используете код повторно, тем больше у вас будет
миграций. Миграции часто требуют от команд сервисов специальной обработки и
тестирования. Внутренние общие библиотеки в некоторых случаях могут быть по
лезны. Но важно всегда анализировать
-
смотреть на код и осознанно принимать
решения.
Внутренние общие библиотеки . Повторное использование : плюсы/минусы
Сервис профилей
Сервис продаж
Общая
библиотека
лоm1рования
Не контролируете :
Можете получить :
• приоритеты;
• архитектуру/дизайн ;
• зависимость от сторонних разрабо~иков;
• бинарную связь .
• производительность ;
• некоторое время ;
• срезанные углы ;
• исправление ошибок.
Рис.
4.18.
Компромиссы при повторном использовании
Самый простой и понятный способ избежать бинарной связи
-
использовать как
можно меньше внутренних общих библиотек. Это позволяет вам проявлять гиб
кость, а также оперативно реагировать на изменения в бизнесе.
Грамотное управление зависимостями
Правило номер один, которое нужно запомнить: библиотеки, используемые в рам
ках изолированной структуры, такой как сервис, обычно более стабильны. В них
меньше подводных камней и шансов, что что-то пойдет не так. Однако особое вни-
■
Антипаттерны: внутренние общие библиотеки
201
мание стоит уделить библиотекам, которые используются другими внутренними
общими библиотеками. Далее дадим несколько советов для управления зависимо
стями. Аналогичные рекомендации можно применить к сервисам, Sidecar или лю
бому другому приложению, в котором вам нужно добавить зависимости.
Сливки зависимостей
Ранее в этой главе мы рассказывали о подводных камнях, связанных с раздутыми
библиотеками. Решение проблемы работы с библиотеками простое: избегайте ис
пользования ненужных библиотек. Будьте точны и выбирайте только самое необ
ходимое.
Часто люди копируют pom.xml из работающего сервиса или библиотеки, даже не за
думываясь о необходимости добавлять новые зависимости. Это может показаться
странным, но такой подход довольно распространен. Итак, правило №
1:
не прини
майте библиотеки как должное. И пока вы выбираете только самые необходимые
библиотеки, убедитесь, что понимаете, какие зависимости эти библиотеки привне
сут в ваш
classpath.
Если вы используете
Apache Maven,
то можете запустить простую команду в своем
терминале, чтобы увидеть полный график зависимостей вашего проекта. В
тоже есть такая функция. Запустите команду, как показано в листинге
Gradle
4.2.
для составления списка всех зависимостей
Листинr 4.2. Команда
1. mvn dependency:tree
Эта команда основана на плагине зависимостей Maven 15 , и вы увидите результат,
показанный на рис.
Другим
полезным
4.19.
ресурсом
для
понимания
зависимостей
является
веб-сайт
mvnrepository: http://mvnrepository.com/, на котором есть вся эта информация и
многое другое (рис. 4.20). Вы можете найти фрагмент XML, добавляющий зависи
мость Maven в вашем pom.xml для любых зависимостей от транзитивности, компи
ляции или среды выполнения.
Веб-сайт
mvnrepository -
отличный ресурс для Jаvа-инженеров, который мы ис
пользуем почти ежедневно. Рекомендуем вам уделить некоторое время на его изу
чение. Это особенно полезно для анализа библиотек с открытым исходным кодом.
Прежде чем добавлять их в свой проект, можно изучить зависимости и выбрать
оптимальные варианты.
Конечно, если у вас есть общие внутренние библиотеки, они не будут отображаться
в дереве зависимостей. Вам нужно будет загрузить исходный код библиотеки и за
пустить mvn dependency:tree или использовать плагин
IDEA плагин maven-helper
16
IDE.
Для пользователей
позволяет выполнять поиск в вашем
pom.xml
IntelliJ
файле
15
Плагин зависимостей Maven: https://maven.apache.org/plugins/maven-dependency-plugin/index.html.
16
Вспомогательный плагин IntelliJ IDEA Maven: https://plugins.jetbrains.com/plugin/7179-maven-helper.
202
■
Глава 4
Рис.
4.19.
Результат выполнения команды
mvn dependency: tree,
выведенный на терминал
• <•
crl3REPOSIТORY
._,,.,..,__,. ,__
G
-
Gu•v•: Goog~ Core Lltи-art•• For J•v• • 31. 1,jre
0.-..••-olQOoW.,..J~i,c,,~hl~\Ulfr<-Ш,..,
М#59Ц.-i
.....,_
-~-
...
iW ,
--
LofOr,of-•
"""'""-
-------~·---
-01 ,юа
po,,o(IOJ.8,
\l,,,l\dle(J.IН8;
V-"11
1С11111
JJ,J&I
artlfкt8
~ ...0,.-,й~.~~..1..i,.,,.,.~l
~.!1!1.д....\:!"118:.!!'
~.J..
i~! •· ~ttp1 ,1 f11vnr1po1i tary . coiit,,.t1 f•ct/c01J.9009\e.9111v1/~•v•
<~(у..
,qirowlO>-CQ8 .~\l, \IIНV8</\l(Ol№ l4»
~rttf.Ct1~UIYl•/1rttl1ctld»
...,.пton>)1. 1• Jr-.</ver1101P
LC,W,'41~
ю-.
М!рt//,,_,,,(_......,.~
.......
-"·Н,Тf>°"'""
1!1111:11!11111
......
l,ani,.~~
ou,;,gi.•1~ uo·----~mvct,moi,
c/~ncp
с----а lnr;:6ud8,--.,i-н~~
• Get Started with Mattermost
~ .,!.
totn •.,....~.~•1f''IIS
R~l.h---
~ G
(CW"'~rt,,C)ll)l\t•l!'nll~~'""'
_,_
11:11111
~uь,-·
188111G ,,_·~·ll"h'••~•
-----
G
--
,......
:ом'"9't lfl'Wt • t1~ю
....,_
Рис.
4.20.
Запись в
mvnrepository для Google Guava -
https://mvnrepository.com/
■
Антипаттерны: внутренние общие библиотеки
(рис.
4.21 ).
Плаrин
maven-helper
203
особенно полезен при миграции кода: он помогает
понять, какая библиотека предоставляет конкретную зависимость, на случай, если
потребуется выполнить какие-либо исключения.
■
ц• .-
.,J"
ф
.
QO•
..... f
"'
Al~ мfrм
81'fj,INI.J,,,oot.- ,...,.,.___. S.8.2
tom.Qltnr.lЬ.~~1(0f\tl'.a.
"
,_
,_,_.,
.,,.,_
Ptof~
...
1
""""
·-,.,.
qi;
iu,.LjМetlo,111'1
ot9-tplfulf4-
•lt-.,tat,__, ,.t
.............. 111
""'"""'
rtIOWUI\
ft.ot~~fl"
""' ,. ,_,_. ~
• тооо
•i.-..
"IOl(II,.
Рис.
• .._
4.21.
.
, ....,..
с~
о~
~
Вспомогательный nлагин
Maven
в действии с
lntelliJ ldea
Используя эти три инструмента, вы получите всю необходимую информацию для
принятия взвешенных решений. Избегайте копирования и вставки файлов pom. xml от
других команд и существующих сервисов. Хотя при создании нового сервиса или
библиотеки выбор зависимостей может занять некоторое время, в долгосрочной
перспективе это окупается.
Еще один совет по выбору зависимостей заключается в том, что зависимости также
добавляются при разработке новых функций и даже при исправлении ошибок.
Очень важно обращать внимание на изменения в ваших файлах pom.xml во время
код-ревью. Добавьте проверку pom.xml и проверку зависимостей как часть вашего
чек-листа для код-ревью.
Избегайте использования родительского РОМ
В
Apache Maven
есть возможность использовать иерархические pom. Это полезная
функция, позволяющая избежать дублирования определений зависимостей в не
скольких проектах. Однако неправильное ее использование может привести к би
нарной связи и другим нежелательным последствиям. Это нормально, когда в ва
ших сервисах и внутренних общих библиотеках есть несколько проектов. Однако
не стоит совместно использовать
библиотек.
pom.xml
ни для
разных сервисов, ни для разных
204
■
Глава 4
Предположим, сервис профилей объявил spring-core в своем pom.xml. Сервис отчетов
использует тот же самый pom.xml из сервиса профилей в качестве родительского
сервиса pom.xml. Сервис отчетов также использует
чет использовать более новую версию
Spring.
Spring,
но теперь эта команда хо
Сервис отчетов не может изменить
корневой pom, не затронув сервис профилей. Конечно,
Maven
допускает исключе
ния, а локальный pom.xml всегда выигрывает в плане стратегии разрешения. Не сто
ит полагаться на родительский pom.xml. Это только создает дополнительную слож
ность и взаимосвязь. Лучше избегать такого подхода.
Объявляйте зависимости явно
Зависимости имеют свои зависимости, но зависимости от зависимостей всегда мо
гут изменяться. Вы не должны напрямую зависеть от транзитивной зависимости
без явного объявления в вашем pom.xml. Достаточно одного изменения от поставщи
ка библиотеки, чтобы нарушить ваш код, будь он внутренний или внешний.
Для лучшей гибкости зависьте только от зависимостей, явно объявленных в вашем
pom.xml. Вспомогательный плаrин
Maven,
о котором мы упоминали выше, также
будет полезен. Он позволит вам легко перемещаться по интерфейсу плаrина,
выполнять поиск и следить за разрешением зависимостей. Если вы используете
прямой импорт, ваш код будет прерываться во время компиляции. Если же вы при
меняете отражение, это может быть обнаружено только тестами или во время вы
полнения приложения. Никогда не полагайтесь напрямую на транзитивные зависи
мости.
Экономичные библиотеки
Подход «экономичная библиотека»
(Lean Library)
применим как к внутренним, так
и к внешним библиотекам. Не имеет значения, созданы они в вашей компании
с открытым или закрытым исходным кодом. Когда ваша продукция представляет
собой внутреннюю общую библиотеку, вам, как специалистам по решению про
блем, нужно подумать о побочных эффектах, которые вы окажете на ваших потре
бителей. Чем меньше вы влияете на их путь к классам, тем лучше. Это означает,
что важно следить за зависимостями и не навязывать своим пользователям опреде
ленные траектории.
Экономичные библиотеки означают, что вы заботитесь о внутренних общих биб
лиотеках и разрабатываете их с нулевым или минимальным количеством зависимо
стей, которые тщательно анализируются и выбираются. Задача сложная, но выпол
нимая. Экономичные библиотеки обладают следующими свойствами.
♦
Стабильные контракты. Контракт будет минимальным и изолированным; он
не будет содержать сотни операций только ради предпочтений. Предпочтения
связаны со стоимостью, и это повлияет на удобство обслуживания библиотеки.
♦ Высокая согласованность. Экономичная библиотека не должна быть пресло
вутой «кошелкой». Предоставляйте функциональность, которая естественным
образом сгруппирована по бизнес-области библиотеки, т. е. библиотека доступа
к данным не должна выполнять аутентификацию и авторизацию.
Антипаттерны: внутренние общие библиотеки
■
205
♦ Изоляция. У библиотеки должен быть радиус поражения на случай сбоя, когда
это уместно, или в противном случае функционал fail fast 17 .
♦ Тщательное управление зависимостями. Экономичные библиотеки не будут
воспринимать зависимости как нечто само собой разумеющееся и будут вклю
чать только строго необходимое. Экономичные библиотеки позволят избежать
производителей
раздутых библиотек сторонних
и
обеспечат управляемость
и компактность графика зависимостей.
♦
Наблюдаемость. Если это не настоящая библиотека утилит, публикуйте ключе
вые показатели, которые отражают успешность, сбои, использование, проценти
ли задержек и общую производительность внутренних вызовов. Эти данные
должны быть достаточными для того, чтобы пользователи могли понять поведевыявлять, устранять и исправлять про
1ч1е системы, а владельцы библиотек блемы.
♦
Прозрачное владение. У экономичных библиотек будут четкие правила владе
ния и обслуживания. Команда-владелец будет устранять ошибки, применять
меры безопасности, создавать документацию, обучать пользователей и сделает
все необходимое, чтобы бережно относиться к этой библиотеке и уважать ее по
требителей.
Спектр возможностей
Мы рассмотрели несколько альтернатив внутренним общим библиотекам. Сущест
вует широкий спектр возможностей. Давайте подведем итоги.
Слева направо на рис.
4.22
показано, что мы можем использовать экономичные
внутренние общие библиотеки, где тщательно выбираем зависимости, тщательно
контролируем бинарную связь и ограничиваем радиус распространения. Мы можем
использовать шаблон
Sidecar,
перенося логику в клиент-серверные
Клиенн:ерверные
Sidecar
Прозрачные
Инфраструктура
Экономичные внутренние
общие библиотеки
про-
Sidecar
Сервисы
К8s/сетка сервисов
(+) Гибкость
(+) Оптимизация
Рис.
17
Sidecar,
4.22. Спектр возможностей
Fail-fast system. При проектировании систем отказоустойчивая система обеспечивает мгновенное уведом
ление о любых сбоях через свой интерфейс. Такие системы не пытаются продолжить потенциально оши
бочные процессы, а останавливают работу. Для этого они часто проверяют состояние системы в нескольких
точках операции, чтобы любые сбои могли быть обнаружены на ранней стадии.
-
Пер.
•
206
■
зрачные
Глава 4
Sidecar,
или даже рассмотреть возможность переноса некоторой логики на
уровень инфраструктуры с помощью таких инструментов, как
Envoy, Istio и k8s.
SOA, микро
Наконец, на правильном пути мы можем перейти к сервисам, будь то
сервисы или даже бессерверные архитектуры. Можно даже полностью обойти про
блему, используя существующие пакеты
SDK,
копируя код или применяя откры
тый исходный код.
С левой стороны решения могут быть более оптимизированы; встроенные библио
теки могут быть компактнее и экономичнее, но не всегда. С правой стороны нахо
дятся более абстрактные, полностью независимые решения. Они более гибкие и
менее
взаимосвязанные,
но
менее
оптимизированные для
решения
локальных
за
дач.
Что нужно запомнить
Поздравляю! Мы подходим к концу главы
4.
Вот несколько ключевых моментов,
которые нужно запомнить:
♦ Качественная библиотека должна иметь открытый явный контракт и соответст
вующую реализацию.
♦
Библиотеки могут быть как внутренними, так и внешними по отношению к ва
шей организации.
♦
У библиотек есть проблемы: постоянная миграция, отсутствие стабильных кон
трактов и бинарная связь.
♦
Разработчики создают библиотеки по разным причинам: например, чтобы избе
жать дублирования, поддерживать разработку своего резюме, абстрагироваться
от будущих проблем, передать управление другой команде, оптимизировать
производительность и из-за отсутствия доверия.
♦ «Фреймворк»
-
это серьезный антипаттерн и часто становится серьезным ис
точником трудностей для морального состояния разработчиков, низкой ценно
сти, сложности и ряда других проблем.
♦
Библиотеки с открытым исходным кодом
-
это здорово. Мы должны их ис
пользовать!
♦
♦
Библиотеки могут использовать языковые идиоматические средства.
Библиотеки предлагают более доступный способ повышения надежности по
сравнению с сервисами или вспомогательными средствами.
♦
В некоторых случаях библиотеки демонстрируют более высокую производи
тельность.
♦
Иногда нет смысла изобретать велосипед, использование библиотек
-
лучшее
решение.
♦
Внутренние общие библиотеки могут иметь множество проблем, таких как не
обходимость использования определенного стека, подхода или решений.
♦
Библиотеки могут вызвать эффект короткого замыкания, когда попытка испра
вить одну зависимость приводит к нарушению другой.
Антипаттерны: внутренние общие библиотеки
♦
■
207
Избегайте больших фреймворков и раздутых библиотек. Не отправляйте часто
меняющиеся конфигурации вместе со своей библиотекой.
♦
Эффект размывания команды, как правило, сильнее проявляется в библиотеках.
Хотя есть естественные стимулы для создания библиотек, стимулы для их об
новления иногда отсутствуют.
♦
Внутренние утилиты часто являются серьезной проблемой. Избегайте использования общих утилит в сервисах и библиотеках.
♦
Внутренние обёртки часто не приносят большой пользы, и их следует избегать.
♦
Правильное управление зависимостями
♦
Клиенты/драйверы сервисов требуют тщательного подхода и внимания, чтобы
-
это всегда хорошая идея.
избежать бинарной связи. Те же проблемы возникают во внутренних библиоте
ках сервисов.
♦
Библиотекам требуется грамотное управление, четкая структура и активная под
держка пользователей.
♦
Создайте библиотеку, когда вы способны сделать что-то действительно лучше.
Если имеются ошибки в существующей библиотеке, если у вас есть пользова
тельская проблема, которую никто не решил, если вызов сервиса неестествен,
или если ваш код идеально подходит для повторного использования, то это хо
роший повод для создания новой библиотеки.
♦
Избегайте создания библиотек, если не доверяете своим инженерам. Это не
только подчеркнет ваши предпочтения в программировании, но и сделает биб
лиотеку громоздкой или сложной. Такую библиотеку не стоит использовать по
вторно.
♦
Сервисы должны быть универсальными и применимыми в большинстве случаев.
Так можно избежать бинарной связи, получить значительно большую гибкость и
упростить процесс миграции.
♦
Шаблон
Sidecar
является мощным, и его следует рассматривать как альтернати-
ву библиотекам.
♦
Sidecar могут быть
♦
Kubernetes
♦
Еще одним вариантом является подключение к инфраструктуре через
Istio
♦
или
прозрачными или иметь клиент-серверную архитектуру.
упрощает развертывание и использование
Sidecar.
Envoy,
k8s.
Рассмотрите простые альтернативы: скопируйте код, напишите его самостоя
тельно, используйте
SDK
или внесите свой вклад в открытый исходный код.
♦ Некоторое дублирование может быть полезным, например конфигурация или
установочный код; некоторое повторное использование может быть вредным,
например бизнес-правила или поддержка соответствия требованиям. Важно по
нимать различия.
♦ Повторное использование
-
это палка о двух концах. С одной стороны, оно
может лишить вас контроля и возможности принимать решения, оставляя уяз-
208
■
Глава 4
вимыми для ошибок, бинарных связей и раздуrых зависимостей. С другой
-
помогает сэкономить время, добиться большего с меньшими затратами, ускоря
ет процесс проектирования и позволяет полностью сосредоточиться на бизнесе.
♦ Тщательно подбирайте зависимости, избегайте родительских pom в масштабах
всей компании, избегайте зависимости от транзитивных зависимостей, всегда
четко выявляйте зависимости.
♦ Использование библиотек с открытым исходным кодом в сервисах
дело, но использование их во внуrренних общих библиотеках
-
-
это одно
совершенно
другое. Эrому нужно уделять гораздо больше внимания.
♦ Экономичные
библиотеки
отличаются
стабильными
контрактами,
высокой
целостностью, изоляцией, тщательным управлением зависимостями, высокой
наблюдаемостью и прозрачным владением.
♦
Существует целый ряд альтернатив библиотекам, таких как
Sidecar,
доступ
к инфраструктуре и сервисам. Рассмотрите все варианты для каждого варианта
использования.
ГЛАВА
5
Оценка
Оценка
-
это сеrоДНJ1шнее средство внесения изменений в зав~рашние инструкции.
Кэрол Энн Томлинсон
Прочитав четыре главы, посвященные сложным реалиям архитектуры программно
го обеспечения, вы поймете, что готовы к переменам. Но придержите коней! Вы не
сможете строить планы на будущее, не понимая настоящего. Оценка
(assessments)-
этo инструмент, необходимый для работы, и важно, как вы ее проводите. Нельзя
подходить к этому небрежно. Нужно вложиться в процесс и сделать всё правильно:
прочитать код, провести инвентаризацию имеющегося и понять, как устранить не
достатки. Мы расскажем, как грамотно подходить к обновлению вашего программ
ного обеспечения и каким ключевым компромиссным решениям необходимо сле
довать. Полностью информированный, вы преобразуете эту оценку в стратегию
(strategy),
которая поможет достижению ваших бизнес- и технологических целей.
Когда вы завершите этот этап, начнется настоящая революция. Конечно, проведе
ние процедур оценки может показаться скучным, но это только начало вашей
трансформации, критический анализ, необходимый для того, чтобы поразить моно
лит в самое сердце и исправить его раз и навсегда. Сила инженерии в переменах:
в способности изменять программное обеспечение, изменять к лучшему жизнь ва
ших инженеров, изменять вашу компанию и, в свою очередь, весь мир. Программ
ное обеспечение не имеет границ, кроме тех, которые вы устанавливаете сами. Не
соглашайтесь на статус-кво! Будьте смелее. Не просто перестраивайте свою кодо
вую базу, а переосмысливайте ее.
Но сначала вам нужно заполнить электронную таблицу. Позже вы поблагодарите
нас.
Структура главы
В этой главе мы рассмотрим следующие темы.
♦
Что такое оценка?
♦
Зачем проводить оценку?
•
Типичные проекты модернизации.
210
•
♦
■
Глава
5
Успешные проекты модернизации.
0
Мотивация.
0
Оценка.
0
Следите за конусом неопределенности.
0
Технологические и бизнес-потребности.
0
Стратегия модернизации.
0
Гибкий процесс разработки.
Решения и компромиссы.
•
•
Создание или покупка.
0
Обоснование покупки.
0
Обоснование создания.
Переписывание или рефакторинг.
♦
Сила обратной совместимости.
♦
Элементы надлежащей оценки.
•
•
•
Масштабный анализ кода.
0
Классификация и принятие решений.
0
Владелец.
0
Скорость изменения бизнеса.
0
Публичные контракты.
0
Нижестоящие зависимости.
0
Вышестоящие зависимости.
0
Код ориентирован на пользователя?
0
Сложность.
0
Уровень прохождения/ покрытие тестами.
Анализ базы данных.
0
Классификации уровня независимости.
0
Классический монолит.
0
Микросервисы или надлежащие сервисы.
0
Распределенный монолит.
0
Различные фреймворки доступа к данным.
0
Изолированные схемы.
0
Изолированные таблицы.
Сопоставление бизнес-областей.
0
Список всех бизнес-областей.
0
Помещение системы в карантин.
Оценка
♦
♦
■
211
Результаты оценки.
•
Быстрые результаты.
•
Определение приоритетов, ожиданий и стратегии.
•
Влияние на бизнес в сравнении с затраченными усилиями.
•
Порядок действий.
•
Радикальные изменения.
Что нужно запомнить.
Что такое оценка?
Оценка
это процесс, при котором вы анализируете, понимаете и
(assessments) -
классифицируете состояние системы или группы систем. Оценка
-
это важнейшее
действие и ключевой этап в планировании миграции, модернизации или любого
крупного продукта по рефакторингу.
Все оценки начинаются со сбора информации с помощью технических опросов,
анализа кода
(code analysis),
операционных панелей мониторинга, анализа журна
лов логов или баз данных, а также с помощью различных инструментов и действий.
Сбор данных может быть ручным, автоматизированным или гибридным. Оценка
может быть такой же быстрой, как выполнение задачи, например за
1О
минут во
время код-ревью, или как самостоятельный проект, занимающий несколько меся
цев.
Результаты оценки часто публикуются в виде отчета или презентации, что обеспе
чивает необходимый охват и уточнение большого проекта и позволяет командам
выработать стратегию. Объединив результаты оценки с четким представлением
о целевой архитектуре, вы можете создать прозрачный план. Можно точно опреде
лить шаги, которые необходимо предпринять для исправления распределенного
монолита или преобразования его в модульный монолит, компонент за компонен
том, будь то рефакторинг, переписывание или полная перестройка функциональ
ности. Оценка позволяет расставить приоритеты задач и правильно распределить
ресурсы, инфраструктуру и персонал.
Короче говоря, оценка
-
ключевой инструмент для любого крупного технологиче
ского проекта с готовой инфраструктурой. На протяжении всей этой книги мы под
робно рассматривали, как оценивать решения, выявляя их плюсы и минусы, пре
имущества и недостатки. Но все начинается с оценки: без глубокого понимания
проблемы невозможно найти решение.
Зачем проводить оценку?
Прежде чем обсуждать оценку, нам нужно немного отвлечься и рассмотреть про
цесс модернизации в целом. Оценка
-
один из важных первоначальных шагов.
Если вы не видите роль оценок в их полном контексте, вы можете не понимать, за-
212
■
Глава 5
чем они вам нужны. Пропуск оценок
в проектах модернизации
- это типичная
(modemization projects).
ошибка, которую допускают
Типичные проекты модернизации
Запуск проекта модернизации может показаться пугающей или даже невыполни
мой задачей. Возможно, вы видели результаты многих проектов, подобных пока
занному на рис.
5.1:
руководители предприятий или старшие технологи приходят
к четкому решению, которое хотят реализовать. Ваша организация сплачивается и
готова вложить деньги и людей в многолетнюю инициативу ... Но в конечном итоге
проект проваливается и не достигает поставленной цели. Ваши инженеры сталки
ваются с побочными эффектами неудачной разработки сервиса, бизнес все больше
отстает в достижении своих целей, и все усилия в целом оказываются напрасными.
Расходы превышают бюджет
ТеХНОllОfМЧЕ!Сl(ЗЯ
или бизнес-мотивация
--11•••
Исполнение
- - • • Не доделано
Технические проблемы
остаются
iii
ххх
Рис.
5.1. Типичные
проекты модернизации
Успешные проекты модернизации
Мы здесь для того, чтобы рассказать вам о том, что проекты модернизации воз
можны и что мы воочию убедились в их успешности (рис.
в
тщательном,
методичном
подходе,
полном
анализе
5.2).
Секрет заключается
вашего
технологического
ландшафта и увязке его с вашими технологическими и бизнес-потребностями
(technology and business needs).
Полученная в результате стратегия станет вашим
лучшим шансом на реализацию проекта, который вы сможете осуществить, и при
ведет к истинному успеху, завершению существования вашего монолита и началу
нового светлого будущего. Независимо от сложности монолита или системы, с ко
торыми
вам
приходится
сталкиваться,
важно
верить
в
то,
что
проект
возможен:
в противном случае вы обрекаете себя на неудачу.
Теперь давайте подробно рассмотрим каждый этап успешной модернизации.
Оценка
■
213
Технологическая
$
мотивация
Технологические
потребности
Стратегия
Оценка
модернизации
Гибкий
процесс
разработки
Успех!
Бизнес•
потребности
Бизнес-мотивация
Рис.
5.2.
Успешные проекты модернизации
Мотивация
У вас может быть много причин выступить с инициативой по преобразованию.
К этому шагу вас могут подтолкнуть различные мотивы, обстоятельства и факторы,
например следующие.
♦ «Зеленое поле». У вас есть возможность создать что-то инновационное и со
вершенно новое: полностью финансируемый проект, полная поддержка руко
водства, а также власть и ресурсы для проведения изменений в руках вашей
команды.
♦ Новые возможности для бизнеса. Некоторые части вашей бизнес-экосистемы
развиваются, но другие находятся в режиме технического обслуживания или
на грани банкротства, возможности для трансформации могут быть неодинако
выми.
♦ Консолидация. Ваша компания была приобретена и нуждается в интеграции
в глобальную платформу.
♦
Стартап ищет РМF. Ваш стартап все еще находится в процессе становления,
пытаясь найти продукт, соответствующий рынку
♦
Высокая
нагрузка
по
регулированию
и
(Product Market Fit, PMF).
соблюдению
требований.
Ваша
крупная компания борется со старой технологической платформой, но норма
тивно-правовая база регулятора затрудняет изменения.
♦ Сложная миграция. Вы должны перейти от очень старой технологии, такой как
настольные приложения, к веб-приложениям или современному мобильному
интерфейсу.
♦ Облачная миграция. Вы находитесь в центре обработки данных, и вам необхо
димо перейти в облако.
♦ Единый монолит. У вас регулярно возникают проблемы с вашей единой боль
шой системой классического монолита.
♦ Пренебрежение бизнесом. Вам необходимо убедить свое руководство в том,
что существующие системы, архитектура и инфраструктура больше не могут
214
■
Глава 5
поддерживать компанию. Руководители могут быть не в курсе, им может быть
все равно, или они могут подумать, что это просто ИТ-проблема.
♦ Неэффективная
миrрация
микросервисов,
ведущая
к
распределенному
монолиту. Ваша команда получила финансирование для перехода на микросер
висы, но, по правде говоря, миграция не принесла результатов; в итоге у вас по
лучился
большой
распределенный
монолит или
несколько
распределенных
монолитов.
♦ Большие мечты. Вы намерены что-то изменить, но не хватает бюджета.
Возможно, вы сможете вспомнить один или несколько таких моментов, с которыми
сталкивались в своей карьере. Независимо от того, являетесь ли вы ветераном мно
гочисленных попыток модернизации или сталкиваетесь с ней впервые, ваш сле
дующий шаг
-
оценить ваш текущий сценарий.
Оценка
Можно подумать, что оценка
(assessments) -
это пустая трата времени, ведь все
знают, в чем проблема! Или что это своего рода менталитет старой школы, который
не позволяет действовать быстро и ломать вещи. Исходя из нашего опыта, мас
штабная оценка действительно необходима, для того чтобы получить следующее.
♦
Определение ожидаемоrо результата. Если вы не знаете, за что боретесь, как
вы можете победить? Каково условие победы вашего проекта? Когда вы можете
остановиться и объявить о победе? Очень важно заранее определить успех, пре
жде чем ваш проект превратится в безнадежный хаос.
♦
Создание ценности. Очень немногие организации могут успешно осуществлять
многолетние проекты по модернизации. Возможно, вам знакомы такие названия
проектов, как «Цифровая трансформация», «Гибкая трансформация» или просто
«Модернизация», поскольку многие из этих проектов терпят неудачу. Что еще
хуже, отсутствие доверия может привести к тому, что ваш бизнес будет зани
маться теневыми ИТ, передавая работу внешним подрядчикам, не входящим
в состав вашей технологической организации. Вам необходимо как можно быст
рее обеспечить реальную отдачу от вашего проекта.
♦
Правильный выбор. Если вы на самом деле не знаете проблему, как можете
быть уверены в эффективности своей стратегии ее решения? Почему именно
этот подход важнее всех остальных?
♦
Определение приоритетов. У вас может не хватить средств, чтобы все перепи
сать. Поэтому необходимо расставить приоритеты
(prioritization).
В зависимости
от суммы технического долга это может быть внушительный счет на несколько
миллионов долларов, который придется оплачивать годами или даже десятиле
тиями.
♦
Оценки и обязательства. Ни одна организация не подписывается на проект,
стоимость которого измеряется суммой из
8-9
цифр, без оценки. Все команды
должны предоставить хотя бы приблизительные расчеты. Проведение оценки
сделает ваши прогнозы более точными и реалистичными. Когда ровно через
Оценка
■
215
Х месяцев, как вы и предсказывали, будет получен первый результат, это повы
сит доверие к вашей команде в трудный период.
♦ Численность персонала. Откуда вы знаете, что у вас правильный состав ко
манды? Возможно, вам нужны дополнительные сотрудники. Оценка поможет
обосновать и объяснить необходимость изменений.
♦
Сейчас или никогда. Другого шанса исправить проблему может и не представиться. Лучше действуйте сразу правильно.
Всё просто: у вас есть шанс, и чем больше вы знаете о проблеме, тем выше ваши
шансы на успех. В масштабах компании могут быть сотни и тысячи сервисов, один
классический монолит и большой распределенный монолит. Реализация проекта по
модернизации будет непростой, поэтому более тщательная подготовка принесет
свои плоды. Хорошо зарекомендовала себя концепция разработки программного
обеспечения под названием «конус неопределенности».
Следите за конусом неопределенности
Проекты по миграции и модернизации похожи на любые другие проекты по разра
ботке программного обеспечения; у них есть масштабы, риски, люди и т. д. Внача
ле работа идет медленнее, и у вас появляется больше неизвестных, но со временем
вы продвигаетесь быстрее и узнаете больше о своих сервисах и компонентах. Стив
Макконнелл описывает это явление как конус неопределенности (Cone of Uncertainty) в своей книге 1997 года «Руководство по выживанию в программных про
ектах» (Software Project Survival Guide ). Эта концепция была заимствована из
химической промышленности примерно в 1958 г., позже была применена в про
граммном обеспечении Барри Бохемом и в 1981 г. получила название «кривая во
ронки» (Funnel Curve ).
Конус неопределенности показывает, что в начале проекта вариаций гораздо боль
ше и оценить их очень сложно. По прошествии времени ситуация проясняется, а по
мере уточнения требований поставки становятся более определенными, с меньшим
разбросом по времени и результатам. В начале работы над классификацией можно
не знать точно, сколько компонентов удастся сохранить или сколько из них перера
ботать. По мере продвижения эта ясность будет приходить. Разумно оценить тру
дозатраты после завершения работы над классификацией, а не до нее. Классифика
ция поможет вам правильно оценить ситуацию и принять решение о том, что де
лать с вашей технологией.
Многим инженерам может показаться, что анализ и оценка
это пустая трата
-
времени, и они скажут: «Давайте просто все перепишем». Нужно соблюдать осто
рожность, когда вы просто переписываете код ради него самого,
что практически
не приносит пользы бизнесу. Реальность такова, что очень трудно оправдать любые
долгосрочные инвестиции без прямой выгоды для бизнеса.
Если посмотреть на диаграмму конуса неопределенности (рис.
5.3 ),
то оценка по
хожа на сбор требований. И то и другое сужает конус неопределенности. Вы знае
те, что нужно сделать, но, возможно, не знаете всех деталей того, как вы это еде-
216
■
Глава 5
лаете. У дачи вам даже в попытках оценить ситуацию без анализа! Мы настоятельно
рекомендуем провести оценку, прежде чем приступать к серьезному развитию.
Нет, оценка не означает, что вы реализуете комплексный проект; можно наращи
вать ценность постепенно. Бизнес-требования могут меняться каждый день, но ва
ши технические требования, общая архитектура и структура вашего монолита не
изменятся в одночасье. Возвращаясь к главе
1 « Что
не так с монолитами?», сле
дует отметить, что монолиты по своей сути медленно внедряют любые новые тех
нологии! Заблаговременное проведение всесторонней оценки безопасно и эффек
тивно. Оценка уменьшает влияние конуса неопределенности на ваши проекты.
4.
2.
~~
~~
s:
t;
1,5.
s
>- 1,25.
"'s: 1,0.
:3 О,8х
о
%
1D
...........
а.
"'s:
%
7
s:
j
~..,
0,67.
0,5.
~
,r.
1/~
0,25.
Время
Требования
Первона чальная
собраны
Программное обеспечение
концеnция
Утвержденное
Проектирование
определение
пользовательского
продукта
интерфейса
Завершено детальное
реали зовано
проектирование
завершено
Рис.
5.3.
Конус неопределенности.
Источник: https:/lwww.construx.com/Ьooks/the-(;one-of-uncertainty/
Технологические и бизнес-потребности
Проведя оценку, вы получаете прекрасную возможность изучить ландшафт своей
компании, сопоставить результаты оценки с общими технологическими потребно
стями и потребностями бизнеса
рис.
5.2.
(technology and business needs),
как показано на
В конце концов, вы можете по-разному подходить к своей будущей архи
тектуре и плану реализации. Почему бы не взглянуть на свое предприятие с другой
стороны и не посмотреть, где у вас есть возможность убить двух зайцев одним вы
стрелом? Возможно, одно из ваших решений приведет к значительному увеличе
нию выручки и принесет много денег бизнесу, или же, перейдя от рефакторинга
к полному переписыванию, вы значительно повысите эффективность и масштаби
руемость вашей команды инженеров. И, кстати, улучшение финансовых результа-
Оценка
■
217
тов бизнеса облегчит финансирование вашего плана: успешный бизнес и лучшее
программное обеспечение
-
это беспроигрышная ситуация!
Стратегия модернизации
Теперь у вас есть подход, который объединяет полное понимание существующих
у вас технологий, с видением существующих технологических и бизнес-потреб
ностей организации. Вы должны объединить это в стратегию
ции
-
(strategy)
модерниза
видение изменений, которые будут стимулировать вашу организацию к
осуществлению модернизации.
Продажа идеи и убеждение вашей компании в необходимости реализации страте
гии модернизации выходят за рамки нашего описания в книге. Для начала мы бы
порекомендовали
Change ).
книгу
Джона
Коттера
«Лидерство
в
изменениях»
(Leading
Джон описывает 8-шаговый процесс успешного проведения организаци
онных изменений, который хорошо подходит для этой книги:
1.
Придайте срочный характер изменениям.
2.
Сформируйте мощную коалицию.
3.
Разработайте концепцию изменений.
4.
Распространите ее среди общественности.
5.
Устраните препятствия.
6.
Добейтесь краткосрочных результатов.
7.
Реализуйте изменения.
8.
Закрепите изменения в корпоративной культуре.
Гибкий процесс разработки
Теперь самое сложное: процесс разработки. Разработка программного обеспечения
является сложной задачей по нескольким причинам. Перечислим лишь некоторые
из них.
♦
Тяжелая работа. Некоторым или всем вашим инженерным командам предстоит
проделать большой объем работы.
♦
Напряженность. Бизнес никогда не останавливается. Проект модернизации за
трагивает все те же кодовые базы, что и ваши команды разработчиков, отвлекая
внимание от того, что, по мнению бизнеса, должно быть приоритетным. Разли
чия
в
целях
и
ограниченные
ресурсы
создают
напряженность
в
отношениях
между командами, менеджерами и организациями.
♦ Дисциплина. Легко столкнуться с проблемами в общении и потерять концен
трацию, направление и даже энергию; поддерживать работу в хорошем состоя
нии непросто.
Ремонт монолитов требует глубоких технических знаний,
а
управлять такими проектами сложно.
Дисциплина имеет решающее значение. Это ключ к успеху в подобных проектах
или любой успешной организации. Тони Салданья в своей книге
2019
года «Поче-
218
■
Глава 5
му •~ифровые преобразования терпят неудачу»
объясняет, что до
70 %
(Why Digita\ Transformations Fail)
всех цифровых преобразований терпят неудачу по удиви
тельной причине: из-за отсутствия дисциплины в определении и выполнении пра
вильных шагов .
Теперь, когда вы ознакомились с успешным проектом по модернизации техноло
гий, можете понять, что все начинается с успешной оценки. Оценка важна для того,
чтобы вы могли детально разобраться в том, с чем имеете дело, применительно
к каждому сервису или программному компоненту. Цель при проведении оценки
-
дать представление о состоянии дел в ваших программных системах, чтобы выра
ботать стратегию правильного устранения проблем.
Как можно выбрать правильные шаги и выработать правильную стратегию, не имея
доступа к текущему сценарию? Нет, проведение оценки не означает, что вы попали
в ловушку проекта «водопад» . Оценка- это ключ к успеху.
Решения и компромиссы
Оценки предоставят вам много поводов для размышлений. Независимо от того, ка
кие решения вы примете, вот несколько общих принципов, которые мы считаем
полезными при проведении анализа компромиссов.
Создание или покупка
Разработчикам нравится творить, однако не все нужно создавать. Как и в архитек
туре программного обеспечения, здесь должны быть компромиссы (рис.
работчики
5.4).
Раз
как строители, которые всегда хотят что-то построить; когда у вас
-
есть молоток, все кажется гвоздем! Но подумайте также о возможности покупки.
Создать
или
Купить
...
Большая зависимость от людей
(+}
Малая зависимость от людей
(+) Низкие затраты на поставщиков
(-}
Высо кие затраты на поставщиков
(-)
(-}
Высокие первоначальные инвестиции
(+}
Низ кие первоначальные инвестиции
(+}
Больше капитальных затрат ,
(-}
Больше операционных расходов ,
(+}
Более низкие риски
(-}
Низкая кастомизация
чем эксплуатационных расходов
(-}
Более высокий риск
(+) Точное управление функциями
Рис.
5.4.
чем капитальных затрат
Создавать или покупать
Оценка
■
219
Обоснование покупки
Сколько раз вы сталкивались с очень неудачными решениями, разработанными
самостоятельно? К сожалению, такое случается часто. Для создания правильного
решения
требуются
опыт
и
талант.
Инженеры
часто
наследуют
устаревшее
программное обеспечение от других инженеров. Так зачем продолжать бороться
с устаревшей системой? Замените ее на новое решение от другого разработчика.
Хотя не каждое решение можно купить, для многих повседневных бизнес-операций
существуют готовые продукты, которые вы можете приобрести для своего исполь
зования. За последние несколько лет наша индустрия программного обеспечения
значительно улучшилась, в основном благодаря движению стартапов. Похоже, что
для
многого
(Software as
а
существует
поставщик
Service, SaaS)
программного
обеспечения
как
услуги
и необязательно разрабатывать все собственными си
лами. Иногда имеет смысл положиться на сторонние решения, особенно в следую
щих случаях.
♦ Значительная экономия средств. Когда вы проводите анализ соотношения
между созданием и покупкой и видите значительную экономию средств, это
может быть очевидным. Но помните о скрытых расходах на поддержку, когда
начнете работать. Убедитесь, что все функции, которые вам необходимы, вклю
чены в стоимость. Проведите тщательный анализ.
♦
Смена продукта. Фокус, приоритеты и/или инвестиции означают, что про
граммное обеспечение охватывает область, которая является товаром массового
потребления или иным образом не является приоритетной для бизнеса.
♦ Устаревший продукт
(EOL).
Старое решение из-за одного или нескольких
ключевых факторов необходимо вывести из эксплуатации. Зачем пытаться мо
дернизировать его, если есть более эффективная альтернатива?
♦ Сложность в обслуживании. Если ваше собственное решение неэффективно,
проблематично или сложно в обслуживании, вы, вероятно, экономите на инже
нерном или операционном персонале, который вам не понадобится при покупке
готового решения.
♦ Лучшее решение. Здесь может возникнуть серьезная ошибка, связанная с зани
женными затратами; команды должны быть честными и признавать, что внеш
ние решения могут оказаться эффективнее собственных, независимо от того,
сколько инвестиций в них было вложено.
Обоснование создания
Несомненно, покупка программного обеспечения может ускорить разработку ре
шения для бизнеса. Что не так-то просто купить, так это интеграцию. Конечно,
некоторые решения поставляются с разъемами и интеграцией с популярными инст
рументами, но это не распространяется на ваши внутренние системы, и всегда не
обходимы определенные усилия по интеграции. Что делать, если в вашем SааS
решении отсутствуют ключевые функции? Если не уделить внимание деталям или
не провести достаточно глубокий анализ требований, можно потерпеть фиаско.
220
■
Глава
5
Профессиональные сервисы и разработка на заказ, скорее всего, обойдутся гораздо
дороже, чем ваши инженеры!
Таким образом создание может оказаться оптимальным выбором.
♦
Основной бизнес. Если решение критично для успеха бизнеса. Не упускайте из
виду важнейшие функции компании!
♦
Инновации. Вы полагаетесь на программное обеспечение как на ключевой фак
тор, отличающий вас от основных конкурентов в отрасли.
♦
Экономия средств. Значительная экономия средств; да, такое случается. Иногда
создание собственными силами позволяет значительно сократить расходы, осо
бенно если вам нужны не все функции, предлагаемые при покупке.
♦
Недостаток продукта. На рынке нет решения, полностью отвечающего вашим
потребностям.
С последним пунктом вам нужно быть очень осторожным. Легко влюбиться в про
граммный код и внутренние проблемы компании. Иначе их называют «вывернутым
наизнанку мышлением». Ваша задача
-
не решать внутренние проблемы компа
нии, а удовлетворять своих клиентов! Вместо этого подумайте о том, что происхо
дит снаружи. Потратьте время и усилия на решение проблем ваших клиентов и
обеспечьте наилучший пользовательский опыт. Покупка вместо создания позволит
вам сосредоточиться на этих ключевых проблемах.
Еще раз: вы не можете отдельно от всего купить интеграцию со своими внутренни
ми системами. Если покупаете систему расчета заработной платы, вам нужно будет
привязать ее к своей системе бухгалтерского учета, и это нельзя обойти. Конечно,
на рынке есть интеграционные платформы, основанные на модели Enterprise
Service Bus (ESB), такие как MuleSoft, ServiceMix, SааS-решения, А WS Step Functions with Lambdas, или облегченные решения с открытым исходным кодом, напри
мер Apache Camel. Инструменты могут снизить стоимость интеграции, но не могут
заменить ее полностью. Брэндон Байарс (Brandon Byars) в своей статье «Интегра
цию нельзя купить» (You Can't Buy Integration) 1 обращает внимание на следующие
пункты:
♦
Создание необходимо всегда. Даже при покупке интеграционного продукта вам
необходимо выполнить интеграцию самостоятельно.
♦ Чистые интерфейсы.
Приложите усилия
к созданию
чистых интерфейсов
в системах; в предыдущих главах мы продолжим обсуждение стабильных и пуб
личных контрактов.
♦
Полагайтесь на языки программирования. Используйте код, а не визуальные
представления или
♦
XML.
Интеграция важна. Рассматривайте интеграцию как стратегическую часть ва
шего бизнеса.
1
Опубликовано в 2021 году Брэндоном Байарсом на веб-сайте Мартина Фаулера, удивительном источнике
https://martinfowler.com/articles/cant-buy-integration.html.
архитектурной информации:
Оценка
■
221
Другими словами, вы не можете купить свой основной бизнес. Конечно, можно
купить множество систем и воспользоваться возможностями коммерческой инте
грации, но у вас не будет бесплатного обеда. Даже при покупке присутствует необ
ходимость создания.
В
году Стив Джобс
1997
(Steve Jobs) выступал на Всемирной конференции разра
Apple (World Wide Developers Conference, WWDC), и ему пришлось отве
сложный вопрос инженера об OpenDoc. Джобс дал блестящий ответ: «Са
ботчиков
чать на
мое сложное заключается в следующем: каким образом это вписывается в целост
ную, масштабную концепцию, которая позволит вам продавать продукцию на
8-1 О
миллиардов долларов в год? И одна из вещей, которую я всегда понимал,
заключается в том, что начинать нужно с работы с клиентами, а затем переходить
к технологии. Вы не можете начать с технологии и попытаться понять, где вы со
бираетесь ее продавать. И я совершал эту ошибку, вероятно, чаще, чем кто-либо
другой в этом зале. И у меня есть шрамы, подтверждающие это. И я знаю, что это
важн0>>2.
У
Amazon
есть набор удивительных принципов лидерства, которые лежат в основе
их личной работы и подходах к принятию решений3 . «Одержимость клиентами» ключевой принцип, согласно которому «лидеры начинают с клиента и работают
в обратном направлении».
Уроки
Apple
и
Amazon,
манд, занимающихся
которые мы здесь упомянули, особенно значимы для ко
серверными сервисами
и
микросервисными архитектурами,
которые не имеют прямого взаимодействия с конечными пользователями. В отли
чие от интерфейсных проектов, здесь легко упустить клиента из виду. А при любом
анализе компромиссов всегда важно учитывать влияние каждого из рассматривае
мых вариантов на потребителей.
Переписывание или рефакторинг
Еще один важный вопрос при принятии решения о будущем системы или сервиса
заключается в том, нужно ли их полностью переписывать с нуля. Или можно про
вести рефакторинг кода на месте, чтобы помочь ему вписаться в новую архитекту
ру? Переписывание или рефакторинг (рис.
5.5)?
Многие инженеры любят упрощать этот ответ и создавать все с нуля, но иногда
рефакторинг оказывается лучшим решением, поскольку он позволяет сохранить
проверенный временем код в новом контексте. Это непростое решение. Не бывает
простых решений, когда нужно проанализировать большую и сложную архитекту
ру. Вполне вероятно, что придется переписать некоторые системы и сделать рефак
торинг других.
Потрясающий вид Стива Джобса в расцвете сил в действии: https://www.businessinsider.com/stevejobsreaction-to-insult-201S-l О и https://www .youtube.com/watch ?v=oeqPrU m Vz-o.
2
3
Еще один легендарный документ Кремниевой долины, который редко используется в качестве свода
руководящих принципов для предприятий, работающих с клиентами:
bttps://www.amazon.jobs/content/en/our-workplace/leadersbip-principles.
222
■
Глава 5
Отраслевой взгляд
Переписывание
Рис.
5.5.
или
...
Рефакторинг
Отраслевой взгляд: переписывание или рефакторинг
Чтобы оценить, возможен ли рефакторинr, нужно учесть некоторые аспекты.
♦ Критичность. Насколько важна эта система или сервис для дифференциации и
непрерывности бизнеса? Если они не критичны, стоит ли их переписывать?
♦
Скорость изменений бизнеса. Как часто бизнес запрашивает обновления или
новые функции для этого компонента? Требуются ли изменения редко, умерен
но или часто? Переписывать постоянно меняющиеся цели сложно; незначитель
ный рефакторинr может оказаться проще.
♦
EOL.
Используем ли мы технологию, срок службы которой подходит к концу
в ядре системы/сервиса? Система работает на устаревшем настольном языке, а
мир переместился в мобильное и веб-пространство?
♦
Растем или сокращаемся. Растет ли бизнес в той области, которую поддержи
вает данная система или сервис, или он сокращается или даже полностью свора
чивается? Ваш ответ должен повлиять на решение, стоит ли вкладывать в такой
бизнес крупные средства.
♦
Возможности для бизнеса. Необходимо ли переписывание для ускорения роста
бизнеса? Какую выгоду принесет бизнесу переписывание, или мы можем обой
тись рефакторинrом для снижения затрат или увеличения дохода?
♦
Технические усилия. Сколько времени, внимания и людей потребуется, чтобы
переписать сервис вместо рефакторинга?
Инженеры всегда стремятся создавать, внедрять и совершенствовать. Однако не все
нужно изобретать. Джоэл Спольски, создатель
манды
Excel
в
Microsoft
в
1991-1994 rr.,
Trello
и программный менеджер ко
в своем потрясающем блоrе «Вещи, кото
рые вы никогда не должны делать, часть 1» (Things You Should Never Do, Part 1)4
рассказывает о стратегических ошибках, которые совершают компании, пытаясь
переписать программное обеспечение с нуля.
♦
Обновление
Netscape
с
4.0
до
5.0,
которое так и не состоялось! Все прошло на
столько неудачно, что компании полностью отказались от версии
нее запустили версию
♦
Компания
Borland
так затянулась, что
4
5.0
и вместо
для
Windows
6.0.
купила
Arago, но попытка внедрить ее в dBase
Microsoft Access заняла это место в отрасли.
Все ранние записи Джо,ла в блоrе легендарны 11 по-прежнему актуальны. несмотря на то что прош,10 бо
20 лет: https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/.
лее
Оценка
■
223
♦ Компания
Microsoft почти совершила ту же ошибку, попытавшись переписать
Microsoft Word для Windows в своем печально известном проекте Pyramid 5 .
Джоэл объясняет, почему инженеры предпочитают перестраивать все с нуля. По
его мнению, писать собственный код проще и увлекательнее, чем разбираться
в существующем. В конечном счете резюмирует это следующим образом:
« Читать
код сложнее, чем писать его».
Еще один важный вывод из поста Джоэла: «Идея о том, что новый код лучше ста
рого, явно абсурдна». Старый код использовался, тесты и ошибки исправлялись
много раз. Он прошел боевую проверку, и часто в нем нет ничего плохого! Джоэл
утверждает, что на уровне компании, когда вы выбрасываете свою кодовую базу и
начинаете все сначала, вы даете своим конкурентам преимущество на
2-3
года, а
также теряете все знания и исправления ошибок, внесенные в кодовую базу. Ожи
дая завершения переписывания и выхода первого релиза, вы ставите свою компа
нию
в
невыгодное
стратегическое
положение,
лишая
ее
возможности
выпускать
новые функции или быстро реагировать на потребности рынка, а также вынуждаете
ее проводить дорогостоящий цикл наверстывания упущенного. Как вы можете ви
деть, рефакторинr и улучшение кода имеют свои преимущества.
Давайте более внимательно рассмотрим статью Дэна Маккинли о выборе скучной
технологии, которую мы упоминали в предыдущей главе, и обобщим его советы.
♦ Скучное программное обеспечение, такое как
Python,
MySQL, Postgres, Squid, Cron
и
не так уж и плохо. Старое программное обеспечение также не является
плохим программным обеспечением.
♦
Скучная технология хорошо изучена, известны способы ее отказа, она надежна
в производстве и имеет качественную официальную и неофициальную докумен
тацию.
♦ Представьте, что у вас есть
3
инновационных токена, которые можно потратить
на новую технологию. Но только тогда, когда у вас появится что-то зрелое и
стабильное, вы сможете двигаться дальше.
♦
Примите скуку!
Совет Дэна здесь уместен, потому что при переписывании программного обеспече
ния, мы часто стремимся использовать разные методы: новые базы данных, языки,
фреймворки и библиотеки. Это в какой-то степени хорошо! Именно здесь нужно
применить мудрость Дэна: одновременное внедрение слишком большого количест
ва новых технологий может привести к сбоям и усложнить нашу работу. Далее мы
расскажем о том, как можно минимизировать эту проблему, не прибегая к иннова
ционным токенам, в главах
и
7 «Надлежащее
6
«Принципы надлежащего предоставления сервисов»
тестирование сервисов».
На данный момент переписывание программного обеспечения может показаться
просто плохой идеей. Если переписывание сделано некачественно, то это одно-
5 Хорошую
Microsoft.
статью о рефакторинrе и переписывании, рассказывающую о Project Pyramid и неудачах
можно найти здесь: https://entгision.com/Ыog/гebuild-veгsus-гefactoг/.
224
■
Глава
5
значно плол:о. Но помните, что в архитектуре программного обеспечения мало чер
но-белых решений. Как показано на рис.
5.6,
все имеет масштаб/спектр, и, возмож
но, имеет смысл переписать некоторые из модулей и сделать рефакторинг других.
Да, переписывание программного обеспечения может показаться рискованным
-
нужен официальный проект, нужны инвестиции и финансирование. Всё может за
кончиться неудачей. Но, с другой стороны, бездействие также сопряжено с риском,
т. к. проблемы естественным образом растут благодаря усиливающимся эффектам,
которые обсуждались в предыдущих главах. Бездействие рискованно. Рефакторинг
может быть безопаснее, но проект не принесет пользы бизнесу, если промежуrоч
ный вариант не приведет к изменениям, достаточным для решения вашей пробле
мы. При принятии решения необходимо сбалансировать все эти конкурирующие
факторы.
Большое влияние
Малое влияние
r-----------------·----·-·--·-···-------·---------------,
'
'
- -----· ·-· .. -
--
Рефакторинг
... -- -- -- - . . -- - -
...
Переписывание
Бездействие
Рис.
. -. --
5.6.
Слектр лерелисывания и рефакторинга
Поскольку переписывание, как правило, обходится дороже, один из способов сни
зить риск в этом случае
сто
потенциальную
-
убедиться, что бизнес получает нечто большее, чем про
экономию
средств.
Положительные
результаты
включают
в себя:
♦ совершенно новые возможности: внедрение функции, оказывающей большое
влияние на бизнес, или решение давно назревших проблем клиентов;
♦ увеличение выручки: функцию, которая может быть непосредственно преоб
разована в увеличение продаж,
выход на новые рынки или четкое отличие от
конкурентов.
Вы должны мыслить как бизнес. Нужно найти способы сопереживать их трудно
стям, их потребностям в маркетинге продукта и привлечении клиентов... а затем
привязать переписывание кода к целям бизнеса.
В противном случае существует риск того, что ваша переработка превратится
в большой центр затрат, в результате станет очень трудно поддерживать инициати
ву в долгосрочной перспективе. Вы ведь не хотите создавать впечатление, что ваша
технологическая организация работает медленно, что приводит к высоким затратам
и низкой ценности для бизнеса.
Теперь вы, возможно, думаете, как понять, можно ли сохранить систему или сер
вис? Единственный способ узнать это: выполнить оценку и действительно прочи
тать код. Иногда компании обращаются к моделям зрелости, консультантам, оцен
кам и даже инструментам и сервисам для принятия решений, игнорируя тот факт,
что просмотр кода
ции.
-
самый дешевый и эффективный способ разобраться в ситуа
Оценка
■
225
Сила обратной совместимости
Обратная совместимость
(backward compatibility) -
это просто. Вы вносите изме
нения в код, исправляете ошибки или вводите новые функции, но при этом не на
рушаете работу существующих пользователей. Для них все работает так, как будто
ничего не изменилось. Обратная совместимость
-
это мощный и эффективный
шаблон проектирования.
Другими словами, обратная совместимость
-
ключ к ускорению всех форм мигра
ции, модернизации, облачных переходов и даже исправлению монолитов. Чтобы
обеспечить обратную совместимость, необходимо следующее.
♦
Публичные контракты. Находите и разбирайте все контракты, включая откры
тые или скрытые связи между системами, с помощью анализа кода
(code ana-
lysis ).
♦ Не нарушайте публичные контракты. При внесении изменений в код убеди
тесь, что контракты полностью соблюдаются: входные данные, выходные дан
ные и поведение. Тестирование
-
это ключ к успеху!
Как только вы определите объем контрактов и должным образом протестируете их,
можно приступать к созданию обратно совместимых решений. Хотя шаблон обрат
ной совместимости может применяться не ко всем вашим компонентам или сцена
риям в ходе проекта модернизации, по возможности следует сохранять обратную
совместимость. Это ускорит миграции и обеспечит их безопасность.
А WS применяет этот шаблон при создании и предоставлении управляемых серви
сов. Они могут взять кодовую базу из проекта с открытым исходным кодом и зна
чительно модифицировать ее для запуска с улучшенными возможностями на своих
облачных платформах. Это может вызвать споры6, но результатом будет обратная
совместимость
системы
с
лучшими
показателями
цены
и
производительности.
Приведем несколько хороших примеров управляемых сервисов А WS.
♦
MySQL API: Amazon Aurora MySQL.
♦
♦
Postgres API: Amazon Aurora PostgreSQL.
Redis API: Amazon ElastiCache.
♦
Memcached API: Amazon ElastiCache.
♦
Elasticsearch API: Amazon OpenSearch.
RabbltMQ API: Amazon MQ для сервиса RabЬitMQ.
♦
Amazon предлагает решения с обратной
100 % поддерживают общедоступные API
совместимостью, которые не всегда на
и модели поведения с открытым исход
ным кодом. Однако они часто оказываются достаточными для успешной миграции
с более высокой производительностью и эксплуатационными возможностями по
сравнению с самостоятельным запуском программного обеспечения на экземпля
рах ЕС2 или контейнерах. При этом они практически не требуют усилий.
В этой статье Шей Банон рассказывает о конфликте ElasticSearch с А WS из-за OpenSearch:
https://thenewstack.io/amazon-elastic-and-the-fight-for-open-source-freedom-in-the-enterprise/.
6
■
226
Глава
5
Следует рассмотреть возможность отмены обратной совместимости в тех случаях,
когда:
♦
Функция утратила актуальность. Ее больше не используют;
отличается,
API
что нарушает совместимость, но это не затрагивает потребителей.
♦ Приложение больше не требуется. У старевшее приложение выводится из экс
плуатации во время миграции, и пользователи отсутствуют.
♦
Сложность того не стоит. Переписать приложение и перевести всех потребите
лей на новую систему проще, чем поддерживать текущий
API,
или же появля
ются бизнес-возможности для роста с новой системой.
Принцип обратной совместимости применим к внутренним общим библиотекам,
базовым и бизнес-сервисам. Рекомендации по сохранению обратной совместимости
стандартны:
определите
контракт
и
проведите
тесты,
подтверждающие,
что
кон
тракт сохранен. Затем можно обновить код или даже полностью отключить базо
вую
реализацию,
потому
что
до
тех
пор,
пока
контракт
сохраняется,
с
вашими
потребителями все будет в порядке.
Контракт
Версия
Контракт
• Имеет 50 классов
1
реализации сервиса
Версия
Рис.
5.7.
• Имеет 30 классов
2
реализации сервиса
• Ввод заблокирован
• Ввод разрешен
Обратная совместимость в бизнес-сервисе
Давайте проиллюстрируем это на примере. На рис.
5. 7
изображены два сервиса
с одинаковым публичным контрактом, но с двумя совершенно разными реализа
циями. Реализация версии
1
содержит
50
классов и использует
Oracle
в качестве
базы данных; код полностью синхронизирован с блокирующим вводом-выводом.
Версия
2
сохраняет контракт версии
1,
но заменяет
Oracle
на
вели полный рефакторинг, сократили количество классов до
блокирующий ввод-вывод с использованием
Future
Cassandra. В ней про
30 и перешли на не
или асинхронного драйвера из
DataStax.
Как и все в архитектуре программного обеспечения, подход с обратной совмести
мостью не может полностью решить ваши проблемы и имеет свои недостатки.
♦ Проблема с контрактом. Очевидно, что вы не можете существенно изменить
контракт, если хотите сохранить обратную совместимость. Если контракт ока
зался неудачным, вы застряли с ним.
♦
Утечка информации о реализации контрактов. Допустим, из ваших контрак
тов утекают детали
реализации, такие
как прямое
использование
порядкового
Оценка
номера из вашей базы данных вместо
GUID,
■
227
не зависящего от реализации. Мо
жет быть сложно поддерживать порядковый номер, если вы хотите изменить
реализацию базы данных. Это ограничивает вашу возможность свободно изме
нять реализацию.
♦
Техническая задолженность. Если код сервиса низкого качества, обратная со
вместимость не решит проблему автоматически.
♦ Недостатки дизайна. Если сервис не соответствует бизнес-области или не при
носит пользы, сохранение контракта не решит эту проблему.
Недостатки можно устранить, не затрагивая потребителей, например:
♦ технический долг: может быть устранен путем рефакторинга или переписыва
ния;
♦
некоторые недостатки дизайна: могут быть устранены, если они присутствуют
в реализации.
Может оказаться, что некоторые необходимые изменения в контракте и/или дизай
не, влияющие на публичный контракт, невозможно внести без ущерба для потреби
телей. Вы можете решить внедрить их, несмотря на трудности с переходом на но
вый контракт у всех потребителей. Наш совет
-
необходимо тщательно проанали
зировать всю вашу экосистему. Это поможет вам лучше понять ситуацию и решить,
насколько вы готовы идти на компромисс. Возможно, часть изменений отложите на
будущее или реализуете в новых проектах.
Элементы надлежащей оценки
Правильно выполненная оценка
(assessments)
является ключом к получению пол
ной картины проблем в вашей системе, а также к обоснованию и выбору правиль
ных решений. К оценке можно подходить различными способами, но наилучшая
оценка начинается с ознакомления с кодом. Игнорируйте свои большие архитек
турные фреймворки, откажитесь от сертификатов CMMI7 и откройте свой IDE. Без
чтения кода невозможно провести полноценную оценку.
Масштабный анализ кода
Анализировать код
(code analysis)
сложно. Когда инженеры сталкиваются с плохо
написанным спагетти-кодом, они могут не захотеть продолжать работу. Главное это навык, который со временем будет совершенство
не бояться. Чтение кода ваться; читать код будет все проще.
Чтение кода требует времени. Еще одним важным методом, способным ускорить
ваше
7
понимание
кода,
является
отладка
CMMI (CapaЬility Maturity Model Integration) -
модульных или
интеграционных тестов.
это комплексная модель производительности и зрелости,
набор моделей (методологий) совершенствования процессов в организациях разных размеров и видов дея
тельности. CMMI содержит набор рекомендаций в виде практик, реализация которых, по мнению разработ
чиков модели. позволяет реализовать цели, необходимые для полной реализации определённых областей
деятельности.
-
Пер.
228
■
Глава
5
Если модульных/интеграционных тестов нет, можно отладить программное обес
печение через пользовательский интерфейс или любую другую доступную началь
ную точку.
Чтобы зафиксировать результаты анализа вашего кода, необходимо составить про
стую таблицу с совместным доступом в
Microsoft Excel
или
Google Sheet.
В этой
таблице нужно разбить существующую программную архитектуру на список ком
понентов. Если у вас распределенный монолит, это может быть перечень клиент
ских
API,
сервисов и библиотек. В случае классического монолита может быть
список классов
Java.
А если это модульный монолит с полным стеком, то у вас бу
дет разбивка ключевых модулей и зависимостей. Степень детализации
(granularity)
вашего программного обеспечения зависит от архитектуры приложения и от харак
тера кодовой базы, которую вы оцениваете.
EJ
Тип компонента
1
с,~
Публичный
Владелец
Ориентирован Скорость
-к-он_тра_кт___ .__на_по_льзо_ва_т-ел_я_.? ..._~~-~_::_ни_я_
__.
Уровень
1
зависимости
"
-~•~
Вышестоящие
прохождения/
Бизнес-область
зависимости
покрытие
(as-is)
тестами
Состояние баз данных
Рис.
5.8.
Параметры анализа кода
Давайте немного углубимся в то, что считаем основными аспектами анализа кода
(рис.
♦
5.8),
независимо от того, какое программное обеспечение вы оцениваете:
Название компонента. Название сервиса или системы; то, как люди восприни
мают компонент.
♦ Тип компонента. Опишите природу вашего компонента: интерфейсное прило
жение, серверное приложение, клиентский
API,
интеграционный модуль, кон
вейер передачи данных, сервис или микросервис, устаревшее настольное при
ложение, внутренняя общая библиотека, инфраструктурный модуль и т. д.
♦ Владелец. Частное лицо, команда или организация, являющиеся владельцами.
♦
Скорость изменения бизнеса. Как часто меняется бизнес-запрос? Ежедневно,
еженедельно; постоянно или редко?
♦
Состояние публичного контракта. Сколько контрактов публикует компонент?
Насколько они хороши? Насколько велик или сложен контракт?
♦
Список нижестоящих зависимостей. Перечислите нижестоящие сервисы или
интеграции. С кем общается этот компонент?
Оценка
♦
■
229
Список вышестоящих зависимостей. Перечислите все сервисы или компонен
ты, которые обращаются к этому компоненту, в идеале с указанием протоколов
и операций, которые они используют.
♦
Ориентирован на пользователя. Используют ли люди (потребители, сотруд
ники, подрядчики) этот компонент напрямую? Или это исключительно межма
шинная связь, т. е. сервис, вызывающий сервис?
♦
Сложность. Опишите сложность и неясность решения компонента. Перечисли
те известные антипаттерны и технические неполадки.
♦
Уровень прохождения
/
покрытие тестами. Насколько постоянен показатель
прохождения тестов? Имеет ли компонент достаточное покрытие тестами?
♦
Состояние баз данных. Насколько они изолированы? Кто является читателями,
а кто
♦
-
авторами? Для каких таблиц?
Бизнес-область
as-is.
Опишите естественные границы бизнеса, которые охва
тывают этот компонент. Далее в этой главе мы рассмотрим упражнения по со
поставлению предметной области.
У вас могут быть и другие аспекты, которые важны для вас, вашего бизнеса и
вашей уникальной ситуации. Не стесняйтесь добавлять их к этим аспектам, они
являются лишь отправной точкой.
Классификация и принятие решений
В конечном счете вашей компании придется принимать какие-то решения. Как пра
вило, в масштабах компании ситуация часто бывает сложной, и невозможно все
исправить одним решением. Ваш выбор не является бинарным. Например, инжене
ры хотели бы принять единственное решение
-
переписать все заново. Но про
граммного обеспечения слишком много, расходы были бы слишком велики и ис
тощили бы компанию на годы.
Поэтому необходимо провести некоторую рационализацию, рассмотрев следующие
категории (рис.
5.9):
Улучшить
Игнорировать
Рис.
5.9.
Переписать
Вывести
из эксплуатации
Рационализация классификации
230
Глава
■
5
♦
Переписать. Какие компоненты можно и нужно переписать?
♦
Улучшить. Какие компоненты можно сохранить за счет некоторой степени ре
факторинrа?
♦
Вывести из эксплуатации. Какие компоненты следует вывести из эксплуата
ции?
♦ Игнорировать. Какие компоненты хороши или приемлемы в том виде, в котором они есть?
Но давайте не будем спешить с выводами, пока не разберемся в каждом из аспектов
анализа кода. В конце концов, вы не можете выносить суждения о том, чего не по
нимаете.
Владелец
В предыдущих главах мы рассмотрели, насколько важно иметь четкие границы
владения
(ownership)
программными компонентами. У современных решений есть
Jul
.....
б,
2008 - Feb 16, 2023
.
..
•
1
1 s~r~~n
.
,.,.
:м.,,,.
,
..
,Шнi4+н 1 '4,м, , ,
201е
..
J'>ot'U••
.......u..i.11.., . , Jilo.11A.i
2СО)
201•
2022
.,
...
..
.
.-., +Ji, ь+A:tNt,f: Ьtltti:N , ,.,
1010
2018
""'
11....1....... ,
.,
. ,.
Источник:
.
...
.
Рис. 5.10. Лучшие редакторы кода Spring на GitHub.
https://github.com/spring-projects/spring-framework/graphs/contributors
.
Оценка
явные владельцы кода; например, у
хранить в своем репозитории
щих в файле
те
GitHub
CODEOWNERS
git
GitHub
■
231
есть функция, которая позволяет вам
файл, отображающий всех ваших сопровождаю
(владельцы кода/. Конечно, в случае если вы не используе
или применяете более старый инструмент управления конфигурацией
программного обеспечения
(Software configuration management, SCM),
можете при
нять собственное соглашение.
Организации редко получают право собственности на компоненты. Даже на на
чальном этапе разработки, когда ясно, кто создал компонент, отдельные лица могут
покинуть компанию из-за размывания команды, и вы вернетесь к исходной точке.
В такой ситуации можно изучить коммиты и написать простой скрипт, который
соберет
или
12
5-1 О
самых активных участников в вашем репозитории за последние
3, 6
месяцев. Скорее всего, это и есть настоящие владельцы текущего кода. Ис
пользуя пользовательский интерфейс
вы можете легко просмотреть эту
GitHub,
информацию для каждого репозитория; например, на рис.
редакторы кода для
5.10
показаны основные
Spring Framework.
Если сложно получить эту информацию с помощью инструмента
SCM,
можно най
ти ссылки на кодовую базу или компонент в инструменте управления запросами,
таком как
JIRA.
Обратитесь к своим сотрудникам: спросите архитекторов или
старших инженеров. Возможно, они знают фрагмент кода, который вы изучаете.
В противном случае, возможно, вы просто нашли код без подлинного владельца.
Такое, к сожалению, часто встречается в старом коде монолитов.
Скорость изменения бизнеса
Чтобы лучше понять этот аспект, важно различать чисто технические изменения
и изменения, обусловленные бизнесом. Каждый раз, когда команда обновляет код
и это изменение не приводит к прямой выгоде для бизнеса, мы будем определять
его как техническое изменение. Техническое изменение может включать:
♦ Исправление безопасности. Как для библиотеки сервиса, такой как
для
поддерживающей
Ubuntu
или
инфраструктуры
/
операционной
log4j,
так и
системы, такой
как
Windows Server.
♦ Незначительные изменения в библиотеке. Из-за исправления ошибки, напри
мер обновление java
♦
commons-lang3
с версии
3 .8.0 до 3 .8.1.
Внутренняя миграция. Обновление ваших внутренних общих библиотек, клиентов/драйверов и конфигураций.
♦
Облачная миграция. Эволюция, обновления для перехода с А WS
♦
Миграция JDК. Обновление, например
Elb
на
Alba.
Java 8 до Java 17.
Мы не отрицаем ценность технических изменений. Они могут быть необходимы
для обеспечения безопасности, снижения затрат и/или повышения производитель-
8
Соглашение о владельцах кода (CODEOWNERS convention) широко используется на GitHub и полностью
поддерживается в рабочих процессах:
https://docs.github.com/en/repositories/managing-your-repositoryssettings-and-features/customizing-yourrepository/about-code-owners.
232
■
Глава 5
ности. Часто они происходят в ходе обычной разработки. Однако иногда разработ
чики хотят внести изменения ради самих изменений, предпочитая стиль функцио
нальности и реальной пользе. Подобного следует избегать.
Бизнес-изменения обусловлены желанием и потребностью в создании новых функ
ций или исправлении ошибок в коде, с которыми сталкиваются клиенты. Компо
ненты, которые часто меняются, имеют важное значение в жизненном цикле орга
низации и, возможно, являются критически важными для бизнеса. На самом деле
быстрые изменения дают инженерам возможность инвестировать без претензий;
и наоборот, низкий уровень изменений означает, что бизнес может не обращать
внимания на этот компонент и отказываться от значимых инвестиций. Ваш анализ
должен быть глубоким. Даже тот факт, что компонент не обладает пользователь
ским интерфейсом, ориентированным на клиента, не дает бизнесу права игнориро
вать его. Косвенные зависимости могут образовывать несколько уровней, позво
ляющих выявить критически важный для бизнеса компонент.
Скорость изменений показывает, насколько быстро код адаптируется к потребно
стям бизнеса. Быстро меняющийся бизнес-код показывает, что команды нуждаются
в быстрой разработке. Команды, находящиеся под давлением, допускают ошибки.
По нашему опыту, сервисы с высокой скоростью бизнес-изменений накапливают
технические долги и сложность в больших объемах, поскольку на тщательное про
ектирование и архитектуру остается все меньше времени. Внимательно прочитайте
код этих сервисов, оцените технические долги и сложность, чтобы выявить скры
тые проблемы. Небольшой сервис может быстро вырасти в размерах под давлением
бизнеса
(business pressure ).
Не стоит просто измерить его один раз и игнорировать
в течение нескольких лет; ваш снежный ком может быстро превратиться в гору
спагетти-кода.
Публичные контракты
В предыдущих главах мы подробно рассматривали публичные контракты (puЬ\ic
contracts).
Понимание масштабов публичных контрактов для ваших компонентов
чрезвычайно важно по следующим причинам.
1.
Тестирование: вы можете применить контрактное тестирование
/
интеграцион
ные тесты и убедиться, что не нарушаете работу потребителей и все продолжает
работать так, как ожидалось.
2.
Метрики: размер и сложность публичного контракта могут подсказать вам, на
сколько легко вы сможете провести рефакторинг этого контракта.
3.
Анализ контракта: понимая масштабы публичного контракта, а также вариан
·:ты его использования, вы можете определить, является ли контракт подходящим
или нет.
Распознать публичный контракт бывает сложнее, чем кажется, потому что могут
быть скрытые контракты. Вот несколько примеров.
♦ Внутренние общие библиотеки. Представьте, что в библиотеке вызывается
класс, к которому не следует обращаться. В
Java
часто делают все классы обще-
■
Оценка
233
доступными, что может привести к злоупотреблениям со стороны пользова
телей.
♦ Общие таблицы. Когда у вас есть сервис, подключенный к базе данных, все
вызовы RPC 9 должны выполняться через публичный контракт сервиса, т. е. ин
терфейс
REST/HTTP.
Тем не менее пользователи могут получить доступ к таб
лицам напрямую, минуя сервис.
♦
Общие объекты и файлы. Перечисления,
POJO
и общие конфигурационные
файлы, используемые несколькими сервисами, также являются формами скры
тых контрактов.
Инвентаризация публичных контрактов может показаться простой задачей, но для
полного анализа может потребоваться много времени, особенно при работе с боль
шими кодовыми базами. Часто этот анализ хорошо сочетается с тестированием.
Когда вы находите публичный контракт, оцените, полностью ли он охвачен теста
ми. Затем воспользуйтесь моментом, чтобы добавить недостающие модульные, ин
теграционные тесты и тесты контракта.
Нижестоящие зависимости
Компоненты вызывают другие компоненты; сервисы вызывают другие сервисы.
Сервисы, от которых зависит функционирование любого компонента, являются его
нижестоящими зависимостями. Нижестоящие зависимости
cies)
(downstream dependen-
важны для получения полной картины пути доступности компонента и для
выявления любых временных связей между компонентами. Это является важным
фактором при выполнении оценки.
При наличии бинарных или библиотечных зависимостей, как мы показали в главе
4
«Антипаттерн: внутренние общие библиотеки», для анализа графика зависимо
стей можно использовать свой инструмент сборки, такой как
Maven
или
Gradle.
Но
определение зависимостей во время выполнения может оказаться не таким про
стым делом.
Современные инструменты обеспечения наблюдаемости, такие как А WS
(https://aws.amazon.com/xray/),
предоставляют
карты последующих вызовов. Существует также
способы
построения
сервисной
Zipkin (https://zipkin.io/)
в качест
ве альтернативы с открытым исходным кодом. Другие решения, такие как
(https://kiali.io/)
для
Kubemetes/Istio,
X-Ray
Kigali
также могут показать текущую топологию
сервисов, запущенных в кластере. В качестве альтернативы просто просмотрите
журналы исходящего доступа вашего приложения, если таковые существуют. Все
это отличные способы обнаружить ваши нижестоящие зависимости.
9
RPC (от англ. remote procedure call) -
это класс технологий, позволяющих программам вызывать функции
или процедуры в другом адресном пространстве (на удаленных узлах либо в независимой сторонней систе
ме на том же узле).
-
Пер.
234
■
Глава 5
Вышестоящие зависимости
В той мере, в какой мы смотрим вниз по течению, нам также необходимо смотреть
вверх по течению: что зависит от этого компонента? Кто является потребителем
этого конкретного программного обеспечения? Примерами возможных вышестоя
щих потребителей могут быть другой сервис, другой модуль или компонент в ва
шем монолите, внешний
API,
интерфейсное приложение, настольное приложение
или классический монолит.
Также важно понимать варианты и сценарии взаимодействия пользователей с ва
шим программным продуктом. Почему они вызывают этот компонент или класс?
Что и как они хотят сделать? На какие функции вашего сервиса они полагаются?
Иногда функции больше не нужны. Наличие кода, его тестирование и даже реали
зация не всегда означают, что функция действительно необходима.
Обнаружить вышестоящих потребителей трудно, потому что их невозможно найти,
просто просмотрев код. Вызовы выполняются только по сети, а для входящих
вызовов вы можете не найти следов в своей базе кода. Нужно обратиться к более
широкой базе кода всего вашего решения в поисках ссьmок, изучить журналы дос
тупа для всего предприятия или, в идеале, воспользоваться инструментами распре
деленной трассировки, которые мы описали в предыдущем разделе.
Код ориентирован на пользователя?
Когда мы обсуждаем вышестоящие зависимости или потребителей, мы подразуме
ваем межмашинные зависимости вашего программного обеспечения. Каждая из
этих зависимостей использует какой-либо протокол связи, такой как
НТТР, или
GRPC,
устаревший классический
RPC,
REST
через
или прямой вызов компонента
в классическом монолите.
Измерение, ориентированное на пользователя
(User Facing dimension),
охватывает
взаимодействие с людьми, возможно, с помощью устаревшего графического ин
терфейса настольного приложения, современного веб-приложения или внешнего
интерфейса, ориентированного на ваших клиентов, или даже макроса
вызываемого
Microsoft
Ехсе\ или
Access.
Visua\ Basic,
Современные приложения могут упро
стить понимание ваших пользователей, если они используют такие аналитические
инструменты, как
Google Analytics
или Неар
Analytics.
Они покажут, какие страни
цы или функции действительно популярны, а какие вообще не востребованы.
Сложность
Сложность
(complexity)- один
из самых важных показателей, на который следует
обратить внимание при анализе кода. Сейчас самое время указать на любые техни
ческие проблемы и несоответствия в дизайне. Для оценки задайте следующие
вопросы.
♦ Технические проблемы: какие технические проблемы присутствуют в базе кода?
♦ Тип монолита: есть ли у нас признаки классического или распределенного мо
нолита? Является ли сам компонент классическим монолитом? Считаете ли вы,
Оценка
■
235
что компонент вносит свой вклад в распределенный монолит из-за отсутствия
независимого развертывания или внутренних общих библиотек?
♦
Надежность кода: трудно ли читать код или его сложно поддерживать?
♦
Проблемы с исправлением ошибок: много ли у нас ошибок, связанных с этим
компонентом?
♦
Доступность: часто ли этот компонент недоступен?
♦
Производительность:
часто ли компонент испытывает большую нагрузку?
Существуют ли заметные узкие места в производительности?
Бизнес-правила: имеются ли в компоненте сложные бизнес-правила?
♦
Метрики кода способны помочь выполнить оценку. SonarQube 10
-
популярный
инструмент анализа кода с открытым исходным кодом, который предоставляет раз
личные показатели в прозрачной форме.
системами сборки, такими как
Maven
и
SonarQube интегрирован с несколькими
Gradle, и предоставляет простой способ
сканирования исходного кода ваших проектов и получения подробных отчетов.
На рис.
-flt
показан пример отчета
5 .11
~ SonarQuЬe
lssues
Findbugs Plugin
COde
Measures
Quat,ty Gate
SonarQube.
-
--
,_
Flnd8ugs IS а J)fOQram that uses stauc
Ьugs in Java code tt сап
detect а vaлety of common eodll"IQ mtStakes.
1nclu<Jing thread synchroniZatton proЬlems,
anatysts to look for
Leak
Bt1gs & Vulnerabllitles
PerкxJ'
.а~2
о
Vul~raь11111es
8LIQS
28 2016 2 00 РМ Vetson Э 4 4
NOW-mьet'
Ad1flfltst1auon •
NewBugs
last зо days
IOt'
ао
mtsuse of API methods
о
New
2.4k
Java -
of Code
LIП(>
21•
XMl. 1 290
VUlnerablllties
Quallty Gote
{~au11}
Code Smells
S011.irQuьe
way
Quallty Prottles
(.,ava) SOnar way
73
DеЫ
CodeSrne,IIS
о
Ne-,1DeЬt
о
NewCode
Smells
f'(Mt
Sonar way
4t Home
Jit
lssues
С) Sources
О
Duplicatюns
Oeveloper connectюn
Кеу
0.0%
о
Dupl1Catюнs
Dupl1cat&d Blocks
org.sonarsource.sonar-flooЬugs-ptug1n-.sona,
Du~icauons оп New Code
Events
Ai'
Vtrslon 3.4 4
,vw:·IЬef.._ti
"Jl~
Quallty Gate Green {was Red)
Nuv,
Рис.
F
)11
5.11. Отчет SonarQube, Источник: https://en.wlkipedia.org/wiki/SonarQube
10 SonarQube один из самых популярных инструментов анализа Jаvа-кода с открытым исходным кодом:
https://docs.sonarqube.org/latest/,
236
■
Глава
5
SonarQube требует настройки. Возможно, потребуется настроить правила и исклю
SonarQube поможет вам оценить техническое состояние всех программных
чения.
компонентов, даже если вы не настроите конкретные правила.
Уровень прохождения
Охват тестированием
/
покрытие тестами
(test coverage) -
еще один ключевой показатель. Что важнее:
стопроцентная проходимость или стопроцентный охват тестированием? Вопрос
с подвохом: стопроцентный охват тестированием
это миф. Инструменты, обе
-
щающие простую оценку охвата тестированием, обычно проводят только простые
типы тестов, такие как модульные тесты, тесты контрактов и интеграционные тес
ты,
реализованные
junit.org/junit5/).
в распространенных платформах, таких как
JUnit (https://
Однако они упускают из виду другие возможные формы тестиро
вания, такие как стресс-тестирование, хаотическое тестирование, тестирование баз
данных или тестирование конфигурации. Кроме того, эти инструменты часто до
пускают простые ошибки, например путают модульные тесты с интеграционными.
Классические монолиты часто страдают от недостатка автоматизированного тести
рования. Так что повезет, если там вообще найдутся какие-нибудь тесты, которые
вам помогут. Автоматизированные и надежные тесты важны, потому что после
внедрения
проекта модернизации
или
перехода
на
соответствующие
сервисы
вы
сможете полагаться на тесты, чтобы определить, все ли работает корректно.
Анализ базы данных
Теперь, когда вы освоили методы анализа и инвентаризации кода, для подавляюще
го большинства оценок важно обратить внимание на состояние ваших хранилищ
данных. Необходимо провести инвентаризацию баз данных, используемых вашими
программными компонентами. Вы можете обнаружить один или несколько различ
ных сценариев:
♦
Классический монолит. Единая база данных для всех сервисов.
♦
Микросервисы или надлежащие сервисы. Сервисы могут иметь выделенные
базы данных и не иметь общего доступа к ним, что является идеальным сцена
рием.
♦ Распределенный монолит. Сервисы могут иметь свои собственные базы дан
ных, но также иметь доступ к общим базам данных.
♦
Различные фреймворки доступа к данным. Сервисы могут использовать раз
личные формы доступа к данным, помимо простого
♦
SQL.
Изолированные схемы. Сервисы указывают на один и тот же кластер базы
данных, но используют разные схемы.
♦
Изолированные таблицы. Сервисы используют одни и те же схемы, но запи
сывают и считывают данные в разные таблицы.
Оценка
■
237
Классификация уровня независимости
Распределенные монолиты, изолированные схемы и изолированные таблицы - это
разные точки спектра независимости базы данных с точки зрения уровней взаимо
действия. Оценить
их бывает непросто.
Для определения зависимости
можно
использовать следующий подход.
♦ Низкий уровень. Один или два сервиса, используют одну и ту же схему или
группу таблиц.
♦
Средний уровень. Несколько сервисов, используют одну и ту же схему или
группу таблиц.
♦
Высокий уровень. Сотни сервисов, используют одни и те же таблицы (распреде;1енный монолит).
Определение уровня независимости позволит вам понять, можете ли вы разделить
таблицы или схемы и использовать их как единое целое или же нужно переписать
сценарий для пользы бизнеса. Распределенные монолиты
-
это всегда самые
сложные сценарии. Классические монолиты часто проще, чем распределенные, по
тому что весь код находится в одном месте, и его гораздо проще реорганизовать и
проанализировать последствия. В распределенных монолитах влияние может быть
неочевидным и проявляться только постфактум.
Классический монолит
В главе
1 « Что
не так с монолитами?» мы определили, что типичный классиче
ский монолит будет иметь один большой программный компонент и, аналогично,
выполнять чтение и запись в один большой кластер реляционных баз данных, даже
в одну схему. При планировании будущего развития стоит рассмотреть возмож
ность разделения базы данных по бизнес-областям. Возможно, некоторые таблицы
изолированы, и целесообразно извлечь их с помощью изолированного соответст
вующего сервиса.
Микросервись1 или надлежащие сервисы
Снова и снова мы видим, как организации прибегают к микросервисам, но непра
вильно понимают их ключевые элементы. Не всегда. Возможно, вам повезет, и не
которые или все ваши микросервисы будут иметь правильную структуру базы дан
ных, полностью независимую от всех других компонентов с изолированным физи
ческим оборудованием, схемами и таблицами. Но даже в этом случае у ваших
сервисов все равно могут возникнуть серьезные проблемы.
♦ У вас много сервисов, которые, возможно, когда-то представляли ценность, но
не служат никакой цели в вашей новой архитектуре.
♦ Возможно, сервисы слишком малы, их необходимо объединить, чтобы не тра
тить ресурсы базы данных на ненужное разделение.
♦ Вы знаете, что вам нужно прекратить использование сервиса, но не можете убе
дить бизнес продолжить реализацию проекта. Очистка кода так и не становится
приоритетной.
238
■
Глава
5
Возможно, что с вашей микросервисной архитектурой все в порядке. В таком слу
чае поздравляю
-
вы один из редких счастливчиков!
Если вам удалось создать правильные сервисы, подобные тем, которые мы опишем
в последующих главах, то это отлично. Вы не только избежали проблем, связанных
с микросервисами и распределенным монолитом, но и уверены в принципах проек
тирования и архитектуры баз данных, которым мы вас научили. Тем не менее биз
нес-требования меняются. Оцените степень детализации сервиса, а также размер
и масштабируемость ваших баз данных на предмет необходимости расширения и
консолидации сервисов или их дальнейшего разделения.
Распределенный монолит
Конечно, как мы показали в главе
3
«Антипаттерны: распределенные монолиты»,
более вероятным сценарием с наивно спроектированными микросервисами являет
ся распределенный монолит. В этом случае развязка может оказаться очень слож
ной, и не исключено, что вам придется рассмотреть возможность переписывания
системы. Имея это в виду, вот несколько стратегий, которые следует рассмотреть:
♦
Предложите полностью переработать проект с выгодой для бизнеса. В результа
те вы сможете работать независимо и больше не будете использовать общие
концепции баз данных. Бизнес будет инвестировать, потому что проект откроет
новые возможности для роста, внедрит инновационные функции или напрямую
увеличит прибыль.
♦
Своевременно внедряйте новые возможности. Беритесь за бизнес-проекты или
технические проекты, которые потребуют создания по-настоящему независимой
базы данных. Но делайте это постепенно, сохраняя синхронизацию со старой
базой данных. Интеграция может быть сложной, сроки могут быть длительными
и сопряжены с определенными рисками, но иногда это лучший вариант.
♦
Вместо того чтобы создавать новое собственное решение, купите его. Оно мо
жет подойти для некоторых сервисов, но вряд ли подойдет для вашего основно
го бизнеса. Синхронизация и преобразование данных могут оказаться очень
сложной задачей при переходе от специализированной системы к готовому
варианту. Будьте готовы к дополнительным расходам за преобразование и раз
работку на заказ. В любом случае об этом следует задуматься.
Различные фреймворки доступа к данным
Когда люди слышат о классическом или распределенном монолите, они сразу
думают об
SQL.
Но, возможно, в вашей системе используется нереляционная база
данных. Это не сильно меняет картину, в стратегическом плане задачи те же.
Изолированные схемы
Есть что исследовать. Иногда на первый взгляд может показаться, что компоненты
связаны общей базой данных. Но, углубившись в код, вы обнаружите, что они ни-
Оценка
■
239
когда не используют одни и те же схемы и логически изолированы. Вы открыли
для себя прекрасную возможность, которую следует отметить. Введение· физиче
ского разделения может быть простым и быстрым решением, которым вам следует
воспользоваться.
Изолированные таблицы
Как и в случае с изолированными схемами, нужно обратить внимание на использо
вание таблиц в вашем коде. Использование одной и той же схемы не обязательно
означает, что компоненты используют одни и те же таблицы. Хотя вы, возможно,
нечасто сталкиваетесь с подобным в реальной жизни, не ожидайте худшего
-
вы
можете быть приятно удивлены.
Сопоставление бизнес-областей
Сопоставление бизнес-областей
(domain mapping) -
это процесс анализа ключевых
бизнес- и технических аспектов деятельности вашей организации и их логической
группировки, помогающий планировать разработку и организовывать ключевые
процессы. Сопоставление бизнес-областей
-
ключевой навык для разработчиков
программного обеспечения. Им следует постоянно заниматься не только в контек
сте модернизации и исправления монолитов, но и по мере дальнейшего развития
ваших систем и предоставления новых возможностей и инноваций.
Сопоставление предметной области основано на принципах моделирования пред
метной области (Domain Driven Design, DDD) Эрика Эванса 11 . DDD - это подход
к проектированию
и
моделированию программного обеспечения,
при
котором
предметная область находится в центре всего. Предметное мышление формирует
архитектуру и дизайн, опираясь на понимание бизнес-правил, причин изменения
данных, а также бизнес-процессов, вариантов использования, бизнес-терминов и
языка, используемого экспертами в предметной области.
DDD имеет ряд принци
(Domain), ограниченный кон
текст (Bounded Context), многоуровневая архитектура (Layered Architecture), сущ
ности (Entities), значения объектов (Value Objects), агрегаты (Aggregates), фабрики
(Factories), события предметной области (Domain Events), сервисы (Services), хра
нилище (Repository), контекстные карты (Context Maps) и шаблоны ограниченного
контекста (Bounded Context Pattems).
пов и базовых основ, таких как предметная область
Эксперты в предметной области сообщают инженерам и архитекторам о потребно
стях бизнеса и о том, как он должен работать. Мы используем эту информацию для
разработки программного обеспечения, но можем упустить концепции при перево
де. В будущем это может привести к ряду проблем, таких как:
♦ Пробелы в коммуникации. Обсуждение новых функций и ошибок может быть
затруднено.
11
Книга Эрика Эванса 2003 года «Дизайн, управляемый предметной областью: решение сложных задач
в основе программного обеспечения»
(Domain Driven Design: Tackling Complexity in the Heart of Software)
остается захватывающим чтением. имеющим большое -значение для разработчиков архитектуры программ
ного обеспечения.
240
♦
■
Глава
5
Пробелы в дизайне. Программное обеспечение может вести себя не так, как
ожидает бизнес, и вносить изменения может быть труднее.
♦ Технический долг. У нас может быть сложный код, в котором мы выполняем
ненужные шаги, потому что наше понимание задачи неверное или в нем отсут
ствуют ключевые концепции. В результате код получается менее точным, чем
должен быть.
Чтобы восполнить этот пробел,
вания языка (uЬiquitous
DDD вводит концепцию повсеместного использо
language): общего словаря, который инженеры, дизайнеры и
эксперты в предметной области должны всегда использовать, чтобы говорить на
одном языке и сократить разрыв между системным проектированием и коммуника
циями.
Моделирование предметной области
DDD -
это не полнота и не попытка идеально
отобразить реальность в ваших бизнес-областях, это не знание всех деталей, а вне
дрение ключевых абстракций для эффективной разработки программного обеспе
чения и проектирования бизнес-процессов. Идеальное
-
враг хорошего. В про
граммном обеспечении мы сталкиваемся со множеством задач и вариантов исполь
зования и не всегда можем решить все проблемы в рамках одной предметной
области с помощью одной абстракции. Как и в любом анализе архитектуры про
граммного обеспечения, здесь нет серебряной пули, универсального решения,
и
DDD
не является исключением. В
DDD
мы будем использовать несколько моде
лей, и это нормально точно так же, как нормально наличие нескольких сервисов
в архитектурах
DDD
SOA
или микросервисов.
можно использовать во многих сценариях, но при разработке программного
обеспечения мы разделяем их на две категории: «зеленое поле» и «коричневое по
ле». Представьте, что мы создаем новый сервис. Если сервис изолирован, мы сво
бодны в разработке нашей предметной области и моделей. Однако, когда мы имеем
дело с устаревшими системами и пытаемся устранить неполадки с помощью ини
циатив по модернизации, к сожалению, мы не можем позволить себе сразу отка
заться от всего старого программного обеспечения. Поэтому нам необходимо вне
сти рациональные изменения с учетом, того, что:
♦
Можно игнорировать. Даже при наличии пробелов, какое программное обес
печение мы можем оставить как есть? Это правильный выбор только в ситуаци
ях, когда влияние на бизнес невелико или вообще не имеет значения.
♦ Несет преимущества для бизнеса. Что можно улучшить и что принесет пользу
бизнесу? Ищите большое положительное влияние на бизнес
(business
iшpact).
♦ Является «низко висящим плодом». Какие изменения легко осуществить?
Если предстоящие изменения не окажут существенного влияния на бизнес, воз
можно, стоит их проигнорировать.
♦ Имеет рыночные ориентиры. Конкуренты вынудили вас действовать, и вам
нужно наверстать упущенное.
♦ Является обязательным требованием. Силы, которые вы не можете остано
вить. Юридические требования или требования законодательства не оставляют
Оценка
■
241
выбора, иначе программное обеспечение выйдет из строя и/или перестанет
функционировать.
Для сценариев модернизации именно здесь важно сопоставление предметных об
ластей: сгруппируйте сервисы по бизнес-областям, насколько это возможно. Груп
пировка обеспечивает ключевые преимущества:
♦
Группировка системы по бизнес-областям позволяет четко определить приори
теты, поскольку мы можем соотнести технологии с ценностью для бизнеса и
оценить отдачу от инвестиций в наши изменения.
♦
Согласование сервисов помогает разобраться в них и увидеть различия и сходства, предлагая возможности для их объединения или разделения.
Для распределенных и классических монолитов могут возникнуть трудности с при
вязкой программного обеспечения к бизнес-областям. Возможно, код запутан или
в компании не осталось реальных владельцев или экспертов в этой области. Высо
кая степень связности и техническая сложность затрудняют сопоставление бизнес
областей. Для исправления ситуации можно рассмотреть следующие подходы.
♦
Перечислите все предметные области. Вместо подробного сопоставления биз
нес-областей вашей кодовой базы просто перечислите все имеющиеся предмет
ные области. Извлекайте по одной бизнес-области за раз.
♦
Поместите систему в карантин. Пометьте ее как «большой ком грязи» и созна
тельно ограничьте количество разрешенных изменений в системе. Остановите
процесс ухудшения и предотвратите дальнейшее развитие проблемы.
♦
Войдите в самое сердце тьмы. Сделайте самое сложное, найдите в коде пред
метные области «как есть», но сопоставьте их с совершенно новой структурой
бизнес-областей, которая отражает то, как на самом деле работает ваша компа
ния сегодня.
Список всех бизнес областей
Когда дело касается сложного и запутанного кода с множеством объектов и таблиц,
подробное отображение может показаться пугающим. Простое перечисление всех
предметных областей, охватываемых монолитом, может быть четким и понятным.
Это станет хорошей отправной точкой. Конечно, важно понимать, действительно
ли используется бизнес-область, о которой идет речь, или это просто мертвый код
или потерянная ссылка.
Возможно, приведенные предметные области можно было бы разделить на уровне
кода, но вместо этого они связаны на уровне доступа к базе данных. Перечислив
бизнес-области, можно найти возможности для разделения или вывода из эксплуа
тации в пользу других решений.
Рассматривая рис.
5.12,
можно предположить, что платежи по кредитным картам
можно осуществлять с помощью существующего SааS-провайдера
-
это могло бы
стать одним из способов уменьшить размер распределенного монолита и количест
во бизнес-областей. Что касается авторизации и аутентификации, это довольно об
щий подход и может стать новым изолированным сервисом. Не исключено, что на
первый взгляд сложно определить конкретные проекты или быстрые выигрыши
242
■
Глава 5
в рамках своих бизнес-областей. Но даже в этом случае оценка поможет понять
степень взаимосвязи и сложности в распределенном монолите. Перечисление биз
нес-областей
-
хорошее начало.
•
Реализация сервиса
ОбщаяБД
Продажи/маркетинг
•
Брон ирование авиабилетов
•
Бронирова ни е отелей
•
Операции бэк-офиса
•
Проверка платежей
•
Платежи по кредитным картам
•
Аудит/ предотвращение мошенничества
•
Аутентификация/авторизация
\._.
Рис.
5.12.
l
r
_/
Список бизнес-областей в примере распределенного монолита
Помещение системы в карантин
Попытка выделить проблему может быть эффективным решением, но это непросто.
Важно соблюдать осторожность . Если у вас уже есть распределенный монолит
с нечеткими концепциями, не стоит изолировать проблему, создавая новый сервис
или копируя код, чтобы не ухудшить ситуацию Давайте проиллюстрируем это дву
мя примерами: в одном мы успешно устраняем проблему и улучшаем сервис, а
в другом
-
решение приводит к худшему положению, чем было в начале.
Изолированная новая функция (рис.
5.13, слева): допустим,
Google или Meta 12
ла клиентам входить в систему через
компания предложи
с помощью
Новые кодовая база
OpenID
/ сервис
не устраняют проблему ..
Общественный контракт
Реализация
общественного
Реализация сервиса
сервиса
Общественное
Общая БД
хранилище
Изоли рованна я но вая функци я
Проблема усугубляется
(Хорошо)
( Плохо)
Рис.
12
5.13.
Правильные и неправильные решения
Организация запрещена на территории РФ. -Ред.
Новая реализация
сервиса
Оценка
■
243
Connect 13 . Ваши возможности аутентификации объединены в распределенный мо
нолит, который вы поместили в «карантин». Эта функция является довольно уни
версальной и не обязательно должна быть в распределенном монолите, несмотря на
то, что там присутствует аутентификация. Браузер пользователя может перенапра
вить на нашу новую функциональность и предоставить к ней доступ отдельно от
стандартного входа по электронной почте. Несмотря на то что нам нужны новые
таблицы, мы предпочитаем не предоставлять общий доступ к базам данных и не
переносить данные. Наш результат великолепен и является хорошим примером
того, как мы успешно устраняем проблемы.
Усложнение проблемы (рис.
5. 13,
справа): теперь давайте представим другой сце
нарий, в котором мы нарушаем карантин. Владельцы распределенного монолита
аутентификации настаивают на том, чтобы мы использовали их программное обес
печение повторно. Однако у них нет времени на разработку новых
API.
Вместо это
го они предлагают нам выполнять чтение и запись из общих таблиц для объедине
ния сеансов
-
тех же самых общих таблиц, которые используются в любой другой
системе. Помните, что это распределенный монолит.
Итак, вы оцениваете два варианта:
♦
Создание новоrо сервиса. «Микросервиса» с новой кодовой базой, но с исполь
зованием той же базы данных и общих таблиц.
♦
Внутренняя общая библиотека. Ускорьте работу с общими таблицами, ис
пользуя внутреннюю общую библиотеку от команды распределенного монолита
в новом «микросервисе».
В обоих случаях вы не устранили основную проблему: отсутствие изоляции базы
данных в нашем распределенном монолите. Нарушение карантина только увеличи
ло размер распределенного монолита, а во втором случае теперь вдобавок ко всему
у вас есть бинарная связь! Написание кода в новом сервисе не решит всех проблем,
если оно выполнено неправильно. В конце концов, решения нужно принимать
в каждом конкретном случае, тщательно оценивая ситуацию. Нельзя просто пред
полагать, что новая база кода будет лучше. В последующих главах мы расскажем,
как создавать надлежащие сервисы и эффективно переходить на них.
Результаты оценки
Теперь, когда вы подготовили свою оценку, пришло время обобщить результаты
и предложить рекомендации для достижения желаемых изменений.
Быстрые результаты
В результате оценки вы, возможно, выявили быстрые результаты
(quick wins)
и возможности для внесения реальных улучшений при небольших инвестициях.
13
Основан на протоколе OAuth 2.0: https://openid.net/developeгs/ho,v-connect-woгks.
■
244
Глава 5
Эти возможности могут быть связаны с широким набором компонентов, включая,
но не ограничиваясь ими.
♦
Код, основанный на той же базе кода, но использующий другую изолированную
группу таблиц.
♦ Код, использующий разные таблицы либо в той же самой, либо в другой схеме.
♦
Низкая степень связи группы функций в рамках бизнес-области, что позволяет
легко вынести эту группу функций из сервиса в выделенный и полностью изо
лированный сервис.
♦ Недостаток интереса со стороны бизнеса может привести к выводу из эксплуа
тации сервисов или простому удалению ненужного кода и данных.
♦ У вас отличные показатели прохождения тестов и хороший охват, поэтому вы
можете с уверенностью разделять компонент.
♦
У вас есть несколько относительно независимых компонентов с небольшим ко
личеством мест для разделения кода, и разделение можно произвести с мини
мальными усилиями.
Быстрые победы хороши тем, что они приносят немедленную пользу технологиче
ским
и бизнес-командам и укрепляют доверие к проектам по
модернизации.
В оценках следует отметить, какие сервисы/системы представляют собой «низко
висящие
плоды»,
потому что
которые легко улучшить,
позже,
когда
вы
начнете
расставлять приоритеты в работе, эта информация пригодится. Чтобы быть уверен
ным в быстрой победе, вам, конечно, нужны результаты полного анализа кода. Это
поможет узнать, кто использует эту конкретную функцию или группу таблиц. Без
такого анализа невозможно оценить влияние изменений на всю организацию. Как
упоминалось ранее в этой главе, такие инструменты, как распределенная трасси
ровка или анализ с помощью инструментов
SCM,
например
GitHub,
помогут уви
деть эффект от изменений.
Определение приоритетов, ожиданий и стратегии
После завершения оценки у вас появится отличная основа для обсуждения ожида
ний
(expectations),
расстановки приоритетов
(prioritization)
и стратегии
(strategy)
с руководством отдела технологий и бизнеса. Прежде всего, ваш бизнес может
бьпь в курсе того, почему текущее положение дел является неприемлемым. Не
смотря на то что бизнес может не до конца осознавать технические сложности,
у него часто возникают повторяющиеся и явные проблемы, такие как:
♦ простои, нестабильность, потеря данных;
♦ медленное выполнение заказов, длительное ожидание появления новых функций;
♦ высокая стоимость обслуживания;
♦ высокая текучесть кадров;
♦ плохой пользовательский опыт, отсутствие мобильных приложений;
Оценка
♦
■
245
рыночные факторы, такие как низкие темпы роста или конкуренты/стартапы,
угрожающие бизнесу.
Убедить бизнес на начальном этапе, что все должно быть по-другому, может быть
легко. Но сложнее всего поддерживать многолетний дорогостоящий проект модер
низации. Этот проект станет целевым, потому что:
♦
очень вероятно, что он будет дорогостоящим;
♦
будет закрыт, если не покажет стабильных результатов;
♦
будет конкурировать с другими бизнес-инициативами;
♦
ожидания бизнеса будут заключаться в том, чтобы завершить строительство
быстро и экономично.
Учитывая этот контекст, важно добиваться быстрых побед и постоянных результа
тов. Поэтому принимайте решения обдуманно. Расставляйте приоритеты, учитывая
не только «низко висящие плоды», но и их влияние на бизнес.
Влияние на бизнес
в сравнении с затраченными усилиями
Взгляните на рис.
5.14.
Проведите квадрантный анализ по каждому сервису, систе
ма за системой, учитывая ситуацию в компании в целом. Не отдавайте предпочте
ний какой-либо конкретной команде или местным реалиям. Независимо от энту
зиазма ваших инженеров, переписывать все системы одновременно
-
плохая идея.
~
Быстрый
u
ф
::,:
выигрыш
Переписывание
<')
s
<D
"'
Рефакторинr
::,:
ф
s
:,:
"'s
~
Вывод
Вывод
из эксплуатации
из эксплуатации
Игнорирование
Игнорирование
(быстро)
(медленно)
Усилия
Рис.
5.14.
.....
--
Влияние на бизнес в сравнении с затраченными усилиями
Медленный вывод из эксплуатации. Компоненты, оказывающие незначительное
влияние на бизнес, но требующие больших усилий для миграции. Возможно, биз
нес потерял к ним интерес или они просто не нужны. Переписывание такого кода
было бы трудоемким процессом. Подумайте о выводе сервиса из эксплуатации
-
удалении пользователей, удалении кода и очистке данных. Или игнорируйте про
блему до тех пор, пока не сможете устранить.
246
■
Глава 5
Быстрый вывод из эксплуатации. Компоненты с низкой отдачей для бизнеса и
минимальными усилиями по миграции. Эти системы вы все равно вывели бы из
эксплуатации или проигнорировали, учитывая их низкую ценность для бизнеса.
Конечно, можно рассмотреть рефакторинг или даже переписывание. Но если цен
ность для бизнеса невелика, какой в этом смысл? По сравнению с изображенными
справа внизу наши системы требуют меньше усилий, так что вы, возможно, сможе
те себе это позволить.
Быстрый выигрыш/рефакторинг. Системы или сервисы, которые мы могли бы
улучшить без особых усилий, потому что они изолированы или их легко изолиро
вать, к тому же они приносят большую пользу бизнесу. Решение очевидно: мы
должны это сделать.
Переписывание. Наш самый большой риск и, вероятно, самые большие выгоды
связаны с этим квадрантом. Проекты в этом секторе могут оказать большое влия
ние на вашу организацию, принеся прямой или косвенный доход, рост или эконо
мию. Однако для достижения таких результатов потребуется приложить значи
тельные усилия. Мы можем с легкостью утверждать, что именно на эту область
следует отдать основную часть вашей энергии в области разработки, направляя ее
на кардинальные изменения,
развития вашей
компании.
которые могут по-настоящему изменить траекторию
Переписывание систем
в этом секторе оправданно
с учетом необходимых усилий. Если в качестве альтернативы рассмотреть рефак
торинг, то можно применить подходы обратной совместимости и разработать ши
рокое тестовое покрытие для вашего публичного контракта. Это обеспечит безо
пасную разработку, за которой затем могут последовать переписывание или более
масштабные улучшения.
Децентрализация
-
это здорово. Наличие большого количества команд, наделен
ных полномочиями, позволяет организациям наращивать скорость. Однако нужно
соблюдать осторожность. Одним из важных аспектов является то, что вам все рав
но необходимо видеть всю экосистему/организацию в целом. Крупные компании,
в которых работают от десятков до сотен команд, могут легко поддаться энтузиаз
му отдельных групп, но при этом не всегда могут управлять всей организацией как
единым целым.
Мэри и Том Поппендик в своей книге
2003
года «Разработка бережливого про
граммного обеспечения: набор гибких инструментов»
An Agile Toolkit)
(Lean Software Development:
подробно объясняют семь ключевых принципов бережливого
производства.
1.
Устраняйте ненужные затраты.
2.
Расширяйте возможности обучения.
3.
Принимайте решения как можно позже.
4.
Выполняйте их как можно быстрее.
5.
Расширяйте возможности команды.
6.
7.
Добивайтесь целостности в коллективе.
Смотрите на общую картину.
Оценка
Принцип №
7,
■
247
«Смотрите на общую картину», здесь имеет решающее значение
-
вы должны смотреть на экосистему в целом, рассматривать бизнес в целом и избе
гать локальной оптимизации. В противном случае все команды будут говорить, что
всё имеет значение и что всё важно. У каждой технической команды есть свои
приоритеты; Jаvа-инженеры хотят делать то, что лучше для них, что облегчает их
жизнь. То же самое касается фронтенд-инженеров, администраторов баз данных,
DеvОрs-инженеров,
QА-инженеров.
Максимизация собственных локальных ре
зультатов может быть полезна для вашей команды, но не всегда эффективна для
бизнеса.
Порядок действий
Теперь давайте представим сказанное в виде последовательности действий
events ),
1.
(order of
которые вам следует выполнить.
Создайте централизованную книгу
Excel
или таблицу
Google Docs,
в которой
перечислите параметры, важные для вашей оценки.
2.
Самостоятельно примените руководство к
2-3
сервисам, следуя принципам ана
лиза кода, данных и сопоставления бизнес-областей, изложенным в этой главе.
При необходимости измените параметры.
•
Для оценки необходимо непосредственно ознакомиться с кодом.
•
Примите во внимание изолированность баз данных и других хранилищ дан
ных.
3.
Поделитесь листом
Excel
со своими командами и объясните, как его заполнять.
В идеале это командная работа всей организации, а не централизованная работа
нескольких человек. Однако, если у вас есть разработчики программного обес
печения, было бы неплохо включить их в процесс оценки.
4.
В рамках оценки выполните сопоставление бизнес-областей и группировку сер
висов.
5.
Классификация и принятие решений (игнорирование, вывод из эксплуатации,
улучшение, переписывание) не должны проводиться изолированно.
•
Это не одно решение, это одно решение для каждого компонента.
•
Не забывайте «смотреть на общую картину» и рассматривать экосистему
в целом.
6.
Объедините результаты оценки с вашими технологическими и бизнес-потреб
ностями, чтобы определить стратегию модернизации.
•
В зависимости от результатов оценки можно отказаться от некоторых серви
сов.
•
Рассмотрите возможность применения разных стратегий для разных серви
сов.
•
Рассмотрите возможность
применения решений обратной
и покупайте, а не только создавайте.
совместимости
248
•
■
Глава 5
Что касается вариантов использования, связанных с переписыванием, со
трудничайте с бизнесом, продуктом и
UX,
чтобы предложить новые возмож
ности и отличия для вашего бизнеса и пользователей.
•
Соблюдайте зону неопределенности и будьте особенно осторожны с предва
рительными оценками.
7.
Собирайте отзывы и делитесь ими.
Радикальные изменения
Возможно, после всех оценок и анализа результатов вы осознаете, что перед вами
стоит сложная задача. Кодовая база, которую едва понимают инженеры, или биз
нес, в котором они работают по-своему. Никто не видит необходимости в измене
ниях; по мнению ваших руководителей, система работает так, как она работает все
гда. Повседневная работа заключается в ежеквартальном планировании, выделении
ресурсов и составлении бюджета, а не в поиске реального пути продвижения впе
ред.
Никакие оценки, сопоставление предметной области или стратегии модернизации
не решат вашу проблему, если у вас укоренилось культурное предубеждение про
тив изменений. Все попытки внедрения инноваций или модернизации просто при
ведут вас к повторному созданию той же системы. Без творческого подхода полу
чите те же результаты. Если вы думаете, что многократное выполнение одних и тех
же шагов с использованием одного и того же подхода приведет к разным результа
там, вы ошибаетесь. Действительно ли предлагаемая вами версия
монолит
людям
1.0,
2.0 -
но с микросервисами и ничем иным? Перемены пугают
проще
принять
стратегию
модернизации,
которая
выглядит
это просто
некоторым
как
немного
улучшенная старая архитектура. Но спросите себя, решаете ли вы какие-либо ре
альные бизнес-проблемы?
Выход
-
в разрушении. Возможно, вашей компании нужна созданная с нуля мо
дель предметной области, новая карта города, на которой старые границы стирают
ся, или UХ-дизайн, который в первую очередь ориентирован на клиента, а не на
бизнес, диктующий только требования. Настоящие инновации требуют, чтобы вы
взорвали настоящее, чтобы открыть путь в будущее.
Подробный обзор бизнес-стратегий и технических подходов для трансформации
вашего текущего бизнеса
-
это тема, достойная отдельной книги. Но надо отме
тить, что вы можете оказаться в безвыходной ситуации с вашим программным
обеспечением. Единственный выход
-
это творческое переосмысление. Основыва
ясь на текущей оценке, но полностью выходя за привычные рамки, можно создать
новый, инновационный дизайн.
Иногда радикальный отказ от прошлого
-
единственный путь в будущее. Людям
не всегда легко принять истинно дальновидное
мышление:
когда вы
предлагаете
начать с нуля и переосмыслить свой бизнес, нужно быть смелым, напористым,
увлеченным и непреклонным. В конце концов, вы можете удивиться той поддерж
ке, которую получите.
Оценка
■
249
Что нужно запомнить
Поздравляю! Мы подходим к концу главы
5.
Вы прочитали половину книги! Про
должайте свой путь! Вот несколько ключевых моментов, которые нужно запом
нить:
это ключ к успеху. Не следует ее пропускать.
♦
Оценка -
♦
Ваша цель при проведении оценки
-
получить представление о состоянии сер
висов и систем.
♦
В рамках результатов оценки вы хотите знать специфику каждого сервиса или
компонента программного обеспечения. Оценка также должна проводиться по
каждому сервису.
♦
Понимание общего процесса модернизации:
•
Понимание мотивации ваших технологий и бизнеса.
•
Проведение оценки. Никогда не пропускайте этот шаг!
•
Стратегии модернизации разрабатываются на основе сочетания результатов
вашей оценки с технологическими и бизнес-потребностями.
•
Гибкий процесс разработки
-
не используйте водопадную модель управле
ния проектами.
♦
Помните о конусе неопределенности.
•
Избегайте оценки и принятия решений до завершения работы по классифи
кации и составлению карт предметной области.
•
Более поздние оценки, как правило, становятся более точными по мере нако
пления знаний о ситуации и принятия решений по каждой системе или сер
вису.
♦ Реализация
-
дело непростое; многие проекты заканчиваются неудачей. Чем
лучше вы понимаете проблему, тем больше шансов на успех.
♦
Прежде чем приступить к созданию, выполните анализ компромиссов между
созданием и покупкой.
♦ Даже при покупке что-то придется создавать. Вы не сможете купить все свои
интеграции.
♦ Учитывайте влияние на клиента: работайте в обратном направлении и в первую
очередь учитывайте пользовательский опыт.
♦ Переписывание и рефакторинг относятся к спектру задач, это не бинарный вы
зов.
♦ При переписывании учитывайте стоимость и старайтесь создавать программное
обеспечение, способное значительно повлиять на бизнес.
♦ Не переписывайте код без причины, также подумайте о его рефакторинге и
улучшении.
■
250
♦
Глава
5
Выберите скучную проверенную технологию и ограничьте количество внедряе
мых одновременно инноваций по мере достижения зрелости.
♦
♦
Обратная совместимость
-
отличный способ ускорить миграцию.
Обратная совместимость может использоваться с внутренними общими библио
теками, базовыми сервисами и бизнес-сервисами. Ее всегда следует учитывать.
♦
Для обеспечения надлежащей обратной совместимости необходимо идентифи
цировать все публичные контракты и провести тесты. Затем можно полностью
или частично изменить реализацию, сохранив целостность контракта.
♦
При проведении анализа кода обратите внимание на следующие аспекты:
•
Кто или какие команды являются владельцами?
•
Какова скорость изменений в бизнесе?
•
Каковы публичные контракты и насколько масштабен этот контракт?
•
Каковы нижестоящие зависимости?
•
Кто является потребителем?
•
Используют ли люди этот компонент напрямую или только через машины?
•
Какова сложность решения?
•
Проходят ли тесты стабильно и имеет ли компонент достаточное покрытие
тестами?
♦
После завершения работы по классификации вам необходимо оценить каждый
компонент. Предлагаемые категории:
•
Переписать: какие компоненты можно и нужно переписать?
•
У луч шить: какие компоненты можно сохранить за счет некоторой степени
рефакторинга?
•
Вывести из эксплуатации: какие компоненты следует вывести из эксплуата
ции?
•
Игнорировать: какие компоненты хороши или приемлемы в первозданном
виде?
♦
Анализ базы данных важен. Рассмотрите возможность оценки уровня независи
мости схемы или группы таблиц: низкий, средний или высокий.
♦
Domain Driven Design (DDD) -
мощный инструмент при разработке программ
ных архитектур.
♦
DDD
может применяться как для разработки с нуля, так и для существующих
технологий, сервисов, классических или распределенных монолитов.
♦ Сопоставление предметных областей
-
это эффективный способ определить
подходящие бизнес-области для вашей архитектуры программного обеспечения.
♦
Повсеместныii язык
-
это пространство, где инженеры и эксперты в предмет
ной области разрабатывают общий словарный запас, чтобы избежать ошибок и
ускорить разработку.
Оценка
♦
Группировка сервисов по бизнес-областям
-
■
251
хорошая идея, поскольку упроща
ет принятие решений о приоритетах и помогает увидеть четкие возможности для
разделения или объединения сервисов.
♦
Составьте список всех предметных областей, которые наблюдаете в распреде
ленном виде. Позже вы сможете распределять приоритеты по одной бизнес
области за раз.
♦
Изолирование распределенного монолита может остановить проблему, но будь
те осторожны, новые базы кода и сервисы могут ее усугубить.
♦
В ходе своей работы по оценке обращайте внимание на преимущества и воз
можности быстрого успеха.
♦
Быстрый успех достигается за счет изучения кода и определения его использо
вания и потребителей. Для анализа использования можно применить
GitHub
или
аналогичные инструменты.
♦
После проведения оценки рассмотрите соотношение приложенных усилий и от
дачи от бизнеса в качестве стратегии расстановки приоритетов.
♦
Обзор в целом позволяет убедиться, что, применяя соотношение отдачи и уси
лий для бизнеса от системы к системе, вы не забываете о своей организации
в целом.
♦
Радикальные изменения. Откажитесь от них! Начните сначала! Будьте смелыми,
бросайте вызов существующему положению вещей и со страстью и энергией
ведите свои команды к лучшему результату.
ГЛАВА
6
Принципы надлежащего
предоставления сервисов
В вопросах стиля плывите по течению; в вопросах принципов стойте как скала.
Томас Джефферсон
В главе
6
вы узнаете секреты успешного развития сервисов. Эти знания улучшат
любой проект, который вы когда-либо создадите в будущем. Вы узнаете основные
принципы, которые помогут двигаться вперед, делать всё правильно и в конечном
итоге повысить ценность вашего бизнеса.
Принципы, которые мы рассмотрим, касаются архитектуры программного обеспе
чения в области разработки сервисов. Эти принципы подобны универсальным
законам, которые принесут пользу в долгосрочной перспективе. Следуя им, вы
сможете ориентироваться в сложных ситуациях и легко выходить из болота техни
ческих проблем, с которыми сталкиваетесь при работе с плохими монолитами.
Структура главы
В текущей главе мы рассмотрим следующие темы:
♦
♦
Сервис-ориентированная архитектура.
•
Типы сервисов.
•
Когда следует использовать сервисы.
•
Когда следует отказаться от сервисов.
•
Преимущества
SOA.
0
Сокращение сроков вывода на рынок.
0
Сокращение затрат и упрощение обслуживания.
0
Расширяемость и адаптивность.
0
Независимость.
0
Краткое описание преимуществ
Вначале контракт.
•
Новый сервис.
•
Существующий компонент.
SOA.
Принципы надлежащего предоставления сервисов
♦
•
Кодирование контракта с помощью
•
Обратная совместимость.
■
253
OpenAPI.
SOA и изоляция.
•
Изоляция хранилищ данных.
•
Изоляция библиотек.
□
•
Противопоставление вкусов и мостов в библиотеках и монолитах.
Изоляция публичных контрактов.
□
Анализ проекта.
□
Автоматизация работоспособности контрактов.
□
Неочевидные моменты.
□
Обработка ошибок в контрактах.
□
Доступность сервиса.
♦ Что нужно запомнить.
Сервис-ориентированная архитектура
Сервис-ориентированная архитектура
(Service Oriented Architecture, SOA) -
это,
как ни странно, подход к созданию программного обеспечения, основанный на
независимых сервисах. Эги сервисы
-
автономные программные блоки, которые
выполняют повторяемую, определенную задачу без необходимости делиться внут
ренними деталями реализации. Кшщепция
SOA бьmа представлена в
конце 1990-х гг.,
но, к сожалению, в то время оказалась в неудачном положении. В индустрии
SOA
часто ассоциируется с большими тяжеловесными системами и шаблонами для ин
теграции разрозненных программных систем. Интеграция важна и имеет ценность,
но
SOA -
гораздо больше, чем просто интеграция. Для применения этой архитек
туры не нужна корпоративная сервисная шина (Enterprise Service Bus, ESB)1 или
язык выполнения бизнес-процессов (Business Process Execution Language, BPEL)2.
Не требуется никаких специальных технологий:
SOA
можно реализовать на любом
языке и на любом технологическом стеке.
Сервисы предоставляют множество возможностей для бизнеса.
SOA
рассматривает
сервисы как первоклассные решения. В этом архитектурном стиле вы полностью
ориентируете свои решения на сервисы.
SOA
не диктует, как должны выглядеть
другие типы приложений или компонентов, такие как интерфейсные приложения,
внутренние общие библиотеки, пакетные задания, компоненты инфраструктуры.
Однако определенно можно
применить подход,
ориентированный на сервисы,
к любому подобному компоненту. До тех пор, пока компонент может функциони
ровать
самостоятельно,
1 Enterprise
2 BPEL
предсказуемо
и
многократно
выполнять
свою
Service Bus из Википедии: https://en.wikipedia.org/wiki/Enterprise_service_bus.
из Википедии: https://en.wikipedia.org/wiki/Вusiness_Process_Execution_Language.
задачу
и
■
254
Глава 6
скрывать детали своей реализации от вызывающих его потребителей, существуют
основания для применения
SOA.
Манифест SOA 3 был написан в конце 2000-х rr. в ответ на некоторые из худших
проектов, которые пытались сделать
SOA
с использованием технологий крупных
поставщиков и потерпели неудачу. Этот документ стал одним из лучших руко
водств по правильному внедрению
гие темы текущей главы (рис.
SOA;
он говорит сам за себя и раскрывает мно
6.1 ).
Манифест
Сервисная ориентация
-
SOA
это парадигма , определяющая то , что вы делаете .
Сервис-ориентированная архитектура
(SOA) -
это тип архитектуры ,
который является результатом применения сервисной ориентации .
Мы применяем сервисную ориентацию , чтобы помочь организациям
стабильно создавать устойчивую коммерческую ценность , повышая гибкость
и экономическую эффективность в соответствии с меняющимися потребностями бизнеса .
В ходе нашей работы мы определили приоритеты :
Ценность для бизнеса важнее технической стратегии
Стратегические цели важнее преимуществ конкр етного проекта
Внутренняя совместимость вместо пользовательской интеграции
Общие сервисы поверх специализированных реализаций
Гибкость важнее оптимизации
Эволюционное с:оверwенствование вместо стремления к изначальному идеалу
То есть , хотя мы и ценим то , что находится справа , то , что находится слева , мы ценим больше .
Рис.
6.1.
Манифест
SOA
Типы сервисов
Можно написать целую книгу о типах и успешных реализациях сервисов в рамках
SOA.
Вот несколько полезных общих шаблонов при рассмотрении их функцио
нальности.
♦ Бизнес-сервис. Это функциональность, которая напрямую поддерживает биз
нес-процессы компании или подразделения. Такие сервисы понятны и ценны
для предприятий, т. к. улучшают их работу. Большинство ваших сервисов долж
ны быть бизнес-сервисами, поскольку они повышают ценность бизнеса вашей
компании до такой степени, что, когда мы просто используем слово «сервис»,
оно должно подразумевать бизнес-сервис. Примерами бизнес-сервисов являют
ся: сервис продаж, сервис воспроизведения музыки, сервис бухгалтерского уче
та, сервис платежей, сервис доставки, сервис организации поездок.
3
Веб-сайт манифеста SOA, к сожалению. не работает, поэтому вместо него мы разместим ссылку на Intemet
Archive:
https://web.archive.org/weЬ/20091101191437/http://www.soa-manifesto.org/. Диего Пачеко. автор
обширного блога о
and-isolation.html.
SOA
и изоляции, здесь: https://diego-pacheco.Ыogspot.com/2014/11/soa-microservices
Принципы надлежащего предоставления сервисов
♦
■
255
Базовые сервисы. Реализуют бизнес-функции, предназначенные для повторно
го использования в организации или в масштабах всей компании. Базовыми сер
висами должны быть бизнес-сервисы, однако они имеют дело с более широкими
концепциями. Примерами базовых сервисов являются: сервис аутентификации,
сервис предоставления прав, сервис профилей, сервис пользовательских настро
ек, сервис поиска, сервис оповещений пользователей.
♦
Сервис-обёртка. Особый вид бизнес-сервиса, который переносит функциональ
ность из целевых сервисов. Обёртки требуются, когда рассматриваемый целевой
сервис неэффективен, имеет устаревший контракт или неправильную абстрак
цию. Сервисы-обёртки создаются тогда, когда у нас нет исходного кода или
возможностей для изменения целевого сервиса. Примеры сценариев, когда стоит
создать сервис-обёртку, включают в себя: устаревшие банковские функции,
перевод
API
с
SOAP
на
REST,
исправление проблемных старых контрактов, ре
шение проблем со скоростью/лимитами (необходимость создания очереди для
повторной попытки), сжатие сложного и многословного контракта.
♦
Платформенные сервисы. Предоставляют общие технические возможности
или функциональные возможности. Платформенные сервисы не имеют и не
должны иметь бизнес-кода. Они иначе называются техническими сервисами.
Примерами сервисов платформы являются: сервис настройки, сервис изображе
ний, сервис шифрования, сервис экспорта, сервис сертификатов, сервис анони
мизации личных данных.
Когда следует использовать сервисы
В
SOA
сервисы должны быть выбором по умолчанию. У вас должно быть гораздо
больше сервисов, чем библиотек. Вот несколько критериев, которые позволят
определить, когда следует создавать сервис, а не внутреннюю общую библиотеку
или что-то еще.
♦ Инкапсулирующие бизнес-правила. Относятся к вашему основному бизнесу.
Например: расчет процентной ставки, расчет комиссионных с продаж, выбор
наилучшего маршрута доставки для водителя, аренда автомобиля, бронирование
авиабилетов, обработка платежей.
♦
Требуется постоянство бизнес-процессов. Бизнес-записи должны сохраняться
и считываться сервисами. Внутренние общие библиотеки не должны иметь дос
тупа к хранилищам данных, таким как реляционные базы данных.
♦
Высокая скорость изменений. Когда частота изменений высока
ходят каждую неделю или даже ежедневно
-
-
они проис
сервисы становятся правильным
выбором. Внутренние общие библиотеки сталкиваются со множеством проблем,
таких как нарушение изоляции и принудительная миграция. В отличие от биб
лиотек, сервисы требуют меньшего количества миграций, поскольку являются
независимыми. Они лучше приспособлены к изменениям и имеют более высо
кий уровень изоляции.
256
■
Глава 6
Когда снедует отказаться от сервисов
Сервисы не являются панацеей от всех бед, у них также есть недостатки и ограни
чения. Исходя из нашего опыта, мы можем дать несколько рекомендаций. Но имей
те в виду, что здесь нет абсолютных правил, каждое требует более тщательного
рассмотрения.
♦ Производительность. Сценарии, для которых вы хотите, чтобы вычисления
выполнялись близко к данным. Для этого перемещайте вычисления, но не пере
мещайте данные. Внутренние общие библиотеки являются локальными и встро
енными, но сервисы по своей природе являются удаленными, и отправка данных
в сервисы сопряжена с затратами. Примером может служить загрузка файлов
в sз.
♦ Сложность. Иногда у вас слишком много сервисов, и каждый добавляемый
сервис будет усложнять работу. Подумайте о том, чтобы использовать меньшее
количество сервисов или добавить код к существующему сервису.
♦ Путь к надежности. Каждый добавляемый сервис должен быть запущен. Чем
больше сервисов, тем больше требуется усилий по обеспечению надежности.
Иногда не стоит платить за надежность. Например, действительно ли для расче
та отпусков вам нужен сервис с усложненной доступностью и надежностью или
же достаточно простой библиотеки, выполняющей математические вычисления,
которые редко меняются, если вообще меняются?
Преимущества
SOA
SOA
дает множество преимуществ, которые могут подтвердить многие компании.
Здесь мы кратко расскажем о четырех ключевых аспектах, которые встречаются
особенно часто.
♦
Сокращение сроков вывода на рынок. Сокращение сроков выполнения зака
зов очень важно для любой компании, а возможность совместного использова
ния, отдельные компоненты и публичные контракты позволяют командам рабо
тать быстро и без помех.
♦
Сокращение затрат и упрощение обслуживания. Благодаря скрытому и изо
лированному
внедрению
рутинные улучшения
могут
выполняться
независимо
в централизованном сервисе «создай один раз и используй в любом месте».
♦
Расширяемость и адаптивность. Каждый сервис может расширяться и адапти
роваться к изменяющимся рыночным условиям с помощью
API
и/или измене
ний в реализации.
♦ Независимость. Сервисы могут создаваться и развиваться изолированно, про
двигаясь вперед независимо от других сервисов.
Все эти преимущества в совокупности делают
SOA
настоящим инструментом биз
нес-инноваций: ускорение разработки, легкое расширение, упрощение обслужива-
4
S3 или Simple Storage Service - сервис, где хранятся цифровые данные большого объема. - Пер.
Принципы надпежащего предоставления сервисов
ния и возможность командам работать независимо.
SOA
■
257
позволяет вашим коман
дам оставаться сосредоточенными на проблемах бизнеса.
Давайте углубимся в детали и рассмотрим несколько реальных примеров.
Сокращение сроков вывода на рынок
Сервисы
-
это общие строительные блоки. Возвращаясь к нашему примеру, да
вайте подробнее рассмотрим сервис для компании
Acme Widget,
где для развития
электронной коммерции сервис платежей поддерживает чеки и платежи по кредит
ным картам (рис.
6.2).
Контракт
Веб-сайт
Реализация
электронной коммерции
сервиса
платежей
БД платежей
Рис.
6.2.
Сервис платежей, поддерживающий веб-сайт электронной коммерции
Предположим, что компания решила освоить другие рынки и выйти на новые на
правления бизнеса, открыв сеть обычных магазинов бакалеи. Поскольку сервис не
зависит от веб-сайта, можно использовать этот сервис платежей совместно с бизне
сом по продаже продуктов (рис.
6.3).
Бизнес по продаже продуктов сразу же полу
чает возможность оплаты чеками и кредитными картами. Не исключено, что при
дется также работать с наличными, но вы уже используете ряд бизнес-возмож
ностей, поскольку не нужно начинать с нуля.
Веб-сайт
электронной коммерции
Реализация
сервиса платежей
Приложение для бизнеса
по продаже продуктов
БД платежей
Рис.
6.3. Сервис платежей, совместно используемый в двух видах бизнеса
258
■
Глава б
Сервис платежей используя свои преимущества, ускорил запуск продуктовых мага
зинов компании
♦
Acme Widget.
Возможность совместного использования. Правильно спроектированные сер
висы предлагают
API,
который можно использовать в различных обстоятельст
вах. Нет необходимости кодировать все заново
-
сервисы по умолчанию могут
предоставлять общие возможности остальной части вашей компании. Конечно,
эти точки доступа должны быть предусмотрены специально. Повторное исполь
зование путем общего доступа к таблице базы данных
♦
-
плохой вариант!
Реальный прирост производительности. Используя уже имеющиеся решения,
вы экономите время и затраты на разработку, тестирование и исправление оши
бок. Ваша команда может быть уверена в том, что существующая реализация
работает и, вероятно, даже пройдет проверку в боевых условиях.
♦ Расширяемость. Как только будут добавлены платежи наличными, эта функция
также станет доступна и для другого вашего бизнеса.
♦ Беспроигрышный вариант. В случае возникновения ошибок ваши исправле
ния будут применены централизованно, что принесет прозрачную пользу обоим
видам бизнеса. Позже, когда вы улучшите работу сервиса платежей, оба пред
приятия сразу же ощутят преимущества.
Вы решили, что лучший способ увеличить прибыль компании АСМЕ
Widget -
это
освоить новые способы взаимодействия с клиентами, такие как:
♦
Мобильное приложение. Стандартная, предпочтительная форма интерфейса
для молодого поколения. АСМЕ, несомненно, упускает из виду тех, кто не мо
жет найти ее мобильное приложение, чтобы зайти в него и совершить покупку
на ходу.
♦
Чат-бот. Очень популярный в Китае или странах Южной Америки, таких как
Бразилия, разговорный искусственный интеллект (ИИ,
artificial intelligence, AI)
становится все более и более функциональным, будь то более ранние поколения
простых ботов, основанных на намерениях, или более сложные генерирующие
ИИ с большими языковыми моделями 5 , такие как Anthropic6 от Claude или
ChatGPT от OpenAI7. Вместо оплаты услуг агента клиенты могут общаться
в чате с ботом, чтобы найти подходящий виджет для своих нужд.
♦ Голосовой интерфейс. Подобно
могут просто сказать,
пании
Alexa: купи
Acme Widget Company!
Google Assistant
или
Amazon Alexa
клиенты
мне новый набор больших виджетов от ком
Раньше у вас был только один интерфейс
-
веб-сайт. Теперь у вас их четыре: веб
сайт, мобильный интерфейс, чат-бот и голосовой помощник. Каждый интерфейс
5
Большие языковые модели (Large Language Models, LMS) в Википедии:
https://en.wikipedia.oгg/wiki/Laгge_language_model.
6
Разговорный искусственный интеллект Anthropic называется Claude и на момент написания этой книги
https://www.anthropic.com/index/claude-2.
находится во 2-м поколении:
7
Открытый диалоговый ИИ ChatGPT от Open AI: https://openai.com/Ьlog/chatgpt.
Принципы надлежащего предоставления сервисов
имеет схожие требования к выполнению платежей. С помощью
SOA
■
259
и многоразо
вого сервиса платежей вы можете использовать все эти функциональные возмож
ности и гораздо быстрее запускать новые каналы продаж (рис.
6.4).
Даже в рамках
одного бизнеса ориентация на сервисы приносит свои плоды.
Веб-сайт электронной коммерции
r-----
Мобильное приложение
для электронной коммерции
Реализация
сервиса платежей
Чат-бот
для мобильной коммерции
БД платежей
Решение
для ГОЛОСОВОГО помощника
Рис.
6.4.
Сервис платежей, используемый в четырех различных интерфейсах
Хотя эти подходы используются в бизнесе по-разному, они основаны на одних и
тех же принципах архитектуры
висов,
SOA
и ее общих сервисах. В отличие от микросер
которые, как следует из названия, являются микро-,
висами,
SOA
мелкозернистыми сер
не требует глубокой детализации. В сервисе может быть много функ
циональных возможностей, и с точки зрения
SOA
это нормально. Главное, чтобы
эти функции были сгруппированы логически, как, например, в нашем обсуждении
моделирования предметной области
(Domain Driven Design, DDD)
в предыдущей
главе.
В качестве контраргумента вы можете возразить, что это не так просто. Сервисы не
только экономят время: совместное использование сервиса двумя видами бизнеса
может означать множество новых изменений в сервисе платежей, которые вам не
нужно было вносить раньше, таких как:
♦
Изменения в контракте. Вы хотите добавить поле «Источник», чтобы узнать,
был ли платеж произведен через веб-сайт, мобильный телефон, текстовым или
голосовым способом.
♦
Дополнительные интеграции. Для текстового и голосового интерфейсов могут
потребоваться другие интеграции со сторонними сервисами или другие на
стройки платежного сервиса.
♦ Миграция данных. Поддержка новых каналов может означать изменение таб
лиц базы данных, что приведет к миграции данных, затрагивающей все каналы.
♦
Дополнительное тестирование. Каждый канал имеет свои независимые вари
анты использования, требующие более тщательного тестирования.
260
■
Глава 6
Не увеличат ли все эти дополнительные изменения время вашего выхода на рынок
в будущем? Используя обратную совместимость, вам нужно всего лишь изменить
сервис, а не переписывать его с нуля. Такие изменения не нанесут ущерба другим
потребителям, поскольку вы можете поддерживать стабильный и четко определен
ный публичный контракт. Даже для нового поля «Источник» существуют методы,
которые позволяют внедрить изменения, не нарушая работу пользователей платеж
ного сервиса, о которых мы расскажем более подробно в текущей главе. Поддер
жание обратной совместимости гарантирует, что ваши изменения не повлияют на
потребителей, что позволит вам быстрее продвигаться вперед для поддержки биз
неса.
Сокращение затрат и упрощение обслуживания
Применяя сервис-ориентированное мышление, вы можете сократить время и затра
ты на поддержку и совершенствование своего программного обеспечения: это ог
ромное преимущество для любой реализации
SOA.
Без
SOA
классические и рас
пределенные монолить1 сталкиваются с серьезными проблемами в обслуживании,
что приводит к повышению стоимости и сложности из-за ряда факторов, таких как:
♦
Нежелательные побочные эффекты. Из-за высокой степени связности коман
ды не могут безопасно работать изолированно. Одна команда вносит изменение,
которое нарушает работу потребителей, а затем команда потребителей отправ
ляет в ответ РR-файл, который поочередно нарушает работу пяти других ко
манд. Отсутствие изоляции усложняет решение даже простых проблем.
♦
Высокая сложность. Без четких границ трудно понять, что делает код и как он
работает; неясность приводит к ненужной и случайной сложности, что является
одной из форм технической задолженности. Может возникнуть эффект размы
вания команды, что приведет к потере знаний и замедлению миграции.
♦
Недостаточное тестирование и обратная связь. Без четкой изоляции системам
может не хватать надлежащего тестирования, чтобы узнать, не нарушаете ли вы
старые функциональные возможности (то, что называется, регрессионным тес
тированием).
Общее отсутствие охвата тестированием снижает уверенность
в качестве выпускаемого программного обеспечения. В результате ошибки об
наруживаются не на этапе разработки, а только в процессе промышленной экс
плуатации, что удлиняет циклы обратной связи.
♦
Высокая стоимость. Инженеры стоят дорого; в большинстве компаний они
стоят дороже всего, дороже чем сервисы, инструменты и т. д. Некачественные
монолиты делают техническое обслуживание более болезненным и сложным,
и, таким образом, они влияют на основные технологические затраты
-
на пер
сонал. В сочетании со сложностью и динамичностью нашего мира, с меняющи
мися требованиями, новым законодательством, уходом поставщиков из бизнеса
и прекращением производства программного обеспечения компании не могут
позволить себе дорогостоящее техническое обслуживание и идти в ногу со вре
менем.
Вы, должно быть, задумываетесь, как
SOA
решает все эти задачи?
SOA
помогает
нам во многих отношениях, потому что сервисы и ориентация на сервисы, в общем,
■
Принципы надлежащего предоставления сервисов
261
определяют границы. Сервисы абстрагируют реализацию от интерфейса для нас,
например сервис будет абстрагировать:
♦ Язык программирования. Абоненты не имеют представления, на каком языке
построен сервис
♦
Операционная система. Абстрагируйтесь от операционной системы. Не имеет
значения,
♦
- Java, Rust, Typescript, Zig.
Ubuntu
это,
Amazon Linux 2 или
даже
Microsoft Windows.
Инфраструктура. Скрывайте базовую сервисную
А WS ЕС2, бессерверные
Lambdas, ECS
или
EKS,
инфраструктуру,
будь то
или локальное размещение.
Это возможно при условии, что вы управляете сетевой адресацией и соблюдаете
публичный контракт.
♦
Фреймворки и библиотеки. Вы можете использовать
CXF
♦
только
Apache
Хранилища данных. Скрывайте, является ли ваша база данных реляционной,
NoSQL
♦
Spring,
или вообще не использовать фреймворк.
или
NewSQL.
Зависимости во время выполнения. Скрывайте любые нижестоящие зависи
мости, такие как другие сервисы.
♦
Решения по реализации. Не важно, как организован код: по уровням, функци
ям или бизнес-областям; является ли ваш стиль программирования процедур
ным,
объектно-ориентированным
или
функциональным;
используете ли
вы
шаблоны проектирования; применяли ли вы чистый код.
Независимо от того, говорим ли мы «абстрактный» или «скрытый», «защищаю
щий» или «разделяющий», это все равно будет иметь те же преимущества и значе
ние. У вашего правильно спроектированного сервиса есть контракт
стабильный контракт
-
надеюсь,
и совершенно отдельная реализация. По сути, контракт
-
создает периметр или границу, защищающую внутренние компоненты сервиса.
Граница сервиса подобна стене; по другую сторону стены может находиться все
что угодно. Как абонент вы не можете наблюдать за ней и фактически защищены
от любых деталей (рис.
6.5).
У вас может получиться очень сложная и запутанная
.
--
Контракт
.. .
Реализация
сервиса
.
платежей
,,.
...._
...._
f
.
:::
БД платежей
~
Граница
Рис.
6.5.
Граница сервиса
Потребители
1
262
■
Глава б
реализация, но это не страшно. Важно, чтобы контракт был четким, стабильным и
простым в понимании. Граница сервиса создает безопасную зону для внесения из
менений и ограничивает радиус действия возможных негативных последствий для
наших потребителей. Главное условие
-
не нарушать публичные контракты и
поддерживать обратную совместимость.
Четкие границы сервиса значительно облегчают работу с неопределенностями,
сложностями, некорректным тестированием или длительными циклами обратной
связи. Отделяя реализацию от контракта, вы предотвращаете побочные эффекты
и высокую степень связности; пользователи видят только публичный контракт, не
затрагивая реализацию.
Потребители часто обращаются к сервисам удаленной связи по протоколу НТТР.
Когда ваше приложение и программное обеспечение находятся в одном и том же
модуле развертывания и вызываются локально, у вас практически нет границ. Если
другие программные компоненты, такие как внутренние общие библиотеки, содер
жат
300
библиотек, все эти библиотеки будут присутствовать в вашей среде выпол
нения, и вы рискуете столкнуться с бинарной связью. Однако, когда у вас есть
сервис, пользователи не имеют доступа к вашим библиотекам независимо от их
количества, будь то
10
или
12
ООО. Даже если вы назначаете драйвер сервиса, со
храняйте его минимальным и требуйте минимум библиотек, если не их полное от
сутствие.
Границы и изоляция обеспечивают преимущества, снижая затраты и упрощая об
служивание и совершенствование программного обеспечения. Естественная изоля
ция
SOA
обеспечивает развязку и предоставляет команде инженеров следующие
возможности:
♦ Полная свобода изменений. Свободное изменение любой абстрактной концеп
ции: языка программирования, операционной системы, фреймворков и библио
тек, хранилищ данных, зависимостей или целых реализаций.
♦ Улучшение миграции. Выполнение любой миграции кода или данных, без на
рушения работы пользователей.
♦
Экспериментирование. Эксперименты с новыми технологиями контролируе
мым и безопасным способом, не выходя за границы сервиса.
♦
Оптимизация затрат. Затраты могут быть оптимизированы за счет использо
вания сервиса в масштабах всего бизнеса. Вам не нужно переопределять код,
нужно обслуживать меньше компонентов и использовать меньше облачных
ресурсов.
Теперь представьте, что вы выполняете все эти действия в монолите, где имеется
бинарная связь и мало четких границ. Рутинные действия приводят к головным бо
лям при обслуживании. Изоляция является ключевым фактором, уменьшающим
радиус действия и общий риск изменений, а также снижающим общие рутинные
риски и затраты на ваш технологический пакет.
Принципы надлежащего предоставления сервисов
■
263
Расширяемость и адаптивность
Совместное использование бизнес-функций и возможностей через общие SОА
сервисы
-
преимущество этого стиля архитектуры. На этом достоинства не закан
чиваются. Есть еще одно важное свойство
-
расширяемость.
Современный мир отличается высокой конкуренцией и динамичностью. Ваши кон
куренты могут быть как локальными, так и глобальными. Каждый год приносит
разнообразные изменения и потрясения: войны, глобальные пандемии, экономиче
ские спады, инфляцию и множество других проблем. Компаниям необходимо
быстро реагировать и иметь возможность расширять и улучшать существующие
бизнес-возможности, не начиная с нуля. Например, Федеральная резервная система
США недавно запустила свою платежную систему
жей
Acme Widget Company должен
FedNow.
Теперь сервис плате
использовать ее, чтобы ускорить перевод денег
и удовлетворить своих поставщиков.
Давайте отличим адаптивность от расширяемости как еще одно свойство, которое
предоставляет нам стиль или архитектура
SOA.
Речь идет не обязательно о добав
лении нового, сколько о тонкой настройке уже существующего. Одним из приме
ров адаптивности может быть настройка существующего сервиса платежей с целью
снижения процентной ставки с
2
до
1,5 %
для долгосрочных клиентов премиум
класса.
Ключевой момент заключается в том, что
SOA
позволяет безопасно и быстро вно
сить изменения. Вы можете расширять сервисы или адаптировать их к меняющим
ся рыночным условиям без их полной перестройки, без риска массового разверты
вания или дорогостоящей миграции.
Независимость
Надлежащие сервисы развертываются независимо и являются автономными. Сер
висы, по сути, способствуют быстрой работе команд, параллельной работе с дру
гими проектами, доставке компонентов с меньшим риском вмешательства и сни
жают издержки для бизнеса.
Однако независимость
-
это не просто идеальное состояние. В реальном мире
у большинства команд есть разные степени независимости, потому что существуют
и другие ограничения, как хорошие, так и плохие. Управление
процесс в большинстве крупных организаций, и его цель
-
-
необходимый
ограничивать команды
в их работе. В идеальном мире эти ограничения обеспечивают глобальную слажен
ность работы команды, внедрение передовых практик и обязательный анализ про
екта. В результате создается качественная и надежная архитектура программного
обеспечения в целом. В реальном мире ограничения часто представляют собой
просто искусственные барьеры, препятствующие росту, а архитекторы навязывают
предпочтения, которые на самом деле не приносят никакой пользы. Эти гейткипе
ры ограничивают то, что на самом деле предоставляют сервисы: полную свободу
изменений, например возможность использования многоязычности или внедрения
хранилища данных в вашей организации и за ее пределами, что позволяет коман
дам быстро продвигать бизнес вперед. Шлюзы и гейткиперы сдерживают прогресс
команд.
264
■
Глава 6
Внедрение ограничений во все процессы жизненного цикла разработки программ
ного обеспечения предотвращает масштабирование организации. Но полное их от
сутствие превращает вашу компанию в «дикий Запад», где команды делают все,
что хотят, и так, как им заблагорассудится. Если вы хотите, чтобы все имена пере
менных в ваших контрактах были одинаковыми, это замедлит вашу работу и при
ведет к необходимости совместного использования
POJO,
что в итоге приведет
к распределенным монолитам. Вы действительно цените такой выбор? У вас будут
сотни команд и тысячи сервисов. Подходят ли эти ограничения для вашей компа
нии?
Организациям
необходимо
правильно
сбалансировать эти
факторы.
Компании
выбирают стандартизацию, повторное использование, общий опыт разработчиков
и множество точек координации вместо масштабируемости, скорости и независи
мости (рис.
6.6).
Независимость
Централизованное управление
(+) Масштабируемость
(+) Скорость
(+) Полная стандартизация
(+) По-настоящему независимые команды
(+) Более быстрое выполнение бизнес-задач
(-) Хаос
(-) Отсутствие централизованного контроля
(-) Меньшая стандартизация
Рис.
6.6.
(+) Полное повторное использование
(+) Постоянный опыт разработчиков
(-) Тесная координация
(-) Очень медленные технологические циклы
(-) Групповое проектирование
Независимость в сравнении с централизованным управлением
Эффективное управление включает лучшие практики в контракты и способствует
упрощению последовательности работ и оптимальным методикам. Плохое управ
ление приводит к тому, что сама по себе реализация требует повторного использо
вания совместно используемых библиотек и баз данных (табл.
Таблица
6.1. Независимость в сравнении с централизованным управлением
Независимость
Хорошо
6.1 ).
Централизованное управление
Плохо
Хорошо
Плохо
Развертывание
Контракты
Контракты
Присвоение имен
кода
Бизнес-области,
Сопоставление
Схемы баз данных
Детали
Подробности
приводящие к дубли-
бизнес-областей
реализации
рованию
Стек наблюдаемости
Выбор технологий
Мониторинг
реализации
Инструменты развертывания
«снежинок»
Хотелось бы, чтобы независимость бьmа бинарным, идеальным состоянием: вы
либо обладаете ею, либо нет. На самом деле вам придется пойти на некоторые ком
промиссы. Только не делайте неправильных выводов и не теряйте смысла
SOA.
Принципы надлежащего предоставления сервисов
Краткое описание преимуществ
Общее преимущество
SOA
■
265
SOA
заключается в том, что оно позволяет вашему бизнесу
развиваться быстрее. Нельзя себе позволить, чтобы для каждой новой возможности
инженерам приходилось перестраивать всю вселенную с нуля. Сервисами
SOA
можно легко обмениваться, расширять их и адаптировать, что позволяет оператив
но реагировать на изменение потребностей вашего бизнеса.
вать
программное
обладающее
обеспечение,
множеством
SOA
внутренних
ществ, что, в свою очередь, ускоряет работу вашего бизнеса (рис.
2.
1. Сокращение сроков
позволяет созда
преиму
6.7).
Сокращение затрат
и упрощение обслуживания
вывода на рынок
4.
3. Расширяемость
Независимость
и адаптивность
Инструмент, способствующий инновациям в бизнесе
Рис.
6.7.
Краткое описание преимуществ
Давайте обратимся к скептикам
SOA
SOA
или командам, которые вообще отвергают
сервисы или микросервисы. Возможно, ваш монолит позволяет повторно использо
вать все программные ресурсы. Зачем гнаться за модными тенденциями и беспоко
иться о современной архитектуре? Если вы в это верите, мы были бы удивлены,
узнав, что вы так далеко продвинулись в нашей книге. Но честно спросите себя: как
быстро вы выводите продукты на рынок? Насколько просты ваши релизы? Легко
ли вносить какие-либо изменения? Довольны ли ваши инженеры? Люди обладают
способностью адаптироваться к самым сложным условиям, но это не означает, что
все в порядке, разумно или надежно.
Возьмем утверждение: «Любое программное обеспечение может способствовать
инновациям». Верно ли это? Нет, потому что классические монолиты или распре
деленные монолиты присутствуют в программном обеспечении и имеют антипат
терны, а также приводят к обратному результату: медлительности, трениям и слож
ным изменениям. К настоящему времени вы уже должны знать ответ на вопрос,
почему антипаттерны, побочные эффекты и усилители основаны на отсутствии
надлежащих принципов, а именно:
♦ Чрезвычайная хрупкость. Изменив таблицу, перечисление,
POJO,
класс или
зависимость в pom.xml, вы нарушите работу других команд, а они, в свою очередь,
нарушат вашу работу. Отсутствие системной изоляции создает огромные про
блемы. Хрупкость нарушает работу пользователей, экспоненциально увеличива
ет стоимость и сокращает сроки выполнения.
266
♦
■
Глава 6
Безумный радиус действия. Вы должны беспокоиться о десятках или сотнях
классов и миллионах строк кода, потому что мир слишком велик и не имеет гра
ниц. Любое изменение может нарушить все и всегда.
♦
Скрытые проблемы. Оценить влияние изменений сложно, или же для обнару
жения ошибок требуется больше времени из-за отсутствия надлежащего тес
тирования, тестирования вправо 8 (shift right testing) или контрактного тестиро
вания.
♦ Сложные проекты, медленное выполнение. Ваши технологические решения
влияют
на
многие
команды,
например
повторное
использование
раздутых
библиотек приводит к бинарному взаимодействию. Все замедляют работу друг
друга.
♦
Технический долг, паралич и плохое развитие. Плохие монолиты неизбежно
приводят к такому конечному состоянию: ваше программное обеспечение не
было разработано для совместного использования, ему не хватает стабильных и
публичных контрактов, а ваши попытки поделиться бизнес-возможностями при
водят к более тесной связи между компонентами. Технический долг царит во
всем стеке. Предсказать результат изменений настолько сложно, что большин
ство попыток улучшить ситуацию в реальности только ухудшают ее, усугубляя
ваши проблемы. Все боятся менять код, рефакторинг становится ругательством,
а страх перед новыми технологиями очень высок.
Это краткий список. Без соблюдения надлежащих принципов могут произойти
очень плохие вещи. И просмотрите этот список еще раз: каждый из этих пунктов
замедляет работу, ни один бизнес не может развиваться быстро с таким количест
вом технологий, которые несут на себе такую нагрузку. В то время как хорошие
принципы важны в любой архитектуре программного обеспечения,
SOA
включает
в себя принципы, заложенные в самой природе стека. Построение с использовани
ем принципов
SOA
позволяет легко использовать эти преимущества, не попадая
в эти антипаттерны.
Когда дело доходит до характера создаваемых вами сервисов, у вас есть выбор. Что
касается размера, то благодаря сосредоточению внимания на бизнесе и предостав
лению сервисов, ориентированных на бизнес-сферу, ваши сервисы по своей приро
де будут немного больше, чем обычные микросервисы, но, как правило, будут
иметь правильный баланс между размером и функциональностью. Конечно, вы не
ограничены только бизнес-потребностями
-
с помощью
SOA
вы можете получать
платформенные или технические сервисы, такие как аутентификация, права досту
па, эксперименты, пользователи/профили, сервисы по управлению конфигурацией
и сервис координатора развертывания; ваше воображение
-
это единственный
предел.
8
Тестирование вправо (shift-right testing)- это еще один способ сказать «тестирование в рабочей среде)).
Создание приложений таким образом, чтобы можно было безопасно внедрять изменения в рабочей среде,
ограничивая их влияние на клиентов, помогает выявить скрытые дефекты, проявляющиеся только в реаль
ных условиях (и множество других преимуществ). Подробнее об этом в следующих главах.
Принципы надлежащего предоставления сервисов
SOA -
■
267
это хорошо, у него есть очевидные преимущества для вашей организации,
но его не всегда просто внедрить. Позвольте нам поделиться с вами еще несколь
кими ключевыми концепциями, которые, как вы услышите, будут обсуждаться
в рамках
SOA
и которые при практическом применении принесут пользу вам, ва
шим проектам, вашему бизнесу и вашим инженерам.
♦
Высокая степень абстракции и оrраниченности. Поддерживайте публичные,
стабильные контракты и четкий объем сервиса с определенными границами.
В предыдущих главах мы рассказывали об опасностях распределенных моноли
тов, и несоблюдение этих рекомендаций подвергнет вас риску.
♦
Разделение задач
(Separation of Concerns, SOC).
В предыдущей главе мы под
робно рассмотрели сопоставление предметных областей; разделение бизнес
областей в сервисах позволяет разделять и группировать сервисы в соответствии
с тем, как работает ваш бизнес. Если сделать это неправильно, то появятся
функции, которые должны работать врозь, и наоборот. Это приведет к нелогич
ным сценариям. Представьте, что ваш сервис продаж организует покупки и рас
считывает налог с продаж. Когда сервис продаж вызывает сервис платежей для
совершения платежа, тогда сервис платежей должен вызвать сервис продаж для
расчета налога. Налог с продаж должен жить либо отдельно, либо в сервисе пла
тежей. Неправильное сопоставление бизнес-областей компании может привести
к таким абсурдным ситуациям, как эта.
♦
Совместимость. Предоставляйте сервисные интерфейсы с использованием ши
роко распространенных протоколов, в идеале с открытым исходным кодом. Это
позволит командам использовать сервисы в различных контекстах и приложени
ях. Избегайте написания собственных протоколов без веских причин, таких как
нестандартное оборудование или необходимость решения других задач, ради
кально отличающихся от тех, с которыми сталкиваются большинство корпора
тивных компаний.
♦
Слабая взаимосвязь. Сокращается объем информации, которой сервисы обме
ниваются друг с другом. Не допускайте утечки деталей реализации; это отлич
ный способ привязать себя к определенной технологии и потерять свободу вы
бора.
♦
Документация по АРI-контрактам. Мы поговорим о контрактах чуть позже,
но важно уделить время разработке проверенной и всеобъемлющей специфи
кации OpenAPI9 • Это всегда пойдет на пользу потребителям. И каждый сможет
извлечь выгоду из хорошего примера.
♦
Динамический реестр и обнаружение. Сделайте ваши сервисы доступными
для пользователей с помощью обширного реестра сервисов и инвентарного спи
ска; помогайте пользователям находить сервисы с помощью таких инструмен
тов, как
9
Netflix Eureka (https://github.com/Netflix/eureka).
Веб-сайт OpenAPI определяет четкую спецификацию для НТТР-интерфейсов. Более подробную информа
https://www.openapis.org/.
цию смотрите в примечании ниже в этой главе.
■
268
Глава б
Напоследок хотим сказать вам следующее: соблюдение правильных принципов по
зволяет нам расширять возможности инженеров и учитывать потребности бизнеса.
Неправильные действия не приведут к успеху. Только верные шаги и правильные
решения позволят быстро добиться желаемого результата.
Вначале контракт
При кодировании сервиса можно использовать два подхода (рис.
них
-
6.8).
Один из
начать с реализации, где вы работаете над своими бизнес-функциями и мо
делями данных, а затем определиться с
API.
Такой подход называется «сначала
реализация». Первым побуждением многих инженеров является начать с кода реа
лизации. Как я могу понять, каким должен быть
API,
пока не разработаю модель
базы данных или не создам первую версию?
В качестве альтернативы можно начать с контракта, также известного как подход,
основанный на заключении контракта. Вначале начните писать код контракта и
создайте
WSDL
некоторые
для
и
SOAP
артефакты,
OpenAPI
представляющие
использовать этот открытый АРI-файл
та на основе файла
контракт:
для любого современного
yaml
API.
WADL
для
REST,
Инструменты могут
и напрямую генерировать код контрак
yaml.
(1) Вначале контракт
(2) Сначала реализация
..............
•
(А) Вначале код контракта
.................
(Б) Вначале метаданные
(А) Сначала код реализации
.. ............ .
(Б) Сначала база даных
при генерации кода
Рис.
6.8.
«Вначале контракт» против «сначала реализация»
У каждого подхода есть свои плюсы и минусы, и выбор лучшего подхода для дан
ного проекта может показаться сложным. Дпя нас всё сводится к ключевому вопро
су: создаете ли вы новый сервис или улучшаете существующий?
Новый сервис
Если вы создаете новый сервис, ответ очевиден: сначала вам следует выбрать кон
тракт. Если вы начнете с реализации, контракт будет отражать реализацию, что аб
солютно неправильно. Утечка информации о деталях реализации в контракт
-
один из самых простых способов столкнуться со случаем высокой степени связно-
Принципы надлежащего предоставления сервисов
■
269
сти и свести на нет вашу свободу изменений, являющуюся ключевым преимущест
вом
SOA.
Для качественного сервиса контракт всегда должен быть абстракцией от реализа
ции. Представьте, что вы создаете сервис поверх базы данных с тремя таблицами,
каждая из которых содержит
1О
столбцов. Логично заключить контракт с тремя
операциями, связанными с каждой таблицей, и десятью параметрами, каждый из
которых назван в честь столбца. (В конце концов, почему бы не использовать имя
столбца повторно, если оно уже есть?) Такой контракт совершенно неправильный.
Это не контракт и не настоящий сервис, вы просто вслепую открываете таблицу
базы данных. Такой подход является антипаттерном, и мы будем называть его
«удаленным просмотром». Если контракт не предусматривает абстракции, у вас
прост~ возникает сложность.
Когда вы приступаете к работе над контрактом, не имеет большого значения, ре
шите ли вы начать непосредственно с кода контракта и затем сгенерировать мета
данные
(W ADL, WSDL
или
OpenAPI yaml),
будь то вручную или во время вьшол
нения, генерируя их с помощью аннотаций, или же наоборот, начнете с метаданных
и сгенерируете код контракта. Однако второй подход не всегда позволяет генери
ровать самый чистый код и, скорее всего, потребует ручной настройки, но все это
зависит от вашего стиля и предпочтений.
Существующий компонент
В таком случае нужно создать сервис или предоставить
API
поверх уже сущест
вующей реализации. Возможно, у вас есть классическое монолитное или настоль
ное приложение, которому необходимо предоставить доступ к функции внешнему
вызывающему устройству. Или же есть существующий сервис с некорректным
контрактом, который либо слишком велик, либо слишком мал и нуждается в пере
стройке, или любое количество других архитектур и ситуаций.
Независимо от мельчайших деталей, вам, возможно, придется поэтапно переклю
чаться между «сначала реализация» и «вначале контракт», чтобы добиться прогрес
са и выполнить поставленную задачу. Вы по-прежнему хотите вначале заключить
контракт везде, где это возможно, но вам, вероятно, придется идти на компромис
сы, когда первые версии контракта будут отражать большую часть существующей
модели данных или любой другой формы контракта, которая будет развиваться.
Миграции будут подробно рассмотрены в последних двух главах книги, главе
«Миграция кода» и главе
9
10 «Миграция данных».
Всегда спрашивайте себя: кто будет вызывать контракт в существующем коде?
Если у вас еще нет пользователей для этого нового контракта, представьте, что это
новый пользовательский интерфейс. В зависимости от объема и сложности рефак
торинга, который вы вынуждены выполнять, возможно, придется пойти на некото
рые компромиссы. Но если это новый пользовательский интерфейс и у вас еще нет
пользователей, воспользуйтесь этой возможностью; и даже с существующим кодом
вы всегда можете обратиться и предложить лучший вариант контракта. Не ограни
чивайте себя!
■
270
Глава 6
Кодирование контракта с помощью
Спецификация
OpenAPI
OpenAPI
широко используется в отрасли для описания сервисных
контрактов, также называемых
API. OpenAPI обладает хорошими инструментами
Java, Node JS, Go, Python, РНР, Ruby и др., визу
для нескольких языков, таких как
альными редакторами, инструментами для генерации кода, возможностью макети
рования данных, проверки подлинности, безопасности и многим другим.
На рис.
6.9
показан пользовательский интерфейс
файла метаданных сервиса в формате
OpenAPI
OpenAPI yaml. Давайте
из опубликованного
углубимся в код для
получения такого результата. С полным кодом можно ознакомиться здесь:
https://
github.com/diegopacheco/fixing-monoliths-book/tree/main/chapter6/openapi-contract,
где вы можете ознакомиться непосредственно с файлом OpenAPI yaml и всем Jаvа
кодом.
/vЗ/api-<locs
OpenAPI definition CD e:e>
Server•
1 http:lllocalhost:8080 • Generated server url
...,,
1
л
profile-controller
/service/profite/user / {id}
V
. . /service/profile/user/batch/{ids}
V
Schemas
User
л
>
Рис.
Контракт сервиса
6.9.
Пользовательский интерфейс
ProfileContract
OpenAPI
и пример его реализации важны. Мы будем воз
вращаться к ним на протяжении всей оставшейся части этой главы.
Весь код находится в одном проекте, но правильным решением было бы разбить
его как минимум на два модуля
Maven,
чтобы отделить контракт от реализации:
profile-service-contract и profile-service-impl. Некоторые инженеры могут сгенери
ровать это разделение в разных формах, например назвать контракт api, а реализа
цию
-
server.
■
Принципы надлежащего предоставления сервисов
271
- отсутствие привязки
Spring Boot, Spring, Tomcat или лю
Обратите внимание на одну важную особенность проекта
к фреймворку. Не связывайте свой контракт с
бым другим фреймворком. Помните, что контракты должны быть независимыми.
Наш пример приложения не завершен на
часто
присутствуют в
классе сервиса,
и
l 00 %;
не
мы пропустили проверки, которые
сохраняемость
включили
терфейса ОАО или репозитория. Цель этого примера
в
просто показать
-
виде
ин
OpenAPI
в действии.
1. @RestController
2. @RequestMapping ( "/service/profile")
3. puЫic class ProfileController iшplements ProfileContract (
4.
private String pattern = "уууу-ММ-dd";
private SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
5.
6.
7.
8.
9.
10.
11.
12.
@GetMapping ( "/user / ( id} ")
@Override
puЬlic User getUserByid(@PathVariaЫe UUID id) (
// Мы просто возвраш;з.ем пользователя User обратно
Это всего ЛИ111Ь пример,
//
и вызывать базу данных
13.
из
UUID
обычный сервис будет вылолнять проверки
(ОАО)
(Service)
.
return new User (id, dateFormat. format (new Date ()), "default-"+id+"@company.io");
14.
15.
16.
17.
18.
19.
@Override
@GetMapping ( "/user /batch/ ( ids} ")
@ResponseStatus(HttpStatus.OK)
puЬlic List<User> getUserByids(@PathVariaЫe List<UUID> ids} (
<User> обратно из UUID.
20.
//
Мы просто возвраш;з.ем список
21.
//
Это всего лИlIIЬ пример, обычный сервис будет вылолнять проверки
и вызывать базу данных
22.
23.
24.
25.
26.
(Service)
(ОАО).
List<User> result = ids. stream () .map ( (u) -> (
String normalize = u.toString() .replaceAll("-"," ");
return new User(u,dateFormat.format(new Date()),
"default"+normalize+"@company.io");
}) .collect(Collectors.toList());
return result;
27.
28.
Рассматривая листинг
6.1,
мы видим, что у нас есть простой контроллер
в котором реализуем контракт сервиса
с
Spring
или
Spring Boot.
ProfileContract,
REST,
поэтому контракт не связан
Мы сопоставляем две операции
rest:
одну (luser/(id}), где
можно передать идентификатор пользователя (UUID), и другую (/user/batch/(ids)),
где можно запросить несколько uuш, разделенных запятой. В
RFC 2616
не указано
272
■
Глава б
ограничение на максимальную длину строки запроса. Однако помните, что многие
НТТР-серверы ограничивают длину запроса. Например, значение по умолчанию
для
Tomcat равно 8 кб,
OpenAPI -отличный
но вы можете увеличить его до
65
кб.
стандарт. Стоит рассмотреть возможность его использования
в своих сервисах, но важно не связывать свои контракты с библиотеками
или
Spring Doc
OpenAPI,
Spring-*.
Обратная совместимость
Как мы уже говорили в предыдущей главе, обратная совместимость
compatiЬility)
-
(backward
это сверхспособность. Когда у вас постоянно нарушаются кон
тракты на обслуживание, вы создаете нестабильность и замедляете весь процесс
разработки. Такая ситуация становится серьезной проблемой и снижает производи
тельность. В классическом или модульном монолите, по крайней мере, весь код
находится в одном месте, и можно проводить рефакторинг с помощью
IDE.
При
распределении, использовании разных кодовых баз в разных проектах и разверты
вании на разных компьютерах такой простоты нет. В таких условиях важно, чтобы
контракты на обслуживание были стабильными и не нарушались часто. Быстрые
перемены
-
это прекрасно, но постоянно ломать процессы потребителей недопус
тимо.
Для обеспечения обратной совместимости важно различать обработку изменений,
которые нарушают целостность системы
затрагивают
(non-breaking changes).
между этими двумя изменениями (рис.
... . .... ... .. . . ......
•
НЕ нарушает код.
•
•. Mf ~EJ ~ы~:ь ~~~~~н~ п~л~~~т~я~и • •
Изменения, не нарушающие целостность
(breaking changes),
и тех, которые ее не
Итак, прежде всего, нам нужно понять разницу
6.10) .
. ................... .
• Приведет к НАРУШЕНИЮ кq:ia,
•
: Н~ ~o,:-ei:, б':т~ пео~rн~~~о. п~~т.ел~м: •
Изменения, нарушающие целостность
+ Добавить новую операцию
+ Переименование/удаление операции
+ Добавить необязательный параметр
+ Переименование/удаление параметра
со значением по умолчанию
+ Переименование/удаление поля
+ Добавить поле в результирующий объект
+ Добавить новый метор/формат
(gRPC/PB)
в возвращаемом объекте
+ Удалить метор/формат (например ,
REST/JSON)
+ Изменить формат , например ГГГГ- ММ-ДД
Рис.
6.10.
Сравнение изменений, нарушающих и не нарушающих целостность
В двух словах, изменения, нарушающие целостность, ломают код
API
ваших поль
зователей и не могут быть проигнорированы. Пользователи могут игнорировать
изменения, не нарушающие целостность, до тех пор, пока им не понадобятся до
бавленные функциональные возможности или данные. Короче говоря, вы можете
Принципы надлежащего предоставления сервисов
■
273
свободно вносить изменения в контракт и в свой код, если они не нарушают цело
стность.
Давайте возьмем контракт с профилем, который мы рассмотрели в листинге
6.1,
и начнем вносить некоторые изменения! Во-первых, давайте внесем кардинальное
изменение с новой операцией
getUserByEmail (листинг 6.2).
1. i.mport java.util.List;
2. i.mport java.util.UUID;
3.
4. /**
5. * Спецификация коН'Iракта:
6. * <Ь>Порядок</Ь> : Не гарантируется.
7.
8.
9.
<br/>
<br/>
<Ь>Date Fonnat</b>: гггг-мм-дд
*
*
<Ь>Шифрование</Ь>: Зашифрованный текст <Ьr/>
*
<Ь>Сmибки </Ь>: Ее.ли ни один пользователь не найден, возврд1Щ1ется
*
<Ь> Идемпотентность </Ь>: Все операции
<br/>
пустой пользователь
10.
<br/>
<br/>
11. *
12. */
ProfileContract {
User getUserByid(UUID id);
List<User> getUserByids(List<UUID> ids);
13.puЫic inteпaoe
14.
15.
16.
Изменение, не нарушак:щее целостноть: Добавление новой операции
17 .
//
18.
User getUserByEmail(String email);
19. 1
getUserByEmail -
это новая операция, и ни один пользователь пока не может ее вы
звать. Пользователи могут полностью игнорировать ее. Они продолжают вызывать
две другие операции
REST без
приостановки, не требуя изменения кода.
Допустим, у нас есть драйвер для
ProfileContract.
Его нужно изменить, чтобы вне
дрить новую операцию. Пользователи могут получить новую версию драйвера без
необходимости внесения изменений в код, потому что мы не меняем уже сущест
вующие методы, а добавляем новый. Таким образом, все в порядке. Со стороны
потребителей ничего не меняется.
Теперь давайте посмотрим на пример изменения кода, нарушающего целостность.
1. i.mport java.util.List;
2. i.mport java.util.UUID;
3.
4. /**
5. *
Спецификация КОН'lракта:
<br/>
6. *
<Ь>Порядок</Ь>: Не гарантируется.
<br/>
■
274
Глава б
<br/>
<br/>
7. *
<Ь>Формат даты</Ь>: гггг-мм-дд
8. *
<Ь>Шифрование</Ь>
9. *
<Ь>Опмбки </Ь>: Если ни один пользователь не найден, возвращэ.ется пустой
:
Зашифрованный текст
пользователь
10. *
<Ь> Идемпотентность </Ь>: Все операции
<br/>
<br/>
11. *
12. */
13.
puЬlic interface ProfileContract
14. User getUserByid(UUID id);
15. List<User> getUserByids(String[] idArray);
16.
Рассматривая этот фрагмент кода (листинг
getUsersByis
♦
мы видим, что пакетная операция
претерпела существенные изменения:
Изменение-1, нарушающее целостность: тип и название параметра name изме
нились с
♦
6.3),
ids
на
idArray.
Изменение-2, нарушающее целостность: тип параметра изменен с List на
String[J (список заменен на массив строк).
Пользователи getUsersByids не могут игнорировать это изменение, поскольку оно
затронуло формат, типы и требования к контракту. Те, кто использует только
getUsersByid, могут считать, что они в безопасности, ведь у них нет кода, написанно
го для getUsersByids. Это может быть верно в некоторых протоколах, таких как
JSON
через
REST/HTTP.
Но в других протоколах, таких как RМI, это не так.
И если вы используете драйвер сервиса, обновление будет обязательно для всех,
поскольку в противном случае получите поврежденный код, ожидающий вызова и
вызывающий ошибки. Даже если вы никогда не использовали getUsersByids и вас не
волнуют изменения, теперь будет над чем поработать.
Иногда изменения, нарушающие целостность, неизбежны и не имеют альтернати
вы. В других случаях инженер внес их незаметно, и теперь они находятся в про
мышленной эксплуатации. Постоянные изменения, нарушающие целостность,
-
это плохо, они замедляют процесс разработки. Но все же есть способы справиться
с этой проблемой:
♦
Пусть это сломается. Не очень хорошо, но иногда просто заставить всех изме
ниться не так уж и сложно. Не масштабируется.
♦ Управление версиями
API.
Внесение изменений в новую версию публичного
контракта, представленную сервисом. Существуют несколько стратегий для
этого подхода, таких как:
• версия с использованием FQDN 10 , например
profilev2.acme.internal;
°
1 Fully Qualified Domain Name (полное доменное имя) в Википедии:
https://en. wikipedia.org/wiki/Fully_ qualified_ domain_ name.
profilevl.acme.internal
или
Принципы надлежащего предоставления сервисов
■
275
•
версия с использованием URL-aдpeca, например /profile/vl/ или /profile/v2/;
•
версия с использованием уровня пакета или объекта, например ProfileContractVl
ИЛИ
•
ProfileContractV2;
использование метаданных версии, например НТТР-заголовок, version:vl или
version:v2.
♦
Косвенная обратная совместимость. Перевод старых вызовов в новый кон
тракт на каком-либо среднем уровне: клиентском драйвере, АРI-шлюзе, уровне
маршрутизации, таком как
Управление версиями
-
ESB, Envoy, nginx
или А WS
ALB.
это очень мощный инструмент, но при неправильном ис
пользовании он имеет ряд очевидных недостатков. Например, сколько версий вы
поддерживаете параллельно? Может быть сложно поддерживать более
3.
Дубли
руете ли вы код для создания этих версий? Возможно, вам потребуется выполнить
некоторое преобразование объектов, чтобы избежать использования трех баз кода.
На рис.
6.11
представлен сервис с тремя версиями контракта:
V 1, V2
и УЗ. Мы мо
жем обеспечить надлежащую обратную совместимость, контролируя версии кон
трактов и вводя новую основную версию публичного контракта каждый раз, когда
у нас происходят изменения, нарушающие целостность. Таким образом мы избега
ем нарушения прав потребителей.
Пользователь А
с устаревшим
Пользователь В
Пользователь С
Пользователь В
пользовательским
с микросервисом
с сервисом
с сервисом
интерфейсом
КонтрактVЗ
. Возможно , мы отключим
1 в следующем спринте .
версию
Пользователю А необходимо
выполнить миграцию
в течение
2 недель .
Реализация
сервиса профилей
Та же реализация сервиса
Та же БД
Три версии контракта сервиса
БД профилей
Рис.
6.11.
Простой сервис, поддерживающий три контракта (три версии)
276
■
SOA
Глава 6
и изоляция
Пожалуй, наиболее значимым вкладом любого стиля архитектуры сервисов/микро
сервисов является то, что изоляция
-
это самое важное. Как мы узнали из главы
2
«Антипаттерны: отсутствие изоляции», изоляция должна применяться ко всем
элементам сервиса. Но есть три ключевые области любого сервиса, которьJе осо
бенно важны для обеспечения идеальной изоляции: публичные контракты, библио
теки и хранилища данных. Эти области являются самым важным полем битвы или
«границами» в борьбе за защиту вашего сервиса. Все три границы должны быть
изолированы на
100 %.
Сохранение изоляции имеет решающее значение, поскольку вы хотите предостав
лять сервисы с низкой связностью, высокой степенью согласованности и независи
мостью от других сервисов. В некоторых областях наша отрасль проделала разум
ную работу, применив принцип изоляции:
♦
базы кода: часто по одной для каждого проекта в системе контроля версий,
такой как git/GitНub;
♦ конвейеры развертывания: системы
задания по развертыванию, такие как
♦
наборы для тестирования: в
тестов, например
♦
Java
JUnit или TestNG;
CUCD,
подцерживающие независимые
Travis CI или Jenkins;
есть несколько очень популярных наборов
серверы/контейнеры: запуск вашего сервиса или компонента на отдельном
выделенном
экземпляре
OpenStack или VMware,
с
использованием
систем
виртуализации,
или облачных решений, таких как А WS ЕС2,
таких
как
ECS/EKS.
Однако опыт показывает, что отраслевые методы изоляции далеки от желательных
и на самом деле отражают антипаттерны:
♦ хранилища данных или базы данных: совместное использование таблиц,
пользователей баз данных и схем между сервисами;
♦ библиотеки: бинарная связь, скрытые конфигурации, неочевидные ловушки
зависимостей;
♦
публичные контракты: плохо спроектированные, скрытые контракты, утечка
информации о реализации из-за спецификации таблиц.
Для эффективного использования принципа изоляции необходимо правильно при
менять его для каждой границы, что означает разные вещи. Такие сложные задачи
требуют постоянного внимания для закрепления принципов на протяжении всего
жизненного цикла разработки программного обеспечения.
Давайте углубимся в изучение того, как мы можем обеспечить надлежащую изоля
цию трех основных компонентов: хранилищ данных, библиотек и публичных кон
трактов. Как мы узнали из главы
2
«Антипаттерны: отсутствие изоляции», изо
ляция обеспечивает преимущества за счет уменьшения связи между компонентами
и радиуса поражения. Изоляция на всех трех наших направлениях требует от инже
неров и архитекторов разных подходов (рис.
6.12).
Мы можем обеспечить изоля-
Принципы надлежащего предоставления сервисов
■
277
цию только в том случае, если будем уделять внимание ключевым решениям по
разработке программного обеспечения и архитектуре на протяжении всего жизнен
ного цикла разработки. Эти сложные моменты принятия решений могут возникать
на протяжении всего срока службы сервиса
-
от разработки до запуска и даже вы
вода из эксплуатации. Принятие правильных решений требует постоянного внима
ния для надлежащего выполнения таких сложных задач.
Не используйте
Делайте :
совместно :
• Пользователей
• Экономичные библиотеки
• Экономичные драйверы
• Небольшое число зависимостей
• Схемы
• Таблицы
Надлежащие
принципы
изоляции
Изоляция публичных контрактов
Делайте :
• Простой контракт
• Общий сервис
Не делайте .
• Скрытые контракты (P0JO, очереди ,
JS0N, перечисления и т . д. )
• Явное тестирование
• Минимальные зависимости
Рис.
6.12.
Краткий обзор принципов изоляции
Ключевой момент из этой книги: архитектура и дизайн программного обеспечения
имеют большое значение. Часто они не рассматриваются должным образом или
даже полностью игнорируются, особенно после запуска, что приводит к пробле
мам. Как и во всем, что касается архитектуры программного обеспечения, понима
ние принципов является ключевым. Осведомленность
-
это здорово, но мы долж
ны выйти за рамки осведомленности и перейти к культуре, где эти принципы явля
ются неотъемлемой частью вашей инженерной культуры. Ключевое слово здесь
-
культура, а не процесс; ключевые принципы должны быть живой, неотъемлемой
частью функционирования всех команд, а не формальностью. Они не должны быть
похожи на устаревшую вики-страницу, не отражающую реальность, или контроль
ный список запуска, который кто-то просто проверяет и движется дальше.
Изоляция хранилищ данных
В главе
2
«Антипаттерны: отсутствие изоляции» подчеркивается важность изо
ляции данных. Возможно, ваш сервис использует специально созданные специали
зированные базы данных и применяет Polyglot Persistence 11 , применяя подходящий
для этой работы инструмент. Однако предположим, что ваш сервис использует одну
реляционную базу данных, такую как
11
MySQL
или
Postgres,
а также несколько нере-
Polyglot Persistence означает, что в распоряжении команд для выполнения своей работы имеется широкий
спектр хранилищ данных, а не только одна технология, которую все инженеры вынуждены использовать
в любых условиях. Мы обращаем внимание на
Persistence:
https://maгtinfowler.com/Ыiki/
Oracle. Вот хорошая
PolyglotPersistence.html.
статья Мартина Фаулера о
Polyglot
■
278
Глава б
ляционных хранилищ данных
NoSQL,
таких как
Cassandra, Neo4J
или
Riak.
Важно
не предоставлять доступ к основной базе данных другим сервисам.
Обмен данными между сервисами должен осуществляться через их интерфейсы,
и никогда никакими другими способами. Это исключает доступ к базе данных или
манипулирование скрытым общим файлом . Чтобы быть точным, правильный вызов
интерфейса сервиса означает обмен данными:
♦
целенаправленное раскрытие: используйте то, что указано в публичном кон
тракте;
♦ удаленный вызов: вы используете любой механизм связи, который предостав
ляет сервис, например JSON через HTTP/REST, gRPC, GraphQL или даже
SOAP/XML для устаревших
Как показано на рис.
6.13,
приложений.
компании АСМЕ
Widget требуется,
чтобы ее сервис про
даж вызывал сервис платежей . Сервис платежей может предоставить доступ к сво
им АРI-интерфейсам с помощью простого вызова
или
gRPC
с
Protobuf;
осуществляется только через
вис
платежей
Cassandra.
имеет
REST,
возвращающего
JSON,
на самом деле это не имеет значения. Важно то, что вызов
API;
прямой
прямого доступа к базе данных нет. Только сер
доступ
к
своему
хранилищу
Postgres и
данных, MySQL,
данных,
Аналогично у сервиса продаж есть только одна база
и это единственный сервис, который может взаимодействовать с этой базой дан
ных.
Контракт
Контракт
Рис.
С точки зрения
DevOps
6.13.
Изоляция баз данных
вы можете использовать скрипт
Terraform
совместно для
обеспечения баз данных и компонентов инфраструктуры, но в идеале мы должны
развертывать каждое приложение и базу данных в отдельных выделенных класте
рах. Изоляция инфраструктуры за счет использования разных кластеров важна,
поскольку это уменьшит радиус поражения в случае сбоя. Если один сервис исчер
пывает 12 свои ресурсы, это не обязательно приведет к отключению других сервисов
или приложений, необходимых для обеспечения доступности и надежности.
Все компании разные, и вам может потребоваться сократить расходы и совместно
использовать кластеры. По возможности не делайте этого для промышленной экс-
12
Нехватка ресурсов в Википедии: https://en.wikipedia.org/wiki/Starvation_(computer_science).
Принципы надлежащего предоставления сервисов
■
279
плуатации! Откажитесь от подобной затеи. Иногда разумно сократить расходы,
создав небольшие кластеры в среде, не связанной с промышленной эксплуатацией,
или даже в общих кластерах. Экономия средств всегда полезна для вашего бизнеса,
но не настолько велика, если побуждает инженеров нарушать изоляцию. Совмест
ное использование кластеров может привести к тому, что команда начнет разработ
ку проекта с обращения к базам данных разных сервисов, нарушая изоляцию.
И прежде чем кто-либо заметит, команда напишет много кода, корабль отчалит,
а вы получите дорогостоящее решение. Следование правильным принципам рано
или поздно обязательно окупится.
Изоляция библиотек
Напомним, что библиотеки, как описано в главе
«Антипаттерны: отсутствие
2
изоляции>>, могут нарушить изоляцию, особенно внутренние общие библиотеки.
Внутренние общие библиотеки должны быть изолированы. С библиотеками изоля
ция работает по-другому. Недостаточная изоляция библиотек
-
одна из наиболее
важных проблем в нашей отрасли, которая по-прежнему требует внимания. Для
изоляции библиотек крайне важно уменьшить усиливающие эффекты. Мы говорим
о таких раздутых библиотеках, которые имеют простую функцию, но поддержива
ют десятки или даже сотни зависимостей. Создание и использование экономичных
библиотек
-
важный шаг к преодолению этого рубежа. Внутренние общие биб
лиотеки должны поддерживаться в рабочем состоянии и иметь активного вла
дельца.
На первый взгляд может показаться непонятным, как внутренние общие библиоте
ки создают связь между сервисами. На рис.
платежей и продаж АСМЕ
Widget Company;
6.14
мы возвращаемся к сервисам
базы данных были опущены из сооб
ражений экономии места и сосредоточения внимания на библиотеках. Хотя эти два
Контракт
Контракт
Реализация
сервиса платежей
сервиса продаж
Common
Spring Веапs
@Configurations
Реализация
1-----~~ Утилиты
Проверки
Рис.
6.14.
Связность сервисов через библиотеки
Бездействие
280
■
Глава б
сервиса имеют изолированные публичные контракты и изолированные хранилища
данных, они косвенно связаны своими внутренними общими библиотеками, утили
тами и
Spring Bean @Configurations, двумя общими шаблонами, которые
4 «Антипаттерны: внутренние общие библиотеки».
мы рас
смотрели в главе
Напомним, что библиотека утилит часто служит свалкой данных
-
от простых
функциональных утилит, таких как операции по манипулированию строками, до
проверки данных, форматирования чисел или обычной проверки номера телефона,
электронной почты или аналогичных данных. Из-за большого разнообразия про
блем бизнес-правила очень легко могут просочиться в библиотеки такого рода, что
часто и происходит. Что еще хуже, библиотеки утилит нередко используют другие
библиотеки для автоматической проверки данных, такие как
Конфигурации/аннотации
Common Spring bean
Hibemate.
кажутся достаточно безобидными,
чтобы ими можно было делиться, но теперь сервисы не владеют своими конфигу
рациями. Цена, которую вы заплатите
это попытка понять бесконечные уровни
-
делегирования, чтобы разобраться в библиотеках для исправления ошибок.
Сервисы платежей и продаж фактически обязались обновлять свои две библиотеки
при появлении исправлений безопасности или багфикса, которые, вероятно, заста
вят все сервисы мигрировать почти одновременно или в массовом порядке. Бинар
ная связь усугубляет ситуацию; в нашем примере средства проверки данных ис
пальзовали
Hibemate
в качестве зависимости, а конфигурации компонентов
скорее всего, будут работать в
Spring Bean.
Spring,
Теперь обновления могут привести
к конфликтам зависимостей, и отделы платежей и продаж больше не смогут обнов
лять свои сервисы изолированно. Такие масштабные миграции являются дорого
стоящими и занимают много времени. Они требуют координации между команда
ми с большим количеством ошибок и сложностей при устранении неполадок.
И, конечно же, компания
Acme Widget,
скорее всего, обладает обширной экосисте
мой сервисов, насчитывающей от десятков до сотен сервисов. Так что все эти воз
действия распространяются далеко за пределы двух затронутых сервисов. Все это
снижает ключевое преимущество
SOA -
сокращение затрат и упрощение обслу
живания. Кроме того, ограничивает возможности команд, желающих эксперимен
тировать с новыми технологиями.
В обоих случаях инженеры компании
Acme Widget
создали эти библиотеки и поде
лились ими с другими пользователями из лучших побуждений, полагая, что по
вторное использование кода
-
это хорошо. Но повторное использование может
оказаться ловушкой со своими побочными эффектами и последствиями. Повторное
использование не дается даром. Все это происходит из-за того, что библиотеки час
то воспринимаются как нечто само собой разумеющееся, и люди не осознают, что
повторное использование может оказаться дорогостоящим. Отсутствие активного
управления библиотеками приводит к тому, что проблема остается незамеченной
до тех пор, пока не станет слишком поздно. Тогда распространение вашей библио
теки начнет активно мешать проектам по переходу на новые технологии.
Хуже всего то, что все библиотеки в нашем примере необязательны! Всех побоч
ных эффектов и высокой степени связности можно было бы избежать, не создавая
библиотеки. Задумывались ли инженеры компании АСМЕ
Widget
о том, действи-
Принципы надлежащего предоставления сервисов
■
281
тельно ли они необходимы? Часто библиотеки создаются по необоснованным при
чинам:
♦ Неправильное повторное использование. Повторное использование во избе
жание ввода текста или поверхностное повторное использование.
♦
Случайное повторное использование. Преждевременная оптимизация; инже
неры предполагают, что какая-то команда может повторно использовать код, но
этого никогда не происходит. Повторное использование должно быть осознан~
13
ным, а не случаиным
♦
.
Выбор, основанный на мнении. Инженеры могут предпочесть использовать
hibernate validator вместо использования инструкций if или чего-то подобного.
♦ Ненужные абстракции. Использование сложных объектов проверки вместо
простого кода.
Случайное повторное использование имеет второе значение, которое означает, что
соединение посредством повторного использования происходит случайно, а не
является сознательным выбором. Даже стиль кода может привести к случайному
повторному использованию 14 .
Помните, что правильными причинами для создания внутренней общей библиотеки
должны быть:
♦
Критичность. Это сложная, рискованная и запутанная проблема, например
шифрование.
♦
Производительность. Создание сервиса замедляет работу и является неправильным решением, т. е. просто переносом файлов на SЗ.
Важно задуматься о понятии основных и второстепенных внутренних общих биб
лиотек. Чтобы решить, что важно для вашей компании, определите четкие крите
рии для выбора: когда следует создавать новую внутреннюю общую библиотеку,
а когда нет. Каждая компания индивидуальна, поэтому важно создать свое собст
венное руководство. Вот несколько советов.
♦
Избегайте создания этих необязательных внутренних общих библиотек:
•
утилиты;
•
константы, общие перечисления и
•
компоненты конфигурации
•
инициализация и инициализаторы;
•
внутренние клиенты;
•
общие проверки;
POJO;
(@Configuration Spring Beans);
13 Хорошая статья Бена Моррисона «Случайное повторное использование»:
bttps://www.ben-morris.com/tbe-code-reuse-mythwby-internal-software-reuse-initiatives-tend-to-fail/.
14 Ярослав Тулач в своей книге 2008 года «Практический дизайн API: признания архитектора Java
Framework» рассказывает о том, как стиль кода может привести к случайному повторному использованию.
282
♦
■
Глава б
•
настройка безопасности:
•
обёртки: для систем очередей, фреймворков отчетов и других клиентов.
TLS, mTLS,
сертификаты;
Возможные кандидаты для основных внутренних общих библиотек:
•
наблюдаемость: централизованное ведение журнала, инструментарий/метри
ки, распределенная трассировка;
•
динамические свойства: флаги функций и эксперименты.
Мы подчеркиваем слово «возможно», потому что у каждой компании свои пробле
мы и реалии. Возможно, общие библиотеки вообще не нужно разрабатывать,
и имеет смысл просто использовать решения с открытым исходным кодом или по
лагаться на сторонние шаблоны и поставщиков. Однако вы по-прежнему хотите,
чтобы все библиотеки были компактными; их свойства одинаковы независимо от
того, кто их реализует.
Когда вы создаете внутреннюю общую библиотеку по правильным причинам, вам,
по сути, нужно убедиться, что созданная библиотека является экономичной. Резю
мируем уроки из главы
4 «Антипаттерны:
внутренние общие библиотеки»:
♦
библиотеки должны быть действительно необходимы и приносить пользу;
♦
библиотеки должны иметь мало зависимостей или вообще не иметь их;
♦ зависимости также должны быть четко определены и необходимы;
♦
внутренняя общая библиотека
♦
повторное использование кода не должно быть основной причиной создания
-
это не сервис, придется идти на компромиссы;
внутренней общей библиотеки;
♦
следует избегать необоснованного выбора и больших фреймворков.
Противопоставление вкусов и мостов
в библиотеках и монолитах
Владение является ключом к надлежащему обслуживанию общей библиотеки или
любого фрагмента общего кода монолита. Если внутренняя общая библиотека ис
пользуется десятками или сотнями сервисов или находится глубоко в вашем клас
сическом монолите, необходим надежный архитектурный дизайн и управление,
в идеале со стороны одного владельца. Любой код, у которого нет владельца, осо
бенно внутренние общие библиотеки, легко использовать не по назначению. Инже
неры мо,ут захотеть избежать миграции и рефакторинга и следовать коротким пу
тем, который в долгосрочной перспективе обойдётся недешево. Иногда сложность
заключается в том, что правильный и неправильный подходы выглядят одинаково,
что приводит нас к противопоставлению вкусов и мостов.
Вкус
-
это
когда один
и тот же алгоритм, логика или решение
копируются
и вставляются в разные места с небольшими изменениями или вообще без изме
нений. Представьте, что у вас есть мороженое; у него могут быть такие вкусы, как
шоколад, ваниль или клубника. Вкусы лучше всего проиллюстрировать на примере.
Принципы надлежащего предоставления сервисов
На рис.
6.15
■
283
мы видим внутреннюю общую библиотеку, которая может генериро
вать последовательные идентификаторы, и мы можем использовать эти идентифи
каторы для сохранения данных в сервисах. На текущий момент внутренняя общая
библиотека имеет только один класс с именем
IDGenerator.java,
который генериру
ет последовательные идентификаторы. Команда сервиса отчетов желает изменить
этот код, чтобы он возвращал
UUID
вместо
Biglnteger
для улучшения изоляции
и надежности. Но теперь у них возникли следующие проблемы.
♦
Нет владельца. У этой внутренней общей библиотеки нет владельца, следова
тельно у нее нет полномочий рассматривать предлагаемые изменения в дизайне,
и некому задавать вопросы. Как и у многих неуправляемых внутренних общих
библиотек, здесь нет документации и комментариев.
♦
Отсутствие тестов. В таких библиотеках обычно нет тестов, они полагаются на
пользователей для тестирования кода.
♦
Отсутствие списка потребителей. Этой библиотекой пользуются очень многие
команды; вам нужно точно знать, кто является пользователями, чтобы выяснить,
кто вносит ошибки, или отследить злоумышленников.
♦
Внедрение новых функций. Команда сервиса отчетов находится под давлением
бизнеса, требующего выпуска множества функций, и времени на обдумывание
у нее совсем немного.
Сервис
Сервис
Сервис
профилей
продаж
отчетов
Сотни/тысячи
других сервисов
Внутренняя общая библиотека
• IDGenerator
Рис.
6.15.
Происхождение вкусов
Такая реальность широко распространена в нашей отрасли. Это сочетание техниче
ской сложности и высокого давления со стороны бизнеса. Разработчики, которые
просто хотят побыстрее завершить разработку своих функций, испытывают на
стоящий страх. Создается новый класс под названием: NewGenerator. java, инженер
выполняет рефакторинг своего кода и сохраняет старый класс IDGenerator. java. По
смотрите, как создается новый вариант? Позже другой разработчик может решить,
что
uuro
слишком велик, и предпочтет использовать
Biginteger
для экономии места
284
■
Глава б
в базе данных, при этом он захочет, чтобы идентификаторы увеличивались по
друrому. Так что просто скопируйте NewGenerator.java и создайте третий вариант
AlternativeGenerator. java. Теперь у вас есть три варианта (рис.
Сервис
профилей
Сервис
Сервис
продаж
отчетов
6.16).
Сотни/тысячи
других сервисов
Внутренняя общая библиотека
• IDGenerator
• NewGenerator
• AlternativeGenerator
Рис.
6.16. Дерево
вкусов
Вкусы могут проявляться по-разному; в этом примере они сосредоточены в одной
и той же внутренней общей библиотеке. Однако существуют и другие варианты.
Например, вкусы присутствуют в монолите, большом сервисе или даже зависят от
другой внутренней общей библиотеки.
Теперь представьте себе следующий сценарий: мы обнаружили фундаментальный
недостаток в AlternativeGenerator, и потребители больше не должны его использо
вать. Тот же контекст, тот же результат; вывод класса из эксплуатации не происхо
дит, и вкус просто остается там. Затем разработчики приходят и уходят из коман
ды, и нынешняя команда не знает, кто из них прав, а кто нет. По случайности неко
торые
разработчики
в
конечном
итоге
используют
неправильный
генератор
идентификаторов AlternativeGenerator, и из-за этого сталкиваются с ошибками, тратя
часы на устранение неполадок; вот так вкусы создают мины.
На первый взгляд, наличие дополнительных функций может показаться хорошим
решением,
поскольку
это
дает
вам
возможность
повторно
использовать
сущест
вующий код с некоторыми изменениями. Внутренние общие библиотеки делают
это еще хуже, поскольку они, как правило, неуправляемы и создаются быстро, что
бы удовлетворить потребности бизнеса, без надлежащего проектирования про
граммного обеспечения или архитектуры. Мы называем библиотечные нововведе
ния антипаттернами и одной из форм технического долга. Нововведения могут воз
никнуть даже в хорошо управляемом коде или экономичных библиотеках, если вы
не будете осторожны.
Принципы надлежащего предоставления сервисов
■
285
Подведем итог большим проблемам со вкусами.
♦ Неясность приводит к сложности. Оrсутствие документации и владельца
означает, что никто не может отличить правильное от неправильного. Какой
класс мне следует использовать
♦
Сложные задачи
-
кто знает?
по устранению неполадок/доработке. Решение проблем
с добавками может оказаться невозможным, поскольку разные команды создают
их и оставляют «гнить». Вы не сможете разобраться с большим комом грязи. На
устранение основных неполадок может уйти много времени.
♦ Эффект мины. Одна и та же ловушка, когда со временем появляется несколько
разработчиков, люди снова и снова сталкиваются с одной и той же проблемой:
классическая мина.
♦ Недостаточное время вывода на рынок. Все эти проблемы замедляют цикл
проектирования, влияя на производительность. Множество неудачных попыток
и месяцы на реализацию.
Теперь давайте рассмотрим ту же ситуацию, но с другой стороны; давайте погово
рим о мостах, а не о вкусах. Мост строят, когда между двумя городами проходит
река или море и возникает необходимость в строительстве дороги между ними. Но
вас когда-нибудь учили, как инженеры строят или ремонтируют мосты? Представь
те, что мост слишком мал, и вам нужно, чтобы на нем было больше машин. Вы за
прещаете всем автомобилям из обоих городов пользоваться мостом, пока вы его
ремонтируете? Представьте, что этот мост соединяет остров с городом; остановка
всего движения по мосту неприемлема. Итак, инженеры создают второй мост, рас
положенный рядом с первоначальным мостом, также известный как параллельный
мост (рис.
6.17).
Подождите секунду, но это звучит как своеобразный вкус, не так
ли? В чем разница?
Вкусы
-
это незавершенные мосты, но один из них связан с техническим долгом, а
другой устраняет его. В случае с мостами все ненужные скопированные реализации
Рис.
6.17.
Параллельные мосты в действии. Источник: https://hudsonvalleypost.com/
watch-the-tappan-zee-bridge-transform-into-mario-cuomo-bridge/
286
■
Глава б
заменяются, все виды использования отменяются, а код удаляется. Вкусы
-
это
антипаттерны, потому что мы усугубили проблему, а нам следовало бы решить ее
с помощью правильного инженерного подхода. Вкусы и мосты
-
это почти одно и
то же, одна и та же стратегия, но одно заканчивается, а другое просто гниет. То есть
мосты
-
это хорошо, а вкусы
-
это антипаттерн. Давайте применим нашу про
блему с генератором идентификаторов в том же контексте, но теперь сделаем это
немного по-другому. Будем использовать альтернативный подход для решения на
шей задачи:
♦ Инвентаризация. Составим список потребителей и разберемся в их вариантах
использования.
♦ Тестирование. Добавим тесты, чтобы обнаружить все публичные контракты во
внутренней общей библиотеке.
♦ Рефакторинг и очистка. Мы проведем рефакторинг всего пользовательского
кода и удалим ненужный код/вкусы. Удаление ненужного кода является обяза
тельным! Очистка- позволит мосту не превратиться в сервис.
Короче говоря, все дело в подходе. Наведение мостов требует неустанных долго
срочных лидерских усилий. Даже если у вас есть благое намерение достроить мост,
вы можете быть вынуждены не достраивать его из-за других обстоятельств. Таким
образом, ваш незавершенный мост превращается во вкус. Силами, работающими
против вас, могут быть:
♦
♦
Размывание команды. Инженеры приходят и уходят.
Изменение. Регулярное мероприятие или «черный лебедь». Изменение приори
тетов в связи с неотложными деловыми вопросами; смена руководства, и прио
ритет игнорируется; или резкое изменение, такое как пандемия, война или эко
номический спад, из-за которого о выводе из эксплуатации забывают.
Как и во всем, что касается архитектуры программного обеспечения, существуют
компромиссы и сценарии, в которых наведение мостов с помощью рефакторинга
также не является правильным решением.
Изоляция публичных контрактов
Контракты должны быть общедоступными и стабильными и оставаться независи
мыми от какой-либо языковой реализации. Когда компании становятся моноглота
ми, использующими только один язык, они теряют мотивацию и начинают совме
стно использовать объекты в своих контрактах вместо того, чтобы придерживаться
концептуальных типов: повторно использовать
дачи данных
(Data Transfer Objects,
POJO,
перечисления, объекты пере
ОТО) и объекты значений
(Value Objects, VO)
в своих публичных контрактах, которые поставляются в виде JАR-файлов.
Выгоды незначительны, но связность огромна, опасна и подвергает вас дополни
тельным антипаттернам:
♦
Использование библиотек. Как только ваш контракт распространяется через
JAR
и код в
git,
легко потерять контроль. Любой желающий может добавить не-
Принципы надлежащего предоставления сервисов
■
287
нужные зависимости, такие как аспекты, тяжелые фреймворки и другие внут
ренние общие библиотеки.
♦ Инерция миграции. Даже если у вас был только один contract-commons.jar
модуль, вам все равно нужно будет убедиться, что все ваши сотни или тысячи
сервисов используют его,
причем правильную версию.
Пользователи могут
вообще не обновляться, или при обновлении у них могут возникнуть проблемы,
если изменения не имеют обратной совместимости.
♦
Неправильные принципы. У некоторых возникает ложная иллюзия, что, имея
общий набор
POJO,
люди будут последовательно и надлежащим образом ис
пользовать одни и те же объекты в своих контрактах. Но это трудно контроли
ровать, и на практике так происходит не всегда.
♦
Бинарная связь. В конечном счете вы связываете свой публичный контракт
с другими проектами и внутренними общими библиотеками, что неоправданно
увеличивает зависимость сервисов, и это нежелательно.
Давайте вернемся к нашему примеру
ProfileContract
и покажем, как вы можете наи
лучшим образом выделить его публичный контракт.
1. import java.util.List;
2. import java.util.UUID;
3.
4.
5.
6.
interface ProfileContract
User getUserByid(UUID id);
List<User> getUserByids(List<UUID> ids);
puЫic
7.
Напомним, что публичный контракт
-
это единственный интерфейс, в котором вы
будете определять все возможности вашего сервиса. Контракт должен обладать
такими свойствами, как:
♦ Чистый. Информация о реализации не просачивается к потребителям.
♦
Простой. Понятен потребителям.
♦
Минимальный. Не содержит десятков и сотен операций.
♦
Экономичный. Не имеет внешних зависимостей, кроме локальных объектов,
определенных в проекте.
♦
Без бинарной связи. Нет импорта, кроме стандартного
Наш
ProfileContract (листинг 6.4)
Java JDK.
обладает всеми этими свойствами. Он чистый: вы
не можете определить, использует ли сервис реляционную базу данных, такую как
Postgres,
базу данных
такую как А WS
NoSQL, например Cassandra, или базу данных документов,
DocumentDB. Это отличное свойство, потому что нам нужно, что
бы публичный контракт касался бизнес-возможностей, и мы хотим отразить нечто
иное, чем базовое постоянное хранилище. Он простой, поскольку есть операции
с описательными именами и аргументами, и минимальный, поскольку есть только
288
■
Глава 6
две операции. Никаких внешних зависимостей или импорта, выходящих за рамки
стандартного
Java JDK,
не существует.
Публичные операции возвращают объект User (пользователь); давайте рассмотрим
его поближе (листинг
6.5).
1. i.шport java.util.Objects;
2. i.шport java.util.UUID;
3.
4. puЬlic class User {
5.
6.
private UUID id;
7.
private String createdAt;
8.
private String email;
9.
puЫic User() {)
10.
11.
12.
puЬlic User(UUID id, String createdAt, String email) {
13.
this.id = id;
14.
this.createdAt = createdAt;
15.
this.email = email;
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
puЬlic
retшn
UUID getld()
id;
void setid(UUID id)
this.id = id;
puЬlic
puЬlic
String getCreatedAt()
createdAt;
retшn
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
void setCreatedAt(String createdAt)
this.createdAt = createdAt;
puЬlic
puЫic
String getEmail()
email;
retшn
void setEmail(String email)
this.email = email;
puЬlic
@Override
puЬlic Ьoolean
и
(this ==
equals(Object
о)
retшn
о)
true;
Принципы надлежащего предоставления сервисов
40.
51.
52.
53.
54.
55.
56.
289
(о== null 11 getClass() != o.getClass()) return false;
User user = (User) о;
return OЬjects.equals(id, user.id) && Objects.equals(email, user.email);
il
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
■
@Override
int hashCode()
return Obj ects. hash (id, email) ;
puЬlic
@Override
String toString()
retum "User {" +
"id=" + id +
", createdAt='" + createdAt + '\' ' +
", email='" + ernail + '\'' +
puЬlic
1} 1;
Объект user представляет собой простой
POJO;
у него есть: пустой конструктор,
полный конструктор по умолчанию, средства получения и установки, операции
equals/hashCode
и метод
toString.
Если вы внимательно присмотритесь, то заметите несколько интересных свойств:
♦
Экономичность. Пользовательский объект не импортирует ничего, кроме
standard JDK;
java
нет зависимостей от открытого исходного кода или внутренней
общей библиотеки.
♦
Простота. Только основные поля, такие как
id,
адрес электронной почты и дата
создания.
♦ Совместимость. Дата указана в виде строки, что способствует внутренней со
вместимости между всеми языками и является ключевой частью Манифеста
SOA.
♦
Никаких бизнес-правил. Сам объект пользовательского контракта не устанавливает никаких бизнес-правил.
Реализация контракта будет осуществляться в другом проекте и модуле. Хотя реа
лизация и контракт могут базироваться на одной и той же базе кода, они должны
быть разными проектами, чтобы не было увязки публичного контракта с реализа
цией сервиса, чего следует избегать любой ценой.
Анализ проекта
Прежде всего, вам необходимо выполнить анализ проекта. Одного код-ревью не
достаточно, поскольку инженеры часто не всегда заботятся о целостности контрак
та
SOA.
Архитекторы станут вашими союзниками в проверке контракта и обеспе
чении его согласованности и корректности. Вот некоторые аспекты, которые необ
ходимо учесть при анализе публичных контрактов.
290
♦
■
Глава б
Проверка зависимости. Есть ли у нас нулевые зависимости?
♦ Документация. Понятен ли интерфейс? Можем ли мы определить, что делает
сервис, просто прочитав контракт? Можем ли мы добавить немного
Javadoc
для
неочевидных вещей?
♦ Полномочия сервиса. Не слишком ли много делает сервис? Следует ли приме
нить это в другом сервисе не из-за количества строк кода в реализации, а из-за
того, что в контракте слишком много различных бизнес-возможностей?
♦
Взаимосвязь между бизнес-областями. Сервис охватывает несколько бизнес
областей или пересекает несколько направлений бизнеса неудобным образом?
Это может быть тревожным сигналом о более серьезных проблемах.
♦
Избегание делегирования. Контракт такой же, как в другом сервисе? Это про
сто делегатор?
♦
Согласованность. Есть ли у нас согласованность в именовании? Понятны ли
названия и являются ли они описательными? То есть электронная почта называ
ется
♦
email,
а не
field34.
Стабильность контракта. Является ли контракт стабильным или мы нарушаем
его каждый спринт?
Автоматизация работоспособности контрактов
Помимо анализа проекта, можно применить некоторую автоматизацию для обеспе
чения наилучшего результата. Одной автоматизации недостаточно; архитектура
и дизайн требуют человеческого взгляда и командного подхода. То, чему мы вас
научим, поможет отметить действия и указать на запахи, но не сможет решить
ваши проблемы за вас.
Измерить изоляцию в публичных контрактах просто; проект контракта должен
иметь нулевые зависимости, которые легко проверить в вашем pom.xml
build.gradle
(gradle).
(maven)
или
У вас могут быть зависимости для тестирования, но во время
выполнения или компиляции зависимости должны быть нулевые. Простые шаги
для автоматизации этого процесса:
♦
Проверьте свои
pom.
Простое сопоставление строк или проверка grep могут
подтвердить отсутствие зависимостей.
♦
Проанализируйте свои артефакты. Проанализируйте файл зависимостей; вы
можете выполнить гораздо больше проверок, но при минимальном количестве
зависимостей.
♦ Используйте плагины (листинг
6.6).
Используя
maven-dependency-plugin,
уста
новите все зависимости в папку; папка должна быть пустой. После запуска: mvn
clean install
вам следует проверить, есть ли у вас папка с именем
target/lib.
Если папка существует и содержит JАR-файлы, ваш контракт нарушает правило
зависимостей. Если папка не существует или пуста, значит, у вас нет зависи
мостей.
Принципы надлежащего предоставления сервисов
■
291
1. <plugin>
2.
<groupid>orq .apache .maven.pluqins</groupid>
3.
<artifactid>maven-dependency-pluqin</artifactid>
4.
<executions>
5.
<execution>
6.
<id>copy-dependencies</ id>
7.
<phase>prepare-pa.ckaqe</phase>
8.
<goals>
9.
<goal>copy-dependencies</goal>
10.
</goals>
<configuration>
11.
12 .
<outputDirectory>$ {project. build. directory} /
liЬ</outputDirectory>
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteifNewer>true</overWriteifNewer>
<excludeScope>test</excludeScope>
<includeScope>coпrpile</includeScope>
<includeScope>runtiJDe</includeScope>
</configuration>
</execution>
</executions>
</plugin>
Неочевидные моменты
В этой главе мы рассказали вам об основах разработки контрактов и важности изо
ляции. Наш очень простой публичный контракт великолепен, и мы избежали неко
торых явных и очевидных ошибок. Но многие другие проблемы, связанные с кон
трактами, связаны с неочевидным, скрытым поведением в контракте, которое при
водит к плохим результатам.
Вы можете не увидеть их,
просто взглянув
на
определение кода публичного контракта. Давайте вернемся к нашему примеру
с
ProfileContract (код 6.4, 6.5) и
рассмотрим некоторые скрытые риски.
♦ Форматы дат: мм-дд-rrrr, дд/мм/rrrr, ISO 8601 15 , rrrr-мм-дд? Часто люди ис
пользуют даты, когда им нужно указать время и часовой пояс.
♦
Строки: в строках может прятаться множество скрытых деталей контракта.
Документируйте любой пользовательский формат, который может подразуме
ваться в ваших строках.
♦
Шифрование: учитывает ли ваша компания личные данные электронной поч
ты? Если да, то нужно ли их защищать с помощью шифрования? Если нужно, то
15 JSO 8601 устанавливает стандарт для записи дат и времени:
https://www .iso.org/iso-8601-date-and-timeformat.html.
Глава б
■
292
какой ключ или протокол используется? Как пользователи получат доступ
к этому ключу?
♦ Порядок:
getUserByids возвращает список пользователей; каков порядок в этом
списке? Упорядочен ли он в алфавитном порядке по электронной почте,
UUID
или в порядке, указанном в пакетном запросе? По возрастанию или по убыва
нию?
♦ Целевые показатели уровня обслуживания (Service Level Objectives, SLO) 16 :
требуют ли потребители выполнения определенных целевых показателей уровня
обслуживания или имеют иные нефункциональные ожидания, такие как произ
водительность, например:
Как быстро должно быть восстановлено обслуживание? В течение
•
1О- 100 мс
или даже быстрее?
Каковы последствия простоя? Какие показатели безотказной работы нужны
•
вашим потребителям? Можете ли вы себе это позволить?
♦ Исключения и ошибки: какие ошибки может возвращать сервис? Как пользо
ватели обнаруживают их?
Идемпотентность: можем ли мы безопасно вызывать эти методы снова и снова?
♦
♦ Доступность: предоставляет ли сервис доступ к своим операциям с помощью
REST?
С помощью
SOAP?
С помощью
gRPC
и протокольных буферов? Или ка
ким-то другим способом?
Чтобы решить некоторые из этих проблем, часто приходится прибегать к зависимо
стям. Для упрощения метода шифрования можно использовать внутреннюю биб
Joda-Time. Таким обра
лиотеку шифрования или указать формат даты, используя
зом, мы могли бы лучше выполнить работу по разъяснению требований контракта.
Но тогда мы нарушим правило отсутствия зависимостей и объединим наш сервис
Joda-Time или
с
внутренней общей библиотекой. Не стоит!
У нас есть лучшие варианты, такие как тестирование и документация. Можно про
сто написать
Javadoc,
пояснив некоторые аспекты поведения (листинг
6. 7),
а также
добавить надлежащее тестирование контракта и обеспечить согласованность его
поведения.
Листиjf!f~t,J,~мение JavadoC,i!J'~~~Tb контракт бо~.~~~~м
1. iшport java.util.List;
2. iшport java.util.UUID;
3.
4. /**
5. * Спецификация контракта: <br/>
6.
7.
*
<Ь>Порядок</Ь>
*
<Ь>Формат даты</Ь>: гггг-мм-дц
Не гарантируется.
<br/>
<br/>
Service Leve\ Objectives определяют цели для юпочевых показателей обслуживания:
bttps://en.wikipedia.org/wiki/Service-level_objective.
16
Принципы надлежащего предоставления сервисов
8.
9.
*
<Ь>Шифрование</Ь>
Запмфрованный текст
*
<Ь>Опмбки </Ь>
Если ни один пользователь не найден, возвраIЩJется
■
293
<br/>
пустой пользователь
<br/>
10. * <Ь> Идемпотентность </Ь>: Все операции <br/>
11. *
12. */
13. puЫic interface ProfileContract {
14.
User getUserByid(UUID id);
15.
List<User> getUserByids(List<UUID> ids);
16.
Тестирование контракта необходимо для постоянного соблюдения его условий и
обеспечения прозрачности в случае нарушений со стороны инженеров. Тестирова
ние контракта будет подробно рассмотрено в следующей главе
7
«Надлежащее
тестирование сервисов».
Многие инженеры утверждают, что документация,
Javadoc
и комментарии устаре
ют. Требовать от команд документировать очевидные вещи, такие как методы по
лучения/установки,
-
пустая трата времени. Она будет устаревать, поскольку
у них нет мотивации ее обновлять. Наши неочевидные опасения вряд ли будут ме
няться каждый день. Не забывайте, что технический долг в масштабе компании не
всегда фиксирован в одном измерении. Код может стать устаревшим и бесполез
ным, связанным с другими фрагментами кода, но фактически ненужным и неис
пользуемым.
Обработка ошибок в контрактах
Обработка ошибок является важнейшим элементом вашего контракта. Листинги
и
6.2,
6.1
по сути, охватывают только «безопасный путь». В них нет описания того,
какие ошибки возвращаются или какая полезная информация может быть передана.
Каждый язык и протокол
API
имеют свои собственные соглашения и способы ре
шения этой проблемы. Вот некоторые распространенные методы.
♦
Возвращать значение
null.
Можно просто возвращать значения null, но это
очень плохая идея. Трудно понять, что означают значения
null в каждом контек
сте: ошибку, отсутствие данных или частичный сбой. Лучше избегать такого ва
рианта.
♦
Воспроизвести ошибку на вызывающем
драйвера сервиса
можно
сопоставить
устройстве.
исключения
При
сервиса
использовании
непосредственно
с вызывающим устройством, затем транслировать их через протокол клиенту,
чтобы они отображались в его коде во время выполнения. Это не всегда осуще
ствимо
или
возможно
на каждом
языке
программирования,
а также
является
источником связности. Если вы делаете это неправильно и предоставляете ис
ключения из реализации, вы связываете клиентов непосредственно с вашим сер
висным КОДОМ.
♦
Использовать сетевой протокол. Используйте неявные концепции в
протоколе; например, ваш запрос
REST GET
может вернуть значение
API или
404, если
294
■
Глава 6
передан неверный идентификатор, который обычно понимается как «не най
ден».
♦
Возвращать пустой объект. Просто возвращайте пустой объект; в случае наше
го
ProfileContact
мы можем просто вернуть успешный результат, но пустой
JSОN-объект. Это может означать, что объект не был найден.
♦
Возвращать пользовательский объект
екты
error
error.
Мы можем явно определить объ
в нашем контракте и, в зависимости от протокола, связать его с воз
можными возвращаемыми состояниями нашего контракта. Например,
Boot ·может
сопоставлять исключения с пользовательскими ответами
Spring
REST/JSON,
где вы можете добавлять информативные детали к вызывающему объекту.
В зависимости от языка и протокола можно использовать устоявшиеся стандарты.
Трудно дать универсальные рекомендации, поскольку не все языки одинаково
обрабатывают ошибки
не у всех есть исключения!
-
и в конечном итоге вы
-
ограничены протоколом обмена данными. Но не стоит пренебрегать явным опреде
лением этих неблагоприятных результатов пути, их документированием и тестиро
ванием в рамках любого тестирования контракта.
Доступность сервиса
Доступность
-
Мы
использовать
можем
это способ предоставления нашего контракта внешним абонентам.
HTTP/REST, gRPC
API
или
сетевой
протокол,
и буферы протоколов, или даже
сов. Воздействие, как правило, стабильно
слишком часто переходя с
REST
на
gRPC,
-
такой
SOAP
как
JSON
через
для устаревших серви
команды не нарушают контракты,
но незначительные изменения в поведе
нии могут полностью сломить потребителей. Если ваши пользователи ожидают по
лучить определенную полезную нагрузку, когда вы возвращаете НТТР-код
500,
это
должно постоянно поддерживаться и рассматриваться как возможный источник
изменений, нарушающих целостность. Раскрытие информации также может подра
зумевать определенное поведение. В протоколе НТТР есть методы с неявными
ожиданиями, такие как
GET,
которые не должны изменять данные и являются
идемпотентными. Также существуют хорошо зарекомендовавшие себя протоколы
с кодами ошибок, такими как
404.
Учитывая доступность, у нас есть несколько различных вариантов. Например, мы
могли бы добавить аннотации
REST
к нашему проекту контракта или даже отдель
ный проект по контракту данных и контракту RESТ. Мы могли бы написать общий
уровень, который обрабатывает код доступа к сервису. Это позволит нам отправить
драйвер сервиса, полностью абстрагируя метод доступа. А потребители смогут
просто сохранить контракт с методами и данными, предоставляемыми драйверами,
с косвенной связью с транспортным протоколом. Подобные опасения могут пока
заться излишними. Если сервису продаж необходимо вызвать сервис профилей, то
это всегда будет делаться с помощью одного и того же механизма связи. Если это
JSON
через
HTTP/REST,
это всегда будет так. Однако при анализе более широкого
спектра потребителей мы должны учитывать:
Принципы надлежащего предоставления сервисов
♦
Другие
внутренние
сервисы,
возможно,
написанные
■
295
на разных языках или
имеющие совершенно разные варианты использования, например пакетные или
ориентированные на клиента.
♦
Пользователей или потребителей, работающих с интерфейсными приложения
ми: веб-сайтами, мобильными приложениями, голосовыми интерфейсами, чат
ботами.
♦
Конвейеры обработки больших данных или данные для модели машинного обучения.
Один сетевой механизм может не подходить для всех, и иногда требуется поддерж
ка нескольких способов предоставления доступа к вашему сервису. Это особенно
актуально для зрелых сервисов, где всегда есть место рефакторингу и улучшениям.
Возможно, у вас есть некоторые старые SОАР-сервисы, созданные из-за каких-то
устаревших решений или сторонних внешних интеграций с очень специфическими
потребностями. И технологии меняются. Допустим, большинство ваших сервисов
могут быть представлены в формате
JSON
через
HTTP/REST,
но если вы запускае
те новый сервис сегодня, то, возможно, захотите использовать
gRPC/Protobuf.
По
всем этим причинам вашим сервисам может потребоваться более одного открытого
сетевого протокола (рис.
6.18).
:
:
Внешний API
Потребитель
...... i · .... ·
Контракт
Реализация
сервиса продаж
RESTl}SON
gRPC/PB
1
Доступ
Контракт
Реализация
сервиса
профилей
Рис.
С помощью рис.
тракт
SOA -
6.18
6.18.
Разъединение доступа по форме контракта
и этого начального раздела мы хотим донести до вас, что кон
это не только простой Jаvа-объект или спецификация
OpenAPI.
Это
данные, операции, объекты ввода, объекты вывода и набор неочевидных ожиданий
в отношении поведения. Доступность
-
это то, что мы добавляем к сетевому взаи
модействию и более широким задачам. Как видно, один и тот же контракт и сервис
используются двумя разными потребителями: один потребитель является внутрен
ним, а другой потребитель является сервисом, использующим
REST/JSON.
Второй
потребитель является внешним и имеет другие ожидания в отношении производи
тельности.
296
■
На рис.
Глава 6
6.18
показан один и тот же сервис профилей, один и тот же контракт, но
с разными настройками. В нашем сервисе существует множество различных спосо
бов обработки нескольких настроек, в том числе:
♦ Уровень косвенности. У нас есть стандартный внутренний уровень, обеспечи
вающий доступ к информации,
-
возможно, на основе конфигураций или анно
таций.
♦
АРI-шлюз. Простое использование решения АРI-шлюза, такого как А WS
Gateway,
API
позволяет переводить сервисы на различные протоколы.
♦
Облегченный
ESB. Мы могли бы
ServiceMix или Mule ESB от SalesForce.
♦
Apache Camel. Мы могли бы
ние, такое как Apache Camel.
использовать
ESB,
такой
как
Apache
использовать облегченное интеграционное реше
♦ Бессерверное решение. Мы могли бы использовать А WS
Lambda для
преобра
зования форматов/протоколов.
♦ Драйверы. У нас могло бы быть два драйвера, один с
♦
REST,
а другой с
gRPC.
Сервисы. Мы могли бы создать еще один сервис, который бьт бы обёрткой,
и перевести его с
REST
на
gRPC,
оставив сервису профилей только одну форму
доступа.
В поисках компромисса предлагаем рассмотреть следующие параметры: слож
ность, дополнительные накладные расходы, простота миграции, стоимость и гиб
кость. Нет правильного или неправильного
-
просто то, что имеет больше или
меньше смысла для вашего сценария и компании.
Что нужно запомнить
Поздравляем вас с завершением главы
кую
6!
Надеемся, что теперь вы понимаете, ка
важную роль должны играть сервисы в современных архитектурах,
помогая
устранять неполадки.
♦
Сервис-ориентированная архитектура
(SOA) ставит сервисы
в центр разработки.
♦ К распространенным типам сервисов относятся бизнес-сервисы, базовые серви
сы, сервисы-обёртки и платформенные сервисы.
♦ Создавайте сервисы, когда вам нужно совместно использовать бизнес-логику,
сохранять бизнес-данные или иметь высокую скорость изменений, которые
лучше всего инкапсулировать.
♦
Избегайте создавать сервисы и отдавайте предпочтение другим решениям, когда
сервис может повлиять на производительность, неоправданно увеличить слож
ность или повлиять на уровень надежности.
♦
SOA -
это настоящий инструмент бизнес-инноваций, обеспечивающий такие
ключевые преимущества, как:
•
сокращение сроков вывода на рынок;
•
снижение затрат и упрощение обслуживания;
Принципы надлежащего предоставления сервисов
♦
•
расширяемость и адаптивность;
•
независимость.
■
297
Общие сервисы позволяют использовать функциональность в разных контекстах
и в разных подразделениях вашего бизнеса. Вы можете использовать сущест
вующий код вместо того, чтобы начинать с нуля.
♦
Надлежащие сервисы позволяют абстрагироваться от всего, что связано с их
реализацией.
♦
Независимость позволяет сервисным командам работать быстро и масштабиро
ваться. Для этого вам нужно пойти на компромисс в отношении централизован
ного управления.
♦
Сложно найти баланс между централизованным управлением и независимостью.
Жестко регламентируйте такие элементы, как контракты, сопоставление бизнес
областей и стеки развертывания и наблюдаемости, но позвольте командам само
стоятельно определять детали реализации и выбирать технологии.
♦
Передовые концепции
SOA,
которые следует учитывать, включают высокую
степень абстракции, разделение задач, интероперабельность, слабую связь, до
кументацию по контрактам на
API,
а также динамический реестр и обнаружение
сервисов.
♦
Предпочтение отдается вначале заключению контракта, а не реализации.
♦ Код контракта ⇒ метаданные, или метаданные ⇒ код контракта
-
это вопрос
стиля и предпочтений.
♦
Существующие решения иногда требуют, чтобы вы сначала приступили к их
реализации. Ключевым фактором является количество ваших потребителей. На
личие нового пользовательского интерфейса (ноль пользователей) позволяет
вначале создать контракт.
♦
OpenAPI -
отличный стандарт, он широко используется, и его следует рассмат
ривать при принятии решений.
♦ При использовании
с библиотеками
OpenAPI убедитесь, что вы
OpenAPI, Spring Doc и Spring-*.
♦ Обратная совместимость
♦
-
не связываете свой контракт
это суперспособность.
Изменения, не нарушающие целостность, означают, что вы не нарушаете поль
зовательский код и, следовательно, пользователи могут игнорировать эти изме
нения.
♦
Изменения, нарушающие целостность, означают, что вы нарушаете пользова
тельский код и пользователи должны иметь с этим дело.
♦
Примеры изменений, нарушающих целостность:
•
переименование/удаление существующей операции;
•
переименование/удаление существующего параметра;
298
♦
♦
♦
■
Глава б
•
переименование/удаление существующего поля в результирующем объекте;
•
удаление метода/формата, т. е.
REST/JSON.
Примеры изменений, не нарушающих целостность:
•
добавление новой операции;
•
добавление необязательного поля в возвращаемый объект;
•
добавление необязательных параметров со значением по умолчанию;
•
добавление нового метода/формата, например
gRPC/PB.
Стратегии для устранения изменений, нарушающих целостность:
•
пусть это сломается и не масштабируется;
•
версионирование
API:
□
доменное имя;
□
URL-aдpec;
□
пакет/объект;
□
метаданные, т. е. НТТР-заголовок о косвенной обратной совместимости.
Если вы применяете управление версиями
API,
то вам необходимо поддержи
вать несколько версий контрактов. И здесь имеются свои недостатки:
•
Сколько версий будут поддерживаться? Это связано с затратами.
•
Как избежать дублирования кода? Рассмотрите возможность преобразования
кода и использования одной реализации вместо нескольких кодовых баз.
♦ Изоляция является наиболее важным вкладом в архитектуру SОА/микросер
висов.
♦ Изоляция должна применяться в трех ключевых областях:
•
хранилища данных;
•
библиотеки;
•
публичные контракты.
♦ Принципы должны быть частью вашей инженерной культуры, а не процесса.
♦ Изоляция базы данных является ключом к качественным сервисам.
♦ Сервисы взаимодействуют друг с другом, они не имеют доступа к другой базе
данных, кроме своей собственной.
♦ Сервис может поддерживать многоязычие и использовать специально созданные
базы данных.
♦ Кластеры баз данных не должны совместно использоваться различными серви
сами, за исключением потенциально непроизводственных.
♦ Избегайте создания внутренних общих библиотек только для повторного ис
пользования кода.
Принципы надлежащего предоставления сервисов
♦
■
299
Избегайте создания внутренних общих библиотек без веских причин:
•
повторное использование, чтобы избежать ввода текста, или поверхностное
повторное использование;
•
случайное повторное использование; инженеры предполагают, что какая-то
команда может использовать этот код повторно;
♦
•
выбор по собственному усмотрению;
•
ненужные абстракции.
Сосредоточьтесь на возможных причинах создания внутренних общих библио
тек:
•
сложная, рискованная и запутанная проблема, например шифрование;
•
создание
сервиса
замедляет
производительность
и
является
неправильным
решением, например перемещение файлов на SЗ.
♦
При создании основных внутренних общих библиотек убедитесь, что они явля
ются экономичными:
•
действительно необходимы и повышают ценность;
•
имеют мало зависимостей или не имеют их вовсе;
•
зависимости также должны быть тщательно подобраны и необходимы;
•
внутренняя общая библиотека -
•
повторное использование кода не должно быть основной причиной создания
это не сервис; придется идти на компромиссы;
внутренней общей библиотеки;
•
следует избегать произвольного выбора и больших фреймворков.
♦ У внутренних общих библиотек могут быть технические проблемы.
♦ Вкусы приводят к разного рода проблемам и противоречат шаблонам.
♦
Только наводите мосты, а не добавляйте вкусы, для этого:
•
добавьте тесты, чтобы обнаружить все публичные контракты;
•
проведите инвентаризацию потребителей и разберитесь в их вариантах ис
пользования;
•
проведите рефакторинг всего пользовательского кода и удалите ненужный
код/вкусы.
♦ Не используйте библиотеки и не пытайтесь повторно использовать код в пуб
личных контрактах.
♦
Надлежащие контракты должны быть чистыми, простыми, лаконичными, эко
номичными и не содержать двоичной связи.
♦ Чтобы изолировать публичные контракты, не имейте внутренних или внешних
зависимостей и используйте только локальные объекты, определенные в самом
проекте контракта.
300
■
Глава 6
♦ Проведите анализ проекта, чтобы убедиться в целостности, согласованности и
правильности ваших контрактов.
♦ Возможно автоматизировать обнаружение зависимостей в публичных контрак
тах с помощью
maven:
maven-dependency-plugin
или некоторых простых
greps
на
pom.xml.
♦
♦
Неочевидные соображения в контрактах включают:
•
форматы дат;
•
строки;
•
шифрование;
•
упорядочение;
•
целевые показатели уровня обслуживания
•
исключения и ошибки;
•
идемпотентность;
•
доступность.
Тестирование и документирование
-
(SLO);
эффективные способы сообщить о неоче
видных соображениях; никогда не создавайте зависимости для решения этих
проблем.
♦
Обрабатывайте ошибки в контрактах явно, поскольку они являются частью ва
шего публичного контракта.
♦
•
Избегайте возврата null.
•
Повторите ошибку в вызывающем устройстве.
•
Используйте сетевой протокол.
•
Возвращайте пустой объект.
•
Возвращайте пользовательский объект с ошибкой.
Доступность
это то, как сервисы предоставляют контракты внешним абонен
-
там, используя такие протоколы, как
JSON
через
REST/HTTP, gRPC/protobuf
или SOAP/XМL.
♦
Иногда бывает необходимо предоставить несколько вариантов доступа к одному
и тому же контракту. Вы можете сделать это напрямую или косвенно, используя
пользовательские
Apache Camel,
уровни
косвенной
связи,
АРI-шлюзы,
облегченный
ESB,
бессерверные решения, драйверы пользовательских сервисов или
отдельные сервисы делегирования.
ГЛАВА
7
Надлежащее тестирование
сервисов
Тестирование показывает наличие, а не отсуrствие ошибок.
Эдсгер Дейкстра
Современные программные решения требуют современных методов тестирования.
Тестирование играет важнейшую роль в создании эффективной архитектуры про
граммного обеспечения, независимо от стиля. Хорошее программное обеспечение
легко тестируется. Последнее, что вам захочется создать, выходя из своего моноли
та,
-
это нечто такое, что будет работать так же медленно из-за того, что вы не
включили в свои проекты разнообразные стратегии тестирования.
Тестирование помогает обрести уверенность при внесении изменений, что позволя
ет работать быстрее и стабильнее. Если вы считаете, что можете добиться такой
уверенности,
используя
только
комплексное
или
интеграционное
тестирование,
пересмотрите свою позицию. Мы научим вас передовым методам, таким как хаоти
ческое тестирование и тестирование в производственных условиях. Эги техники
помогут вам найти баланс между скоростью, безопасностью и затратами.
Эффективное тестирование
-
одна из самых сложных задач, поскольку организа
ции верят в мифы и при оценке качества ориентируются на неправильные цели и
ключевые результаты (Objectives and Кеу Results, ОКR). После прочтения текущей
главы вы будете готовы к решению всех задач, связанных с новой архитектурой
программного обеспечения.
Структура главы
В этой главе мы рассмотрим следующие темы:
♦
♦
Зачем нужно тестирование?
•
Корректность.
•
Влияние изменений.
•
Готовность к эксплуатации.
Особенности тестов программного обеспечения.
•
Типы тестов.
302
♦
■
♦
7
Признаки плохих тестов.
•
Непоследовательная частота отказов.
•
Хрупкость при рефакторинrе.
•
Зависимость от данных.
0
♦
Глава
Неэффективные циклы тестирования.
•
Постоянная настройка тестов.
•
Независимость тестов.
Характеристики хороших тестов.
•
Постоянная вероятность успеха.
•
Устойчивость к рефакторинrу.
•
Изоляция зависимости от данных.
0
Прямые входные данные.
0
Внутренние состояния.
•
Быстрые циклы обратной связи.
•
Самостоятельные тесты.
•
Автономные тесты.
Манифест тестирования.
•
Тестирование на всем протяжении важнее, чем в конце.
•
Предотвращение ошибок важнее, чем их поиск.
•
Понимание при тестировании важнее, чем проверка функциональности.
•
Создание наилучшей системы важнее, чем ее разрушение.
•
Ответственность команды за качество важнее, чем ответственность тести
ровщика.
♦
Разнообразие тестирования.
•
Почему тестирование важно для архитектуры программного обеспечения.
•
Лучшие практики тестирования сервисов.
•
Практическое стресс-тестирование.
0
Gatling для тестирования
производительности.
•
Пирамида тестирования.
•
Стратегии для тестирования на продуктиве.
0
Пограничный маршрутизатор.
0
Пользователи бета-версии.
0
Аудит в реальном времени
0
Воспроизведение трафика.
/ сравнение
и сброс результатов.
Надлежащее тестирование сервисов
303
Хаотическое тестирование.
•
0
«Обезьянья армия»
0
Toxiproxy.
0
Матрицы отказоустойчивости.
Внутреннее состояние
•
♦
■
Netflix.
-
продвинутое глубокое погружение.
0
Генерация синтетических данных.
0
Тестирование интерфейсов.
0
Настройка тестовых данных.
0
Макетирование интерфейсов.
Что нужно запомнить
Зачем нужно тестирование?
В этот самый момент вы, возможно, задаетесь вопросом: почему в книге по архи
тектуре программного обеспечения рассказывается о тестировании? Тестирова
ние
-
критически необходимо для правильно спроектированных решений. Прежде
чем мы рассмотрим архитектуру, давайте начнем с основ разработки программного
обеспечения.
При разработке программного обеспечения мы вносим изменения, добавляем или
удаляем код, мы рискуем. Мы всегда можем что-то изменить и оказать влияние на
наших конечных пользователей или даже на другие команды и инженеров, разра
ботчиков программного обеспечения, внедряя изменения, нарушающие целост
ность. Тестирование должно дать ответы на основные вопросы (рис.
7.1 ):
♦
Корректность. Как мне доказать, что решение работает?
♦
Влияние изменений. Не нарушило ли что-то наше изменение? Есть ли какое
либо влияние на другие команды?
Тестирование
Р е шение
г-----------
___________ .,11
1 Корректность:
1Это работает?
1Классический монолит 1
1Модульный монолит
1Сервисы SOA
1Микросервисы
1
...
"111
------------
1
1 Влияние изменений :
1
1 Мы что-то сломали?
L-----------1
------------------~
1 Готовность к эксплуатации :
1
1 Есть ли у нас уверенность в том , что мы сможем запустить 1
1это в промышленную эксплуатацию? ______ 1
1
1
Рис.
7.1.
Почему тестирование имеет значение
304
♦
■
Глава
7
Готовность к эксплуатации. Есть ли у нас уверенность в том, что решение
будет запущено в промышленную эксплуатацию? Безопасно ли это? Изучили ли
мы основы? Как мы к этому относимся?
Корректность
Основной вопрос: независимо от имеющейся у вас архитектуры решения, будь то
классический монолит, модульный монолит,
такой как распределенный монолит
-
SOA,
микросервисы или антипаттерн,
когда инженер вносит изменения, как он
узнает, что все сделано правильно? Когда можно объявить код завершенным?
Когда вы выполнили свои критерии приемлемости? Когда вы достигаете того, что
ваша команда определяет как «готово»
(definition of done, DOD)? Когда вы удовле
творяете всем правилам очереди тестирования Kanbani Независимо от архитекту
ры программного обеспечения, независимо от того, работает ли ваша команда
с использованием гибких методов
(Kanban,
ХР,
Scrum
и т. д.), вам необходимо от
ветить на фундаментальный вопрос: откуда вы знаете, что ваше программное обес
печение выполняет то, для чего оно предназначено?
Тестирование
-
отличный способ ответить на этот вопрос.
Влияние изменений
Даже если решение правильное, вам все равно нужна уверенность в том, что ваши
изменения будут работать и не приведут к каким-либо нежелательным побочным
эффектам, таким как нарушение работы других функций, которые ранее работали
(регрессионное тестирование), или нарушение вышестоящих/нижестоящих зависи
мостей (контрактное тестирование).
Готовность к эксплуатации
Уверены ли вы в том, что ваши изменения будут внедрены в рабочую среду? Вери
те ли вы в то, что решение будет работать как с предыдущим кодом, так и с вашими
новыми изменениями? Как вы достигаете такой уверенности? Тестирование
важный способ получения ответа на поставленный вопрос. Попытка получить точ
ный ответ на него с помощью тестирования, доказывающего нулевой риск до за
пуска в промышленную эксплуатацию, может оказаться дорогостоящей перспекти
вой. Продвинутые концепции, такие как производственный аудит, наблюдаемость,
откаты, канареечное тестирование 2 и другие методы выпуска/DеvОрs, могут стать
лучшим способом сбалансировать риски и усилия. Однако главное внимание сле
дует уделять тестированию.
1
Хорошая статья о политике очереди Kanban:
https://sbucblsingla.Ыogspot.com/2016/09/explicit-kanbanpolicies-make-life.html.
2
Канареечное тестирование - это способ проверки новых версий программного обеспечения при реальном
использовании. Вместо того чтобы выпускать версию сразу д;1я всех пользователей, её сначала запускают
д;1Я небольшого числа людей, которые проверяют работу ИТ-продукта.
-
Пер.
Надлежащее тестирование сервисов
■
305
Особенности тестов
программного обеспечения
По сути, у вас должны быть хорошие тесты. Даже если вы придерживаетесь пра
вильных стратегий тестирования и достигаете идеального баланса в тестовой пира
миде, это не даст результата, если у вас плохие тесты. То же самое и с архитекту
рой программного обеспечения: идеальное соблюдение
SOA
не поможет вашей
организации, если весь код написан некачественно.
Наша главная задача
-
научить вас отличать хорошие тесты от плохих. Для каж
дого написанного вами теста важно уметь определить, расширяет ли этот тест ваше
понимание корректности, результативности и готовности кода к эксплуатации. Все
тесты должны давать вам четкий сигнал для оценки и принятия решения о том, что
следует предпринять. Хорошие тесты облегчают такое суждение, а плохие страда
ют от подводных камней, антипаттернов, ненужных затрат и технического долга
точно так же, как и любой фрагмент кода. Неудачные тесты усложняют работу ин
женеров-программистов и вашей организации, занимающейся тестированием, за
трудняя принятие решений, отладку, создавая значительный риск и в конечном
счете приводя к страху перемен.
Давайте поможем вам избежать всего этого!
Типы тестов
Полный спектр вопросов эффективного тестирования программного обеспечения
выходит за рамки данной rлавы3 . Мы будем много говорить о роли, которую раз
личные виды тестов могут играть в ваших стратегиях тестирования, поэтому давай
те
определим
некоторые
из
распространенных
типов
тестов,
которые
опишем
далее.
♦
Модульные тесты. Модульные тесты
(Unit tests)
оценивают минимально воз
можную часть кода, такую как методы, функции и классы отдельного про
граммного компонента.
♦
Интеграционные тесты. Охватывая несколько компонентов, интеграционные
тесты
(lntegration tests) оценивают,
как конкретные компоненты работают вместе
в более широкой программной системе.
♦
Сквозные тесты
(End to End,
Е2Е). Демонстрируют полную функциональность
приложения, как правило, в полностью развернутой среде. В тестах Е2Е исполь
зуются несколько компонентов, данные и весь стек приложений для оценки кон
кретных пользовательских потоков.
3
В качестве отличных книг для начинающих, охватывающих различные аспекты тестирования программно
го обеспечения, мы рекомендуем «Гибкое тестирование: практическое руководство для тестировщиков и
гибких команд» Лизы Криспин, «Шаблоны тестирования
xUnit:
рефакторинr тестового кода» Джерарда
Месароса, «Принципы, практики и шаблоны модульного тестирования» Владимира Хорикова и «Экстре
мальное программирование: разработка через тестирование» Кента Бека.
306
■
Глава
7
♦ Исследовательские тесты. Тестирование в произвольной форме для выявления
скрытых требований и неожиданного поведения программной системы, часто
выполняемое человеком. Некоторые исследовательские тесты
(Exploratory tests)
могут быть автоматизированы, например, с помощью фаззинr-тестирования, при
котором программная система получает случайные возможные входные данные
для обнаружения сбоев.
♦
Тесты контрактов. Проверяют, поддерживается ли
API,
предоставляемый для
компонента или сервиса, между выпусками. Ключевая часть оценки того, под
держивается ли обратная совместимость между определенными изменениями
или после сложного рефакторинга, тесты контрактов
(Contract tests)
также могут
служить формой документации.
♦
Функциональные и приемочные тесты. Тесты, которые оценивают, работает
ли новая функциональность приложения так, как задумано бизнесом. Приемоч
ные тесты
(acceptance test)
являются более формальным этапом при завершении
работы и иногда также оценивают нефункциональные атрибуты теста.
♦ Юзабилити-тесты (UsaЬility
Способ убедиться, прежде чем приступать
tests).
к разработке, что клиенты понимают и знают, как пользоваться UХ-интер
фейсом, на примере готовой системы или, что еще лучше, на примере функцио
нального прототипа.
♦ Дымовые тесты (Smoke tests)4 . Быстрые тесты, которые доказывают, что ос
новные функциональные возможности системы работают. Обычно это делается
в рамках производственного развертывания.
♦
Стресс-тесты
(Stress tests), тесты производительности (performance tests) или
(load tests). Если функциональность работает, отправляйте
нагрузочные тесты
запросы, чтобы оценить, работает ли система под нагрузкой, и прямо или кос
венно измерить общую производительность системы. Существуют такие подти
пы, как стресс-тесты, которые выявляют критическую точку в конкретной раз
вернутой конфигурации программной системы.
♦
Хаотические тесты
(chaos tests).
случайные или целенаправленные
Вызывают сбои в программной системе
-
и измеряют их влияние на способность
системы продолжать работать в корректном или ухудшенном состоянии.
♦ Регрессионные тесты
(Regression tests).
Общий термин для обозначения любого
теста, который фокусируется на выяснении вопроса, продолжает ли работать
ранее существовавшее поведение программной системы. Не должно быть спе
циальных регрессионных тестов; большинство типов тестов в этом списке вы
полняются для проверки, всё ли еще работает, по сути, для поиска регрессий.
Приведенный список тестов не является исчерпывающим и не предназначен для
подробного описания каждого типа. Некоторые из вас могут не заметить деталей
4
Smoke test (дымовое тестирование) -
это минимальный набор тестов, прохождение которых показывает,
что продукт готов к дальнейшему тестированию. Цель дымового тестирования
-
убедиться, что наиболее
важные функции приложения работают правильно. Оно обычно выполняется в начале цикла разработки.
Пер.
-
Надлежащее тестирование сервисов
■
307
или захотеть обозначить более четкие границы между конкретными подтипами
тестов. Если оставить в стороне эти споры, нашего списка будет достаточно, чтобы
проиллюстрировать основные моменты обсуждения.
Признаки плохих тестов
Плохие тесты имеют следующие особенности (рис.
♦
7.2):
Непоследовательная частота отказов. Ошибки легко обнаружить, устранить и
исправить. Но если вы иногда терпите неудачу, а иногда проходите ее успешно,
то это совсем другая история, которая приводит к дальнейшим плохим результа
там.
♦
Хрупкость при рефакторинге. Любой рефакторинг кода каждый раз приводит
к нарушению большого количества ваших тестов .
♦
Зависимость от данных. Если данные в вашей среде не совсем идеальны, тесты
немедленно нарушаются. И любой человек может и будет вносить изменения
в эти данные.
♦
Неэффективные
Ваши
тестирования.
циклы
и
инженеры
тестировщики
слишком долго ждут тестовых запусков, необходимых для проверки работоспо
собности кода.
♦
Постоянная настройка тестов. Для успешного выполнения ваших тестов тре
буется постоянная работа с ними, их настройка и корректировка.
♦
Помехи при тестировании. Ваши тесты не могут выполняться независимо друг
от друга или вашей среды тестирования.
Давайте разберемся с каждым из этих признаков/антипаттернов более подробно.
Признаки плохих тестов
г------------,
1 Непоспедовательная
1
1
1 ---------1 Неэффективные циклы
1
частота отказов
,------------•
1 Хрупкость при рефакторинге
тестирования
____ _
-----------,
1 Постоянная настройка
1 тестов
1
1
1
'------------~
1-----------
1
1 Зависимость от данных
1
1_ - - - - - - - - - - - - - - - - -
L---------
Рис.
---------,
1
Помехи
1
, при тестировании
7.2.
1
1
Как выглядят неудачные тесты
Непоследовательная частота отказов
На самом деле нет ничего плохого в том, что тесты терпят неудачу. В разработке,
основанной на тестировании
(Test Driven Development, TDD),
вы пишете тесты на
308
■
Глава
7
провал! И неудачный тест может дать вам уверенность в том, что изменение кода
работает. Конечно, тесты просто нужно исправить.
Проблема возникает, когда в тестировании происходят непоследовательные сбои.
Тесты, которые должны бьши пройти успешно, при каждом четвертом запуске
вдруг дают сбой. Вернемся к метафоре сигнала
вашей
команде?
Непоследовательный
тест.
какой сигнал посылает ошибку
-
В
конце
концов,
тест
начинают
игнорировать: «Этот тест работает неправильно». В крайних случаях весь набор
тестов ведет себя подобным образом, и инженеры полностью перестают обращать
внимание на ваши тесты.
Огсутствие доверия к вашему набору тестов приводит к множеству негативных по
бочных эффектов в команде.
♦ Множество ручных тестов. Если вашим автоматизированным тестам нельзя
доверять, вы возвращаетесь к ручным тестам. Для ручного тестирования требу
ются люди, которые стоят дорого и не поддаются масштабированию. Люди
несовершенны и допускают ошибки, например, не могут протестировать ваш
сервис профилей для нового типа пользователей.
♦
Медленная и дорогостоящая обратная связь. Когда наборы тестов терпят не
удачу и вы можете доверять только ручным тестам, ошибки обнаруживаются
только на поздних стадиях проектирования или даже в процессе промышленной
эксплуатации. Чем раньше вы обнаружите ошибки, тем дешевле их можно будет
исправить, в идеале на локальном компьютере инженера. Ошибки на продуктиве
обходятся дороже, чем ошибки в среде разработки.
♦ Боязнь выпуска изменений. Команды, которые боятся выпуска изменений,
демонстрируют дисфункциональное поведение, например дают очень длинные
оценки (спринты для простых изменений!) и создают искусственные промежут
ки времени для выпуска (раз в шесть недель/квартал). Огсутствие достаточного
количества исправных поставок значительно сокращает сроки разработки реше
ний для бизнеса.
Хрупкость при рефакторинге
Инженеры постоянно меняют код в соответствии с потребностями бизнеса или для
какой-либо технической миграции. Если каждое изменение кода приводит к сбоям
в тестах, значит, ваши тесты являются хрупкими, что нарушает требования к отка
зоустойчивости. Исправление множества тестов при каждом изменении кода явля
ется дорогостоящим и расточительным процессом. Часто проблема возникает из-за
ненужной связи тестов с деталями внутренней реализации. В сообществе ведутся
споры о том, стоит ли тестировать частные методы 5 . Следует тестировать общедос
тупные методы, позволяя инженерам свободно изменять код до тех пор, пока они
5
Для получения подробного обзора обеих сторон дискуссии о том, следует ли тестировать частные методы,
StackOverflow:
смотрите этот замечательный пост в
https://stackoverflow.com/questions/105007/should-i-test-pгivate-methods-oг-onlypublic-ones.
Надлежащее тестирование сервисов
■
309
не нарушают его целостность. Самое главное, если вам нужно протестировать за
крытые методы, это, скорее всего, означает, что дизайн вашего программного обес
печения
нуждается
в
улучшении; т. е. у вас есть
методы,
которые
не
принимают
параметров и возвращают значение voict. Просмотрите свой дизайн, прежде чем пи
сать дополнительные тесты.
Зависимость от данных
Для тестирования нужны входные данные. Для некоторых форм тестирования так
же требуется, чтобы сервисы находились в определенном состоянии и в конечном
итоге были представлены в виде данных. Возвращаясь к сервису профилей компа
нии АСМЕ
Widget,
предположим, вы пишете тест, который оценивает, правильно
ли функция извлекает электронное письмо из базы данных. Чтобы найти нужную
запись для ваших тестов, вы запросили базу данных и использовали идентифика
тор:
23475.
Вы отправили этот тест, и он сработал, но другие инженеры удалили
этот идентификатор в своем тесте, чтобы использовать свой сценарий. Теперь у вас
есть тесты, которые не соответствуют друтим тестам. Все это произошло из-за того,
что ваши тестовые зависимости от данных не были изолированы. Тесты были свя
заны друг с другом с помощью данных.
Неэффективные циклы тестирования
Скорость тестирования всегда относительна. Однако, когда мы проводим тесты на
нашем локальном компьютере, мы ожидаем получить быструю обратную связь
-
от нескольких секунд до нескольких минут. При выполнении тестов на выделенных
серверах с превосходным оборудованием вы можете позволить себе трудоемкую
работу, а тесты займут от нескольких минут до нескольких часов. Различные фор
мы тестирования предполагают разную скорость выполнения.
Ручное тестирование
(Manual testing) -
одно из самых дорогостоящих, поскольку
требует привлечения людей. По мере добавления новых тестов вам требуется либо
больше времени на тестирование, либо больше персонала. Ваши временнь1е рамки
варьируются от часов до дней и недель, а количество сотрудников
-
от одного до
«запредельного». В некоторых проектах мы наблюдали сотни тестировщиков, про
водящих ручное тестирование, в течение короткого периода времени. Ручное тес
тирование плохо масштабируется и обходится дорого: задержка обратной связи
сопряжена
с
определенными
издержками,
а
стоимость
выполнения,
привязанная
к людям, также делает его дорогостоящим.
Ручное тестирование сопряжено со многими проблемами, и люди могут допускать
ошибки. Ручное тестирование
-
это способ, с помощью которого мы извлекаем
максимум пользы из людей и тратим ее впустую, в то время как автоматизация
-
это более эффективное использование времени и ресурсов. Однако ручное тестиро
вание
имеет
смысл
при
проведении
ознакомительного
тестирования,
которое
должно быть ограниченным, но может быть чрезвычайно эффективным при выяв
лении ключевых случаев, пропущенных вашим программным обеспечением.
310
■
Глава 7
Постоянная настройка тестов
Если в каждом спринте вам нужно настраивать одни и те же тесты, требующие по
стоянного внимания, то вы имеете дело с так называемыми ручными тестами. Руч
ные тесты создают проблемы, отнимают время у разработчиков, мешают вашим
командам набирать очки и в целом не являются признаком стабильной системы. За
этим скрываются и другие проблемы, такие как жестко заданные идентификаторы,
нестабильность инфраструктуры, недостаточная масштабируемость, например от
сутствие групп автоматического масштабирования в сервисах, проблемы с ниже
стоящими зависимостями, частые изменения конфигурации или ошибки конфигу
рации и/или отсутствие устойчивости к рефакторингу, когда любое изменение на
рушает большинство или все тесты.
Кто-то может возразить, что постоянная корректировка тестов это просто из
держки, а не признак плохих тестов. Ручные тесты могут быть признаком очень
старательной команды. Возможно, вы страдаете от еще одного нарушения правил
из этого списка, но ваша команда чрезвычайно бдительна в исправлении тестов.
Конечно, постоянные настройки создают иллюзию отличных показателей прохо
димости, хотя на самом деле в работе есть один или несколько антипаттернов. Мы
рекомендуем обратить на это внимание, потому что тут присутствуют следующие
недостатки.
♦
Медленная обратная связь. Если проблема возникла в нижестоящей команде,
почему они не смогли разобраться с ней на своем уровне? Почему пострадавшая
команда замечает это первой? Возможно, в команде, занимающейся разработ
кой, отсутствуют тесты, и эти постоянные изменения в тестировании
-
всего
лишь очень медленный и неэффективный способ для вышестоящих потребите
лей «протестировать» продукт за них. Антипаттерн: медленная и дорогостоящая
обратная связь.
♦
Корневые причины. Если вы просто продолжаете дорабатывать тесты, то про
должаете скрывать проблемы. Необходимо устранять первопричины, а когда
первопричины не устраняются, затраты на обслуживание растут, наборы тестов
выходят из строя, а команды работают неэффективно.
Независимость тестов
Недостаток
изоляции является
недостатком
многих
программных
архитектур;
в тестировании это не исключение. Плохим тестам не хватает самодостаточности,
т. е. их успешное выполнение зависит, например, от внешнего состояния или дру
гих тестов.
♦
Тесты не моrут выполняться независимо. Тестам требуются одни и те же
входные данные и слишком много объектов в нужных состояниях, что не позво
ляет запускать отдельные тесты по одному за раз или использовать эффектив
ные стратегии прохождения тестов. Что довольно плохо.
♦ Требуется упорядочение тестов. Тесты должны выполняться в произвольном
порядке. Действительно ли тестам нужен строгий порядок? Возможно, у вас
есть одна массивная цепочка тестов, которые необходимо выполнять последова-
Надлежащее тестирование сервисов
■
311
тельно. При изменении любого теста все нарушается, поэтому вы не можете ис
пользовать параллелизм. Многие современные средства тестирования позволя
ют выполнять тесты параллельно, например с помощью функции параллельного
выполнения тестов, представленной в
JUnit 5.
Невозможность параллельного
выполнения тестов увеличивает время цикла тестирования.
♦
Хрупкость при рефакторинге. Вы проводите рефакторинг одного теста и нарушаете работу еще одного или нескольких тестов.
Отсутствие самодостаточности
-
это отрицательное свойство, которое вы не хоте
ли бы видеть в своих тестах. Когда тесты мешают друг другу, вы просто увеличи
ваете затраты и время выполнения заказа.
Теперь, когда мы поняли, как выглядят плохие тесты, давайте посмотрим на харак
теристики хороших тестов.
Характеристики хороших тестов
Хорошие тесты обладают следующими качествами (рис.
♦
7.3):
Постоянная вероятность успеха. Тесты проходят предсказуемо и терпят не
удачу тоже предсказуемо. Инженеры могут рассматривать неудачи тестов как
сильный сигнал о том, что что-то не так.
♦
Устойчивость к рефакторингу. Инженеры могут безопасно выполнять рефак
торинг крупных элементов тестируемого кода, не нарушая работу большинства
тестов .
♦
Изолированные зависимости данных. Ваши наборы тестов используют пря
мые входные данные или непосредственно создают необходимые данные перед
запуском. Тесты не имеют общих зависимостей между данными.
♦
Быстрые циклы обратной связи. Инженеры и тестировщики быстро получают
обратную связь; если командам требуется выполнить более длительные или
сложные тесты, они выполняются позже в процессе разработки .
♦
Самостоятельные тесты. Большинство тестов редко нуждаются в изменении,
если вообще нуждаются, по мере того, как инженеры отправляют код.
Характеристики хороших тестов
г
- - - - - - - - - - - -,
1
1 Постоянная вероятность
1_ycnexa _________ 1
,------------:
Устойчивость
1
1 к рефакторингу
1
'------------~
: Изоляция зависимости
1
от данных
Рис.
7.3.
-----------,1
1 Быстрые циклы
1 обратной связи
1
L----------1
1
1 Самостоятельные
1
·---------•
..---------,
: Автономные
Как выглядят хорошие тесты
:
312
♦
■
Глава
7
Автономные тесты. Тесты изолированы друг от друга и не зависят от других
тестов или строгого порядка их успешного выполнения.
Давайте разберемся в каждой из этих черт/паттернов.
Постоянная вероятность успеха
Хорошие тесты всегда проходят успешно. Если они не проходят, это означает либо
неправильный код, либо изменение требований. Код или тест необходимо скоррек
тировать, и это хорошо! Высокий уровень прохождения тестов имеет жизненно
важное значение для укрепления доверия к тестам. При хорошем опыте работы
сбои являются серьезным сигналом о наличии ошибок, и ваши инженеры обратят
на это внимание. Ничто так не подрывает доверие, как ложные срабатывания, при
водящие к побочным эффектам, о которых говорилось ранее. Такие условия приво
дят
к снижению
качества
и
плохо
написанным тестам
и,
как следствие,
к
плохо
протестированным системам.
Устойчивость к рефакторингу
Как инженер вы хотите иметь возможность проводить рефакторинг кода, не нару
шая при этом все ваши тесты. В противном случае тесты станут помехой. Инже11еры будут различать, когда тест прерывается из-за какой-либо зависимости от
последующего процесса или изменения кода, а когда
вительности к реализации. Последнее
-
-
из-за чрезмерной чувст
проблема теста, а не бизнес-кода, или
печально известный сценарий «ошибка в тесте».
Важно сохранить это свойство в хороших тестах, чтобы обеспечить устойчивость
при рефакторинге кода. В противном случае инженеры будут жаловаться на то, что
тесты только мешают им работать. Они могут начать удалять или писать меньше
тестов, чтобы ускорить процесс. Но тесты должны помогать, а не быть помехой
в работе. Хорошие тесты повышают скорость, придавая вам уверенности в том, что
код работает правильно.
Тесты могут нарушить устойчивость к рефакторингу несколькими способами:
♦
Сложные макеты. Когда команды пытаются имитировать поведение системы и
создают сложные тестовые макеты, результат часто тесно связан с реализацией.
♦
Связь тестов с реализацией. Тестирование ненужных внутренних деталей реа
лизации, таких как полная проверка сообщений об ошибках.
♦ Неправильный механизм подтверждения. Проверка сообщений журнала, а не
типов возвращаемых функций.
Когда вы разрабатываете свои тесты, у вас есть, по сути, два варианта, которые
влияют на связь ваших тестов с реализацией и, следовательно, на их устойчивость
к рефакторингу. Придерживайтесь тестирования только контракта, сохраняя внут
реннюю реализацию невидимой для ваших тестов; или разработайте тест для пря
мой оценки внутренней реализации, напрямую взаимодействуя с ней. Различные
стратегии тестирования возможны только при непосредственном взаимодействии
Надлежащее тестирование сервисов
■
313
с реализацией, например при хаотическом тестировании, отключающем физиче
скую инфраструктуру, узлы базы данных и т. п. Тем не менее даже в этом случае
нет связи ни с одной строкой кода. Но хотите ли вы, чтобы ваши интеграционные
тесты были связаны с вашей внутренней реализацией?
Каждый раз, когда вы привязываете свои тесты к реализации, они будут неустойчи
вы к рефакторингу. Для некоторых типов тестов может потребоваться нечто боль
шее, чем просто макеты; вам может потребоваться манипулировать данными и вы
зывать специальные
API,
чтобы протестировать то, что вам нужно. Во многих слу
чаях это все еще возможно сделать без привязки к внутренней реализации, но
в других случаях у вас может не быть выбора, например при тестировании некаче
ственных монолитов. Связь тестов с реализацией находится на спектре (рис.
7.4),
и у вас есть варианты, которые вы, возможно, не рассматривали:
♦
♦
Измените контракт. Укажите в контракте то, что вам нужно протестировать.
Видимость пакета.
Java
позволяет использовать видимость на уровне пакета
для тестирования кода.
♦
Отражение. Всегда можно что-то изменить в
Java с
помощью отражения.
♦
Различные виды тестирования. Иногда макеты и модульные тесты не являют
ся решением проблемы; переключите свое внимание на другие формы тестиро
вания,
такие
как
хаотичное
тестирование
или
интеграционное
тестирование,
а в некоторых случаях вообще не проводите тестирование .
...
Тестирование
Тестирование
только контрактов
внутренней реализации
Рис.
7.4.
Спектр связи тестов с реализацией
Мы подробно говорили о рисках, связанных с некорректной реализацией в ваших
контрактах; правильный дизайн способствует изоляции, скрывает элементы и не
раскрывает внутреннее поведение и
API.
Если вам нужно выбирать между возмож
ностью тестирования программного обеспечения и правильным дизайном про
граммного обеспечения, всегда выбирайте правильный дизайн. Иногда можно най
ти способ указать что-то в контракте, а также улучшить тестирование без привязки
к внутренней реализации. Это отличный результат и выгодно для всех. Но даже
если ваш набор тестов станет более сложным, в относительном выражении это не
имеет большого значения; правильный дизайн программного обеспечения всегда
принесет гораздо больше пользы в долгосрочной перспективе.
Изоляция зависимости от данных
Хорошие тесты хорошо обрабатывают данные как на входе, так и в рамках своей
реализации в классе в качестве внутреннего состояния. Правильная обработка дан
ных
-
ключевой элемент хорошего программного обеспечения. В противном слу
чае в первую очередь могут пострадать ваши тесты. Давайте поговорим о привыч
ках, которые хорошие тесты демонстрируют при обработке данных.
314
■
Глава
7
Прямые входные данные
Представьте себе простой класс
Java
calculator (калькулятор) с основными опера
циями, такими как сложение, вычитание, умножение и деление. Каждая операция
принимает по два параметра, такие параметры вводятся как int (целое число), и все
операции возвращают значение douЫe (число с плавающей точкой). Как вы реали
зуете свои тесты, чтобы они проходили при таких условиях?
Хорошие тесты будут изолировать каждый параметр для каждого теста. Допустим,
вы хотите протестировать массив параметров на успешное выполнение; тестирова
ние
1и
(1/0
вызывает исключение
( l + О = 1), но при делении не получится
ArithmeticException). Правильный подход заключается
О будет иметь смысл для суммы
в дублировании этих параметров в каждом методе тестирования, чтобы каждый из
них мог по-своему обрабатывать вызываемую функцию. Неправильным подходом
было бы совместное использование этих параметров в виде какого-либо глобально
го состояния или свойства класса; глобальные изменения могут нарушить работу
всех ваших тестов. Хотя это простой пример, в реальности мы столкнулись с более
сложными случаями, которые сводятся к тому же принципу: попытка использовать
общие глобальные состояния делает тесты хрупкими. Сохраняйте изоляцию.
Внутренние состояния
Иногда код не возвращает одинаковые результаты при задании одинаковых пара
метров. Хотя наш класс calculator всегда возвращает одинаковые результаты при
задании одинаковых параметров, что, если бы мы использовали эти параметры для
запроса к базе данных? Тогда результат определяется не только этими параметра
ми; он зависит от состояния чего-то вне кода, базы данных. Вы не можете воспро
извести это вну1реннее состояние только с помощью кода функции, а внутреннее
состояние не отображается в контракте; и именно это внутреннее состояние необ
ходимо воспроизвести тестам.
Итак, как же нам правильно протестировать внутреннее состояние? Существует
множество безопасных методов: например, создание специализированных интер
фейсов тестирования, которые предоставляют доступ к операциям, необходимым
для настройки данных, или иным образом приводят систему в нужное вам состоя
ние; или генерация синтетических данных
(synthetic data generation),
когда вы гене
рируете данные на лету, что отлично подходит для защиты персональных данных,
конфиденциальности и простоты настройки данных. Давайте обсудим эти подходы
на
одном
примере
генерации
данных
и
тестирования
интерфейсов
(testing
interfaces ).
Допустим, нам нужно протестировать операцию findUserByid в сервисе профилей из
нашего примера. Чтобы проверить успешность результата, нам нужно передать уже
существующий
идентификатор
пользователя.
Для
интеграционного
теста
этот
идентификатор пользователя должен существовать в базе данных. Плохие тесты
предполагают, что данные уже есть в базе данных до их запуска, как волшебный
идентификатор, который все используют. Хорошие тесты заранее настраивают
данные перед запуском и удаляют их после этого. Например, мы могли бы исполь-
Надлежащее тестирование сервисов
■
315
зовать интерфейс тестирования для запуска кода, который проверяет и исправляет
волшебный идентификатор тестирования, закодированный в сервисных тестах
профиля. Но что, если нескольким командам нужно запустить этот скрипт одно
временно? А еще лучше, мы можем запустить простой SQL-скрипт, который вво
дит нового пользователя в базу данных и записывает идентификатор, возвращая
этот идентификатор для использования во время тестирования.
Вводя наши собственные данные и используя полученные идентификаторы на эта
пе настройки теста, мы предотвращаем взаимодействие команд и тестов друг с дру
гом и, следовательно, достигаем изоляции зависимости от данных. Все эти подходы
будут более подробно рассмотрены позже в этой главе. Оставайтесь с нами!
Быстрые циклы обратной связи
Как мы уже говорили ранее, скорость относительна, но каждый выигрывает от дос
таточно быстрого выполнения тестов. Скорость помогает организациям масштаби
роваться. Качественные тесты позволяют инженерам быстро получать результаты,
не ожидая по
1О
минут на своем ноутбуке.
Если вы стремитесь к хорошим тестам с быстрым циклом обратной связи, возмож
но, стоит изменить свой подход. Быстрая обратная связь также достигается за счет
тестирования с использованием надлежащей техники и стратегии. Например, если
все тесты относятся к категории Е2Е, они будут медленными и дорогостоящими.
Важно найти баланс между имеющимися в вашем распоряжении формами тестиро
вания. Мы поговорим об этом подробнее, когда рассмотрим пирамиду тестирова
ния.
Быстрая обратная связь также может быть достигнута с помощью правильных ин
струментов. Например, языки со строгой типизацией, такие как
Scala, Rust, Zig
или даже
TypeScript,
Java,
С++,
Haskell,
могут сэкономить вам время на тестирование,
применяя правила и отслеживая ошибки в самой среде
IDE
еще до выполнения ка
кого-либо реального теста.
Самостоятельные тесты
Хорошие тесты не требуют постоянной доработки при каждом изменении кода.
В некотором смысле хорошие тесты похожи на концепцию неизменяемой инфра
структуры
DevOps:
они пишутся один раз, никогда не изменяются и отлично вы
полняются независимо от среды, конфигурации системы или параметров, которые
они принимают. Конечно, когда мы добавляем новый код или меняем поведение,
тесты ломаются и требуют исправления
-
это хорошо, тесты выполняют свою ра
боту. Но хорошие тесты не нужно часто менять в системах, которые имеют после
довательную, стабильную траекторию.
Автономные тесты
Каждый новый тестовый метод в тестовом классе должен однозначно оценивать
новый тестовый пример. В противном случае вы сталкиваетесь с дублированием
316
■
Глава
7
тестов, а наличие слишком большого количества тестов само по себе является бре
менем ДТJЯ обслуживания; или вы объединяете слишком много тестовых примеров
в одном методе, накапливая слишком много утверждений и замедляя понимание и
отладку ошибок теста.
Хорошие тестовые примеры должны обладать следующими свойствами:
♦
Независимость. Тесты должны выполняться индивидуально и не зависеть от
результатов предыдущего теста как для входных, так и для выходных данных.
♦ Поддержка параллелизма. Тесты должны выполняться в любом порядке без
сбоев.
♦
Изоляция. Тестовые примеры и методы тестирования не должны нарушать друг
друга, а также быть устойчивыми к рефакторингу.
Короче говоря, методы тестирования не должны пересекаться или иным образом
влиять друг на друга. Такие тесты, по сути, являются автономными, они работают
сами по себе, без поддержки других. Изолированные тесты допускают параллель
ное выполнение тестов, что является отличным способом ускорить цикл получения
обратной связи.
Давайте вернемся к нашему простому примеру с калькулятором и рассмотрим его
подробнее на примере кода (листинг
1.
7.1 ).
interface CalculatorVl
int sum(int а, int Ь);
int sum(int .. .а);
int div(int а, int Ь);
puЫic
2.
3.
4.
5.
Здесь у нас есть простой контракт, который определяет
суммирования целых чисел либо с использованием
мы
(varargs),
2
3 операции: 2
операции для
параметров, либо любой сум
и еще одна для выполнения деления на
2
целых числа. На практике
вы, возможно, никогда не создадите подобный сервис, но это достаточно просто,
чтобы проиллюстрировать наши соображения. Теперь давайте взглянем на реали
зацию (листинг
1.
iшport
7.2).
java.util.Arrays;
2.
3.
4.
5.
6.
7.
8.
class SimpleCalculator impleшents CalculatorVl
@OVerride
puЫic int sum(int а, int Ь) {
return а+Ь;
puЫic
Надлежащее тестирование сервисов
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
■
317
@Override
int surn(int ... а) {
return Arrays.stream(a) .reduce(0, Integer::surn);
puЬlic
@Override
int div(int
return а/Ь;
puЬlic
а,
int
Ь)
{
Большая часть импорта опущена для простоты. Теперь давайте посмотрим, как
выглядят автономные тесты с тестовыми примерами, закодированными в
(листинг
7.3).
l{iиcttiнr 7.3. Автоноrv~. . м~тесты для'~m,ЮU'fЬкулятора
1.
2.
3.
iшport
org.junit.jupiter.api.Assertions;
org.junit.jupiter.api.Test;
static org.junit.jupiter.api.Assertions.assertEquals;
puЬlic
class SimpleCalculatorTest {
iшport
iшport
4.
5.
6.
7.
8.
9.
10.
11.
12.
@Test
void testSimpleSшn() {
int inputA = 10;
int inputB = 20;
int result = new SimpleCalculator()
puЬlic
.sшn(inputA,inputB);
assertEquals(З0,result);
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
@Test
void testSimpleSumArray() {
int inputA[] = new int[] {1,2,3,4,5,6,7);
int result = new SimpleCalculator() .sшn(inputA);
assertEquals(28,result);
puЬlic
@Test
void testSimpleDivOk(){
int inputA = 30;
int inputB = 3;
int result = new SimpleCalculator() .div(inputA,inputB);
assertEquals (10, result);
puЫic
JUnit 5
318
30.
31.
32.
33.
34.
35.
■
Глава 7
@Test
void testSimpleDivByZero() {
int inputA = 30;
int inputB = О;
Assertions. assertThrows (ArithmeticException. class,
new SimpleCalculator() .div(inputA,inputB);
puЬlic
36.
1)
-> {
}) ;
37.
38.
Прежде всего, как вы можете видеть, в каждом тестовом примере нет ничего обще
го. В тестовых примерах есть изолированные входные переменные, как мы видели
в нашем примере изоляции зависимостей от данных. Рефакторинг тестового при
мера не повлияет на другие тестовые примеры. Тесты практически ничего не знают
о реализации; реализация может меняться, но пока она поддерживает один и тот же
контракт, все будет работать. Тесты полностью независимы и могут выполняться
параллельно. Помимо «счастливого пуrи», тестируются сценарии, подобные деле
нию на ноль. Такие тесты понятны и очень просты для понимания.
Обратите внимание, что в каждом тестовом примере очень мало утверждений.
Каждый метод тестирования должен включать отдельные тестовые примеры, а не
собирать все тесты для множества различных случаев или сценариев в одном месте.
Когда тесты с большим количеством утверждений завершаются неудачей, инжене
ры не сразу понимают, что конкретно нарушено. Рекомендуется использовать один
метод для каждого тестового сценария.
Манифест тестирования
Прежде чем мы продолжим, давайте рассмотрим манифест тестирования
(Testing
Manifesto), представленный компанией Growing Agile в 2013 году6. Положения ма
нифеста тестирования (рис. 7.5) помогают сфокусировать команды на правильном
мышлении, ценностях и
принципах для поддержки надлежащего качества и прак
тики тестирования и даже в некоторой степени при разработке программного обес
печения.
Тестирование на всем протяжении важнее,
чем в конце
Команды, должным образом применяющие гибкие методы разработки, подходят
к тестированию совершенно иначе. Для них это не просто этап или завершение
разработки, а непрерывный процесс, идущий на каждом этапе процесса разработки.
Этот очень важный принцип определяет тестирование как комплексную, непре
рывную деятельность, которая не является бинарной и никогда не заканчивается.
6
Growing Agile -
южноафриканская компания, которая в своих книгах, курсах и семинарах рассказывает
о методах Аgilе-коучинrа, проектирования и тестирования.
См.
https://www.growingagile.eo.za/books/ и https://leanpub.com/AgileTesting.
Надлежащее тестирование сервисов
■
З 19
МанифесVV\ VV\eCVV\upo6aнuя
Ценно:
Тесмиро6ание на Всем 11\ромяжении важнее , чем
rтредом6ращение ощибок важнее ' чем их
понимание
11\pu
месмиро6ании важнее ,
6
конце
11\0UCK
чем V1ро6ерка
,;,,
..,.,ункционалоносми
Создание наилучщеи. сисмемо, важнее , чем ее разрущение
Оилбеилсилбенносw.t, KOMt\HOt,/
важнее '
за качесw.бо
Источник:
чем оw.беилсw.бенносилt,
w.есw.иробщика
Рис. 7.5. Манифест тестирования.
https://www.g rowi ngagi le.co.za/2015/04/the-testi ng-manifesto/
Предотвращение ошибок важнее, чем их поиск
Когда вы отделяете контроль качества от проектирования, вы создаете разные
организации с разными способами измерения ценности. Исторически сложилось
так, что в нашей отрасли организации, отвечающие за контроль качества, оценива
ются по количеству обнаруженных ошибок; поэтому их целью становится поиск
ошибок. Это неправильный стимул, потому что исправление ошибок обходится
дороже, особенно на более поздних этапах разработки. И отдел контроля качества,
и инженеры должны объединиться, чтобы не допустить появления ошибок в про
цессе разработки, и вместо этого работать над тем, чтобы сделать систему более
надежной и устойчивой в процессе производства.
Понимание при тестировании важнее,
чем проверка функциональности
Создание Е2Е-теста для каждой отдельной функции и матрицы возможных вариа
ций является очень дорогостоящим и медленным процессом. Сосредоточьте энер
гию и усилия на тестировании широкого спектра функций;
500,
15
тестов лучше, чем
если они действительно проверяют глубину функции с использованием не
скольких методов. Тестирование требует разнообразия. Нужно стремиться к более
чем одной форме тестирования и сочетать эти методы с четкой наблюдаемостью и
обратной связью. Тестирование для понимания также означает поиск разумных
способов обеспечения уверенности в безопасном и корректном внедрении и внесе
нии изменений.
320
■
Глава
7
Создание наилучшей системы важнее,
чем ее разрушение
Это очень ценно! Цель каждого должна заключаться в том, чтобы приносить поль
зу бизнесу, сотрудничать и работать над улучшением всей системы в целом, а не
просто доказывать, что она не работает, и называть это результатом усилий. Тести
рование помогает понять, как улучшить бизнес. В основе бережливого мышления
лежит принцип встроенного качества, при котором качество должно быть частью
процесса, а не чем-то, что происходит в конце. Тесты являются частью этого про
цесса, а не просто оценкой «прошел или не прошел». Они скорее предоставляют
информацию, помогающую улучшить дизайн, производительность и понимание
всей системы.
Ответственность команды за качество важнее,
чем ответственность тестировщика
Как мудро учит нас бережливое мышление, качество не может быть внешним. Его
должна обеспечивать сама команда. Нельзя сделать тестировщика единственным
ответственным за качество продукта;
это должна быть
ответственность
всей
команды. Это работа каждого: все роли, все инженеры, ответственные за продукт,
все должны заниматься тестированием. Аналогичный подход следует применять
к безопасности, наблюдаемости, эффективной миграции и многим другим важным
инженерным аспектам, выходящим за рамки тестирования.
Разнообразие тестирования
Наша отрасль должна признать, что ее подход к тестированию часто ошибочен.
Идти ва-банк и проводить на предпродуктиве Е2Е-тестирование
-
это неправиль
ный путь. Тестовый код должен быть хорошо написан и поддерживаться, как и лю
брй бизнес-код в сервисах. Тестирование только в предпродуктивных средах имеет
множество ограничений; их недостаточно, чтобы убедиться в корректности вашей
системы, ее низкой эффективности и готовности к работе. Никакой процент тесто
вого покрытия не может подтвердить правильность ваших данных. Он только соз
дает ложное ощущение безопасности. Команды считают, что они выигрывают, ко
гда видят
100-, 90-
или даже 80%-ный охват тестированием, но это может просто
скрыть множество плохих тестов и еще худших практик. Инструменты покрытия
тестами не охватывают все формы тестирования; некоторые инструменты едва
охватывают отдельные ветки. Командам нужно работать лучше, и ответ заключает
ся в большей диверсификации тестирования. В разнообразии есть сила.
Почему тестирование важно для архитектуры
программного обеспечения
Архитектура программного обеспечения охватывает множество дисциплин, от про
ектирования инфраструктуры, кода и организации до структуры и затрат, а также
Надлежащее тестирование сервисов
■
321
всех связанных с этим решений и компромиссов. В основе архитектуры лежит раз
работка программного обеспечения, т. е. то, как отдельные программные компо
ненты объединяются и соединяются друг с другом.
Хороший дизайн программного обеспечения обладает свойством тестируемости.
Тестируемое
программное
обеспечение
не
гарантирует хорошего дизайна,
но
любой хороший дизайн приводит к тестируемому программному обеспечению.
Вспомните примеры «плохих монолитов», которые мы приводили в этой книге.
Ключевым свойством классических и распределенных монолитов является слож
ность их тестирования, внесения изменений и четкого представления о последстви
ях. Плохая архитектура программного обеспечения не поддается надлежащему тес
тированию, оно не является ее неотъемлемой чертой.
Тестирование играет уникальную роль в архитектурах в стиле сервисов, таких как
SOA
и микросервисы: с помощью таких методов тестирования, как контрактное
тестирование и тестирование обратной совместимости сервисных контрактов. Тес
тирование
-
это важный способ доказать, что у вас есть надлежащие сервисы,
и может помочь вам поддерживать их в рабочем состоянии. Контракт на обслужи
вание
должен
проходить
тестирование
для
поддержания
ценности,
поскольку
в противном случае вы рискуете стабильностью вышестоящих потребителей; высо
ка вероятность того, что вы получите изменение, нарушающее целостность.
Лучшие практики тестирования сервисов
Чтобы правильно тестировать сервисы, в нашем коде должно быть больше модуль
ных тестов по сравнению с интеграционными или Е2Е-тестами. На самом деле, мо
дульные тесты должны быть преобладающей формой тестирования. Модульные
тесты хороши тем, что они обеспечивают быструю обратную связь и часто имеют
низкую стоимость разработки и обслуживания, если мы следуем принципам хоро
ших тестов, описанным в этой главе.
Помимо модульных и интеграционных тестов, сервисы в значительной степени вы
игрывают от особого вида тестирования
-
тестирования контрактов. Контрактные
тесты позволяют определить, повлияют ли ваши изменения на потребителей,
-
это
очень важно для сервисов. Контрактное тестирование также предоставляет доку
ментацию о том, как обращаться к вашему сервису. Тесты контрактов бывают двух
видов: локальные тесты контрактов, в которых широко используются имитации и
макеты, и дистанционные тесты контрактов (рис.
7.6).
Локальные тесты контрактов. Локальным тестам не нужен код для связи с уда
ленными ресурсами для их работы, и они должны полагаться на макеты и имита
ции 7 ; их главная цель -
скорость. Инженеры могут постоянно запускать их и от
слеживать, нарушают ли они условия контракта. Чем больше версий контракта
7
Как макеты, так и имитации избегают вызова истинной дистанционной реализации. Имитации будут
иметь, по крайней мере, частично работающие реализации, такие как испоа1ьзование базы данных в памяти
вместо удаленно развернутой, в то время как макеты
поведением: https://www.maгtinfowleг.com/aгticles/.
-
,то просто объекты с заранее запрограммированным
322
■
Глава
7
нужно поддерживать, тем важнее быстрая обратная связь. Иногда можно даже соз
давать локальные тесты по контракту. Если дистанционные контрактные тесты
проходят достаточно быстро, можно обойтись без такой формы тестирования,
и сэкономить время. Всегда приятно добиваться большего меньшими усилиями.
----------------,
',
Локальный тест контракта
1
----------------,1
1
1
1 Дистанционный тест контракта
,_______
1
1
•-------.,-------
1
--------1
Контракт
Контракт
Реализация
Реализация
сервиса
сервиса
профилей
профилей
Имитации/Макеты
Контракт
Реализация
БДпрофилей
Рис.
7.6.
графического
сервиса
Локальные и дистанционные тесты контрактов
Дистанционные тесты контрактов. Дистанционные тесты контрактов охватыва
ют некоторые или все ваши зависимости. Будьте осторожны и избегайте обращения
к более чем
100
сервисам, потому что в этом случае вы получите дорогостоящий
интеграционный или Е2Е-тест, а не что-то быстрое и эффективное. Вам все еще
нужен некоторый уровень изоляции наряду с некоторым уровнем дистанционного
взаимодействия, но не переусердствуйте.
Для создания тестов контрактов вам не нужен какой-либо специальный инстру
мент. Это можно сделать с помощью обычных инструментов тестирования; напри
мер в
JUnit. Для имитаций вы можете использовать
java API; для макетов вы можете использовать фреймворк, такой
как Mockito (https://site.mockito.org/), EasyMock (https://easymock.org/) или даже
PowerMock (https://gith ub.com/powermock/powermock).
Java
вы можете использовать
стандартные
Практическое стресс-тестирование
Стресс- и нагрузочное тестирование
-
важные виды тестирования производитель
ности, которые могут выявить проблемы, недоступные модульным и интеграцион
ным тестам (рис.
♦
7.7).
Например, с помощью стресс-тестов мы можем выяснить:
Ситуации состязания на скорость. Есть ли в вашем коде условия, приводящие
к состязанию на скорость, которое возникает только при одновременном выпол
нении множества попыток?
♦
Утечки. Есть ли у нас утечки памяти, которые возникают только в течение дли
тельного периода времени в условиях стресса?
♦
Емкость. Можем ли мы справиться с ожидаемой нагрузкой? Что, если мы уве
личим базу пользователей в
2,
в
5,
в
1О
раз? Готовы мы или нет?
Надлежащее тестирование сервисов
.:
Контракт
Реализация
Стресс-тест
.:
Что , если мы выполним
50 тыс .
■
323
за п росов в секунду?
_____: Нагрузочный : Рассчитываем обра ботать 10 тыс . запросов в секунду
: тест
•
се р в иса
п рофилей
Рис.
♦
Узкие
места.
Какие
7.7.
Стресс- и нагрузочное тестирование
основные
проблемы
с
масштабируемостью
возникают
в системе при максимальной нагрузке? Есть ли у нас проблемы с процессором,
памятью, дисковым
вводом-выводом
или
с
зависимостью от
нисходящего
по
тока?
Нагрузочное тестирование доказывает, что система может справиться с ожидаемым
пиковым объемом, в то время как стресс-тестирование выходит за пределы того,
что может выдержать сервис или система. Многие компании игнорируют стресс
тестирование, потому что считают, что им не нужен масштаб Кремниевой долины.
Помимо масштабирования, стресс-тестирование и нагрузочное тестирование под
нагрузкой могут выявить скрытые ошибки, связанные с параллелизмом и использо
ванием ресурсов. Да, вы можете игнорировать эту форму тестирования и обнару
живать все в виде инцидентов во время промышленной эксплуатации или сбоев
в работе. Но есть более эффективные способы управления для удобства пользова
телей и проведения должной проверки.
Gatling
для тестирования производительности
Gatling (https://gatling.io/) - это инструмент с открытым исходным кодом, создан
ный на Scala (https://www.scala-lang. org/). Ваш код тестируется на Scala DSL, но
вы также можете использовать другие языки JVM, такие как Java или Kotlin
(https://kotlinlang.org). Gatling довольно хорошо масштабируется. По сравнению
с JMeter (https:// jmeter.apache.org/) Gatling более гибкий, потому что это код, а не
XML. Gatling поддерживает множество протоколов, таких как НТТР, включая SSE,
TLS и WebSockets, а также JMS и MQTT. У Gatling есть фантастический отчет, со
держащий информацию о задержке с процентилями и сбоями (рис. 7.8).
В листинге
7.4
показан пример приложения
Gatling,
использующего
Gatling
DSL.
1 Листинг
1.
7.4. Gatling для стресс- и нагрузочного тестирования, пример кода
puЬlic
class StressTesting extends Simulation
2.
3.
4.
HttpProtocolBuilder httpProtocol = http
.baseUrl("http://computer-database.gatling.io")
НТТР
324
■
5.
6.
7.
8.
9.
Глава 7
acceptHeader ( "text/html, application/xhtml +xml, application/xml; q=0. 9, * /*; q=0. 8")
.doNotTrackHeader("l")
. acceptLanguageHeader ( "en-US, en; q=0. 5")
. acceptEncodingHeader ( "gzip, deflate")
. userAgentHeader ("Mozilla/5. О (Windows NT 5 .1; rv: 31. О)
Gecko/20100101 Firefox/31.0");
10.
11. ScenarioBuilder scn = scenario("BasicSimulation")
12.
. ехес (http ( "request _ 1")
13.
.get ("/"))
14.
.pause(5);
15.
16.
17.
18.
19.
setUp (
scn.injectOpen(atOnceUsers(l))
) .protocols (httpProtocol);
20.
21.)
Stats
Expand all groups
F~odt,e;ght .
Requests•
Total;
ок;
ко;
Collapse all groups
(!) Response Тlme (ms)
О Executlons
%КО;
.C.n.!i.f. :
Mln:
50th
pct:
75th
pct;
95th
pct:·
99th
pct;
Мах;
Mean;
1!10
Dev~
10.303
82
87
89
120
164
178
01
16
0.098
422
435
437
439
441
441
433
5
• SuЬGroup
0.098
252
259
261
266
267
267
259
Se•rch
0 .098
84
86
88 .
91
92
92
87
Setecl
0.098
83
88
89
90
91
91
87
• Browae
0.098
8935
9059
9128
9204
9228
9234
9067
91
• Edlt
0.016
253
420
503
569
583
586
420
167
AII Requests
• Search
Рис.
Источник:
7.8.
Пример ОТ'!ета от
Gatling.
https://gatling.io/docs/gatling/reference/current/stats/reports/
Мы определяем протокол, который хотим использовать, в данном случае НТТР,
и конечную точку
REST,
которую мы хотим вызвать. В строке
18
указано количе
ство одновременных «пользователей», которых мы хотим запустить. В примере
используется число
1,
но могут быть и сотни тысяч, в зависимости от требований
ваших тестов и возможностей аппаратного обеспечения. У
стратегии выполнения, такие как
Gatling есть и другие
rampUsers, stressPeakUsers, constantUsersPerSec и
многое другое.
Пирамида тестирования
Возможно, вы знакомы с идеей пирамиды тестирования
женной Майком Коном в его книге «Успех с помощью
(testing pyramid), предло
Agile», 2009 (рис. 7.9). Идея
заключается в том, что не все методы тестирования имеют одинаковую скорость и
стоимость. Некоторые методы действуют быстро и практически ничего не стоят, но
Надлежащее тестирование сервисов
■
325
не являются всеобъемлющими, например модульные тесты, в то время как другие
тесты дороги в создании/обслуживании и требуют много времени для запуска, на
пример тесты пользовательского интерфейса/Е2Е. Правильная стратегия тестиро
вания должна основываться на множестве дешевых и быстрых тестов по сравнению
с медленными и дорогими, чтобы сбалансировать интеграцию, стоимость и ско
рость.
больше
медленнее
интеграции
Модульные тесты
больше
быстрее
изоляции
Рис.
Источник:
7.9. Пирамида тестирования.
https://martinfowler.com/articles/practical-test-pyramid.html
Пирамида тестирования является отличным вкладом в тестирование и дает нам
представление о том, как проводить тестирование и учитывать соотношение затрат
и скорости выполнения. Пирамида работает по-разному в разных областях разра
ботки программного обеспечения; например, этот баланс интуитивно понятен для
серверного программного обеспечения, но по-разному применим к интерфейсу.
Вы можете спросить: «Если модульные тесты дешевы в написании и быстры в за
пуске, почему бы нам не использовать только модульные тесты?». У модульных
тестов есть свои недостатки.
Вам нужно предугадать все возможные проблемы. Возможно, это самый веский
аргумент. Чтобы провести предварительное тестирование, вы должны уметь «пре
дугадывать» все проблемы, а наша способность предсказывать проблемы имеет
пределы. Мы все еще должны проводить тестирование на предпродуктиве, но нам
нужно совместить его с тестированием в процессе промышленной эксплуатации.
Стоимость и сложность макетов. Зачастую инженеры недооценивают стоимость
и преимущества создания макетов. В итоге вы можете получить тесты, не подтвер
ждающие правильность ваших бизнес-правил, а просто тестирующие макеты. Не
которые даже создают наборы тестов для своих макетов! В результате получаются
сложные макеты, которые не охватывают все сценарии и требуют больше усилий
для обслуживания, чем изначально планировалось.
Современная
разработка
программного
обеспечения
требует
полного
тестов, которые проводятся непрерывно, начиная с момента, когда
ошибку, и заканчивая вашим канареечным тестированием 8 , которое
Канареечное тестирование (Canary Testing):
https: //www.techtaгget.com/w hatis/defi nition/ са nагу-са nа гy-testi ng
8
IDE
спектра
выдает
показывает
■
326
Глава
7
критический сбой для небольшой группы ваших клиентов. Пирамида тестирования
иллюстрирует этот спектр. Соответственно, современные стратегии тестирования
позволяют проводить разнообразные тесты: тестирование свойств, мутационное
тестирование,
стресс-тестирование,
тестирование
контрактов
и
тестирование
в процессе промышленной эксплуатации. Выходите за рамки тестирования на
предпродуктиве, чтобы обеспечить безопасные, дешевые и эффективные резуль
таты!
Стратегии для тестирования на продуктиве
Тестирование на продуктиве
(Testing in production)
-
плуатации звучит опасно, не так ли? Продуктив
в процессе промышленной экс
это место, где сосредоточены
все деньги, риски и, самое главное, клиенты. Разве это не последнее место, где вы
хотели бы тестировать свое программное обеспечение? Но на самом деле всё дале
ко не так однозначно. Тестирование в процессе промышленной эксплуатации
-
это поиск способов безопасного и эффективного выявления проблем в процессе
эксплуатации, которые позволят вам работать быстро, безопасно и с меньшими за
тратами. Синди Шридхаран в своем потрясающем блоге описывает концепцию,
лежащую в основе тестирования в процессе эксплуатации, и разницу между непро
изводственным тестированием и производственным процессом (рис.
•-
7.1 О).
Модулt,нь,е wiecwiь,
Функционалt1нt,1е
-
К.анареечн1;,1е
Фаззинz-месмt,1
-
Мониморцнz
Cwiawiuчecкuй анализ
- Формиро6анце
wiecwit,1
месм1;,1
Тесмь, компоненw~ов
Тес111\ы на основе своисW1в
noкpt,1r,щe месмами
мрафика
- Усмано8ка Ф.лажко8
К.онмролt1н1;,1е мeCW\t,t
для функций
Регрессионнt,1е месмt,1
- Омслежцбание
Тесмь, КОНW\ракмо6
цсключенцй
TeCW\t,t связей
nриемочн1,1е месмы
TecW\t'11
на Му/11\ации
ДЬIМО6Ьlе 111\eCW\ЬI
UI/UX
месмt,1
Тесмы на удобсW160
исполt1зо6ания
Испь~мания
на проникновение
- Моделц ованце yz оз
Источник:
Рис. 7.10. Спектр тестирования Синди.
https://copyconstruct. medi um.com/testing-in-production-the-safe-way-18ca102d0ef
Надлежащее тестирование сервисов
■
327
Ранее в этой главе мы рассмотрели основные вопросы, на которые нам необходимо
ответить: как мы узнаем, что наш код корректен? Знаем ли мы о влиянии измене
ний? Готов ли наш код к промышленной эксплуатации, надежен ли он и готова ли
система в целом к восстановлению после любого сбоя? Чтобы ответить на эти
вопросы, необходимо провести тестирование. Если хотите проверить, как ваша
система восстанавливается после сбоя, нет лучшего способа, чем создать сбой
в контролируемой среде: хаотическое тестирование. Теперь у вас, должно быть,
возникает вопрос: почему именно в рабочей среде? Почему бы не протестировать
в непродуктивной среде?
К сожалению, по нашему опыту, непродуктивная среда никогда не соответствует
рабочей. Существует множество отличий непродуктивной среды от продуктивной,
таких как:
♦
Оптимизация затрат. Если в продуктивном кластере
продуктивном может быть
20
экземпляров, то в не-
3 или 1.
♦
Миграции. Некоторые данные или код будут перенесены только в рабочей среде.
♦
Трафик. Реальный трафик происходит только в продуктивном кластере.
♦ Данные. Из-за масштабируемости, конфиденциальности или проблем с регули
рованием вы не можете использовать те же данные на предпродуктиве,
что и
в процессе промышленной эксплуатации.
♦
Нестабильность. Предпродуктив постоянно меняется и часто нарушается из-за
того, что люди допускают непредумышленные ошибки.
При всех различиях почему мы считаем, что для отслеживания происходящего
в рабочей среде достаточно проведения только предварительных тестов? Почему
бы
не
поэкспериментировать контролируемыми способами, чтобы
ограничить
влияние? Тестирование в рабочей среде не означает, что оно каким-либо образом
повлияет на всех ваших пользователей. Нет смысла тестировать сценарии сбоев на
l 00 %
ваших пользователей, когда
l%
или меньше будет работать нормально.
Одним из распространенных способов ограничения воздействия является развер
тывание программного обеспечения с использованием красных/черных
или синих/зеленых
2 рабочих
(Blue/Green)
(Red/Black)
развертываний. В этом подходе задействованы
кластера, но только один из них активно обслуживает большую часть
или весь трафик. Это также известно как активное/пассивное
оперативное/скрытое
(Live/Dark)
(Active/Passive)
или
развертывание пула.
В обсуждении мы будем придерживаться принципа оперативное/скрытое, когда
основной объем трафика в реальном времени поступает в оперативном пуле, а
в
скрытом
пуле
его
нет,
или
есть только
в
некоторых случаях,
которые
мы
рас
смотрим.
На рис.
7.11
мы показываем типичное оперативное/скрытое развертывание и наде
емся, что идея понятна сама по себе. У нас есть
2
пула с
3
серверами и
3
узлами
базы данных в каждом кластере. Изменения в базе данных реплицируются, но
в остальном это
2
изолированных кластера. Ваши пользователи будут перенаправ
лены в оперативные кластеры. Вы можете развернуть новое программное обеспе-
328
■
Глава 7
чение в скрытом кластере и провести там хаотическое тестирование. Это затронет
НОЛЬ активных пользователей, и все действия будуr выполняться в рабочей среде.
Давайте рассмотрим некоторые из этих сценариев подробнее.
Продуктив
Оперативный
-
Скрытый
весь трафик
Контракт
-
контролируемый трафик
Контракт
Реализация
Реализация
сервиса профилей
сервиса профилей
БД профилей
БД профилей
Рис.
7.11.
Оперативный и скрытый пулы
Пограничный маршрутизатор
Пограничная маршруrизация
(Edge router)
относится к технологическому стеку на
«границе» вашего развертывания, обычно обращенному к клиентам или располо
женному очень высоко в вашем стеке выполнения и направляющему входящие за
просы на серверы назначения. Пограничная маршруrизация
-
это мощный инст
румент, позволяющий проводить комплексное тестирование в производственных
сценариях.
Например, у Netflix есть решение с открытым исходным кодом под названием Zuul
(https://github.com/Netflix/zuul), выпущенное в 2013 г., которое представляет собой
решение для динамической маршруrизации. Zuul, пожалуй, является лучшим при
мером
надлежащего пограничного маршруrизатора с открытым
исходным
кодом.
Он позволяет маршруrизировать трафик на основе любых критериев, поскольку
можно написать код для выполнения маршруrизации. Например, ранее мы описы
вали схему пула оперативного/скрытого трафика на рис.
можем написать код маршруrизации на
или назначить
1%
Java,
7.12.
С помощью
чтобы изолировать
1
Zuul
мы
пользователя
трафика для эксперимента с хаосом, бизнес-тестирования А/В
или любой другой формы тестирования в производственной среде. Другие АРI
шлюзы позволят вам получать аналогичные результаты. Например, такие решения,
Надлежащее тестирование сервисов
■
329
как Nginx (https://www.nginx.com/), А WS API Gateway (https://aws.amazon.com/
api-gateway/), Kong API Gateway (https://konghq.com/products/kong-gateway) и
многие другие.
AWS Elastic Load Balancer
AWS Elastic Load Balancer
AWS Elastic Load Balancer
Zu
ZWI
АРtЗемсе
sn.nlngSeмcl
1W
•• •••· •
Источник:
Рис. 7.12. Использование Zuul в Netflix.
https://github.com/Netflix/zuul/wi ki/How-We-Use-Zuul-At-Netflix
Пользователи бета-версии
Пользователи бета-версии
(beta users) -
это простой способ уменьшить радиус по
ражения и обеспечить безопасные производственные испытания. Считайте, что
ваши пользователи бета-версии
-
это одни из ваших первых «канареек». Пользо
ватели бета-версии соглашаются использовать экспериментальное программное
обеспечение, в котором могут быть ошибки или неполадки, и, в свою очередь, они
попадают в пул пользователей бета-версии и получают другой опыт. Программы
бета-тестирования часто вознаграждают пользователей в обмен на полезные отзы
вы, такие как скидки и сбережения. Мобильные платформы специально разработа
ли
методы,
позволяющие
предоставлять
пользователям
доступ
к
пользователь
скому программному обеспечению с помощью таких программ, как
TestFlight, Android Play Store Beta programs.
Apple iOS
Даже если у вас нет внешних пользова
телей бета-версии, можно пометить внутренних пользователей как бета-тестеров.
Преимущество для вашей организации заключается в том, что, сначала предостав
ляя программное обеспечение пользователям бета-версии, вы сокращаете количе
ство клиентов, пострадавших от ошибок в вашем коде. Это просто еще один способ
тестирования в рабочей среде.
330
■
Глава 7
Контракт
Реализация
Реализация
сервиса профилей
сервиса профилей
~Zииl
БД профилей
БД профилей
Рис.
На рис.
7.13.
7.13
Пользователи бета-версии, подключенные через
4
Zuul
Тox.if rOX'J
-
Неудача
для хаотического тестирования
показано, как, используя АРI-шлюз, подобный
Zuul,
мы можем пере
направлять пользователей бета-версии на разные серверы и выполнять различные
действия в каждом производственном пуле, например хаотическое тестирование
с использованием
Toxiproxy,
о котором поговорим позже в этой главе.
Аудит в реальном времени
/
сравнение и сброс результатов
Наличие нескольких оперативных пулов позволяет использовать другие сценарии
тестирования на продуктиве, такие как аудит в реальном времени (рис.
7.14 ).
Пред
ставьте, что мы хотим выполнить миграцию данных и заменить реализацию базы
данных профилей с
100 %.
Благодаря
MySQL на Postgres. Однако мы не уверены в результатах на
гибкости Zuul или аналогичных пограничных маршрутизаторов
мы можем написать код, который будет дублировать весь трафик, поступающий
в наш оперативный кластер, на скрытый кластер, который имеет другую реализа
цию, обратно совместимый контракт и совершенно новую базу данных. Мы копи
руем/зеркалируем весь текущий трафик, поэтому реальные клиенты взаимодей
ствуют только с оперативным кластером. Ответы из скрытого кластера проверяют
ся на наличие ошибок и отбрасываются, никогда не возвращаясь к реальным кли
ентам.
Сравнивая и отбрасывая результаты, вы можете выявлять ошибки, проверять цело
стность базы данных и создавать записи в соответствии с ожиданиями, при этом
клиенты будут надежно защищены от ошибок в вашей скрытой среде. Такой под
ход поможет вам обрести уверенность в том, что оба решения работают с мини
мальным риском. Наше решение лучше всего работает при обратной совместимо
сти, но, приложив некоторые усилия, его можно адаптировать и для работы без нее.
Надлежащее тестирование сервисов
■
331
,_____...,.~
~
--в ---------..
Контракт
Контракт
Реализация
Новая реализация
сервиса профилей
сервиса профилей
Сравнение результатов
БД профилей
на Postgres
БДпрофилей
на MySQL
Рис.
7.14.
Тестирование на продуктиве: аудит в реальном времени
Идя дальше, мы можем напрямую передавать реальные ответы нашим клиентам,
реализуя их в рамках сервиса, без использования пограничного маршрутизатора,
с помощью двойного чтения и записи в базу данных (рис .
7.15).
По мере поступле
ния запросов вы записываете данные в обе базы данных и ждете обоих ответов
Контракт
Реализация
сервиса профилей
Сравнение на лету
Откат на лету
БД профилей
на MySQL
БД профилей
на MySQL
Рис.
7.15.
•
Сравнение и отбрасывание
Двойной вызов/запись и сравнение
332
■
Глава 7
с тайм-аутом; если
Postgres
Postgres
не отвечает, верните результат
содержатся ошибки, просто верните результат
MySQL. Если в ответе
MySQL. Если оба возвра
щают результат, сравните их и проверьте на наличие ошибок. Если ошибок нет,
и они идентичны на
верните
MySQL.
100 %,
Postgres;
в противном случае
Здесь происходит то, что мы предполагаем, что
источником истины, а
Postgres только
отлично, верните ответ
MySQL
является
это эксперимент, возвращающий результаты
Postgres -
при полном совпадении.
В обоих сценариях очевидное преимущество заключается в том, что вы можете ге
нерировать оповещения, когда ответы
API
или данные не совпадают, и клиенты во
всех случаях защищены. У вас есть простой и быстрый откат
-
маршрутизацию, либо установите флажок, запрещающий запись в
либо отключите
Postgres,
и безо
пасный способ внести кардинальные изменения.
Как и в любой архитектуре программного обеспечения, у схемы двойного вызо
ва/сравнения и отбрасывания есть свои недостатки.
♦ Время простоя. Что делать, если
Postgres
не работает в течение определенного
периода времени? Базы данных будут отличаться, содержать разные данные и
их необходимо будет синхронизировать.
♦
Сбои. Что делать, если
Postgres
продолжает падать? В какой-то момент некото
рые запросы могут постоянно сбоить, пока вы не выполните повторную синхро
низацию. Как для простоя, так и для сбоя у вас может быть компонент, который
синхронизирует их в случае мягких или жестких сбоев.
♦
Стоимость. Вы должны запустить обе базы данных на полную мощность, по
этому такие методы требуют затрат. Возможно, не стоит использовать их при
внесении всех изменений, но при внесении некоторых важных и деликатных из
менений затраты будут оправданы, и это хорошая идея, но не всегда. Вам при
дется выбирать.
Все наши методы могут быть применены на нескольких уровнях стека приложе
ний: сервисный контракт, реализация сервиса, база данных и даже нижестоящие
зависимости. Самым большим преимуществом является быстрый откат в режиме
реального времени. Добавляя показатели наблюдаемости и сбора данных, вы полу
чаете представление о том, что на самом деле происходит в процессе производства.
Мы подробнее рассмотрим методы переноса данных в главе
10 «Мwрация
данных».
Воспроизведение трафика
В предыдущем сценарии мы использовали зеркалирование трафика в реальном
времени, чтобы подвергнуть новый рабочий код реальной нагрузке. Однако не обя
зательно делать это в реальном времени. Вы можете сохранить запросы реального
трафика и воспроизвести их позже в своих сервисах (рис.
Воспроизведение трафика
(Replaying traffic)
7.16).
полезно для выполнения нагрузочного
и стресс-тестирования. С его помощью вы можете воспроизводить реальные запро
сы с гораздо большей скоростью, что также может использоваться в сценариях хао
тического тестирования. Для подцержки этих методов соберите запросы в базе
Надлежащее тестирование сервисов
■
333
данных с высоким трафиком записи, такой как
appendonly,
таком как
Apache Kafka
или
Cassandra, или в лог-решении
AWS Kinesis. В этих системах можно хра
нить полные запросы, включая НТТР-теги, полный путь, параметры тела, парамет
ры запроса, заголовки и все остальное. С помощью
Kafka
или
Kinesis
становится
легко создать процесс, который считывает и воспроизводит весь этот трафик. Но
помните, что это реальные производственные данные. Выполняете ли вы надлежа
щую анонимизацию, чтобы обеспечить безопасное воспроизведение рабочих дан
ных в непродуктивной среде или в скрытом пуле?
Контракт
Оперативный трафик
г-----
Сервис работы
Воспроизведенный
с трафиком
трафик
Скрытый трафик
------,
г-----
1
1
Контракт
1
Реализация
сервиса профилей
БДпрофилей
БД профилей
7.16.
Контракт
Реализация
сервиса профилей
Рис.
------,
Шаблон воспроизведения трафика
Хаотическое тестирование
Хаотическое тестирование
(chaos testing)
или
Chaos Engineering -
это форма тес
тирования на продуктиве. Звучит пугающе, но на практике всё не так страшно. При
внедрении дистрибутива, противоположного централизации, например при исполь
зовании классического монолита сотен или тысяч микросервисов, работающих
в общедоступном облаке, таком как А WS, произойдет сбой из-за слишком большо
го количества отдельных движущихся частей и точек отказа. Вопрос не в том, про
изойдет ли это, а в том, когда это произойдет. Вернер Фогельс, технический дирек
тор А WS, известен фразой «сбои происходят всё время». Мы согласны с тем, что
это очень хорошо описывает облачные вычисления и распределенные системы
(рис.
7.17).
Когда вы придете к осознанию и примете тот факт, что ваша пост-монолитная
архитектура потерпит неудачу, и эта неудача произойдет
-
а она произойдет
-
будете ли вы готовы справиться с ней? Или вы предпочитаете корректировать
пользовательский опыт в процессе промышленной эксплуатации, нанося при этом
ущерб бренду и теряя финансы?
■
334
Глава
7
Контракт
Реализация
сервиса профилей
Что произошло?
Можем ли мы починить это?
БД профилей
Рис.
7.17.
Хаотическое тестирование
-
произойдет сбой
Чтобы предоставить клиентам безупречный, устойчивый к сбоям пользователь..:кий
опыт, необходимо понимать свои способы устранения сбоев и активно тестировать
их на наличие отказов. Тестирование на наличие сбоев не опасно; игнорировать
способы устранения сбоев гораздо опаснее, потому что сбой произойдет, и есть ве
роятность, что вы не будете к нему готовы.
Для проверки на наличие сбоев вам не нужно отключать весь веб-сайт. Ограждения
необходимы для контролируемого создания хаоса с минимальным воздействием на
реальных пользователей. Создание хаоса требует дисциплины и отличной наблю
даемости, чтобы распознать и ограничить радиус поражения.
Хаотическое тестирование может и должно применяться ко многим различным
уровням и компонентам вашей инфраструктуры. Наша цель
-
не предотвратить
сбой, а убедиться, что вы сможете восстановиться после сбоя и ограничить радиус
поражения. Системы, которые легко восстанавливаются после сбоя, являются ан
тихрупкими 9 .
Хаотическое тестирование проводится с научной точки зрения. Вы создаете гипо
тезу о том, как система могла выйти из строя, затем проверяете эту гипотезу с по
мощью экспериментов, анализируете данные. А затем определяете, смогли ли при
ложения и системная инфраструктура восстановиться после сбоя без ущерба для
реальных пользователей. Эксперименты, которые вы проводите, могут быть целе
направленным хаосом, уничтожающим определенные сервисы или элементы ожи
даемыми способами, или случайным хаосом, когда вы воздействуете на системы,
используя любое количество случайных методов.
В
качестве
рис.
примера
планируемого
хаоса
давайте
рассмотрим
архитектуру
( 1)
Сервис профилей выполняет чтение и запись в свою базу данных, представ
ляющую собой 3-узловой кластер
(2)
MySQL
с одним узлом на
Сервис профилей также публикует события на
Kafka,
AZ.
предназначенные для
последующего использования в потоках больших данных/аналитики.
9
на
7.18.
Концепция антихрупкости из Википедии: https://en.wikipedia.org/wiki/Antifragility.
Надлежащее тестирование сервисов
■
335
Контракт
База данных не работает
Реализация
сервиса профилей
Kafka
не работает
Сервис изображений
Реализация
не работает
сервиса
изображений
БД профилей
Рис.
7.18.
-
Сбой
Хаотическое тестирование с научной точки зрения
(3) Сервис профилей также вызывает сервис
Gravatars 10 для изображения пользователя.
изображений, чтобы получить
Итак, что здесь может пойти не так? Каковы сценарии сбоев? Мы можем начать
строить некоторые гипотезы, например:
♦
Сбой типа А: что, если один из узлов базы данных профиля не работает?
♦
Сбой типа сбоя В: что, если
♦
Сбой типа сбоя С: что, если сервис обработки изображений не работает?
Kafka
не работает?
Как только у нас будут свои гипотезы, мы сможем записать, каковы наши ожида
ния в отношении каждого вида сбоя. Например, вот некоторые разумные ожидания,
предполагающие, что мы работаем в облаке А WS; мы не ожидаем сбоя сервиса,
вместо этого:
♦
Сбой типа сбоя А: сервис профилей переключится на узел базы данных в другом
AZ
и повторит попытку .
♦ Сбой типа сбоя В: сервис профилей запишет данные в свою базу данных вместо
Kafka
♦
и повторит попытку позже, не потеряв никаких данных.
Сбой типа сбоя С: сервис профилей вернет общее изображение.
Теперь можно запустить несколько простых интеграционных или даже нагрузоч
ных тестов, которые затрагивают сервис, и проверить, соответствуют ли они нашим
ожиданиям.
Для случайного хаоса мы можем случайным образом выбирать компоненты и при
менять различные инъекции хаоса для создания режимов сбоя, таких как: выклю
чение компьютера, внедрение ошибок, завершение работы виртуальной машины
JVM,
10
задержка, потеря ТСР-пакетов, потребление всей памяти, заполнение всего
Граватары -
,то аватары. лризнанные во всем мире: https://en.wikipedia.org/wiki/Gravatar.
336
■
Глава 7
локального или удаленного диска,
временное отключение сетевого подключения,
возвращение недопустимых типов данных, таких как
другие возможные сбои.
XML вместо JSON, и многие
- это ваше воображение
Единственное ограничение
(и ваша панель управления).
На рис.
7.19
показана общая картина. В сервисе профилей непрерывно выполняют
ся интеграционные тесты или даже специальный нагрузочный тест, рассчитанный
на несколько минут. Тем временем мы создаем хаос, используя либо обезьяну хао
са, либо другой инструмент для создания хаоса. Важно, чтобы наши тесты прошли
успешно и в соответствии с ожиданиями и гипотезами. Запустив этот хаотический
тест для нашего пула скрытого трафика, пока он изолирован, мы можем проводить
тестирование в рабочей среде, не влияя на наших пользователей.
г--------
Интеграционный тест
1
1
или
нагрузочный тест
1
1
I
1
,________ ..
Реализация
сервиса профилей
Реализация
сервиса
изображений
- Сбой
8
1
Рис.
7.19.
«Обезьянья армия»
Netflix
Хаотическое тестирование ...
Общая картина хаотического тестирования
Netflix
является пионером в области создания хаоса. Одним из первых решений
была «Обезьянья армия»
написанная на
и
Java
(Simian Army, https://gitbub.com/Netflix/SimianArmy),
созданная в 2012 году (рис. 7.20).
В обезьяньей армии был определен ряд различных компонентов:
♦
Обезьяна хаоса
(Chaos Monkey):
отключает экземпляры ЕС2, как случайные, так
и целенаправленные.
♦
Горилла хаоса
♦
Кинr-конг хаоса
(Chaos Gorilla):
(Chaos Kong):
отключает целые зоны доступности.
отключает целый регион.
Надлежащее тестирование сервисов
■
337
Обезьянья армия
•
•
•
•
•
Обезьяна хаоса
Обезьяна задержки
Обезьяна-уборщица
Обезьяна соответствия
(и многое рругоеl)
Проверьте отказоусто йчивость
во время выполнения
http://www.infoq .com/presentations/netflix-resiliency-failure-cloud
Источник:
Рис. 7.20. Обезьянья армия Netflix.
https://www.infoq.com/presentations/netflix-continuous-delivery
увеличивает задержку сетевых вызовов.
♦
Обезьяна задержки
♦
Обезьяна-уборщица
(Janitor Monkey):
Обезьяна-охранник
(Security Monkey):
♦
(Latency Monkey):
очищает неиспользуемые ресурсы.
запускает заявки на защиту, когда срок
действия сертификатов подходит к концу.
Сейчас проект обезьяньей армии находится в архиве, но он оказал влияние на всю
индустрию. Обезьяна хаоса по-прежнему поддерживается и активна. Модуль те
перь написан на Golang (https://github.com/netflix/chaosmonkey). Некоторые воз
Netflix Spinnaker (https://spinnaker.io/) и
Gremlin (https://www.gremlin.com/)
А WS Fault Injection Simulator (FIS, https://aws.amazon.com/fis/).
можности были напрямую включены в
повлияли на многие другие решения, такие как
и сервис
Toxiproxy
Toxiproxy (https://github.com/Shopify/toxiproxy) -
это еще один инструмент для
создания хаоса, который позволяет нам создавать сетевой хаос, также вдохновлен
ный работой
Netflix.
Моделирование и наблюдение за тем, как ваше программное
обеспечение реагирует на незначительные сетевые ошибки, может стать мощным
инструментом для предотвращения или воспроизведения редких проблем в процес
се промышленной эксплуатации.
Toxiproxy
был создан
Shopify
в
2014 r.
и предос
тавляет множество способов создания сетевого хаоса с помощью нескольких функ
ций, таких как:
♦
Тайм-ауты
(Timeouts): удерживают
сокет открытым, но никогда не возвращают-
ся к нему .
никогда не отвечает на запрос.
♦
Время простоя
♦
Внедрение задержки
♦
Сокращение пропускной способности
(Downtime):
(Latency injection):
вводит произвольную задержку.
(Bandwidth reduction):
рий с низкой пропускной способностью.
имитирует сцена
338
♦
♦
■
Глава 7
Медленное закрытие
(Slow close): задерживает закрытие
Сброс узла (Reset peer): имитирует сброс ТСР.
♦ Ломтерезка
(Slicer):
ТСР-сокета.
разбивает данные ТСР на небольшие фрагменты и при не
обходимости вводит задержку.
♦
Ограничение данных
закрывает соединение при достижении опре-
(Limit data):
деленного предела передаваемых данных.
Toxiproxy -
это прокси-сервер, поэтому он находится между запросами вашего
решения и целевым сервером или сервисом и проксирует их, что и приводит к вне
дрению ошибок.
Toxiproxy
скольких языков, таких как
и
написан на
Golang, однако у него есть клиенты для не
Java, Go, Haskell, Ruby, Rust, Elixir, NodeJS, РНР, .NET
Python.
На рис.
7.21
показано использование
Toxiproxy
7.18 мы
шим сервисом и базой данных. На рис.
для создания простоев между на
могли бы использовать Т oxiproxy
для создания ожидаемых сбоев в работе сервиса изображений или
Kafka.
г--------.
--------••
1
1
Контракт
Интеграционный
J
нагрузочный тест
I
1
или
'--------J
Реализация
сервиса профилей
База данных не работает
- Сбой
БД профилей
Рис.
7.21.
Хаотическое тестирование
-
внедрение сетевого сбоя с помощью
Toxiproxy
Матрицы отказоустойчивости
Другим популярным методом создания хаоса является матрица отказоустойчивости
resiliency matrix) 11 . Возьмите систему и постройте матрицу со всеми ее нижестоя11
Shopify иллюстрирует концепцию матрицы отказоустойчивости в своем блоге, посвященном планирова
нию отказоустойчивости для мероприятий с высокой посещаемостью :
https://shopify.engineeгing/resiliency-planning-for-high-traffic-events.
Надлежащее тестирование сервисов
■
339
щими зависимостями и оцените, каким будет поведение в режимах сбоя, варьи
рующихся от легких (отказ узла) до экстремальных (отказ всего кластера). Затем
опишите резервные варианты и возможные действия по восстановлению. Давайте
сопоставим некоторые из наших гипотез из рис.
сти в табл.
7.16
с матрицей отказоустойчиво
7.1.
Таблица
Компонент/
тип сбоя
БД профилей
7.1. Матрица отказоустойчивости
Отключение узла
Отключение кластера
Повторная попытка, экспоненциальная
задержка, переход на другой
AZ
Время простоя (красный)
(зеленый)
Сервис
Повторная попытка, экспоненциальная
Переход к кешированию изобра-
изображений
задержка, переход на другой
жений по умолчанию (желтый)
Kafka
AZ
(зеленый)
Повторная попытка, экспоненциальная
Запись в базу данных профилей
задержка, переход на другой
(желтый)
AZ
(зеленый)
Зеленый: система может легко восстановиться после сбоя.
Желтый: система все еще может работать, но некоторые функции отключены или
качество работы ухудшилось. Красный: полный сбой, система не может работать.
Что касается красной линии, то кластер БД профилей полностью отключен, и нам
необходимо рассмотреть варианты сокращения времени простоя. Например:
♦
Резервные варианты. Должны ли мы рассмотреть какой-либо другой возмож
ный резервный вариант? Другая база данных или кешированный результат?
♦
Аварийное восстановление. Должно ли у нас быть решение для аварийного
восстановления? Есть ли у нас резервные копии для разных регионов или за
пределами сайта? Какова процедура восстановления? Сколько времени это за
нимает?
♦
Мультирегиональность. У нас есть эта база данных только для нескольких зон
доступности; следует ли нам рассмотреть решение для нескольких регионов?
Все эти варианты имеют свою стоимость. Иногда лучший вариант для вашего биз
неса
ничего не делать, но создавать качественные резервные копии. Сначала
-
определите свои цели в области доступности и надежности, а затем планируйте
в соответствии с ними.
Внутреннее состояние
-
продвинутое глубокое погружение
Необходимость воссоздания сложного внутреннего состояния, которое, в свою
очередь, зависит от внешних зависимостей, является распространенной проблемой.
Некоторые виды тестов страдают от этой проблемы больше, чем другие. Любой
тест,
в
котором
вам
нужно обратиться к внешним
зависимостям, столкнется
с большим количеством проблем, в том числе дистанционные тесты контрактов,
340
■
Глава
7
дистанционные интеграционные тесты, Е2Е-тесты, стресс-тесты или синтетические
тесты. Тесты с меньшим количеством зависимостей или те, что используют имита
ции или макеты, могут осуществлять дополнительный контроль, например с по
мощью тестов локальной интеграции, тестов свойств или модульных тестов.
При этом проблема значительно усугубляется в распределенных монолитах, где
несколько сервисов и приложений выполняют чтение и запись в одну и ту же об
щую центральную базу данных. Совместное использование командами одной и той
же базы данных значительно увеличивает вероятность коллизий, когда один тест
нарушает работу другого теста из-за общих зависимостей от одних и тех же тесто
вых данных, например из-за использования одного и того же идентификатора. Вот
почему, опять же, важно иметь возможность изолировать тестовые данные. Давайте
рассмотрим некоторые продвинутые методы, позволяющие справиться с этим.
Генерация синтетических данных
Генерация синтетических данных
(Synthetic data generation)
означает именно то, на
что это похоже: генерируйте поддельные данные и используйте их во время тестов.
Такой подход позволяет избежать попыток использовать обработанные рабочие
данные в тестовых данных, обеспечивая анонимность и избегая любых рисков, свя
занных с персональной конфиденциальной (Personally IdentifiaЫe Information, Р11) 12
или защищённой медицинской (Protected Health Information, РН1) 13 информацией.
Хорошо работает использование любой библиотеки или инструмента, способного
генерировать поддельные данные и вставлять их в вашу базу данных перед на
стройкой теста. Примерами такого библиотечного подхода являются faker gem от
Ruby и его Java port, Java-Faker 14 . Для более сложных задач платформы синтетиче
ских данных, такие как Gretel (https://gretel.ai), могут генерировать целые наборы
данных, что является отличным подходом для команд, работающих с большими
данными (рис.
7.22).
Подход к генерации синтетических данных имеет одну проблему: как только дан
ные сгенерированы, вы не можете гарантировать, что в тестах будут использовать
ся разные идентификаторы, поскольку это зависит от инженеров, пишущих тесты.
Вы могли бы устранить проблему с идентификаторами, внедрив таблицу поиска
или сервис в виде вашего инструмента синтетической генерации, который просто
направляет идентификаторы
(рис.
7.23),
для
тестов,
избегая
конфликтов
и
подключений
или просто генерировать новые данные перед каждым запуском теста и
очищать их после этого.
Другой подход заключается в тестировании интерфейсов. Давайте рассмотрим его
подробнее.
12
РП https://en.wikipedia.org/wiki/Personal_data.
13
РЮ https://cphs.Ьerkeley.edu/hipaa/hipaal8.html.
14
Библиотеки faker с открытым исходным кодом отлично работают с часто встречающимися данными
в приложениях, такими как имена или адреса; подумайте о том, чтобы написать свои собственные, если
у вас есть индивидуальные требования.
является
портом
библиотеки
github.com/DiUS/java-faker.
Java-Faker- это порт faker gem от Ruby, который, в свою очередь,
Perl Data от Faker. См. https://github.com/faker-ruby/faker и https://
Надлежащее тестирование сервисов
Продуктив
■
341
Непродуктив
Тесты
Контракт
Реапизация
сервиса профилей
БД профилей
«Поддельная »
БД профилей
Генерация
Сгенерированные поддельные данные
-
Неконфиденциальны
-
Анонимны
-
Не используют данные с продуктива
синтетических данных
Рис.
Продуктив
7.22.
Генерация синтетических данных
Непродуктив
Контракт
Тесты
Реализация
сервиса профилей
Получени е
одного идентификатора
Маршрутизация
БД профилей
сервиса поиска
идентификатора
Генерация
синтетических данных
Рис.
7.23.
Генерация синтетических данных с сервисом поиска
Тестирование интерфейсов
Идея, лежащая в основе тестирования интерфейсов
(testing interfaces),
заключается
в том, что сервис предоставляет определенные конечные точки для облегчения тес
тирования. Допустим, вам нужно иметь возможность удалить некоторые данные
в профиле, например
URL,
чтобы имитировать искаженное изображение или любой
342
■
Глава
7
другой особый случай, который не является поддерживаемой функцией и не может
быть индуцирован простым вызовом стандартного публичного контракта (рис.
Вы
предоставляете
отдельную
конечную
точку
с
определенной
7.24).
операцией:
" / profile / test /change / url ?ID=12345". Подход к тестированию интерфейсов имеет мно
жество преимуществ:
♦
Только для тестирования. Вы не раскрываете внутреннюю часть сервиса, нет
внутреннего ядра, нет базы данных; просто
♦
API,
как и любой другой метод.
Улучшенная разработка. Поставщики сервисов могут проводить тесты, чтобы
убедиться, что этот интерфейс всегда поддерживается и работает. Поскольку
интерфейс встроен в вашу кодовую базу, как и любой другой метод, ваша IDE
предупредит о возможных ошибках, а вы сможете создать тесты для проверки
его корректности.
♦
Снижение уязвимости. Интерфейс тестирования не будет доступен реальным
пользователям, как другие сервисы, внешний
API
для клиентов. Такой механизм
предотвращает злоупотребления, как и любая команда, использующая интер
фейс тестирования вне тестов.
1
1
Тесты
Контракт
____ _ ___ _
1 __ 1
_ __ 1
Реализация
сервиса продаж
RESTIJSON ! ! RESTl}SON
--·--------·······-- -'
·-- -~----------------
Т естирсвание интерфейса
-
Доступно только
во время тестирования
1
-
На прсдуктив не поступает
Воздействие
Контракт
Реализация
сервиса профилей
Рис.
7.24.
Тестирование интерфейсов
Как и у всего остального в архитектуре программного обеспечения, здесь есть свои
недостатки:
♦ Больше контрактов. Теперь сервисной команде приходится обслуживать больше
задач.
♦ Повышенная сложность сервиса. Как побочный эффект сервис становится бо
лее сложным, потому что вам приходится обрабатывать два контракта: обще
доступный и тестовый.
Надлежащее тестирование сервисов
♦
Случайное
использование.
повторное
Ограничение
не
доступа
■
343
является
надежным, и инженеры допускают ошибки. Что, если тестовая конечная точка
каким-то образом попадет в руки потребителю
API
и будет использована для
производственных бизнес-задач?
Тестирование интерфейсов
-
мощный метод, но не универсальное решение. Вы же
не хотите, чтобы в итоге у вас были сервисы с одним допустимым методом и
79
скрытыми методами управления состоянием. Возможно, вам придется пере
смотреть дизайн вашего программного обеспечения или стратегию тестирования.
Как бы то ни было, это мощный инструмент в вашем арсенале инструментов тести
рования.
Настройка тестовых данных
Простая идея : иметь скрипты, которые создают все необходимые тестовые данные,
рядом с источником данных. Реализовать подход к настройке тестовых данных
(Test data setup)
так же просто, как создать папку со скриптами базы данных, кото
рые
запускаются
(рис .
7.25). Мы
перед
тестов
началом
и
создают все
необходимые данные
эффективно выводим эту проблему из сферы обслуживания на дру
гой уровень, ближе к самим хранилищам данных. Она проста, понятна для объяс
нения и выполнения и не требует сложной инженерной подготовки для запуска.
Данные также могут быть синтетическим набором данных, который генерируется
исключительно для тестирования в сочетании с другими нашими подходами.
Самым большим недостатком здесь является то, что при изменении базы данных
скрипты будут работать неправильно. Использование сервисов вместо прямых
Контракт
Реализация
r - - - - - - - - -,
сервиса продаж
:1 RESTIJSON :1
----------Воздействие
Контракт
-------------,
1
:
Настройка тестовых
1
данных
1
1
1
1
Тесты
6Д профилей
7.25.
1
'------------ 1
сервиса профилей
Рис.
,
:____________ 1
1
1
Реализация
1
Настройка тестовых данных
344
■
Глава 7
вставок в базу данных
-
лучший подход для рефакторинга отказоустойчивости.
Однако проблему можно решить, применяя подходы обратной и прямой совмести
мости при внесении изменений в схему на стороне базы данных.
Кроме того, другим командам может потребоваться, чтобы в вашем сервисе ото
бражались определенные данные для успешного проведения тестов. Такой подход
потребует от разных команд выполнения РR-запросов к хранилищу, где находятся
ваши сценарии настройки тестовых данных. К счастью, они не затрагивают код,
который отправляется в производство. Это просто код, который выполняется во
время тестирования, например в конвейерном решении, таком как
Риск его
Jenkins.
повторного использования снижается.
Макетирование интерфейсов
Когда у вас есть подходящие сервисы со стабильными контрактами, понятными
интерфейсами и предсказуемым поведением, их можно легко имитировать
interface).
(Mocking
Это облегчает решение проблем тестирования. Используя такие инстру
менты, как
MockServer
с открытым исходным кодом
(https://www.mock-server.com/),
7.26). Недостатком
вы можете быстро и просто макетировать тестовые вызовы (рис.
здесь является то, что вы не можете по-настоящему имитировать тестирование Е2Е.
MockServer хорошо работает для
;
1. Получить запрос
.,.,otl!!l$%1!!1мt!l!!M%-.---.,.,•·-
,/
1
1
некоторых тестов, но не для всех.
~----------------------~ '
------
2. Сопоставить эагрос
,-,о~, ~Л&ддщ дд,яд:8
Запрос
соответствует
.....,.....
11
Вернуть ответ
~
1
1
1
•
1
1
'
1
1
3.
'
'
1
Ответное
действие
Рис.
7.26.
Общий вид
MockServer.
Источник:
https://www.mock-server.com/
МосkSеrvеr-довольно мощный инструмент. Он позволяет вам сопоставлять шаб
лоны для захвата конкретных запросов и привязывать их к конкретным макетам,
т. е. возвращать определенный
JSON
для определенных идентификаторов. Объеди
нив это с управлением версиями этих JSОN-файлов в
git,
вы получите универсаль
ное решение, которое использует централизованный репозиторий и предоставляет
механизм внедрения для любого сценария тестирования от сервиса к сервису.
Надлежащее тестирование сервисов
■
345
Что нужно запомнить
Поздравляем, вы закончили главу
7.
Тестирование очень важно, поэтому следует
запомнить несколько ключевых идей.
♦
Тестирование имеет значение.
♦
Тестирование необходимо для ответа на важные вопросы:
•
•
Корректность: как узнать, работает ли наше решение?
Влияние изменений: не нарушили ли мы что-то? Оказывает ли это какое-либо
влияние на другие команды?
•
Готовность к промышленной эксплуатации: уверены ли мы в том, что запус
тим это в работу?
♦
Тесты бывают разных типов и разновидностей, в том числе: модульные тесты,
интеграционные
тесты,
комплексные
тесты,
исследовательские
тесты,
тесты
контрактов, функциональные тесты, приемочные тесты, юзабилити-тесты, ды
мовые тесты, стресс-тесты, тесты производительности или нагрузки, тесты хаоса
и регрессионные тесты.
♦
Знание разницы между хорошими тестами и плохими тестами сильно повлияет
на успех вашей стратегии тестирования.
♦
♦
♦
Плохие тесты обладают одной или несколькими из черт-антипаттернов.
•
Непоследовательная частота отказов.
•
Хрупкость при рефакторинге.
•
Зависимость от данных.
•
Неэффективные циклы тестирования.
•
Постоянная настройка тестов.
•
Помехи при тестировании.
Хорошие тесты обладают следующими характеристиками/шаблонами.
•
Постоянная вероятность успеха.
•
Устойчивость к рефакторингу.
•
И1оляция зависимости от данных.
•
Быстрые циклы обратной связи.
•
Самостоятельные тесты.
•
Автономные тесты.
Манифест тестирования описывает правильные принципы, которым необходимо
следовать при тестировании в вашей организации:
•
Тестирование на всем протяжении важнее, чем в конце.
•
Предотвращение ошибок важнее, чем их поиск.
346
■
Глава 7
•
Понимание при тестировании важнее, чем проверка функциональности.
•
Создание наилучшей системы важнее, чем ее разрушение.
•
Ответственность команды за качество важнее, чем ответственность тести
ровщика.
♦
Хороший дизайн программного обеспечения обладает свойством тестируемости.
♦
Сервис-ориентированные архитектуры значительно выигрывают от локального
или дистанционного тестирования контрактов, что помогает сохранить обрат
ную совместимость.
♦ Нагрузочные/стресс-тесты необходимы для ответа на следующие вопросы:
•
Есть ли у нас проблемы с загрузкой?
•
Есть ли у нас утечки памяти?
•
Сможем ли мы справиться с ожидаемой нагрузкой? Что, если мы увеличим
базу пользователей в
•
♦
2,
в
5,
в
10 раз?
Где у нас есть узкие места в области масштабируемости?
Пирамида тестирования устанавливает соотношение затрат и времени на выпол
нение различных типов тестов. Другие рекомендации:
•
Сосредоточьтесь на модульных тестах, а не на UVЕ2Е-тестах.
•
Тестирование на предпродуктиве имеет свои ограничения, поскольку невоз
можно предсказать все возможные проблемы. Рассмотрите возможность тес
тирования в процессе промышленной эксплуатации.
♦
Тестирование на продуктиве.
•
Тестирование в реальных условиях поможет выявить ошибки, которые не
возможно обнаружить на предпродуктиве.
•
Тестирование безопасности в рабочей среде с использованием правильных
ограждений и методов:
♦
0
Оперативный и скрытый трафик.
0
Пограничная маршрутизация.
0
Пользователи бета-версии.
0
Аудит в реальном времени/ сравнение и сброс результатов.
0
Воспроизведение трафика.
Хаотическое тестирование.
•
Форма производственного тестирования.
•
Ключевым моментом является выявление возможных сбоев. Сбои случаются.
Но предпочитаете ли вы быть к ним готовыми или позволите им нанести
ущерб вашему бренду и опыту пользователей?
•
Используйте научный метод: гипотезы, эксперименты и результаты.
Надлежащее тестирование сервисов
•
■
347
Что происходит при сбое, понимаем ли мы режимы сбоя? Можем ли мы вос
становиться?
•
Обезьяна хаоса и Тохiрrоху-полезные инструменты для тестирования хаоса.
•
Используйте матрицу отказоустойчивости для подготовки к экспериментам
с хаосом.
♦ Применяйте передовые методы для решения проблемы тестирования внутрен
него состояния:
•
Генерирование синтетических данных.
•
Тестирование интерфейсов.
•
Настройка тестовых данных.
•
Макетирование интерфейсов.
ГЛАВА
8
Внедрение
'-.#
новых технолоrии
Любая достаточно продвинуrая технология неотличима от магии.
Артур К. Кларк
Все не так! Компании боятся новых технологий, разочарованы неудачными попыт
ками миграции или напуганы страшными историями других организаций. В вашей
компании то же самое? Страх управляет принятием решений. Мы никогда не
должны позволять страху руководить нами и контролировать нас.
Что, если бы мы сказали вам, что все может быть по-другому, и все это может из
мениться к лучшему? Бизнес может обладать новыми возможностями, дифферен
цированностью и инновациями, предоставлять своим клиентам потрясающий опыт
и решения. Сотрудники вашей технологической организации могут быть вооду
шевлены, с радостью приходить в офис, предвкушая новые проекты и возможно
сти. Каждый может занять свое место под солнцем.
Ответ заключается в освоении новых технологий. Не позволяйте страху руководить
вашей организацией и контролировать ее. С вашей точки зрения это может пока
заться невозможным, но вас ждет удивительная вселенная возможностей
-
мир,
где рефакторинr обладает не большей гравитацией и массой, чем Марс. Новые тех
нологии
-
это как новый источник энергии в вашей организации, они мотивируют
людей, заставляют инженеров выполнять больше задач и просыпаться утром бод
рыми, чтобы идти на работу.
Структура главы
В данной главе мы рассмотрим следующие темы:
♦
Применяем новые принципы.
♦
Ресурсы по требованию
-
облачные вычисления.
•
Стабильные контракты.
•
Надлежащая изоляция.
•
Одна учетная запись на сервис.
•
Одна учетная запись для каждой бизнес-области.
Внедрение новых технологий
♦
♦
■
•
Одна учетная запись для всего.
•
Организация учетных записей влияет на степень детализации контрактов.
•
Внутренние общие библиотеки.
•
Бессерверность.
•
Влияние облака на организацию работы команды.
Готовые возможности
-
облачные сервисы и
349
SaaS.
•
Реляционные хранилища данных и хранилища данных
•
Искусственный интеллект и аналитика.
NoSQL.
Изолированные модули развертывания.
•
Контейнеры и
•
Облачный спектр.
Kubemetes.
♦ Доступ к потоковой передаче данных в режиме реального времени.
• Apache Kafka.
•
Архитектура
• Kafka
•
♦
♦
♦
и
Kafka.
CQRS/ES.
База данных
ksqlDB.
Эффективные инженеры.
•
Современные языки программирования.
•
Спектр языков программирования.
•
Языки программирования
NM.
Гибкие модели данных.
•
Базы данных
•
Выход за рамки реляционной модели.
NoSQL.
Бережливые коммуникации
-
бинарные
API
и
GraphQL.
•
Взаимодействие между сервисами:
•
Что в
•
Совместимость в сравнении с производительностью.
REST
REST, gRPC
и
GraphQL.
получилось правильным.
• GraphQL.
•
♦
Фреймворк
gRPC.
Что нужно запомнить.
Применяем новые принципы
Ваш прекрасный новый мир не дается бесплатно. Используя принципы, которым
мы вас научили, вы можете быстро и безопасно внедрять новые технологии и полу-
350
■
Глава В
чать беспроигрышную выгоду как для бизнеса, так и для технологических подраз
делений вашей организации. Попытки использовать новые технологии с непра
вильными
принципами
-
это
именно то,
что
ведет к
созданию
распределенных
монолитов. И хотя освоение нового увлекательно, это требует должной осмотри
тельности, тщательного планирования и анализа компромиссов.
Мы посвятили большую часть этой книги тому, чтобы показать вам, как классиче
ские и распределенные монолиты сдерживают вас. Современные архитектуры нуж
даются в изоляции, производительности и использовании новых идей и техноло
гий. Архитектура программного обеспечения находится в центре внимания. Пра
вильный
выбор
и
грамотное
внедрение
новых
технологий
открывают
новые
возможности для ваших команд и клиентов. Неправильная архитектура приведет
к увольнению хороших сотрудников и страданиям потребителей.
Наше послание: создавайте правильную современную архитектуру и надлежащие
сервисы, наилучшим образом использующие новые технологии. Это настоящее зо
лото. Двери откроются для вас.
Давайте начнем!
Ресурсы по требованию
облачные вычисления
Облачные вычисления
-
-
это гораздо больше, чем просто чей-то сервер,
-
это аб
стракция. Они превращают оборудование, такое как серверы, стойки, коммутаторы,
концентраторы, сети, хранилища и центры обработки данных, в программное обес
печение, доступное и защищенное с помощью
API.
Облачные вычисления облада
ют следующими свойствами:
♦
Автоматизация.
ния,
API, CLI
вычислений,
и SDК-пакеты буквально для всех функций: хране
создания
сетей,
обеспечения
безопасности,
контейнеров,
кешей и баз данных.
♦ Гибкость. Быстрое масштабирование во время пакетного трафика и снижение
масштабирования, когда ресурсы больше не нужны.
♦
Модель самообслуживания. Ваши инженеры имеют все возможности, а веб
консоль и АРI-интерфейсы готовы к использованию в любое время.
♦
Несколько моделей выставления счетов. Расширенные инструменты выстав
ления счетов без необходимости заключения сложного контракта; просто введи
те свою кредитную карту. Большинство облачных провайдеров предлагают не
сколько моделей оплаты. Вы можете платить по мере поступления, например
при использовании ресурсов по запросу и в бессерверной архитектуре. Или вне
сти предоплату и получить скидки при бронировании. А если вам нужно меньше
ресурсов, можно выбрать точечные инстансы и платить меньше.
♦ Надежность. Достижение высокой доступности благодаря нескольким уровням
масштабирования и изоляции: развертывание нескольких экземпляров или в не
скольких зонах доступности, регионах и учетных записях.
Внедрение новых технологий
♦ Глобальное присутствие. Облачные регионы и точки присутствия
presence,
■
351
(point of
РОР) по всему миру с расширенными возможностями сетевого пиринга
в сетевых концентраторах.
♦
Управляемые сер висы. Автономные операции с базами данных, кешами, со
общениями, платформами управления контейнерами и другими критически
важными компонентами.
Облачные вычисления меняют правила игры. Каким образом эти технологии обес
печивают такие удивительные возможности? Если вы внимательно читаете эту
книгу, то, вероятно, догадываетесь об одном ключевом компоненте: изоляции.
Базовые сетевые технологии, средства управления и передачи данных, обеспечи
вающие работу этих систем, предоставляют уровень безопасной многопользова
тельской работы, который редко можно бьmо увидеть до появления поставщиков
облачных вычислений 1 .
Ваша команда может создавать необходимые сервисы где угодно
-
в облаке. Однако они будут более эффективными, работая в облаке.
Services (AWS)
локально или
Amazon Web
является ведущим игроком в области облачных вычислений. На
сегодняшний день доступно более
200
сервисов. Основными сервисами А WS
являются:
♦
ЕС2. Для виртуализированных серверов.
♦
EBS.
♦
S3.
Блочное хранилище.
Высокомасштабируемое и надежное хранилище объектов. Даже если вы не
используете другие облачные сервисы, SЗ настолько полезен, что может играть
важную роль во многих архитектурах программного обеспечения.
♦
Сервис реляционных баз данных
(Relational Database Service, RDS). Сервис
MySQL, Postgres, Oracle и SQL Server.
данных, совместимая с АРI-интерфейсами MySQL и
управления базами данных для
♦
♦
Aurora. Облачная база
Postgres.
Lambda. Бессерверная функция
как сервис
(Function as
а
Service, FaaS)
с под
держкой нескольких языков.
♦
ElastiCache. Сервис управления
кешем для
♦
CloudFront. Высокоскоростная
CDN) с низкой задержкой.
сеть доставки
♦
Route53.
♦
SQS/SNS. Сервисы обмена сообщениями и организации очередей с фирменным
API AWS.
Kinesis. Платформа потоковой передачи данных, разработанная специально для
А WS. Kinesis является конкурентом Apache Kafka.
♦
1
Сервис управления
Redis
и
Memcached.
контента (content delivery network,
DNS.
На основных сессиях А WS re:Invent вы сможете получить самое полное представление об аппаратных и
программных инновациях, лежащих в основе современных облачных сервисов, и все они находятся в сво
бодном доступе на У ouTube. Настоятельно рекомендуем сессии Вернера Фогельса:
https://www.youtube.com/гesults?seaгch_ queгy=aws+гeinvent+keynote+playlist.
352
♦
■
Глава В
-------------------------------
ЕМR. С:рвисы управления
данными, таких как
Hadoop
♦
ECS/ECS. У правление
в Kubemetes.
♦
EFS.
♦
IAM.
♦
map/reduce
Spark.
для размещения проектов с большими
и
контейнерами и оркестровка, при этом
Поддержка сетевой файловой системы, совместимой с
размещается
EKS
CIFS
и
NFS.
Системы управления доступом для контроля безопасности инфраструктуры.
КМS. Управление ключами, изначально интегрированное во многие сервисы
А WS, поддерживающее симметричную и асимметричную защиту ключей.
Облачные вычисления и А WS
-
это здорово, но у них, как и у любой другой тех
нологии в архитектуре программного обеспечения, есть свои недостатки.
♦
Стоимость. Облачные технологии не бесплатны, и в долгосрочной перспективе
легко потратить больше, чем планировалось. Оптимизация затрат
постоянная
-
борьба, особенно в больших масштабах. Имейте в виду, что А WS может заме
нить штатный персонал, который бы управлял вашими центрами обработки
данных. Бесплатных услуг не предусмотрено.
♦
Привязка к поставщику. Хотя некоторые сервисы
ные
API,
AWS
многие инструменты являются проприетарными
ко можно
использовать открытые стандарты
имитируют стандарт
(SNS/SQS,
и технологии с
SЗ). Одна
открытым
ным кодом. Это позволит избежать использования проприетарных
API
исход
и серви
сов. Но их поддержка также будет сопряжена с затратами.
♦
Слишком много вариантов. Легко потеряться в море сервисов и разобраться
в нюансах всех возможных альтернатив. Нужно многому научиться.
Проблемы безопасности и инженерного обеспечения: при наличии всех этих воз
можностей ваша организация, скорее всего, отреагирует молниеносно, заблокиро
вав все угрозы! Отделы информационной безопасности настаивают на обеспечении
безопасности, часто реализуемой командами
DevOps.
Это, как правило, ограничи
вает возможности, сервисы и даже стили архитектуры, чтобы избежать ошибок
в системе безопасности. Хотя
DevOps
помогает предотвратить ошибки в области
безопасности и автоматизации, такие ограничения снижают скорость работы инже
нерных команд. Побочный эффект очевиден: разработка замедляется, поскольку
для каждой новой технологии требуются гейткиперы и централизованная разработ
ка. Инженерам может показаться, что облако управляется как центр обработки дан
ных, практически без гибкости, что тормозит внедрение инноваций.
На протяжении всей книги мы подчеркивали важность трех ключевых концепций
в современных архитектурах: изоляции, стабильных контрактов и экономичных
библиотек. Давайте вернемся к этим ключевым принципам построения надлежа
щих сервисных архитектур, но теперь в контексте облака. Принципы останутся
прежними, но соображения изменятся.
Стабильные контракты
Публичные стабильные контракты (StaЫe
contracts)
остаются абсолютной необхо
димостью для любой масштабируемой архитектуры программного обеспечения,
Внедрение новых технологий
■
353
особенно в облаке. Независимо от физической организации, контракт представляет
собой жесткую границу, отделяющую интерфейс от реализации. Пока все ваши
публичные контракты доступны через АРI-шлюз или аналогичный метод, вы може
те использовать любой сервис А WS, и он будет скрыт от пользователей. Публич
ные контракты с частными реализациями приносят огромную пользу, т. к. теперь
команды могут использовать более
200
сервисов А WS, и это будет полностью про
зрачно для потребителей.
Помните, что публичные контракты не означают, что учетные записи или контрак
ты предоставляются клиентам напрямую.
Стабильные контракты
-
это один из способов обеспечить изоляцию между про
граммными компонентами. Но, как мы видели на примере распределенных моно
литов, существует множество способов нарушить изоляцию: прямое обращение
к базам данных вместо использования контрактов, совместное использование сер
висов управления и многие другие темы, рассмотренные в главе
2
«Антипаттер
ны: отсутствие изоляции». Контракт должен быть главным; стабильные контрак
ты
-
это наша основа, а инфраструктура должна поддерживать изоляцию для пре
доставления надлежащих сервисов и принудительного использования стабильного
контракта.
Ваша инфраструктура также может влиять на степень детализации вашего контрак
та, но, чтобы полностью понять эту концепцию, вам необходимо понимать, как
изоляция лучше всего реализуется в облачных архитектурах.
Давайте рассмотрим это подробнее.
Надлежащая изоляция
Изоляция необходима для облачных вычислений. Как мы цитировали технического
директора
AWS
Вернера Фогельса в главе
7
«Надлежащее сервисное тестирова
ние»: «Сбои происходят все время». В основе облачных технологий лежит приме
нение нескольких уровней физической и сетевой изоляции для обеспечения много
пользовательской работы и масштабирования. Эти системы предоставляют множе
ство способов прямой изоляции технологий. (В качестве примера мы используем
AWS.)
♦
Несколько инстансов и сегментированное хранилище. Запустите свое про
граммное обеспечение на нескольких инстансах или контейнерах ЕС2; создайте
кластер баз данных на нескольких узлах и распределите данные по нескольким
томам
EBS
или даже по SЗ, который обладает собственными уникальными
гарантиями отказоустойчивости.
♦
Несколько зон доступности. В каждом физическом регионе есть несколько зон
доступа, которые, как правило, представляют собой физически разделенные
центры обработки данных со своими собственными выделенными сетями, сис
темами электропитания и кондиционирования воздуха. Благодаря тому, что ва
ши экземпляры развернуты в нескольких зонах доступа, в случае сбоя в работе
одной из них ваша система продолжит функционировать.
■
354
♦
Глава В
Несколько регионов. Что делать, если ключевое сетевое соединение разорвано
или все физическое местоположение скомпрометировано? Вы можете запускать
сервисы и хранить данные в разных физических регионах. Полностью мультире
гиональная архитектура актив-актив стоит дорого, но может обеспечить высо
кую скорость работы для клиентов по всему миру. Новые технологии
NoSQL
и
сервисы А WS позволяют создавать безопасные распределенные хранилища дан
ных, которые пересекают границы физических регионов.
♦
Несколько учетных записей. Помимо простого отделения непроизводственно
го
доступа
от
производственного,
вы
можете
развертывать
решения
для
не
скольких учетных записей для обеспечения безопасности или организационной
изоляции. Вскоре мы обсудим более сложные сценарии.
♦
Наличие нескольких облачных провайдеров
/
центров обработки данных.
Зачем ограничиваться только А WS? Решения для управления контейнерами по
зволяют абстрагироваться от базовых технологических принципов, не связанных
с оборудованием и/или облачными провайдерами. Даже простое хранение ре
зервных копий у другого облачного провайдера или в центре обработки данных
может стать преимуществом изоляции . Вы также можете захотеть использовать
несколько облачных провайдеров для доступа к технологиям , уникальным для
того или иного облачного провайдера.
Большинство из этих облачных решений обеспечивают изоляцию с целью обеспе
чения доступности; наличие нескольких учетных записей
-
это способ для органи
заций добиться изоляции с точки зрения технологических решений и команд. Ком
пании довольно часто имеют несколько облачных учетных записей. Это как мини
мум
2-3
учетные записи:
1
для производственных и
2
для непроизводственных
целей; или учетные записи для разных продуктов или бизнес-подразделений. Но
некоторые компании идут еще дальше.
Disney streaming (Hulu, Disney, ESPN и Starz) поделились своим опытом работы
с А WS с несколькими учетными записями А WS на конференции А WS re:Invent
2022, рассказав об опыте работы с данными с использованием А WS в контексте
А WS EMR. В то время Disney активно управляла более чем 100 аккаунтами А WS
(рис. 8.1).
Всего
Категория
Учетные записи
~100
AWS
Используемые сервисы
50+
AWS
Команды , использующие платформу
~20
15+
Бизнес-структуры,
Disney+, ESPN+,
выполняющие рабочие нагрузки
Hulu
Размер хранилища
Рис.
8.1.
Потоковые сервисы
Источник:
Disney:
более
петабайт
100 аккаунтов AWS.
https:/lwww.youtube.com/watch?v=y1 pOBGsPxvw
Внедрение новых технологий
Крупнейший банк Бразилии называется ОТ AKU
■
(https://www.itau.eom.br/),
355
и он
расширяет возможности управления учетными записями в А WS. 1Т AU подели
лась своими удивительными преобразованиями во время презентации на А WS
re:lnvent 2022
записями (рис .
в Лас-Вегасе, показав, как они управляют более чем
5000
учетными
8.2).
Учетная запись
в Интернете текущая архитектура
Рис.
8.2.
Disney
ITAU на re:lnvent 2022 - 5 тысяч учетных записей AWS.
https://www.youtube.com/watch?v=0oakxhLxue8
Презентация
Источник:
и 1Т AU показывают вам пределы того, что вы можете сделать с инфраструк
турой учетных записей А WS. На практике представьте, сколько учетных записей
вы можете выбрать в своей облачной инфраструктуре, сопоставленной с вашей
бизнес-архитектурой (рис.
8.3),
где у вас может быть:
♦
по одной учетной записи на сервис;
♦
одна учетная запись для каждой бизнес-области;
♦
одна учетная запись для всего.
Давайте рассмотрим эти варианты подробнее.
Много
Несколько
Одна
учетных записей
учетных записей
учетная запись
◄
Рис.
1
Одна учетная запись
Одна учетная запись
Одна учетная запись
на сервис
на бизнес-область
для всего
8.3.
Спектр облачных учетных записей в зависимости от технологии
Одна учетная запись на сервис
Облако позволяет легко добиться изоляции: у вас нет причин обмениваться базами
данных между сервисами в процессе производства, и лучшие компании изолируют
356
Глава В
■
ВСЕ, что могут, используя все имеющиеся в их распоряжении инструменты, осо
бенно учетные записи.
♦
Не предоставляйте общий доступ к кластерам управления сервисов. Убеди
тесь, что у каждого сервиса есть свой собственный изолированный и выделен
ный кластер. Например, не предоставляйте общий доступ к кластерам
Aurora
MySQL.
♦
На случай сбоя. Инвестируйте в хаотическое тестирование, чтобы протестиро
вать свою инфраструктуру.
♦
Автоматизация приносит свои плоды. Благодаря облаку, если у вас хорошая
автоматизация, гораздо проще добиться масштабирования «по требованию» и
поддерживать новые, инновационные способы тестирования вашего программ
ного обеспечения. Например, можно протестировать его в рабочей среде, создав
кластеры скрытого трафика с помощью автоматизации . Это позволит легко соз
давать необходимое количество кластеров.
♦
Множество возможностей изоляции. Облако А WS позволяет достигать других
уровней изоляции с помощью учетных записей .
В крайнем случае, у вас может быть один сервис на учетную запись.
На рис.
8.4
показан простой пример надлежащего сервиса, работающего в А WS.
Код сервиса профилей может выполняться в любом компьютерном сервисе, таком
как ЕС2,
ECS/ECS
для контейнеров или даже в бессерверном режиме. При этом он
имеет простую базу данных
Aurora
или
RDS MySQL.
В примере с одной учетной
записью для каждого сервиса все эти ресурсы изолированы в рамках одной учетной
записи
AWS,
без каких-либо подключений к виртуальной сети с какой-либо другой
учетной записью.
Учетная запись сервиса профилей
Контракт
EKS
k8s или без сервера ...
Работает на ЕС2,
с
Реализация
сервиса профилей
БДпрофилей
на
Рис.
8.4.
MySQL
Кластер
Aurora/RDS Claster
Облачная изоляция: один сервис на учетную запись
Одна учетная запись сервиса может показаться экстремальной, но архитектура
А WS это полностью поддерживает. Схема «один сервис для каждой учетной запи
сю> позволяет сервисной команде полностью владеть всеми элементами своего соб-
Внедрение новых технологий
ственноrо сервиса и управлять ими, от кода до инфраструктуры доступа
-
■
357
распро
страненная в Кремниевой долине схема под названием «Вы ее создаете, вы ее и за
пускаете». Недостатком этого подхода является большое количество учетных запи
сей: при наличии
200
сервисов вы легко получите
400
учетных записей, если отде
лите тестовую среду от продуктивной.
Один сервис для каждой учетной записи обеспечивает максимальную гибкость для
сервисной команды в отношении того, как они хотят реализовать свой сервис
(рис.
8.5).
Контракт может быть доступен через АРI-шлюз или совместно использо
ваться между учетными записями с помощью
AWS Private Link.
Учетная запись
А WS обеспечивает жесткую границу вокруг вашего сервиса, недоступную для
внешних пользователей, где вы можете использовать любое хранилище баз данных:
RDS, Aurora, Redis
или SЗ.
.. . . . . . . . . . . . .
Контракт
АРl-шлюз
AWS
Контракт
с,..,,
€/мf;Сцl.,
Реализа ци я
R,,1;,
сервиса профилей
изображени •
MySQL
Рис.
8.5.
EKS с k8s
Хранилище
БДпрофилей
на
Работает на
профилей
Надлежащие контракты в облаке
-
использование одного сервиса для каждой учетной записи
При таком количестве учетных записей и ресурсов автоматизация является абсо
лютной необходимостью. Потребуется много усилий, чтобы предоставить доступ
к сервисам
и наладить сетевое взаимодействие,
но
преимущество заключается
в максимальной изоляции. Стоимость также становится прозрачной: любые затра
ты, связанные с этой учетной записью, могут быть четко распределены на конкрет
ную команду.
Что произойдет, если сервис устареет? Самым простым подходом было бы заархи
вировать данные в А WS
Glacier
и просто удалить всю учетную запись целиком;
или, возможно, другой команде нужно будет воспользоваться этой учетной запи
сью, и теперь у них будут две учетные записи для управления.
358
■
Глава В
У большинства организаций есть главная или централизованная учетная запись для
обеспечения безопасности и решения задач по сборке/развертыванию. Чтобы этот
подход был практичным при использовании одного сервиса для каждой учетной
записи, вам потребуется возможность развертывания с несколькими учетными за
писями .
Одна учетная запись для каждой бизнес-области
Если такой подход кажется слишком экстремальным, вы можете снизить степень
детализации, выполнив сопоставление бизнес-областей. Можно использовать мо
делирование предметной области
(Domain Driven Design, DDD)
для группировки
учетных записей по бизнес-областям или организационным подразделениям, кото
рые совместно используются одним и тем же УРС и подотчетны одному и тому же
подразделению .
На рис.
показан пример одной учетной записи для каждой бизнес-области.
8.6
Организация определила область взаимодействия и назначила ей сервис профилей
и сервис продаж.
Учетная запись для бизнес-обпасти
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ..
Контракт
АРl-шлюз AWS
Контракт
Контракт
..,.
с
0мt;Си~,
14----t
t,,11,
Реализация
сервиса профилей
Работает
на EKS с k8s
Реализация
сервиса продаж
БД профилей
на
MySQL
Хранилище
зображени·
€lмt1e.,,,
t,,1,
профилей
БД продаж
на
Postgres
Aцr~ra/R.Df C/цrfer
.. . .
Рис.
Автоматизация
8.6.
Облачная изоляция: одна учетная запись на бизнес-область
по-прежнему
необходима .
Совместное
использование
бизнес
областей облегчает командам смену владельца без переназначения учетной записи.
Затраты по-прежнему можно просмотреть, обобщить и присвоить бизнес-подраз
делению. Более точные затраты в рамках бизнес-области по-прежнему можно по
лучить, используя распространенные методы, такие как маркировка ресурсов А WS.
При меньшем количестве учетных записей добиться полной изоляции становится
сложнее. Команды могут влиять на ресурсы друг друга из-за ошибочного разверты-
Внедрение новых технологий
■
359
вания или изменения конфигурации, что, очевидно, можно снизить с помощью
ролей
IAM,
но все равно представляет больший риск по сравнению с жесткими
границами учетной записи А WS. Кроме того, что произойдет, если ваша организа
ция изменит свой подход к бизнес-области или бизнес-организации? Вы пере
мещаете сервисы между учетными записями? Помните о том, что вы предлагаете
взамен.
Одна учетная запись для всего
Противоположный подход к управлению учетными записями заключается в том,
чтобы просто поместить все в одну учетную запись. По нашему опыту, это состоя
ние используется по умолчанию, и наша отрасль рекомендует использовать его но
вым пользователям облачных технологий. У компаний может быть разделение на
непроизводственный и производственный сегменты или, возможно, еще несколько
учетных записей, чтобы отделить сервисы, ориентированные на клиента, от воз
можностей автономной аналитики, но на этом все.
Риск того, что команды будут влиять друг на друга, высок, и поэтому сейчас орга
низации хотят централизовать
DevOps,
устанавливая гейткиперов, чтобы избежать
ошибочных воздействий, как в центрах обработки данных. Одно из преимуществ
заключается в том, что сервисам легко менять владельцев, поскольку инфраструк
тура не имеет четких границ. Несмотря на то что вы всё еще можете добиться изо
ляции с помощью групп безопасности, тегов и ролей
IAM,
гораздо проще допус
тить ошибку, сложнее отследить затраты, и при плохом управлении сервисы будут
напрямую взаимодействовать с базами данных друг друга.
Организация учетных записей
влияет на степень детализации контрактов
Очень тонкий момент, который необходимо понять, заключается в том, как количе
ство ваших учетных записей
(рис.
8.7).
может влиять на детализацию ваших контрактов
В каждом случае ваши сервисы должны быть доступны с помощью АРI
шлюза, и, с точки зрения стороннего наблюдателя, они видят только один публич
ный контракт, который предоставляет АРI-шлюз. Итак, если у вас есть один сервис
на учетную запись, вы достигли минимально возможной степени детализации и
предоставляете по крайней мере один публичный контракт на каждый сервис.
Количество
(-)
Степень детализации
Рис.
8.7.
Дизайн вашей облачной учетной записи влияет на степень детализации ваших контрактов
Если у вас есть одна учетная запись на бизнес-область, все ее сервисы используют
этот АРI-шлюз совместно. Для внешнего мира вы представляете более крупный
контракт с более высокой степенью детализации. Несмотря на то что у этой учет-
360
■
Глава 8
ной записи есть несколько сервисов, с точки зрения стороннего наблюдателя, вы
можете рассматривать ее как единый публичный контракт. У вас есть абсолютная
изоляция, а все облако
можете изменить
количество сервисов с
сервисы в бессер
- это ваша внутренняя реализация. Вы
5 на 1О; вы можете преобразовать все свои
верные функции. Пока этот АРI-шлюз обеспечивает обратную совместимость кон
тракта, вы можете делать все, что хотите. Но теперь у вас под рукой вся мощь об
лака, а не только один Jаvа-сервис для выполнения изменений. По сути, мы расши
ряем
концепцию
сервис-ориентированной
архитектуры.
Теперь
вместо
одного
сервиса у вас есть целая учетная запись, с помощью которой вы можете реализовы
вать свои проекты.
При попадании в другую крайность, когда все данные хранятся в одной учетной
записи, вся эта концепция рушится
-
все видят всё, поэтому возникает хаос, но
сила заключается в том, что вы правильно группируете сервисы в одной учетной
записи на нужном уровне детализации для вашего бизнеса или технической орга
низации.
Внутренние общие библиотеки
Единственное, что хотелось бы ограничить,
-
это ваши внутренние общие библио
теки. У вас есть доступ ко всем потрясающим облачным сервисам общего доступа
и практически бесконечно масштабируемому оборудованию: вы можете пересчи
тать свои внутренние общие библиотеки по пальцам одной руки. Пять
-
произ
вольное число, но мы считаем, что оно должно быть как можно меньше. Чем мень
ше внутренних общих библиотек, тем лучше.
Важно иметь в виду, что облачные сервисы часто состоят из двух элементов:
API,
SDK, который может быть доступен для многих язы
ков, таких как Java, Go, Rust, Python, TypeScript и многих других. К сожалению,
А WS SDK на Java используют распространенные Jаvа-библиотеки, такие как Guava
и Jackson, и нарушают наш принцип экономичного использования библиотек. По
думайте хорошенько и постарайтесь избегать использования больших AWS SDK,
часто
REST
с JSONIXМL, и
чтобы упростить процесс миграции.
Если у вас есть одна учетная запись для всего, внутренние общие библиотеки пред
ставляют риск. Они могут взаимодействовать с общими базами данных и общими
управляемыми
сервисами,
что
приводит
к
созданию
распределенного
монолита.
Если у вас есть одна учетная запись для каждого сервиса или для каждой бизнес
области, вы в некоторой степени защищены; каждая библиотека, скорее всего, мо
жет получить доступ к сервисам только из своей учетной записи, что ограничивает
потенциальный ущерб. Однако в большинстве этих сред есть инфраструктура с не
сколькими учетными записями, такая как платформа или учетная запись
DevOps,
для развертывания или наблюдения. Следите за тем, чтобы это не заманило вас об
ратно в распределенный монолит, создав суперглобальную библиотеку с несколь
кими учетными записями, которая разрушит изоляцию.
Внедрение новых технологий
■
361
Бессерверность
Бессерверные вычисления выходят за рамки абстрагирования сервисов; они полно
стью абстрагируют аппаратное обеспечение и операционные системы и позволяют
абстрагировать саму языковую среду выполнения, используя бессерверный дви
жок, т. е. А WS
(рис.
Lambda
8.8).
Бессерверная работа проще для инженерных
групп, где вам не нужно, например, исправлять бессерверную функцию или беспо
коиться об обновлениях
JDK.
Бессерверная работа дает вам прекрасную возмож
ность экспериментировать с другими языками. Бессерверность также хороша, если
вам нужно полностью изолировать стек/решение от остальной части вашего облака
или сетевой платформы, например, если вам нужно разработать стек, совместимый
с
PCI.
Потребитель
Потребитель (сервис)
Написан на
(интерфейс пользователя)
Java
Написан на
Язы ковая среда выполнения
Контракт
дважды абстрагируется , используя :
Бессерверная
реализация профилей
Написана на
Рис.
8.8.
Typescript
+ Бессерверный движо к
+ Контра кт SOA
Go
Язык программирования абстрагирован для потребителей
Вам не нужен сервер, чтобы экспериментировать с новыми технологиями или язы
ками. Стили архитектуры
SOA
и микросервисов могут позволить вам использовать
разные языки: граница сервиса защищает реализацию, лежащую в основе унифи
цированного интерфейса, и вы можете использовать простые протоколы, такие как
l/2/3, REST и JSON . Давайте внесем ясность: немногие организации могут
поддерживать 100 языков программирования, это сложно, но большинство средних
и крупных организаций могут легко поддерживать 3--6 языков. Далее в этой главе
НТТР
мы рассмотрим поддержку нескольких языков.
Как и все остальное в архитектуре программного обеспечения, бессерверность име
ет свои недостатки:
♦
Технические ограничения. На самом деле, бессерверность имеет серверы, но
они абстрагированы от вас; это одновременно и преимущество, и ограничение,
поскольку вы не можете в полной мере использовать возможности сервера: вы
не
можете сохранять данные
в
памяти
в течение длительного
времени,
вы
не
можете безопасно хранить данные в файловой системе между выполнениями.
Некоторые из этих пробелов и многое другое рассмотрено в статье: «Бессервер
ные вычисления: один шаг вперед, два шага назад» 2 .
2
Бессерверные вычисления: один шаr вперед, два шага назад: https://arxiv.org/abs/1812.03651.
362
♦
■
Глава В
Внешнее состояние и риск нарушения изоляции. Поскольку вы не можете
эффективно поддерживать локальное состояние с помощью бессерверных архи
тектур, вам придется полагаться на внешние сервисы. Использование большего
количества облачных сервисов увеличит потребление облачных ресурсов и
усложнит процесс
обеспечения
надежности.
В результате
может появиться
больше библиотек и сервисов, что подвергнет вас большему риску нарушения
изоляции.
Влияние облака на организацию работы команды
Большое преимущество облака в преобразовании заключается в том, что оно по
зволяет разместить программное обеспечение в центре вашей инфраструктуры, а не
наоборот. Времена, когда требовалась отдельная команда администраторов для
управления парком серверов под строгим контролем, ушли в прошлое. Теперь нет
нужды и в центральной команде архитекторов, которая бы диктовала, как разре
шается создавать и расширять архитектуру программного обеспечения, учитывая
физические ограничения и структуру команды.
Вместо этого инфраструктура может трансформироваться и изменяться в соответ
ствии с требованиями вашего сервиса. Сервис управляет инфраструктурой. Струк
тура команды также должна измениться. Вам не нужен централизованный
вам нужен включенный в состав команды
DevOps,
Ops3 ,
предоставляющий помощь, ре
комендации и непосредственно помогающий команде писать скрипты
Pulumi
и
предоставлять облачную конфигурацию. В результате получается мощная кросс
функциональная команда, которая использует все преимущества, необходимые для
создания ценности для бизнеса, и одним из таких преимуществ является изменяе
мая мощь облачной инфраструктуры. Вам нужны разработчики в этой кросс
функциональной команде, готовые приложить все усилия, чтобы адаптировать об
лако к потребностям вашего сервиса.
Давайте внесем ясность: это не приглашение к хаосу. Ни одна организация не мо
жет поддерживать соотношение в
30 языков
1О
инженеров,
20
независимых баз данных и
программирования. Ограничивающим ресурсом здесь является не ин
фраструктура, а люди и плотность квалифицированных специалистов в вашей
организации. Еще раз: принимайте новое, руководствуясь принципами, и мы при
держиваемся пословицы «Выбирайте скучные технологии»4.
Готовые возможности
облачные сервисы и
SaaS
Масштабировать программное обеспечение непросто. Дело не только в наличии
правильной инфраструктуры, но и в наличии правильной архитектуры программ-
3
Ops -
это практика управления и поддержания технологической инфраструктуры орrани1ации. Она
- Пер.
включает в себя всё: от оборудования и программного обеспечения до сетей и ба, данных.
4
Просмотрите любой из разделов книги «Выбирайте скучные технологии». посвященных творчеству Дэна
Маккинли: https://boringtechnology.cluЫ.
Внедрение новых технологий
■
363
ноrо обеспечения и нужных людей для ее создания и эксплуатации. Благодаря
открытому исходному коду масштабировать программное обеспечение сегодня на
много проще, чем
20
крытые
характеристики
решения,
лет назад. У нас есть распространенные, опубликованные, от
которых очень хорошо
известны
и
понятны,
а
также многочисленные примеры компаний, использующих их для предоставления
потрясающих бизнес-возможностей.
Имея такую основу, именно здесь могут пригодиться облачные сервисы и SааS
провайдеры. Вместо того чтобы искать и нанимать команды, обладающие таланта
ми и навыками для масштабной работы с программным обеспечением, облачные
управляемые сервисы могут обеспечить практически идеальную настройку, ис
пользуя лучшие практики и встроенное масштабирование в облаке. Хотя в некото
рых случаях это вызывает некоторые споры
-
посмотрите дебаты о том, не подав
ляют ли крупные облачные провайдеры небольшие компании, которые внедряют
настоящие инновации и просто подпитываются сообществом разработчиков с от
крытым исходным кодом, не отдавая ничего взамен
-
без сомнения, потребители
получают прямую выгоду, получая доступ к хорошо настроенным сервисам, кото
рые просто работают и масштабируются в соответствии с нашими требованиями,
системы, готовые к использованию.
Реляционные хранилища данных
и хранилища данных
NoSQL
Зачем утруждать себя выяснением того, как запустить базу данных в масштабе, ко
гда ваше облако может сделать это за вас? Сократите количество специалистов по
эксплуатации, которых необходимо нанять в вашей компании, и направьте эти
ресурсы на решение бизнес-задач. Вы можете положиться на своего поставщика
облачных сервисов или вспомогательную компанию в вопросах поддержки слож
ных сценариев или отладке.
Давайте рассмотрим неполный список сервисов облачных управляемых баз дан
ных, ориентированных на А WS; многие другие доступны от SааS-компаний или
напрямую через магазин
AWS.
Далее в этой главе мы также представим больше
идей по созданию баз данных.
♦
RDS. Amazon будет напрямую запускать вашу базу данных и управлять ею
с помощью RDS. RDS поддерживает определенные версии MySQL, Postgres,
SQL Server и Oracle и справляется со многими распространенными операцион
ными задачами, такими как создание экземпляров, развертывание в нескольких
зонах доступа, внесение исправлений, масштабирование, наблюдение, монито
ринг и резервное копирование, при этом командам не приходится и пальцем ше
велить. Используя А WS
Outposts5,
вы даже можете запустить
RDS
в своем соб
ственном центре обработки данных!
5 А WS
Outposts предоставляет локальные компьютеры, которые имитируют ограниченную среду А WS:
https://aws.amazon.com/outposts/.
364
♦
■
Глава В
Aurora.
Помимо простого размещения баз данных,
ет более облачную реализацию баз данных
вышение производительности в
3-5
Amazon Aurora предоставля
MySQL и Postgres, обеспечивая по
раз при той же стоимости/размере экземп
ляра, а также расширенные функции, такие как автоматическое создание реплик
для чтения, глобальное развертывание баз данных в регионах и бессерверное
развертывание.
♦
Spanner. Google Spanner (https.1/cloud.google.com/spanner/) - это совершенно
новый тип базы данных от Google, но доступный через знакомый Postgres API.
Spanner предоставляет многорегиональную глобальную базу данных с широким
горизонтальным масштабированием операций чтения и записи, но при этом со
храняет сильные
ACID
♦
♦
реляционные свойства, соответствие строгим требованиям
и упорядоченность 6 •
DynamoDB. А WS DynamoDB - это сервис баз данных с ключами и значе
ниями. DynamoDB одно из основополагающих хранилищ NoSQL. Dynamo
paper от Amazon (https.//www.allthingsdistributed.com/files/amazon-dynamososp2007.pdt) заложил основу для многих других баз данных с открытым исход
ным кодом, таких как Cassandra.
Cassandra. Cassandra -
это столбчатая база данных с открытым исходным ко
дом, но она полностью поддерживается
DataStax,
которая предоставляет как от
крытый исходный код, так и коммерческую ветвь
Cassandra. У DataStax также
Cassandra, Astra, который может быть
развернут в нескольких облаках: А WS, GCP и Azure. У Amazon также есть управ
ляемый сервис, совместимый с API Cassandra, который, по сути, является просто
API поверх DynamoDB. Несмотря на то что он был запущен без полной совмес
тимости с API, управляемая Cassandra от Amazon быстро набирает обороты.
есть собственный управляемый сервис
♦ Потоковая передача данных. Компания
Linkedln Apache Katka
была пионером
в области архитектуры управления событиями с открытым исходным кодом.
Confluent (https.//www.contluent.io/) предоставляет коммерческий дистрибутив
Katka, который работает на всех основных облачных провайдерах. После Katka
у Amazon появился собственный сервис потоковой передачи данных Amazon
Kinesis, но Amazon также располагает собственным управляемым сервисом
Katka.
♦
Поиск.
ElasticSearch -
одна из ключевых поисковых технологий
NoSQL,
от
лично подходящая для текстового поиска, обеспечения безопасности, ведения
журнала и обеспечения наблюдаемости, поддерживаемая собственной компани
ей
(https://www.elastic.co/). Elastic Cloud предоставляет размещенную среду
ElasticSearch на А WS, GCP или Azure с полной поддержкой и расширенными
функциями, предназначенными только для коммерческих пользователей. Как
мы уже говорили ранее,
Amazon имеет собственный
форк
ElasticSearch, OpenSearch,
а также предоставляет управляемый сервис.
6
Статья Google Spanner также представляет собой замечательное руководство по принципам проектирова
ния распределенных баз данных:
https ://sta tic. google use rcon tent.com/media/resea гс h. goog le.com/en// а гс hive/s ра nneг-osdi2012. pdf.
Внедрение новых технологий
■
365
Искусственный интеллект и аналитика
Помимо сервисов по управлению базами данных, большинство облачных компаний
также
предоставляют расширенные возможности или поддерживают целые слож
ные рабочие процессы. Несколько примечательных примеров:
♦
ML/AI.
Облачные компании используют свой внутренний масштаб для предос
тавления
сконфигурированных ИИ-сервисов
предварительно
с добавленной
стоимостью, таких как преобразование речи в текст в реальном времени, преоб
разование текста в речь, поддержка чат-ботов, транскрипция, поддержка естест
венного языка, перевод, визуализация и генеративный ИИ 7 . Многие сер висы мо
гут быть настроены в соответствии с вашим собственным конкретным вариан
то~1 использования.
♦
Инфраструктура больших данных. Облачные провайдеры приложили значи
тельные усилия, чтобы полностью обеспечить жизненный цикл больших данных
и упростить использование программного обеспечения с открытым исходным
EMR (https://aws.amazon.com/emr/) для поддержки инфра
структуры Hadoop, Spark и Hive, а также поддержка хранилища с помощью
Apache Parquet (https://parquet.apache.org/) или ORC (https://orc.apache.org/) и
подцержка современных озер данных с помощью Apache Iceberg (https://iceberg.
apache.org/) и Hudi (https://hudi.apache.org/). GCP располагает одной из луч
кодом. В А WS есть
ших
инфраструктурных
rшатформ
обработки
для
Dataproc (https://cloud.google.com/dataproc)
и BigTaЫe
больших
данных
через
(https://cloud.google.com/
ЬigtaЫe).
♦
Рабочие процессы в области обработки данных. А WS
amazon.com/sagemaker/)
и
GCP Vertex
А1
Sagemaker (https://aws.
(https://cloud.google.com/vertex-ai)
предоставляют комrшексную среду для работы с размещенными записными
книжками и совместной работы, обучения моделям и вывода результатов в ре
альном времени с использованием готовых подходов или путем непосредствен
DHCP, и AWS более примитив
SaaS. Databricks (https://www.databricks.com/)
ного написания собственного кода и моделей. И
ны, но существуют альтернативы
предоставляет одну из лучших SааS-альтернатив для работы с данными, исполь
зуя технологии, размещенные на А WS или
GCP,
с открытым исходным кодом, а
также коммерческие пакеты, которые обеспечивают более высокую производи
тельность, чем обычные приложения с открытым исходным кодом или даже
облачные провайдеры, для решения обычных задач, а также отличную команду
поддержки.
Все эти технологии могут быть использованы полностью или частично в вашем
центре обработки данных уже сегодня или в рамках более масштабной инициативы
по модернизации. Что вас останавливает?
Список поддерживаемых продуктов часто меняется, поэтому для получения ссылок на отдельные продук
https://aws.amazoo.com/machioe-learoiog/aiservices/, GCP: https://cloud.google.com/products/ai/, Azure: https://azure.microsoft.com/en-us/solutioos/ai/.
7
ты обратитесь непосредственно к каждому поставщику. А WS:
366
■
Глава 8
Изолированные модули развертывания
Изоляция
-
это ключ к успеху, секрет эффективности технологии в изоляции; мы
не можем не повторять это снова и снова. Контейнеры
-
отличный способ расши
рить изоляцию ваших сервисов до более низкого уровня операционной системы,
но, конечно, они, в свою очередь, нуждаются в надлежащей инфраструктуре и сер
висах, которые можно использовать в полной мере. Мы коснулись контейнеров и
систем управления контейнерами, таких как
Kubemetes,
в г.юве
4
«Антипаттерны:
внутренние общие библиотеки»; давайте рассмотрим их более подробно.
Контейнеры и
Kubernetes
В программном обеспечении контейнеры позволяют объединить ваше приложение,
зависимости и требования к операционной системе в один независимый модуль
развертывания. Контейнеры
-
это старое изобретение, изначально разработанное
человечеством для хранения продуктов питания, но также используемое для хране
ния, упаковки и транспортировки (рис.
8.9)
Знаете ли вы, что согласно Википедии
стандартный стальной транспортировочный контейнер был создан в 1950-х годах
(https://en.wikipedia.org/wiki(Container)?
Рис.
8.9.
Контейнеры в виде бутылок из Кении. Источник:
https://en.wikipedia.org/wiki/Container
В 2013 году технологическая индустрия пережила аналогичную революцию, когда
Docker (https://www.docker.com/) выпустил свой контейнерный движок с откры
тым исходным кодом. Контейнеры в программном обеспечении - это стандартный
модуль, который упаковывает код приложения и зависимости, чтобы приложение
работало быстро и надежно. Точно так же, как эти большие металлические транс
портные контейнеры, но для программного обеспечения. Контейнеры
Docker
сами
по себе являются исполняемыми пакетами, которые можно запускать практически
в любой среде. Контейнеры обеспечивают некоторую степень изоляции приложе
ния от окружающей среды. По сути,
Docker
использует
LXC,
функции ядра
Linux,
Внедрение новых технологий
■
367
которые обеспечивают безопасность процессов и изолированность (пространства
имен и группы управления).
Контейнеры не являются виртуальными машинами
Виртуальные машины
System,
рис.
8.1 О).
это абстракции физического оборудования . Для каждой
-
вы
машины
виртуальной
(Virtual Machines, VM,
отправляете
ОС), поэтому образы
VM
операционную
всю
систему
(Operating
большие, и их запуск может занять много време
ни. Контейнеры занимают меньше места за счет прямого использования ресурсов
своего хоста. Вместо множества отдельных файлов в операционной системе они
используют многоуровневую файловую систему, где файлы контейнера объединя
ются с базовым образом.
В результате образы
меньше и загружаются гораздо быстрее
-
Docker
становятся значительно
всего за несколько секунд 8 .
Приложения в контейнерах
111111
Гостевая
Гостевая
Гостевая
операционная
операционная
операционная
система
система
система
Dock,,,
Hyperv,sor
Операционная система хоста
Инфраструктура
Инфраструктура
8.10. Контейнеры и виртуальные машины.
https://www.docker.com/resources/what-container/
Рис .
Источник:
Docker как платформа
В Docker есть интерфейс
имеет
множество
компонентов
и
уровней
(рис.
8.11 ).
командной строки, в котором вы можете выполнять такие
docker, docker pull для извлечения
docker будет запущен
docker из общедос
изображения
загружать
будет
который
движок
тупного реестра, такого как Docker Hub (https://hub.docker.com/), или из управ
ляемого частного реестра контейнеров, такого как Amazon ECR (https://aws.
amazon.com/ecr/).
команды, как docker run для запуска контейнеров
docker и
docker engine,
изображений
многое другое. На вашем хостинrе
Контейнеры обладают множеством следующих преимуществ.
♦
Изоляция приложений. Очень важный принцип, который мы продолжаем под
черкивать.
♦
Гибкость. Инженеры могут легко указывать зависимости приложений в одном
файле, не требуя согласования с командами
DevOps.
8 Для дальнейшего изучения этой темы мы рекомендуем прочитать 1амечательный пост о StackOverflow:
https://stackoverflow .com/ q uestions/ 16047 306/how-is-docker-different-from-a-virtual-machine.
368
■
Глава 8
Клиент
Узел
Docker
,.
Изображения
docker run
.
dockerbu1ld
f·· ····
Контейнеры
NGMX
е
,ed,s
о
'"''1'
◄- - - - - - - - - i -
-
Docker
docker pull
~-
daemon
- -
1
L
j
Рис.
♦
8.11. Архитектура Docker.
Источник:
https://docs.docker.com/get-started/overview/
Идентичное поведение. При использовании контейнеров в процессе инженер
ной разработки ваши инженеры запускают на своих ноутбуках именно то, что
выполняется в рабочей среде. Это уменьшает количество ошибок и облегчает
отладку.
♦
Быстрое время запуска. Улучшенное время запуска отлично подходит для
функционирования в качестве сервиса
(function as
а
service, FaaS)
и кратковре
менных процессов.
♦
Повышенная безопасность. Не просто
80
ный
контейнеры
доступ
к
операционной
системе;
прикладных процессов имеют рав
изолируют
процессы
от
операционных систем и могут еще больше повысить безопасность, используя
изолированные среды, такие как
gVisor (https://gvisor.dev/).
У контейнеров также есть недостатки. Каждый раз, когда вы вводите еще один
уровень абстракции, вы увеличиваете сложность и потенциально снижаете произ
водительность, накладные расходы и пропускную способность. Вот несколько при
меров.
♦ У IВМ есть интересная статья, в которой сравнивается производительность вир
туальных машин и контейнеров:
https://dominoweb.draco.res.ibm.com/reports/rc25482.pdf.
♦
сообщил о 5-1 О % накладных расходах при запуске Cassandra на контейне
http ://highscalabllity .com/Ыog/2016/9/28/how-uber-manages-a-million-writes
persecond-using-mesos-and.html.
Uber
рах
♦
Изолированные контейнеры конкурируют за ресурсы процессора, памяти, диска
и ядра, что означает определенный риск возникновения конкуренции за ресур
сы. Ядро
Linux
само по себе очень сложное, поэтому могут возникать коллизии
Внедрение новых технологий
■
ядра, ошибки и неэффективность, как описано в интересной статье от
369
Sysdig:
https://sysdig.com/Ыog/container-isolationgone-wrong/.
♦
Еще
одно
любопытное
обсуждение
производительности
контейнеров
в
StackOverflow: https://stackoverflow.com/questions/21889053/what-is-the-runtimeperformance-cost-of-adocker-container.
В конце концов, ничего не бывает бесплатным. Внедрение большего количества
уровней абстракции всегда сопряжено с определенными затратами. Мы все же
рекомендуем использовать контейнеры. Они дают преимущества в изоляции, быст
ром запуске и гибкости
Контейнеры хороши тем, что они позволяют инженерам повысить производитель
ность благодаря усовершенствованному оборудованию, и инженеры могут легко
управлять контейнерами на своих машинах. Но контейнеры не масштабируются
сами по себе. Невозможно вручную управлять сотнями или тысячами контейнеров
в процессе производства. Вам нужна платформа, кластер и какой-то способ управ
ления оркестровкой, например система управления контейнерами
Мы рассмотрели
Kubemetes (k8s)
в главе
4
-
Kubernetes.
«Антипаттерны: внутренние общие
библиотеки». Ознакомьтесь с этим разделом, чтобы получить представление о его
очевидных преимуществах, но давайте немного углубимся в архитектуру.
Сам
k8s появился на свет в результате более чем десятилетней
Google в рамках проекта Google Borg9, объединившего
рами в
работы с контейне
лучшие разработки
сообщества разработчиков с открытым исходным кодом. Архитектура
k8s состоит
8.12). Па
из двух основных концепций: уровня управления и уровня данных (рис.
нель управления
k8s -
это мозг
k8s,
управляющий рабочими узлами, модулями и
Е)
APl-cepeep
Меt<еджер облачных ф
-,8
rонтроллероs
(опцмонально)
Менеджер ф
'flii:il
контроллеров
elcd 1А\
(постоянное хранилище) ~
ф
kubd<t
kuЬt,proxy ф
Планировщик Е)
Панель уnравления
-
Nod~
Рис.
q
8.12. Кластер k8s. Источник: https://kuЬernetes.io/docs/concepts/overview/components/
Google Borg -
это название внутренних систем управления кластерами Google. Более подробный обзор
представлен тут: https://storage.googleapis.com/pub-tools-puЫic-puЫication-data/pdf/43438.pdf.
■
370
Глава В
принимающий глобальные решения о кластере в целом с помощью таких компо
нентов, как сервер АР!,
ных
-
etcd,
диспетчер управления и планировщик. Плоскость дан
это то место, где происходит реальная работа; в нем находятся рабочие
узлы, на которых размещаются модули/отдельные среды выполнения контейнеров,
процесс
kubelet
для выполнения инструкций уровня управления и
kube-proxy
для
управления сетью.
Для масштабной работы с контейнерами необходимо использовать систему управ
ления контейнерами. Вы можете использовать простые системы, такие как А WS
ECS (https://aws.amazon.com/ecs/),
♦
k8s
обладает рядом преимуществ:
Сообщество. Огромное сообщество инженеров, постоянно развивающее экоси
стему
♦
но
k8s
и внедряющее инновации.
Меньшая степень привязанности. Многие считают, что
спецификация, т. е.
в облаке. Но
k8s
k8s -
это облачная
стандартный способ запуска программного обеспечения
позволяет вам быть открытым и менее привязанным к постав
щикам общедоступных облачных сервисов.
♦
Упрощение и сокращение рабочей нагрузки на
DevOps. В каждой компании
ощущается нехватка специалистов в области DevOps, а соотношение между ин
женерами и разработчиками DеvОрs-систем неравномерно. Так k8s позволяют
инженерам напрямую выполнять большую часть рабочей нагрузки DevOps и
в то же время соблюдать стандарты, что в целом сокращает отставание команды
DevOps.
♦
Экономия средств. Пакетирование
Bin
позволяет размещать больше приложе
ний на одном узле без ущерба для доступности. Вы можете делать больше, за
трачивая меньше ресурсов, и это очень важно, особенно учитывая высокую
стоимость услуг провайдеров общедоступного облака.
♦
Облачная поддержка.
k8s -
сложная система, но вы не должны справляться
с ней в одиночку. Большинство облачных провайдеров предлагают собственные
решения на базе
Kubernetes,
размещенные на хостинrе. Они помогают решить
многие распространенные проблемы, такие как А WS
EKS.
Соответствующие сервисы отлично работают с контейнерами и
k8s.
АРI-интер
фейсы легко и гибко настраиваются, а доступ между контейнерами обеспечивается
с простой конфигурацией.
k8s
не заботится о том, как построено ваше программное
обеспечение: просто контейнер запускается и предоставляет конечные точки в со
ответствии с конфигурацией. Ваши публичные контракты не будут связаны с
k8s.
Языковые эксперименты намного упрощаются, поскольку новый язык и все его за
висимости могут быть легко заданы внутри контейнера, т. е. удовлетворять на
стройкам операционной системы и зависимостям для
Rust
вместо
Java.
При всей
этой абстракции легко повторно использовать один и тот же конвейер развертыва
ния, но с использованием совершенно другого языка.
Как и во всем, что связано с архитектурой программного обеспечения, существуют
компромиссы. Перечислим недостатки
♦
k8s.
Отладка и устранение неполадок. Становится сложнее; появляется больше
уровней, усложняется сетевое взаимодействие, а процессы, происходящие в ядре
Внедрение новых технологий
Linux,
■
371
затрудняют выявление ошибок. Вашей команде потребуются профессио
нальные подготовка и опыт.
♦
Сложность.
k8s
предлагает новые системы и технологии, множество уровней и
усложнений. Все это не предоставляется бесплатно. При переходе на
Kubernetes
вам придется отказаться от устаревшего стека, изменить все конвейеры развер
тывания и интегрировать
сий
k8s
k8s
с вашим облачным провайдером. Обновление вер
также требует усилий. Для многих людей отказ от услуг облачного про
вайдера означает отказ от создания ценности для бизнеса и лишь ненужную
сложность.
Облачный спектр
Облачные вычисления имеют смысл, но стоят дорого. Как облачные вычисления,
так и контейнерные архитектуры хорошо решают одни проблемы, но могуг созда
вать другие, постоянно истощая ваш кошелек. Независимо от того, для обеспечения
безопасности,
соответствия требованиям
или
экономии средств,
иногда имеет
смысл размещать свое решение самостоятельно. Не все рабочие нагрузки должны
выполняться в облаке. Дэвид Хайнемайер Ханссон, соучредитель
тель
Неу,
37 Signals, созда
Ruby on Rails, перенес несколько продуктов 37 Signals, таких как Basecamp и
из облака и k8s, заявив о потенциальной экономии в 1,5 млн долларов в rод1°.
Stack Overtlow 11
-
это монолитный центр обработки данных, размещенный не
в облаке. Он состоит из девяти серверов и обслуживает более
2
миллиардов про
смотров страниц в месяц. Они даже удалили свой уровень кеширования
ухудшения качества. Как
Stack Overtlow
Redis
без
удалось это сделать? Хороший инженер,
сосредоточьтесь на принципах информатики, таких как алгоритмы и структуры
данных. Иногда простые решения
-
это лучшие решения.
Однако не все компании могут добиться успеха, подобного
Stack Overtlow.
Класси
ческие монолиты часто имеют серьезные проблемы. Облачные и SааS-предложения
могут помочь компаниям быстро масштабироваться, как вы видели в наших пре
дыдущих примерах. Дело в том, что эти решения не обязательно являются черно
белыми и могут располагаться в широком диапазоне оттенков (рис.
происходит,
потому
что
сотрудники
находятся
на
определенном
8.13).
этапе
Это часто
развития
своей организации, будь то во времени или в условиях технической сложности.
Локальные центры
Гибридные
обработки данных
Рис.
10
облачных сервисов
Облачный спектр
Истори11 выхо;~а из облачных систем и контейнерюаци11 от 37 Sigлals: https://woгld.hey.com/dhh/
we-have-left-the-cloud25 l 760tъ
11
8.13.
Поставщики общедоступных
и https://dev.37signals.com/bгinging-our-apps-back-home/.
Подробности о Stack Overflow: https://twitteг.com/sahnlam/status/1629713954225405952
и https://news.ycomblnatoг.com/item?id=34950843.
372
■
Глава 8
Лучший ответ на вопрос о том, какой должна быть ваша организация, во многом
зависит от того, как вы туда попали.
В зависимости от возраста вашей компании, ее инфраструктура, скорее всего, про
шла через одну из нескольких таких волн:
♦
Этап
мейнфреймы. Массивные, сложные одиночные машины, на которых
1:
размещается множество приложений. Практически полная изоляция, мощные
решения,
часто
являющиеся
абсолютным
монолитом 12 .
Мейнфреймы
по
прежнему доступны; в А WS даже существует специальная практика переноса
мейнфреймов в облако
♦
Этап
2:
(https://aws.amazon.com/mainframe/).
аппаратные кластеры. Завоевание настольных процессоров
Intel
спо
собствовало созданию архитектур с большим количеством отдельных серверов,
работающих согласованно. Никакой виртуализации
-
всё работает на реальном
оборудовании и с использованием реальных операционных систем.
♦
Этап
3:
виртуализацня. Было очень сложно работать с физическим оборудова
нием, когда требовалось его перепрофилирование; удаление экземпляра, пере
форматирование/переустановка всего. Что делать, если у вас слишком много
оборудования и вы можете запускать
3
приложения на одном компьютере, но
они плохо работают в одной операционной системе или не изолированы друг от
друга? Мощное программное обеспечение для виртуализации позволяет быстро
переназначать оборудование и повторно развертывать экземпляры одним нажа
тием кнопки.
♦
Этап
4:
облако. Виртуализация по-прежнему означает, что вам нужно управ
лять массивными стойками с компьютерами в центрах обработки данных, опла
чивать электроэнергию и кондиционирование, а также отдельные процессоры,
диски и память, которые могут выходить из строя. Зачем беспокоиться обо всем
этом? Многие приложения прекрасно работали, когда не учитывались основные
принципы работы каждой отдельной машины. Крупные компании могут объ
единять сотни тысяч машин и повышать экономическую эффективность за счет
многопользовательской работы. Например, используйте машину, когда я этого
не делаю, и мы оба экономим деньги.
♦ Этап
API
5:
контейнеризация. Все эти облачные провайдеры имеют собственные
и делают в основном одно и то же. Абстрагируйтесь от самого облака! Кон
тейнеризация удовлетворяет всем требованиям вашего приложения, и вы може
те запускать его где угодно: на ноугбуке, в облаке, в центре обработки данных и
даже на встроенном оборудовании. Давайте обеспечим истинную переносимость
в облако.
♦
Этап
6:
настоящий гибрид. Контейнеризация позволила создать по-настоя
щему портативную инфраструктуру; теперь вы можете гибко использовать
12
Мейнфреймы -
это не шутка и не абстрактная идея; они все еще существуют, незаметно управляя мил
лионами долларов и критически важными бизнес-процессами. У А WS есть собственная специализирован
ная практика по переносу мейнфреймов в облако:
https://aws.amazon.com/mainframe/.
Внедрение новых технологий
polycloud 13 :
■
373
выбирайте любой облачный сервис или свой собственный центр об
работки данных в той комбинации, которая соответствует вашим потребностям
и возможностям. Хорошими примерами таких технологий являются платформа
Crossplane с открытым исходным кодом (https://www.crossplane.io/)
Google (https://cloud.google.com/anthos/).
и
Anthos
от
Хотя мы описываем каждую волну как прогрессию, на самом деле каждый класс
архитектуры имеет свои уникальные преимущества. Простой запуск монолита на
одной большой машине эффективен, как мы видели в случае со
Stack Overflow;
простое аппаратное обеспечение обеспечивает максимальную производительность
при меньшем количестве уровней абстракции. Виртуализация позволяет приложе
ниям быть достаточно переносимыми для большинства случаев. Облако дает вам
огромный набор преимуществ благодаря общей среде. Но облачные провайдеры
стоят дорого и по-прежнему ограничивают вас. Контейнеры обеспечивают макси
мальную мобильность. Настоящая гибридная инфраструктура позволяет вам выби
рать любой из вышеперечисленных вариантов по своему усмотрению.
Еще один аспект, который следует учитывать,
-
это техническая сложность и
масштаб вашей компании. По мере своего развития компании проходят различные
этапы сложности, и это может повлиять на правильный ответ:
♦
Ранние этапы/крошечная компания. Ваше программное обеспечение
-
это
то, что безжалостно фокусируется на поиске продукта, соответствующего рын
ку. Вы не ознакомились со всеми вариантами использования, и во многих случа
ях ваше программное обеспечение, вероятно, будет отлично работать на вашем
ноутбуке (например, классический монолит)! Рассмотрите возможность совме
стного размещения сервера или специализированного оборудования, такого как
Hertzner (https://www.hetzner.com/).
♦
Компании малого и среднего бизнеса. Здесь, скорее всего, все усложняется,
и требования, предъявляемые к вашему программному обеспечению, растут, но
вы не являетесь крупной компанией. Добиться экономии за счет масштаба
сложно. Вы выигрываете, используя облачные или SааS-решения, поскольку по
лучаете доступ к экспертно разработанному и эксплуатируемому решению и
можете сосредоточить свой ограниченный персонал на решении бизнес-задач.
♦
Крупные компании. Скорее всего, вы владеете зданиями и целыми кварталами.
Сложность растет, но на самом деле у вас есть экономия за счет масштаба, когда
вы можете позволить себе посвящать людей в технические решения. Контейне
ризация и
k8s
на серверах, размещенных в центрах обработки данных, в сочета
нии с индивидуальными внутренними решениями или специальными облачны
ми решениями могут значительно снизить ваши затраты.
Мы считаем, что облако
-
не единственный выход. Правильные ответы со време
нем меняются, и в зависимости от состояния вашей компании любое из этих реше
ний может иметь преимущества в вашей конкретной ситуации. Нет худа без добра.
13
Polycloud -
зто практика использования нескольких разных облачных провайдеров в организации, по
зволяющая выбирать наиболее подходящий вариант на основе проекта.
-
Пер.
374
Глава 8
■
Затраты, возраст компании, степень зрелости и техническая сложность сведут вас
к одной точке на этой шкале. Только вы можете решить, где именно.
Доступ к потоковой передаче данных
в режиме реального времени
Современные архитектуры требуют всесторонней поддержки асинхронных распре
деленных систем, которым, в свою очередь, необходим доступ к данным в режиме
реального времени. В конце концов, некоторые задачи могут выполняться долго;
некоторые задания могут выполняться только в среде данных и не содержать инте
рактивного компонента; жизнь
-
это нечто большее, чем просто цепочки сервисов,
работающих синхронно. Разработка современного приложения означает, что вам
необходимо освободить место для потоковой передачи данных и асинхронной об
работки.
Еще в главе
2
«Антипаттерны: отсутствие изоляции» мы рассмотрели основы
архитектур, основанных на обработке событий, поддерживающие их технологиче
ские платформы, такие как
Apache Kafka,
и продвинутые архитектуры, такие как
разделение ответственности за выполнение командных запросов
responsibllity segregation, CQRS).
(command query
Давайте подробнее рассмотрим, что это может
означать для ваших современных приложений.
Apache Kafka
Apache Kafka (https://kafka.apache.org/) -
это распределенное хранилище собы
тий и платформа для обработки потоковых данных. По своей сути,
распределенный журнал событий;
Kafka
Kafka -
это
как платформа высоко ценится за ее отка
зоустойчивость и способность поддерживать приложения для обработки данных
в больших масштабах с низкой задержкой. Kafka был создан в Linkedln Джеем
Крепсом, Нехой Нархеде и Джуном Рао в
в
2011
г. на
которые
Linkedln
2011
году.
Kafka
был опубликован
в соавторстве с Джеем Крепсом, Нехай Нархеде и Джун Рао,
впоследствии
основали
Confluent (https://www.confluent.io/about/) Kafka.
компанию, занимающуюся разработкой и поддержкой
Kafka
имеет множество возможных технологических применений и активно ис
пользуется различными организациями в самых разных отраслях, такими как:
♦ Банки, фондовые биржи и страховые компании. Они обрабатывают платежи
и финансовые транзакции в режиме реального времени и без потери данных.
♦ Логистика и автомобилестроение.
Kafka
легко справляется с потоком собы
тий, отслеживая легковые и грузовые автомобили, автопарки и телеметрию от
грузки в режиме реального времени.
♦ Производство. Непрерывный сбор и мониторинг данных датчиков с устройств
Интернета вещей.
♦ Путешествия, розничная торговля, электронная коммерция. Собирайте бес
конечный поток взаимодействий с клиентами и событий, связанных с кликами
Внедрение новых технологий
■
375
в пользовательском интерфейсе; реагируйте на такие события, как заказы, бро
нирование гостиниц и многое другое.
♦
Здравоохранение. Наблюдайте за пациентами в больницах, прогнозируйте из
менения в состоянии здоровья и предупреждайте команды о необходимости
действовать быстро.
♦ Для всех компаний, работающих с большими данными. Собирайте огромный
поток данных из различных подразделений и организаций и направляйте его
в эффективные процессы обработки. Подключайте, храните и делайте данные
высокодоступными
В основе
Kafka
-
основа платформ обработки данных.
лежит концепция распределенного журнала. Что такое журнал?
В данном контексте мы не имеем в виду ведение журнала в приложении, как
в
log4j, logback, commons-logging
или
general observability,
хотя
Kafka
прекрасно
справляется с этими вариантами использования! По словам Джея Крепса 1 4, соавто
ра
Kafka,
логи как концепция являются простейшей формой абстракции хранили
ща. Журнал обладает следующими свойствами:
♦ только для добавления;
♦
полностью упорядоченная по времени последовательность записей;
♦
неизменяемая.
На рис.
показаны эти свойства. Порядок следования записей в журнале осно
8.14
ван на времени. Записи слева более старые, чем записи справа. Новые записи будут
добавляться только при записи в конце журнала и никогда не будут изменены.
Большинство проблем в распределенных системах на самом деле сводятся к согла
сованию того, что и когда произошло; журнал решает эти проблемы и может стать
надежным способом обеспечения идеальной синхронизации удаленной системы:
просто получите журнал и воспроизведите его! Таким образом, журналы решают
две проблемы в распределенных системах: упорядочивают изменения и распреде
ляют данные
-
простая структура данных, которая закладывает основу для реше
ния гораздо более сложной и важной задачи.
Первая запись
Следующая запись
1
Рис.
14
8.14. Что такое журнал. Источник: https://engineering.linkedin.com/distributed-systems/
log-what-every-software-engineer-should-know-aboutreal-time-datas-unifying
Статья Джея Крепса представляет собой потрясающий обзор основопо;1агающих идей, лежащих в основе
Kalka: https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-knowabout-real-time-datas-unifying.
Глава В
■
376
Архитектура
Katka
Kafka
использует эту концепцию журнала и создает остальную поддерживающую
концептуальную архитектуру, необходимую для создания эффективной распреде
Кластер Katka разделен на Темы (Topic), а Тема может
(Partition). Приложения, которые записывают данные
в кластер Katka, называются Производителями (Producer), а приложения, которые
считывают данные из Katka, называются Потребителями (Consumer). Сервисы мо
ленной системы (рис.
8.15).
иметь несколько Разделов
гут быть как производителями, так и потребителями одних и тех же или разных
разделов. Данные в рамках раздела реплицируются в целях обеспечения отказо
устойчивости и высокой доступности.
Производитель
Кластер
Kafka
Тема
Тема
Тема
1
1
Разделf
!Раздел i
1
Раздел!
1
!Раздел i
1
Раздел!
1
!Раздел
Потребитель
Потребитель
Рис.
Производитель
Производитель
1
Разделf
Раздел!
Раздел!
Потребитель
8.15. Высокоуровневый обзор архитектуры Kafka
Чтобы дать вам метафору: вы можете представить тему как папку в файловой сис
теме. Событиями будут файлы в этой папке. Разделы будут подпапками. Внутри
раздела
Katka
сообщения упорядочиваются по смещению, положению сообщения
в разделе. Производители записывают данные в конце раздела, а потребители могут
читать либо из начальной, либо из конечной части раздела.
Способность потребителей
мы
-
Katka
считывать данные из конца или заголовка те
это потрясающая функция (рис.
8.16),
поскольку она позволяет выполнять
обработку в реальном времени, считывая из заголовка, и повторную обработку ис
тории, считывая из хвоста или с определенного смещения в теме. Такая функция
очень полезна для организаций, занимающихся обработкой данных с использова
нием больших объемов данных, а также в любом случае, когда точная синхрониза
ция и воспроизведение событий могут быть преимуществом, например ведение
точной финансовой книги или воспроизведение данных в сценариях восстанов
ления.
Katka
поддерживает постоянные пользовательские соединения на различных язы
ках программирования; начните с чтения конца темы и продолжайте слушать. Как
Внедрение новых технологий
■
377
только появится новое сообщение, ваше соединение будет активировано, а сообще
ние отправлено на почту. Ваше программное обеспечение сможет прочитать его и
активировать, выполнив любое необходимое действие. У вас может быть большое
количество пользователей на разных серверах, каждый из которых ожидает ответа.
Нет необходимости в одном массивном оркестраторе, запускающем сервисы. Бла
годаря низкой задержке, присущей
Kafka,
она может стать сердцем мощной асин
хронной распределенной системы.
Кластер
Kafka
Тема
__,---,
Потребитель
Производитель
ко~ец
загоnовок
Потребитель
Рис.
8.16. Kafka:
темы, разделы, производители и потребители
Помимо этих функциональных характеристик,
Apache Kafka
обладает целым рядом
эксплуатационных преимуществ:
♦
Высокая пропускная способность.
чем за
♦
2
Kafka
может передавать сообщения менее
мс даже между компьютерами кластера с ограниченной сетью.
Масштабируемость. Кластер
Kafka
может масштабироваться горизонтально,
поддерживая тысячи брокеров и триллионы сообщений в день, петабайты дан
ных и сотни тысяч разделов.
♦ Долговечность. Постоянное хранилище с высокой отказоустойчивостью.
Как и во всем, что касается архитектуры программного обеспечения, у нас всегда
есть компромиссы; к недостаткам и ограничениям
♦
Ограниченная наблюдаемость. В
Kafka
Apache Kafka относятся:
отсутствует полный набор инструмен
тов для обеспечения наблюдаемости и пользовательских интерфейсов «из ко
робки».
♦
Настройка сообщений.
Kafka
была разработана как система, предназначенная
только для добавления. Если вам нужно изменить какое-либо отдельное сооб
щение, система работает намного медленнее.
♦
Задержка в миллисекунды.
Kafka
нужна задержка в миллисекунды,
Kafka
работает быстро, но не более того; когда вам
например для
высокочастотной торговли,
не подходит. Предпочтительнее использовать общую память.
378
♦
■
Глава В
Нестабильные сети.
не был создан для нестабильных сетей, когда у вас
Kafka
много клиентов, подключающихся повторно; МQТТ1 5 гораздо лучше подходит
для этого сценария.
также обеспечивает лучшее подключение при нали
MQTT
чии десятков тысяч клиентских приложений.
♦
Kafka
Kafka зовать
не
является
файловым
сервером.
Идеальный
размер
1 Кбайт; максимальный размер сообщения - 1 МБ. Не
Kafka для отправки крупных объектов. Прямая обработка
сообщения
стоит исполь
больших фай
лов будет медленной, и для этого лучше всего подойдет система вроде А WS SЗ.
Часто естественным выбором для записи является
JSON,
но можно использовать
и другие текстовые форматы.
Kafka
и
CQRS/ES
Архитектурная модель
CQRS,
в которой у вас есть один путь реализации и система
хранения для операций записи/команд, а другой
может быть мощной (рис.
8.17). CQRS
-
для операций чтения/запросов,
позволяет нам изолировать операции чтения
от операций записи и, следовательно, обладает лучшей масштабируемостью и изо
ляцией. Это также позволяет использовать технологии, которые лучше всего под
ходят для каждой конкретной задачи, но в результате повышается сложность.
Apache Kafka
может быть использован для реализации шаблона
CQRS; например,
MySQL и в раз-
ваше приложение может выполнять двойную запись в базу данных
Контракт
Реализация
сервиса профилей
Чтение БД
Запись в БД
.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Рис.
8.17. Архитектура CQRS
1' MQTT (Message Queнe Teleinetry Transport) зто упрощенный сетевой протокол, работающий поверх
TCP/IP и ориентированный на обмен сообщениями между устройствами по принципу «издатель - 1юдпис
чию>. Основное предназначение - работа с телеметрией от различных датчиков и устройств. - Пер.
Внедрение новых технологий
дел
Kafka.
Распределенный читатель
Kafka Streams
■
379
может напрямую ответить на
это сообщение, взять его из темы и записать в систему
ElasticSearch,
используемую
в пути запроса. Конечно, эта система в конечном счете обеспечивает согласован
ность данных, но все еще имеет возможность использовать реляционную базу дан
ных для задач, где она эффективна, и систему
NoSQL
для операций, которые она
выполняет лучше. Однако такой подход усложняет систему. База данных «мастер
на все руки», такая как
Postgres,
иногда становится оптимальным решением с дос
таточно хорошими функциями, такими как текстовый поиск.
Обработка событий решает еще одну ключевую проблему для распределенных ар
хитектур. Монолиты, как правило, имеют простую настройку хранилища данных:
центральную реляционную базу данных, которая содержит все данные и может от
вечать на любой запрос. Все таблицы находятся в вашем распоряжении, а объеди
нения
(join)
просты в использовании. Благодаря
SOA
и микросервисам отпадает
необходимость в централизованной базе данных, т. к. она больше не нужна по со
ображениям изоляции. Итак, как мы объединяем данные между сервисами или биз
нес-областями? Здесь на помощь приходят обработка событий
потоковая передача и
Kafka
(рис.
(Event Sourcing, ES),
8.18).
Контракт
Реализация
сервиса профилей
Контракт
Реализация
Реализация
сервиса продаж
сервиса продаж
подписана на тему
БДпрофипей
на MySQL
Kafka
и находится в курсе события
создания профиля
БД профилей
продаж
Рис.
8.18.
Обработка событий и
Сервис профилей будет публиковать событие в
Kafka
Kafka
при каждом создании нового
профиля. Отдел продаж хочет запустить несколько кампаний для увеличения про
даж товаров. Однако у них нет доступа к базе данных клиентских профилей, кото
рого у них и быть не должно. Отдел продаж мог бы вызвать сервис профилей, но
это был бы синхронный вызов и неэффективный опрос, и сервису профиля также
пришлось бы раскрывать эту операцию.
Теперь, поскольку сервис профилей опубликовал событие в
Kafka,
все происходит
асинхронно. Отдел продаж может выполнять объединение данных на своей сто
роне. То же самое может произойти и в более сложных сценариях, когда нужно
соединить несколько тем
в реальном времени.
Kafka
для обработки сложных объединений данных
■
380
Глава В
База данных
ksqlDB
ksqlDB (https://ksqldb.io/) -
это база данных, специально созданная для приложе
ний потоковой обработки (рис.
8.19). Интегрированная с Apache Kafka, ksqlDB по
Kafka практически так же, как с любой обычной базой
запускать запросы в режиме реального времени к Kafka, ис
зволяет вам обращаться с
данных: вы можете
SQL,
пользуя
и создавать материализованные представления, которые поддержи
вают поисковые запросы к этим представлениям. На практике
ksq\DB -
это пере
вернутая база данных: в то время как обычная база данных хранит данные и позво
ляет вам запускать запросы, в
ksqlDB
вы храните запросы, которые выполняются
с данными по мере прохождения разделов
0
0
Kafka.
ksqlDB
-
Stream Processing
Connectors
[8]
[~ APP JI
PULL
Materialized Views
PUSH
Рис.
8.19.
База данных
ksqlDB.
Источник:
https://ksqldb.io/
База данных
ksqlDB обладает некоторыми чертами комплексной обработки собы
(Complex Event Processing, СЕР) и таких решений, как Esper (https://www.
espertech.com/esper/) 16, но использует совершенно другую реализацию, полагаясь
на Kafka. Изменение мышления здесь заключается в том, что вставка данных в ре
тий
ляционную базу данных и последующее выполнение запросов было слишком
медленным. Противоположный подход сработал лучше, поскольку
Kafka
довольно
быстро обрабатывает большие объемы данных.
Еще одним преимуществом
тей и простой язык
(SQL),
ksq\DB
является то, что у нее меньше движущихся час
понятный практически любому аналитику или инжене
ру. Запросы могут быть pull или push; pull означает, что вы запускаете запрос сей
час
и
получаете текущие результаты, а
push
означает,
что
вы
подписываетесь
на
материализованные представления и получаете события по мере их появления. Все
эти особенности позволяют базе данных
ksqlDB
снижать барьеры, мешающие
объединению в распределенных системах.
16
Комплексные системы обработки событий, такие как Esper, позволяют вам реагировать не только на одно
событие,
но и сопоставлять и реагировать на множество событий, происходящих одновременно или
в течение определенного временного интервала. Язык запросов
целей, но он еще не до конца разработан:
ksqlDB позволяет достичь аналогичных
https://en.wikipedia.org/wiki/Complex_event_processing.
Внедрение новых технологий
■
381
Эффективные инженеры
Что такое эффективность? Заключается ли она в том, чтобы делать все быстро? Или
правильно? Быстрота и корректность не противоречат друг другу; корректность и
следование инженерным принципам не замедляют работу, напротив, они позволя
ют нам двигаться быстро и стабильно.
Инженерное дело
-
это марафон, а не спринт; бегуны добиваются успеха, ставя
ногу в нужное место с нужным весом и устойчивостью, раз за разом до самого кон
ца; бегут не спеша и не забывая о правильной технике, чтобы избежать травм. То
же самое и с инженерией: грамотный дизайн и архитектура обеспечивают долго
срочную работоспособность вашей системы. Они помогают принимать решения,
улучшающие функциональность и эффективность. Надлежащее обслуживание по
зволяет нам изучать варианты, позволяющие не только сделать наших инженеров
счастливее, но и повысить продуктивность их работы.
К сожалению, в реальном мире от принципов отказываются из-за срочности бизне
са, и побеждает самый грязный, быстрый и в конечном счете обремененный тех
ническими долгами вариант. В Бразилии такая методология получила название
экстремш~ьная езда верхом
(Extreme Go Horse) 17 .
Оrсутствие надлежащей архитектуры и дизайна программного обеспечения часто
проявляется в виде других проблем, таких как:
♦
Отсутствие принципов. Не применяя надлежащие принципы предоставления
сервисов, такие как изоляция,
SOA,
экономичные библиотеки, команды создают
для себя ловушки, которые снижают производительность и удобство обслужи
вания в долгосрочной перспективе.
♦
Недостаточная
концентрация
квалифицированных
специалистов.
Люди
думают, что архитектура замедляет развитие событий, в то время как на самом
деле людям не хватает опыта. Командам не хватает квалифицированных спе
циалистов, решения превращаются в соревнование за популярность или прини
маются исключительно из-за страха перемен. Плохие решения принимаются при
отсутствии социализации и, что особенно важно, осознания лучших вариантов.
♦
Искусственные зависимости. Разделение команд на группы, создание барьеров
и ненужных межкомандных зависимостей. Например, наличие отдельных групп
контроля качества, администраторов баз данных, DеvОрs-команд. У вас могут
быть выделенные команды, которые специализируются на определенной дисци
плине, чтобы обеспечить наилучшие практики. Но все сотрудники, отвечающие
за контроль качества, администраторы баз данных и операционные администра
торы должны быть объединены в настоящую кросс-функциональную команду,
которая будет работать на благо бизнеса.
♦
Только этот процесс считается медленным. У нас нет времени на архитектур
ные или технологические исследования! Но многолетние проекты с безопасным
17
Экстремальная езда верхом:
https://medium.com/@dekaahn2-axioms-of-the-extreme-go-horse-methodology-xgh9fa739ab55Ь4.
382
■
Глава 8
водопадом
-
это нормально. У нас абсолютно нет времени на ретроспективу
или, может быть, есть всего
планирования
-
15
минут. Но непродуктивные многодневные сессии
это нормально. Планы с сотнями зависимостей от команды,
инженеры, проводящие по пять ежедневных совещаний по текущему состоя
нию,
-
это здорово. Подумайте о экономичном мышлении; знаете ли вы, где
обитает потерянное время?
♦
Плохие стимулы. Вознаграждается только выполнение работы. Нет вознаграж
дения за удаление кода, нет вознаграждения за вывод из эксплуатации сервисов.
Рефакторинг часто воспринимается как оскорбительное слово, риск без возна
граждения.
Вместо этого мы должны доверять нашим инженерам, предоставлять им лучшие
инструменты для обеспечения максимальной корректности и повышения произво
дительности. Начнем с того, что дадим им возможность использовать современные
языки!
Современные языки программирования
Языки программирования
это инструменты, с помощью которых мы можем
-
описать наши задачи и пути их решения в виде кода. Это наш способ общения
с компьютерами. Многие инженеры и менеджеры считают, что узкое место заклю
чается в наборе кода: чем больше строк кода в час, тем лучше, все зависит от про
изводительности и выполнения большего количества задач. Мы считаем, что такой
подход к языкам программирования неверен. Языки
-
это правильный инструмент
для работы, который позволяет нам делать больше с меньшим количеством кода.
Современные языки не только привносят инновации, но и упрощают и повышают
безопасность обслуживания.
Что определяет успех языка? Стоит ли выбирать язык исходя из его популярности?
Учитывайте следующие факторы:
♦
Инженерный резерв. Насколько легко найти инженеров, знающих язык?
♦ Поддержка сообщества. Насколько хорошо поддерживается язык? Насколько
велико сообщество? Существует ли много активных проектов и библиотек с от
крытым исходным кодом? Многие ли компании используют этот язык в произ
водственных приложениях?
♦
Соответствие или принадлежность к определенной сфере. Насколько эффек
тивен этот язык? Применим ли он широко или используется только для узкоспе
циализированных приложений? Что выиграет моя организация от внедрения
этого языка? Есть ли преимущества при разработке? Повышение производи
тельности?
Внутренние общие библиотеки и архитектура программного обеспечения играют
здесь большую роль в выборе языков программирования. Они могут как способст
вовать, так и мешать использованию других языков. Например, если у вас есть сот
ни библиотек, написанных на
Java
или С#, сложнее обосновать перенос всего этого
стека на другой язык, скажем, С++. Мы рассмотрели, как небрежный подход
Внедрение новых технологий
■
383
к внутренним общим библиотекам может замедлить работу вашей организации и
даже создать распределенный монолит; теперь вы видите другое измерение. У нас
и так достаточно проблем, связанных со всеми этими переносами библиотек и тре
бованиями к информационной безопасности в рамках одного языка, как мы можем
поддержать воссоздание всех этих библиотек на новом языке и удвоить нашу рабо
ту по поддержке? Это неправильный выбор; имейте меньше библиотек.
В идеальном мире мы могли бы полностью абстрагироваться от языков и сделать
это деталью реализации, которую могла бы выбрать каждая команда. Но правда
в том, что популярность языка реальна, хороших инженеров найти сложно, и они
не хотят, чтобы в итоге вы были разрознены и тратили свое время на постоянную
настройку новых
IDE
и языковых конфигураций. Поддерживайте
высоком уровне вместо того, чтобы охватывать
100
3-6
языков на
языков поверхностно. В целом
лучше избегать слишком передовых языков с ограниченной поддержкой сообщест
ва. Также не стоит развивать языки, которые находятся на грани исчезновения и не
имеют большого активного сообщества, способного внедрять инновации.
Спектр языков программирования
Одна практика, которую вы можете выполнить,
-
это классифицировать языки,
которые вы используете, и те, которые вас интересуют, в соответствии с деятельно
стью вашей компании, жизненным циклом языка, способом обслуживания и пред
почтениями. Например:
Java -
JavaScript
отлично подходит для разработки интерфейсов,
для серверной части и длительных процессов, а
Python,
возможно, лучше
подойдет для написания сценариев и кратковременных процессов или машинного
обучения. Попробуйте создать простую матрицу, рекомендующую языки для кон
кретных задач, как показано в табл.
Таблица
Язык программирования
Java, Kotlin, Scala, Go
8.1.
8.1. Языки программирования и рекомендации их использования
Рекомендации
Серверные сервисы, пакетная обработка, длительно
выполняемые задания
--
JavaScript, TypeScript
Интерфейс приложения и
Scala, Python, R
Аналитика, машинное обучение, потоковая передача данных
BFF
- - - -
Rust, Zig,
С++
Низкоуровневые решения, компоненты базовой платформы,
sidecar
и компоненты обеспечения безопасности
-
Python, Zsh, Groovy
Общие сценарии, операции, небольшие задачи
- -
-
DevOps
Нужно быть осторожными, когда мы говорим о языках! Правда в том, что языки
программирования
создать сервис на
- это инструменты общего назначения. С их помощью можно
Typescript или модуль пользовательского интерфейса на Rust.
Инженеры часто имеют свои предпочтения, и наша цель здесь не разжигать кон
фликт и не огорчать кого-либо в сообществе. Наша таблица
-
всего лишь пример.
Вам лучше составить свою с учетом опыта и реалий вашей компании.
384
■
Глава
8
Еще одна п~-Jактика, которую применяют некоторые компании,
-
это создание теп
ловой карты, или диаграммы из четырех квадратов, отображающей языки с точки
зрения вашей компании, бизнес-деятельности, жизненного цикла языка и предпоч
тений (рис.
8.20).
Языки
широкого профиля
}мА
VB.NET
С++
Рем-/
Kot/;,,,,
Умирающие
Живые языки
языки
Pytho,,,.
Delphi
r:ctAIA
]5
/гцсt
РА~СЩ
Clojиre
COBOl
Узкоспециализированные
языки
Рис.
8.20.
Пример диаграммы языка программирования
Опять же, это всего лишь пример; не отправляйте авторам письма с угрозами, если
вы не согласны с нашей классиф»кацией, приведенной здесь. Но если в вашей ком
пании есть такая таблица, она поможет инженерам понять, следует ли широко ис
пользовать тот или иной язык или же полностью отказаться от разработки на нем.
В нашем примере на рис.
8.20
представлен один из вариантов выбора языка, кото
рый может быть полезен в самых разных ситуациях: от повседневных задач до уз
коспециализированных приложений или для решения очень специфических задач.
Например, универсальный и динамичный язык прекрасно подходит для сервисов.
А узкоспециализированный активный язык может идеально подойти для опреде
ленных компонентов платформы и сервисов или для очень специфических задач,
таких как безопасность, создание сетей, балансировка нагрузки и управление зада
чами.
Языки также очень важны для привлечения и удержания квалифицированных спе
циалистов; некоторые инженеры никогда не стали бы работать на языках, которые
им не нравятся. Например, инженер по
с
Java.
Rust
может никогда не захотеть работать
Как мы уже говорили, у отдельных людей могут быть свои серьезные пред
почтения! Сильным инженерам, как правило, нравится работать над новыми техно
логиями. Поддержка большего количества языков дает вам больше возможностей
для найма. Разнообразие
граммирования.
-
это всегда хорошо, и то же самое касается языков про
Внедрение новых технологий
■
385
Возможно, вы думаете, что я не хочу добавлять новые языки, я доволен теми язы
ками, которые у меня есть, или мне нравится мой шаблон
monorepo,
и я предпочи
таю использовать только один язык. Это прекрасно! Вы можете внедрить множест
во инноваций, необходимых для выхода из вашего монолита, не вводя большого
количества новых языков. Но имейте в виду следующие обстоятельства.
♦
Инженеры могут иметь строгие предпочтения в зависимости от области техно
логий, с которой они работают; и, помимо предпочтений, это может быть обяза
тельным условием для повышения производительности:
•
Разработчики интерфейсов не хотели бы работать на
го»
настольного
клиента
остались
далеко
в
Java,
прошлом;
а времена «толсто
они
предпочитают
JavaScript/TypeScript.
•
Специалисты по анализу данных полагаются на сотни библиотек и фрейм
ворков, таких как
TensorFlow
для
свои агрегации и
•
Spark Streaming для потокового анализа данных или
Им нужны Scala, R и Python, и они не захотят писать
МL-модели на JavaScript.
ML.
Многим бэкенд-инженерам не понравится писать сервисы на
могут предпочесть
♦
Java, Kotlin, Go,
С# или даже
JavaScript;
они
Rust.
Технологии и языковые предпочтения меняются. Ваша компания может приоб
рести
другие
компании,
которые
внедряют языки,
которых у вас
сегодня
нет.
Принцип адаптивности является ключевым: готовы ли вы и ваши технологиче
ские пакеты реагировать на изменения?
♦
Спросите своих разработчиков, не рассматривают ли они возможность исполь
зования новых языков программирования. Ответы могут вас удивить.
Языки программирования
JVM
Многие организации используют
в качестве основного языка для внутренних
Java
сервисов и аналитики. Одним из удивительных преимуществ экосистемы
Java яв
Java (Java Virtual Machine, JVM), и вы можете рассмот
реть возможность использования языков JVM, таких как Scala, Kotlin, Clojure,
Jython, JRuby, Rhino (JS) и Groovy, которые изначально будут работать в среде Java.
ляется виртуальная машина
Внедрение этих языков может обеспечить следующие преимущества.
♦
Отсутствие трудностей при внедрении:
•
повторно используйте всю вашу внутреннюю программную экосистему, все
ваши внутренние общие библиотеки
•
Java;
повторно используйте всю вашу инфраструктуру и серверы времени выпол
нения, например, если вы запустили
Tomcat,
можно продолжить работу без
изменений;
•
повторно используйте значительную часть всех ваших инструментов, по
скольку вы можете использовать те же инструменты сборки, что и
Gradle,
Maven
или
и, скорее всего, ваши конвейеры развертывания будут работать без
изменений.
386
♦
■
Глава В
Наслаждайтесь поездкой. Воспользуйтесь преимуществами нового синтаксиса,
сокращенного шаблонного кода, новых библиотек и фреймворков, работающих
в
♦
NM,
с некоторыми ограничениями, но очевидными преимуществами.
Путь к совершенному владению языком. Вы можете начать внедрять язык,
который работает на
нения. Например, с
JVM, а затем переключиться на
Rhino на NodeJS, Bun или Deny.
собственную среду выпол
Да, при переходе на новый язык программирования вы можете потерять некоторые
функции, как в случае с
Python, JavaScript
и
Ruby.
Кроме того, возможно даже сни
жение производительности из-за дополнительного уровня абстракции. Но в зави
симости от вашего варианта использования это может быть приемлемо, чтобы по
лучить все преимущества, которые новый язык может предложить.
NM может
Scala, Clojure, Kotlin или других
рассматривайте языки NM как путь для изу
стать вашим основным решением при внедрении
родных языков
NM,
но в остальном
чения.
Гибкие модели данных
На кухне профессионального шеф-повара есть множество инструментов. Он не
использует сковороды только одного типа и не пытается снять цедру с апельсина
кухонным ножом. То же самое и с программным обеспечением
-
подходящий инструмент для работы. Моделирование данных
ключевой вид дея
-
нужно выбрать
тельности при разработке программного обеспечения. Правильная модель данных
упрощает разработку, избавляя от необходимости вносить многочисленные преоб
разования и обходные пути в код приложения. Выбор хранилища данных напря
мую влияет на моделирование данных. Неудачная модель данных может серьезно
затруднить разработку программного обеспечения и адаmацию к изменениям. Гиб
кость
чаев
-
это ключ к успеху. Современные инженеры знают, что в большинстве слу
невозможно
вместить
все
варианты
использования
в
реляционную
модель.
Поэтому давайте рассмотрим некоторые дополнительные опции.
Базы данных
NoSQL
Инженеры и архитекторы не умеют давать названия программному обеспечению.
Как объяснил Фил Карлтон: «В информатике есть только две сложные вещи: очи
стка кеша и присвоение имен» 18 • Технические названия обычно не раскрывают всей
сути и могут сбить людей с толку;
NoSQL -
не исключение. Реляционные базы
данных существуют с 1960-х гг. Они обеспечивают целостность, масштабируемы,
надежны и позволяют нам добиваться поставленных целей. Давайте внесем яс
ность: в реляционных базах данных нет ничего плохого, это инструменты, и они
работают. В
SQL тоже
нет ничего плохого!
18 Считается, что Фил является автором этой знаменитой фразы, хотя трудно это точно определить:
bttps://www .karlton.org/2017/12/naming-tbings-bard/ и bttps://skeptics.stackexcbange.com/questions/19836/
baspbil-karlton-ever-said-there-are-only-two-bard-things-in-computer-science.
Внедрение новых технологий
■
387
Проблема с реляционными базами данных заключается в том, что они чрезмерно
используются в тех случаях, которые не являются оптимальными для их примене
ния, например:
♦
кеширование;
♦
постановка в очередь;
♦
полнотекстовый поиск;
♦
сохранение в памяти;
♦
аналитика в реальном времени;
♦
потоковая передача данных и ее аналитика;
♦
обработка графиков;
♦ хранение блоков;
♦ хранение документов;
♦
получение и обработка временных рядов;
♦
шина обработки событий;
♦
машинное обучение;
♦
высокоскоростные транзакции
♦
граф знаний.
Цель
NoSQL -
/ низкочастотная торговля;
не замена реляционных баз данных во всех случаях их использова
ния, а поддержка вариантов использования, в которых имеет смысл использовать
другой подход. Итак, прежде чем мы углубимся в суть
чем
NoSQL
NoSQL
♦
NoSQL,
давайте разберемся,
не является.
не подразумевает:
Отказ от
SQL.
Многие NоSQL-решения имеют SQL-подобные или полноценные
SQL-интерфейсы.
♦
Единственный способ масштабировать решения на базе СУБД; посмотрите
на Amazon Aurora, бессерверную систему Uber (https://www.uber.com/Ыog/
schemaless-part-one-mysql-datastore/) или Dynomite от Netflix (https://
netflixtechblog.com/introducing-dynomite-making-nondistributed-databasesdistributed-c7bce3d89404).
♦
Отказ от всех форм согласованности и надежности.
Решения
NoSQL,
как и любое программное обеспечение, требуют компромиссов и
дополнительных возможностей, и не только в плане достуnности. Реляционные
базы данных также отличаются высокой доступностью, но они, как правило, обес
печивают высокую согласованность данных, а не их доступность. При анализе ре
шений
NoSQL
можно использовать теорему САР (САР
Эриком Брюэром (рис.
8.21 ).
Theorem),
разработанную
В распределенных базах данных допуск к разделам на
самом деле необязателен, поскольку в противном случае они не могут использо
ваться в качестве источника достоверности. Таким образом, допуск к разделам (СР)
на самом деле необязателен, и приходится выбирать между согласованностью
и доступностью. Чему из них вы хотели бы отдать предпочтение?
388
■
Глава В
Допуск к разделам
Mo"qq
Redi!'
Mel>\co.ched
Col,(cf.DB
НВме
Рис.
8.21. Теорема
САР для
NoSQL
В реляционных базах данных согласованность часто обеспечивается с помощью
АСID-гарантии: атомарность, согласованность, изоляция и долговечность
city, consistency, isolation,
(atomi-
duraЬility). По-прежнему доступны зрелые, надежные и
непротиворечивые системы, а высокодоступные системы по-прежнему непротиво
речивы. Но системы
сти, чем
ACID,
NoSQL
подцерживают более свободную модель согласованно
обычно называемую
BASE:
♦ Принципиальная доступность. Системы
NoSQL
ориентированы на доступ
ность данных, а не на абсолютную согласованность, сначала реплицируя данные
между несколькими узлами.
♦
Неактивное состояние. Хранилища данных не обязательно согласованы при
записи; реплики могут быть не всегда согласованы друг с другом.
♦ Конечная согласованность. Хранилища данных действительно демонстрируют
согласованность, но в более поздний момент времени, например при обратном
чтении.
NoSQL
позволяет нам выбрать правильную форму сохранения данных для кон
кретного случая использования. Все зависит от дизайна и уникальных возможно
стей каждой системы. При масштабировании вам необходимо совместно управлять
своей инфраструктурой: вы ее и создаете, и запускаете. Некоторые корпорации не
хотят добавлять новые базы данных, потому что осознают стоимость обслуживания
баз данных для своих операционных групп. Использование баз данных
-
это не то
же самое, что использование сторонней библиотеки . Такое мышление имеет смысл
в мире классических монолитных приложений и централизованного управления
локальными приложениями старого типа.
Для современных облачных приложений такой подход не имеет смысла и не мас
штабируется. Как подробно обсуждалось в разделе, посвященном готовым возмож
ностям, мы живем в эпоху управляемых баз данных.
Существует множество
продуктов, предлагающих полностью управляемые решения для работы с базами
данных. Операционные группы больше не несут такой тяжелой нагрузки, и пра
вильный выбор в этом вопросе должен позволить организациям использовать но
вые технологии баз данных.
В конечном счете мы говорим о стойкости полиглота, когда инженеры могут вы
брать подходящую базу данных для конкретной работы/варианта использования
Внедрение новых технологий
■
389
при условии, что она должным образом поддерживается. Надлежащие сервисы
способствуют достижению этой цели, позволяя нам абстрагировать базы данных и
легко переносить данные:
♦
переход с базы данных
♦ добавление
♦
внедрение
Redis
SQL
на
Cassandra;
в качестве кеша;
ElasticSearch
в качестве поисковой системы.
Короче говоря, надлежащие сервисы позволяют выполнять миграцию «под капо
том», на лету, и экспериментировать с различными технологиями, обеспечивая
безопасность и прозрачность (рис.
8.22).
Никогда не забывайте, что для обеспечения такой абстракции базы данных надле
жащие сервисы полагаются на изоляцию. Это означает, что команды не должны
использовать эту базу данных совместно с другими приложениями. Изоляция обес
печивает
надлежащую
защиту,
которая
позволяет командам
изменять ,
эволюцио
нировать, мигрировать и менять свое мнение о своих хранилищах данных.
--------· ........................ .
Контракт
Реализация
САс~,
сервиса лрофилей
€/мf,-Сц,,
,(?.,/;r
БД профилей
на
Рис.
MySQL
8.22.
БД профилей
на
Миграция
MySQL
происходит незаметно
Cassandra
Надлежащие сервисы (контракты и изоляция) и
NoSQL
Выход за рамки реляционной модели
Чтобы помочь при оценке баз данных
NoSQL,
мы можем сгруппировать их по раз
личным способам моделирования данных: хранилище ключей/значений, хранили
ще документов, база данных, ориентированная на столбцы , и графическая база
данных (рис .
8.23).
Хранилище ключей и значений. Простейшая форма базы данных
NoSQL:
вы по
лучаете доступ к данным с помощью ключа, который приводит к получению значе
ния.
Redis, MemcacheD, ArangoDB, Aerospike и CouchDB являются примерами хра
Redis, например, допускает ряд расширенных структур
нилищ ключей и значений.
данных для значений, например: строки, наборы , отсортированные наборы, кеш,
390
■
Глава В
Граф
Ключи/значения
~
Ключ
Значение
~
Документ
=
Набор столбцов
1111
-□ 1
1 j 1 11
Рис.
список, поток,
8.23. Типы NoSQL
PubSub, HyperLogLog,
геоданные, растровое изображение и многие
другие. Хранилища ключей и значений отлично подходят для:
♦
кеширования;
♦
управления сеансами;
♦ таблиц лидеров;
♦
настроек;
♦
корзины покупок;
♦ профилей пользователей;
♦ каталога товаров.
Документы. Данные хранятся в виде документов, чаще всего в формате
в качестве альтернативы могут быть представлены в формате
XML
JSON, но
BSON
MongoDB,
или
(двоичный JSON). Примерами баз данных документов являются
RavenDB, RethinkDB, CouchDB, ElasticSearch и А WS DocumentDB. Этот стиль базы
данных NoSQL позволяет использовать гибкую схему или даже формировать ее на
основе набора документов JSON. Хранилища документов идеально подходят для:
♦
ведения блогов;
♦
управления контентом;
♦
веб-аналитики;
♦
электронной коммерции;
♦
обработки платежей;
♦
разгрузки мейнфреймов;
♦
единого просмотра или центра обработки данных.
Столбцово-ориентированная база данных. Также известная как широкая или
колоночная база данных. В отличие от реляционных баз данных, где данные упоря-
Внедрение новых технологий
■
391
дочены по строкам, в столбцовых базах они группируются по столбцам. Такая
структура позволяет более эффективно считывать данные в определенных случаях.
Cassandra,
Google Cloud Datastore и DynamoDB являются примерами такого
NoSQL. Базы данных, ориентированные на столбцы, отлично под
НВаsе,
типа баз данных
ходят для:
♦
агрегации журналов;
♦
управления контентом;
♦
ведения блогов;
♦
электронной коммерции;
♦
управления запасами;
♦
обнаружения мошенничества;
♦
аутентификации;
♦
персонализации;
♦
Интернета вещей и передовых вычислений (данные временных рядов и быстрое
их использование).
Граф. Базы данных в виде графа ориентированы на взаимосвязи между вашими
- ссылками.
NoSQL в виде графа являются Neo4j, Janus Graph, Graph,
AWS Neptune. Базы данных в виде графа отлично подходят
данными; точки данных называются узлами или вершинами, а связи
Примерами баз данных
OrientDB, TitanDB
и
для:
♦
социальных сетей;
♦
пространственных данных;
♦ рекомендаций;
♦
графов знаний;
♦ управления идентификацией и доступом;
♦
наук о жизни.
Бережливые коммуникации
бинарные
API
и
-
GraphQL
Взаимодействие между машинами постоянно развивается. Такая эволюция связана
не только с производительностью, но и с гибкостью и созданием более совершен
ной системы, которую проще обслуживать. Мы рассмотрим возможности, выходя
щие за рамки
REST.
Взаимодействие между сервисами:
REST, gRPC
и
GraphQL
С момента появления сетевых вычислений существовало множество протоколов и
форм связи для удаленных
API.
На заре
SOA SOAP
был очень популярным прото-
392
■
Глава В
колом, но это был не единственный вариант для
RМI, популярный вариант наряду с
EJBs.
API; в то время Java поддерживала
8.24 показана краткая хронология
На рис.
АРI-взаимодействия.
ТСР
CORBA
~ОАР
1'1?1
1?'1'1
1'11ff
т
I
I
l
RPC
XML-RPC
1'181
1'1'18
Рис.
Что в
REST
т
8.24.
GrfAphQL
2015
I
т
I
I
REST
oDATA
gRPC
2000
2001
2016
Временная шкала
API
получилось правильным
АРI-интерфейсы в стиле передачи состояния представления
(Representational State
Transfer, REST) получили широкое распространение. АРI-интерфейсы REST были
созданы для работы через WеЬ/НТТР. Большинство людей связывают REST с за
просом данных через GET или с отправкой данных через POST или PUT. Однако
конструкция АРI-интерфейса REST имеет определенные ограничения: API должен
быть клиент-серверным с сильной развязкой, обладать способностью к кеширова
нию, поддерживать косвенные или многослойные системы, иметь унифицирован
ный интерфейс. Это означает, что
API
должен быть описательным, с четкой мето
дикой идентификации ресурсов и их манипуляций, и использовать гипермедиа как
двигатель состояния приложения
(hypennedia as the engine of application state,
HATEOAS).
АРI-интерфейсы
REST
стали стандартом де-факто для сервисов с тех пор, как Рой
Филдинг ввел этот термин в
2000
г. в своей докторской диссертации «Архитектур
ные стили и проектирование сетевых программных архитектур»
(https://www.
ics.uci.edu/~fielding/pubs/dissertation/fielding_dissertation_ 2up.pdf). Хотя не все
строго следуют первоначальным принципам Роя, сегодня REST является стандар
том: не имеет значения, является ли это классическим монолитом, SОА-сервисами,
микросервисами или бессерверной архитектурой.
Архитектура в стиле
REST обладает очень
♦ Достойная производительность сети.
полезными свойствами, такими как:
REST
поддерживает небольшие взаимо
действия со строгой типизацией.
♦
Простота. Благодаря принципу разделения задач
(Separation of Concerns, SOC)
в разных компонентах реализованы разные функциональные возможности.
♦ Модифицируемость.
REST API
можно обновлять без кардинальных изменений
в клиенте, в отличие от самых старых форм взаимодействия
поддерживает другие далее приведенные качества.
API,
и это свойство
■
Внедрение новых технологий
♦
393
Эволюцноннруемость. Возможность разрабатывать решения с течением времени.
♦
Расширяемость. Важная возможность добавлять больше функциональности.
♦
Настранваемость. Простота внесения пользовательских изменений.
♦
Конфнrурнруемость. Изменение аспектов и поведения с помощью конфигура
ций.
♦ Возможность повторноrо использования. Обмен функциональностью, с помощью интерфейсов
REST
REST.
очень часто используется в сочетании с
ные любого определенного типа
MIME.
JSON,
но может предоставлять дан
Преимущества
заключаются в сле
REST
дующем:
♦
НТТР. НТТР настолько широко распространен, что
REST API
совместимы
практически с любым языком программирования.
♦
Экосистема. Огромная экосистема, можно найти поддержку RЕSТ-клиента или
сервера во всем, что только можно себе представить.
♦ Возможность кешировання. Благодаря стандартам
Web
и поддержке
REST
многоуровневой архитектуры с возможностью кеширования АРI-интерфейсы
REST
дос~упны для кеширования через
полные доменные имена кешируются
♦
CDN,
DNS.
прокси-серверы, сервисы, а их
Возможность отладки. Благодаря текстовому протоколу
JSON
и
REST
инжене
ры легко понимают смысл сообщений, что упрощает диагностику и отладку.
♦ Код по запросу.
REST API
могут возвращать код на
JavaScript
или других
скриптовых языках, которые могут выполняться на стороне клиента.
♦
Проверено в бою.
REST
протестирован в бою во многих сценариях; шаблон
просто работает очень хорошо.
Главным
с
JSON
преимуществом
здесь
является
возможность
взаимодействия;
REST
позволяет легко подключать и интегрировать различные языки, операцион
ные системы и приложения с приемлемой производительностью.
REST
идеален
и отлично подходит для использования конечными пользователями в общедос~уп
ных АРI.
Однако, как и всё в программной архитектуре,
REST
имеет недостатки.
REST
не
является универсальным решением и будет работать не во всех случаях.
♦ Большие объемы данных.
REST
плохо справляется с обработкой больших объ
емов данных, особенно в контексте больших данных.
♦
Отсутствие поддержки аrреrацнн. Если нужно вызвать
lО
сервисов
REST,
вы
получите приложение, работающее в режиме чата, которое будет выполнять по
иск и отправку нескольких запросов туда и обратно. Не подходит для мобиль
ных приложений или других приложений с плохим сетевым подключением.
Можно случайно загрузить ненужные данные, запрашивая больше информации,
чем необходимо.
394
■
Глава В
♦ Производительность. Интернет есть Интернет; если вам нужно что-то, что
работает на более высокой скорости, вам нужно обратить внимание не только на
но и на варианты с меньшей полезной нагрузкой и меньшей задержкой.
REST,
Совместимость в сравнении с производительностью
не единственный вариант для
REST -
API.
Прежде чем мы поговорим о других
формах взаимодействия, важно помнить о некоторых ключевых компромиссах.
Главным компромиссом между
и
gRPC,
REST
и другими вариантами, такими как
GraphQL
является совместимость.
.
Совместимость
Рис.
8.25.
Производительность
Компромиссы: совместимость и производительность
Совместимость важна. Ранее в этом разделе мы упоминали стандарты
RМI. Если вы выбираете их для своего стандарта
можности
Java.
-
вместимость
Выбрав
REST,
API,
Java EJB
и
то ограничиваете свои воз
мы теперь можем общаться на любом языке Но со
не единственный важный фактор; производительность также имеет
большое значение в некоторых вариантах использования. Что вы теряете в произ
водительности, выбирая
EJB -
REST
(рис.
Кстати, мы не утверждаем, что RМI и
8.25)?
это вершина производительности, но пока работайте с нами!
Что, если бы вы тоже могли испытать свои силы? Пробуйте разные решения для
разных вариантов использования. Даже создавайте разные типы доступа к
API
для
своих сервисов, как мы обсуждали в главе
6
ления сервисов». Для общедоступных
где пользователи могут работать с раз
ными языками, выбирайте
REST.
API,
«Принципы надлежащего предостав
А для веб-интерфейсов, где важна производи
тельность, используйте более эффективный протокол.
GraphQL
GraphQL
был разработан
кодом. Это
API
Facebook 19
в
2015
г. как решение с открытым исходным
для запросов и манипуляций, позволяющий формировать запросы,
которые будут выбирать только необходимые вам точки данных.
декларативным
языком
и
отлично
справляется
с
запросами
GraphQL
агрегации,
является
позволяя
устранять такие проблемы, как:
♦ Недостаточная загрузка. Загружается недостаточно данных, что требует до
полнительных запросов.
♦ Избыточная загрузка. В одном запросе загружается больше данных, чем необ
ходимо.
♦
Сокращает количество сетевых обращений. Объединение запросов к не
скольким сервисам в один агрегированный запрос; отлично подходит для мо
бильных приложений.
19
Запрещен на территории РФ. - Ред.
Внедрение новых технологий
♦
■
395
Единый федеративный шлюз. Создание централизованного шлюза для чтения
данных из разных доменов. Здесь необходимо соблюдать осторожность при реа
лизации, чтобы не нарушить изоляцию.
Мы рассмотрели преимущества классических монолитов с единой реляционной
базой данных, где они могут ответить на любой вопрос пользовательского интер
фейса с помощью одного запроса к единой базе данных. Архитектуры распреде
ленных сервисов имеют фрагментированные данные в своих доменах. Внедрив
GraphQL-шлюз, можно объединить несколько различных сервисов в рамках одного
унифицированного шлюза (рис.
8.26).
Теперь пользовательский интерфейс будет
отправлять всего один запрос.
Web U;
Мобильное
приложение
Контракт
Контракт
Реализация
Реализация
сервиса профилей
сервиса продаж
БД продаж
БД профилей
на
на
MySQL
. . . . . . . . . . . . . . ..
·....... .
Рис.
На рис.
8.26
Postgres
8.26. GraphQL
также показано, как мы можем комбинировать
REST
и
GraphQL
для
наших двух сервисов. Сервисы профилей и продаж предоставляют данные с помо
щью
REST
и
JSON.
Эти АРI-интерфейсы можно вызывать напрямую, но
GraphQL
создает уровень объединения и агрегации поверх сервисов. Таким образом, веб
интерфейсы и мобильные приложения могут выполнять один вызов вместо двух
вызовов каждого сервиса.
GraphQL -
это мощный инструмент для мобильных и веб-интерфейсов, но не
является панацеей от всех бед. Вам все равно придется разрабатывать логику объ
единения данных и отдельные запросы к сервисам.
базы данных
NoSQL
или
SQL,
GraphQL
не оптимизирован, как
и плохо справляется с объемом данных. Он никоим
образом не может заменить надлежащие решения для обработки больших потоков
данных, такие как
Apache Spark, Flink
или
Kafka Streams.
Если вам нужна высокая
■
396
Глава В
производительность и вы работаете с большими объемами данных, то
GraphQL -
неподходящее решение.
GraphQL поддерживает множество языков программирования, таких как Java,
Kotlin, JavaScript, Go, РНР, Python, С#, Rust, Sca\a, Flutter, R, Groovy, Julia, Clojure,
OCaml, Swift, Haskell, С, С++ и многие другие.
У
GraphQL
♦
есть ограничения и недостатки:
Нарушение изоляции. У вас может возникнуть соблазн рассматривать
GraphQL
как обычный сервис, полагая, что вы можете сразу перейти к базам данных; это
быстрый путь к созданию распределенного монолита. Когда вы внедряете свои
механизмы разрешения конфликтов, обращайтесь только к сервисам.
♦
Теперь нужно подождать. Раньше вы могли запускать несколько вызовов
REST
параллельно, но теперь нужно дождаться завершения всей агрегации. Желатель
но, чтобы ваш сервис
GraphQL
поддерживал параллельные запросы. Если вы
полагаетесь только на ожидание одного блокирующего запроса, вы удаляете та
кие опции, как асинхронные вызовы из веб-клиентов и с рабочего стола.
♦ Загрузка файлов. Поддержка мутаций ограничена; вы не можете загружать
файлы.
♦
Отсутствие поддержки двоичных файлов.
ный
♦
JSON,
GraphQL
не поддерживает двоич
это не самый эффективный транспортный механизм.
Связность бизнес-областей.
GraphQL -
мощный инструмент, но за его удоб
ство приходится платить. Он может связывать данные нежелательным образом.
Explorer
GitHub GraphQL API
Signed ln as diegopacheco. You'rв ready to exploret
s.gn OtJt
Heads upl GitHub's GraphQL Expюrer makes use of your real, live, productlon data.
►
GraphiQL
1
2
3
,
Туре
Prett,fy
History
<Docs
Expюrer
queries into this side of the screen, and you w1ll
I see intet\.igent typeaheads aware of the current GгaphQL type sche•a,
erroгs hightighted within the text.
• {
# tive syntax, and va\.idation
S
• We'\l get you started ,.,ith
• query{
7•
vi~r {
пате
8
9•
repositories(tast: 3) {
18
noc1es {
11
narne
а
•data": {
•v1ewer•: {
s111pte query showing your username'
•гepositoгies•:
б
12
15
{
)
(
}
13
.
•n~·: "the-algorlth81"
},
}
14
{
~nodes•: [
(
}
"name": • rhino~
}
}
QUl!RY VAAIA8LE.a
}
RfQUl!ST H!AD!AS
}
1
}
{f
Рис.
Источник:
8.27. Использование GraphQL в Github.
https:/ldocs.github.com/en/graphql/overview/explorer
Внедрение новых технологий
■
397
Некоторые сервисы могут содержать конфиденциальную информацию или тре
бовать опасных привилегий для доступа к данным . Не смешивайте эти вещи .
GraphQL
никоим образом не отменяет все варианты использования
полняют
друг
друга
и
могут
использоваться
вместе,
поскольку
REST;
они до
поддерживают
JSON. GitHub также предоставляет общедоступную графику для всех пользовате
лей (https://docs.github.com/en/graphql). На рис. 8.27 показан запрос на получение
списка из трех самых последних репозиториев GitHub.
Теперь, если вас интересует производительность, давайте рассмотрим более инте
ресный вариант.
Фреймворк
gRPC 20
Google
-
в
gRPC
это высокопроизводительный RРС-подобный фреймворк, созданный
2016 r.
как решение с открытым исходным кодом.
ру клиент-сервер;
gRPC
зует буферы протокола
ры протокола
Google
gRPC
имеет архитекту
использует протокол НТТР/2, при этом ваш сервер исполь
Google
с помощью клиентской заглушки (рис.
8.28).
Буфе
представляют собой структурированный двоичный формат
сообщений, предназначенный для небольших и компактных приложений.
gRPC
работает быстро и отлично справляется с потоковой передачей данных с несколь
кими вариантами передачи:
♦
одинарная передача, без потоковой передачи;
♦
потоковая передача от клиента к серверу;
♦
потоковая передача от сервера к клиенту;
♦
двунаправленная потоковая передача.
8.28. Обзор gRPC на высоком уровне.
https://grpc.io/docs/what-is-grpc/introduction/
Рис.
Источник:
20
RPC расшифровывается как Remote Procedure Calls - удаленный вызов процедур . - Пер.
398
■
Глава 8
gRPC способен генерировать код и клиентов на нескольких языках, таких как Java,
Kotlin, Scala, JavaScript, Python, Ruby, Go, Dart, С#, Objective-C и многих других.
Еще раз:
Google
с JSON
gRPC
работает быстро. Даже простое использование буферов протокола
приводит к повышенmо скорости;
Как и у всех технологий, у
свои
REST API
60 % и
gRPC
8 %22 .
есть ограничения и недостатки:
Ограниченная поддержка браузеров. Большинство браузеров не поддержива
ют
♦
перенес
на буферы протокола, что привело к сокращению задержки на
улучшению использования ресурсов на
♦
Linkedln 21
gRPC,
поэтому для перевода вам понадобится уровень веб-прокси.
Сложнее отлаживать.
не предоставляет данные в удобочитаемом форма
те, буферы протокола
являются двоичными. Сложнее разобраться в про
gRPC
Google
блемах и устранить их.
♦
Отсутствие пограничного кеширования. По сравнению с
REST
кеширование
на границе отсутствует.
gRPC
не идеален для АРI-интерфейсов, ориентированных на клиента. Однако для
внутренней коммуникации между сервисами, когда вы жестко контролируете кли
ентов, это хороший выбор и естественная замена
REST (рис. 8.29).
Вне шние
Внутренни е
( клие нтские АРl -интерфейсы )
( в ызовы от сервиса к сервису)
REST + JSON
gRPC + протоколы
Рис.
8.29.
Спектр
gRPC
и
буферизации
REST
П риложе ни е
п ользовател я
Приложения
REST + gRPC+
РВ
JSON
N приложен ий
одно го приложения
за раз ...
Контракт
1/1О готово
Реализация
сервиса профилей
БДпрофилей
на
Рис.
8.30.
MySQL
Миграция с
REST
на
21
Социальная сеть для бизнеса, запрещенная на территории РФ. -
22
Статья о переносе буферов протокола Linkedln:
gRPC
Ред.
https://engineeгing.linkedin.com/Ыog/2023/\inkedinintegгates-pгotocol-buffeгs-with-гest-li-foг-improved-m.
Внедрение новых технологий
■
399
Одно из важных архитектурных и дизайнерских соображений, которое необходимо
учитывать при выборе между вариантами взаимодействия с
gRPC, GraphQL
API,
такими как
или другими, заключается в том, что взаимодействие с
API
REST,
являет
ся частью контракта на обслуживание. Выбрав определенный вариант, вам нужно
будет его поддерживать, а если вы его измените, то нарушите работу потребителей.
Допустим, ваш сервис предоставляет контракт с
ключены
1О
потребителей через
реализовать
преимущества
API.
REST + JSON,
к которому под
Ваша команда хочет перейти на
производительности
и
gRPC,
результативности,
чтобы
например,
меньшую задержку и лучший пользовательский опыт. Как можно это сделать, не
затронув сразу всех
1О
потребителей (рис.
8.30)?
Что нужно запомнить
Поздравляем, вы дошли до конца главы
8!
Позвольте нам кратко изложить некото
рые из полученных вами знаний здесь.
♦
Внедрение новых технологий может придать новый импульс вашим инженерам
и бизнесу.
♦
Не отказывайтесь от своих принципов при внедрении новых технологий.
♦
Облачные вычисления обладают многими очень ценными свойствами.
♦
и
•
Автоматизация
•
Гибкость, возможность масштабирования по мере необходимости.
•
Модель самообслуживания, расширяющая возможности инженеров.
•
Несколько моделей выставления счетов.
•
Высокая надежность.
•
Глобальное присутствие.
•
Управляемые сервисы и автономные операции.
-
API, CLI
SDK.
Облачные вычисления имеют свои недостатки:
•
Стоимость.
•
Привязка поставщика к собственным облачным решениям.
•
Слишком много вариантов.
•
Проблемы безопасности и инженерного обеспечения.
♦ Облачные вычисления обеспечивают множество форм изоляции:
•
Несколько экземпляров и общее хранилище.
•
Несколько зон доступности.
•
Несколько регионов.
•
Несколько учетных записей.
•
Несколько облачных провайдеров
/
центров обработки данных.
400
♦
■
Глава 8
Никогда не используйте совместно управляемые кластеры сервисов в разных
реализациях сервисов.
♦
Облачные учетные записи могут быть настроены несколькими способами для
поддержки изоляции:
♦
•
Одна учетная запись для каждого сервиса.
•
Одна учетная запись для каждой бизнес-области.
•
Одна учетная запись для всего.
С помощью учетных записей вы можете абстрагироваться от всего облака, ис
пользуя контракт с АРI-шлюзом.
♦
Бессерверное использование поможет вам безопасно осваивать новые языки.
♦
Межфункциональные команды
отличный способ получить максимальную
-
отдачу от облака.
♦
Управляемые сервисы могут облегчить жизнь вашей команде.
•
Базы данных, такие как
•
Базы данных
•
такие как
и
Spanner.
Cassandra, Kafka
и
ElasticSearch.
Искусственный интеллект и аналитика, такие как большие данные и рабочие
процессы
♦
NoSQL,
RDS, Aurora
Data Science.
Контейнеры/К8s:
•
Контейнеры являются стандартным модулем для упаковки кода приложения
и зависимостей.
•
Контейнеры отличаются большим временем запуска по сравнению с вирту
альными машинами.
•
Контейнеры обеспечивают изоляцию приложений.
•
Контейнеры обеспечивают инженерную гибкость и помогают повысить безо
пасность за счет отказа от операционной системы и использования изолиро
ванных систем, таких как
•
Контейнеры снижают производительность и пропускную способность.
• Kubemetes
•
gVisor.
обладает множеством неочевидных преимуществ, таких как:
0
огромное сообщество разработчиков и экосистема;
0
меньше зависимостей от поставщиков общедоступных облачных сервисов;
0
упрощение и сокращение очереди на выполнение работ в
0
экономия средств благодаря решению для упаковки в контейнеры.
DevOps;
Контейнеры/К8s значительно упрощают эксперименты с новыми языками
программирования.
♦
Apache Kafka:
• Apache Kafka -
это распределенное хранилище событий и платформа для
потоковой передачи.
Внедрение новых технологий
401
это простейшая форма абстракции хранилища.
•
Журнал
•
Распределенные журналы обладают следующими свойствами:
-
■
0
добавлять можно только новые записи;
0
полностью упорядоченная последовательность записей, расположенных
в хронологическом порядке.
0
•
записи не подлежать изменениям.
Возможность
лов
-
пользователя
считывать
информацию из заголовков разде
это отличная функция, поскольку она позволяет выполнять обработку
в реальном времени (чтение из заголовка), а также повторную обработку ис
тории (чтение из хвоста).
позволяет выполнять масштабные операции чтения/записи, а также
• CQRS
обеспечивает изоляцию.
•
Сервисы и микросервисы, созданные правильно, затрудняют объединение из
за отсутствия централизованной базы данных. И это хорошо.
•
Katka
обеспечивает правильную реализацию поиска событий и, следователь
но, предоставляет механизм для выполнения объединений.
♦
Современные языки программирования:
•
Рассмотрите возможность использования меньшего количества внутренних
общих библиотек и большего количества языков.
•
Бессерверная среда позволяет абстрагировать время выполнения языка.
•
Даже без использования
SOA
микросервисы могут абстрагировать язык с по
мощью контрактов.
•
Рассмотрите возможность составления матрицы ваших языков по жизненно
му циклу и использованию.
•
Языки
JVM -
это отличный способ поэкспериментировать с новыми языка
ми, используя большую часть того, что у вас уже есть в виде внутренних об
щих библиотек, инфраструктуры и инструментов.
♦
NoSQL:
•
В реляционных базах данных нет ничего плохого.
•
Реляционными базами данных злоупотребляют, некоторые варианты исполь
зования для них не подходят.
• NoSQL •
это компромиссы и опции.
Надлежащие сервисы обеспечивают прозрачную миграцию баз данных, экс
периментирование и прозрачность для потребителей.
• NoSQL
позволяет нам перейти от реляционной модели и внедрить другие
типы баз данных, такие как базы данных, ориентированные на ключ/значение,
документы, столбцы и графы.
402
♦
■
Глава В
REST -
это стиль архитектуры программного обеспечения, который отлично
подходит для взаимодействия.
♦
♦
REST
имеет недостатки:
•
Невозможность обрабатывать большие объемы данных.
•
Отсутствие поддержки агрегирования.
•
Низкая производительность.
GraphQL
помогает нам справиться с некоторыми проблемами, такими как:
•
Недостаточная выборка, недостаточная загрузка данных.
•
Избыточная выборка, загружающая ненужные данные.
•
Сокращение количества сетевых запросов, что особенно важно для мобиль
ных приложений.
•
♦ У
•
•
Единый интегрированный шлюз для чтения данных из разных доменов.
GraphQL
есть ограничения и недостатки:
Можно нарушить изоляцию, обратившись напрямую к базам данных.
Теперь нужно ждать: если раньше вы могли выполнять несколько вызовов
REST
параллельно, то теперь придется дождаться завершения всей агре
гации.
•
Нельзя выполнить загрузку файлов.
• GraphQL
не поддерживает двоичный код, поэтому это не самый эффектив
ный механизм передачи данных.
•
Не следует добавлять в
GraphQL
опасные сервисы, например с
PII
или высо
кой чувствительностью.
♦
gRPC
отлично подходит для обмена данными между сервисами:
• gRPC
использует НТТР/2 и буферы протоколов
• gRPC
довольно хорош в двунаправленной потоковой передаче данных между
Google.
клиентом и сервером.
♦
gRPC
имеет ограничения и недостатки, такие как:
•
Ограниченная поддержка браузеров.
•
Буферы протокола являются двоичными, что затрудняет их отладку и устра
нение неполадок.
•
Отсутствует пограничное кеширование.
ГЛАВА
9
Миграция кода
Энтропия
-
это цена структуры.
Илья Приго.Ж'ин
Миграция кода
(Code migration)
будет требоваться всегда, и с этим ничего не поде
лать. Однако она может быть как болезненной, так и плавной
-
всё зависит от нас.
Важно сократить радиус действия и минимизировать последствия миграции. Мето
ды
переноса кода важны, потому что в конечном счете они помогают постепенно
перейти к более эффективному использованию классического или даже распреде
ленного монолита. Некоторые концепции, принципы и практические приемы, опи
санные в этой главе, также будут применены к миграции данных.
Структура главы
В данной главе мы рассмотрим следующие темы.
♦ Почему миграция кода имеет такое значение?
•
Инвентаризация, варианты использования и РОС.
♦
Красная миграция в сравнении с зеленой.
♦
Элементы надлежащей миграции кода.
♦
•
Цель миграции.
•
Сложность.
•
Влияние на клиентов
•
Команда сервисов по сравнению с командой платформы.
-
онлайн и офлайн.
Шаблоны миграции кода.
•
Обратная совместимость.
•
Отложенная миграция.
• Strangler Fig.
0
Преобразование классического монолита в надлежащий
SOA.
404
•
♦
■
Глава 9
0
Преобразование классического монолита в модульный монолит.
0
Преобразование распределенного монолита в надлежащий
Двусторонние двери
SOA.
Amazon.
Препятствия при миграции.
•
•
•
Препятствие
остаточные явления.
-
0
У двоение усилий по инвентаризации и проверке концепций.
0
Распределенные миграции и зависимость от команды.
0
Повторение,повторение,повторение.
Препятствия
-
Препятствия
-
трения и энтропия.
высокие WIР-лимиты, давление бизнеса, соблюдение требо
ваний и другие ловушки.
♦ Пост-миграционный период.
•
Стратегии отката.
♦ Что нужно запомнить.
Почему миграция кода имеет такое значение?
Чтобы выбраться из монолита, нужно выполнить миграцию кода и данных. Мигра
ция кода часто является очень сложной задачей, но при этом воспринимается как
нечто само собой разумеющееся. Это означает, что подготовка, обдумывание, пла
нирование, тестирование, наблюдение и меры предосторожности часто не выпол
няются, что приводит к низкому качеству работы и негативному опыту. Если вы не
в состоянии оплачивать затраты на повторный запуск, у вас нет другого выбора,
кроме как столкнуться с миграцией кода. Миграция
разработки
программного обеспечения,
-
это одна из тем в области
которая часто· изучается
Хотя крупные компании постоянно ее проводят. Миграции
-
недостаточно.
это обычные и ру
тинные действия в программном обеспечении. Например, инженеры также часто
выполняют миграции на своих компьютерах, регулярно обновляя ОС, инструменты
разработчика,
JDK-
и SDК-пакеты, а также версии браузеров.
Миграции происходят по нескольким причинам, таким как:
♦ Истечение срока службы. Программное обеспечение, которое вы используете,
выходит из строя, по крайней мере, для версии
♦
x.y.z.
Окончание срока службы. Поставщик прекращает свою деятельность, а новый
поставщик не хочет его поддерживать.
♦
Соответствие требованиям. Информационная безопасность, нормативные акты
и внешние агеотства вынуждают вашу компанию применять исправления и об
новлять программное обеспечение.
♦ Инфраструктура. Вы экономите средства и повышаете гибкость, т. е. перехо
дите от программного обеспечения, установленного локально, к общедоступно
му облаку.
■
Миграция кода
♦
405
Разделение на части. Вы хотите перейти от классического или распределенного
монолита к более гибкой архитектуре.
♦
Завершение работы устаревшего сервиса. Если ваш текущий сервис или
решение больше не соответствуют потребностям бизнеса или появились более
эффективные альтернативы, например вы создали собственный балансировщик
нагрузки и хотите перейти на А WS
ALB,
пришло время завершить его исполь
зование.
♦
Новые возможности для бизнеса. Ваш бизнес требует новых возможностей,
что вынуждает вас переносить некоторые системы на новые технологии, кото
рые позволяют бизнесу быть более эффективным или обеспечивают лучший
опыт для пользователей.
♦
Консолидация. Ваша компания купила пять компаний, и нет смысла иметь де
сять разных систем аутентификации, вы хотите стандартизировать их, например,
на основе
♦
OAuth
и
Active Directory (АО).
Модернизация. Пришло время переосмыслить ваши решения и перестроить их
архитектуру. Это приведет к миграции.
Как можно видеть, различные причины приводят к одному и тому же результату:
миграции кода. Миграция кода
классические
и
-
распределенные
это инструмент для изменений. Чтобы исправить
монолиты,
нам
нужно
провести
Модернизация, перенос в облако и цифровая трансформация
-
миграцию
ненные причины, по которым приходится выполнять миграцию кода (рис.
Истечение
Соответствие
срока службы
требованиям
Усовершенствования
Консолидация
кода.
очень распростра
9.1).
Починка монолита
Миграция кода
Рис.
9.1 .
Несколько причин, приводящих к миграции кода
Возможно, вам интересно, почему мы снова и снова возвращаемся к этому вопросу.
Многие команды, инженеры и менеджеры считают миграцию ненужной и не вхо
дящей в их обязанности. Они не видят в ней смысла. Миграция очень важна. Она
является важным элементом в решении проблем с классическими и распределен
ными монолитами. Миграция кода
-
это форма рефакторинга. Может ли команда
никогда не заниматься рефакторингом? Да, и, к сожалению, такое случается, но бу
дут ли решения поддерживаемыми? Нет. Миграция кода
-
это сложная задача, не
поймите нас неправильно. Но она неизбежна. Можете ли вы пропустить миграции
кода? Нет. Неочевидное решение проблемы, с которой вы не справляетесь, заклю-
406
■
Глава 9
чается в том, чтобы делать это чаще. Итак, вам нужно научиться выполнять мигра
ции эффективнее, потому что они будут происходить часто.
Инвентаризация, варианты использования и РОС
Как мы уже говорили в главе
5
«Оценки», оценки имеют решающее значение для
любой миграции, и они начинаются с инвентаризации
(Inventories).
Стоит ли начи
нать миграцию кода, не понимая, что вы делаете? Нет. Вы должны уметь разо
браться в проблеме, понимать ее форму и масштабы, с которыми вам придется
столкнуться, а также количество вовлеченных потребителей. Каковы варианты ис
пользования? Очень заманчиво взяться за решение и устранить проблему прямо
сейчас, но вы должны противостоять искушению.
Инвентаризация необходима для понимания проблемного пространства. Нам пона
добится составить инвентарный список, провести анализ вариантов использования
и проверку концепций
(Proof of Concept,
РОС). Прежде всего, начнем с составления
инвентарного списка. Возможно, вам интересно, зачем тратить время и создавать
такой список, если нам все равно нужно выполнить миграцию?
Инвентаризация важна по нескольким причинам.
♦
Масштаб. Инвентаризация позволяет оценить масштаб миграции.
♦ Понимание проблемы. Инвентаризация позволяет получить важную информа
цию о ваших потребителях, зависимостях и ограничениях.
♦ Ход выполнения и отслеживание. Централизованный просмотр хода выполне
ния позволяет отслеживать процесс миграции и не оставаться в неведении.
♦
Стратегия, план и рациональное использование. Инвентаризация позволяет
разработать стратегию и спланировать миграцию, что значительно улучшает си
туацию.
Инвентаризация будет отражать объем работы, которую вам необходимо выпол
нить. Анализируя своих потребителей, вы сможете выявить возможные проблемы;
давайте рассмотрим их на примере.
Цель: перейти с
Ehcache
на
Redis.
Варианты использования:
хеша для устранения
Хранwтще: репозиторий на
Уровень воздействия:
ринг,
3 высокий ==
кеширование
LRU,
выгрузка базы данных, поиск
ifs.
GitHub.
1 низкий
==
прозрачность,
2
средний
=
тот же рефакто
много рефакторинга.
Предположим, что у вас обнаружилось наличие
50 репозиториев на GitHub для пе
30 из них предназначены для кеширования LRU и отлично подходят для
Redis, 1О - для разгрузки базы данных, которая также хорошо подходит для Redis,
и 1О - для поиска, чтобы устранить ifs. Иногда инженеры используют структуры
реноса;
данных для улучшения читабельности кода. Обычной практикой является создание
хеш-карты с ключами, а затем быстрый поиск в ней вместо использования инст-
Миграция кода
рукций
if
или
■
407
В таких случаях вам на самом деле не нужно переходить на
switch.
После изучения кода и создания реестра вы понимаете варианты использо
Redis.
вания и можете выбрать разные пути.
Рассмотрим следующие варианты:
♦
Как есть
вы
♦
(as-is). Можем ли мы написать программу, которая преобразует
Ehcache АР[ в вызовы Redis, Lettuce Java driver API? Да, мы могли бы.
вызо
Уменьшить область применения. Можем ли мы отказаться от всех вариантов
использования поиска по хешу и просто попросить людей использовать обыч
ные Jаvа-хеш-карты? Мы могли бы перейти на
Redis,
но для такого варианта
использования это будет малоэффективно.
♦
Объединение вариантов использования. Можем ли мы объединить варианты
использования кеша
LRU
и разгрузки базы данных? Да, могли бы, следует рас
смотреть возможность объединения вариантов использования.
♦
Прозрачная миграция. Мы можем взломать
фейсы; новая реализация вызовов
Redis
Ehcache
и сохранить АРI-интер
находится в разработке, следовательно,
миграция прозрачна.
♦ РОС. Можно перенести один репозиторий, чтобы увидеть, какие проблемы возникнут.
Теперь этот список вариантов следует превратить в список концепций. Это позво
лит вам проверить их жизнеспособность и выбрать наиболее подходящее решение,
используя анализ компромиссов и учитывая цели «зеленой миграции».
Пример на рис.
9 .2
хорошо согласуется с антипаттерном распределенного моноли
та, где у вас, скорее всего, будет много репозиториев. Даже если у вас нет распре
деленных монолитов и вы используете соответствующие изолированные сервисы,
миграции носят сквозной характер. Как насчет классического монолита, где вся
база кода находится в одном репозитории на
GitHub?
Даже для других случаев
Цель
Миграция кода
1
.._E_h_ca_c_he_ _ ___,1-----------~►~
Redis
Анализ потребителей (инвентаризация)
1
1
1
1
---
-
1
1
30 репозиториев
для кеширования
Рис.
1
1
1
LRU
9.2.
--
1
1О
репозиториев
для разгрузки
базы данных
1
...
-...
Инвентаризация и варианты использования
1О
репозиториев
для устранения
if
408
■
Глава 9
использования, когда компании просто полагаются на монопредставления? Прин
ципы те же, но в вашей инвентарной таблице не будет столбца репозитория
GitHub,
а, возможно, будет другая форма для идентификации потребителей внутри моноли
та, например:
♦
список модулей;
♦
список классов;
♦ список файлов.
У вас все еще могут быть ссылки на
GitHub
или вы можете каким-либо образом
связать код с любым инструментом управления конфигурацией программного
обеспечения
(Software configuration management, SCM),
который вы используете.
Теперь, когда у нас есть инвентаризация, сопоставлены варианты использования
и выполнены некоторые проверки кода, мы поговорим о компромиссах при мигра
ции.
Красная миграция в сравнении с зеленой
Давайте поделимся историей о двух миграциях:
Красная миграция
(red migrations).
Это происходит, когда код ломается по не
скольким направлениям; возникают проблемы с компиляцией, временем выполне
ния и тестированием; ошибки обнаруживаются только в процессе промышленной
эксплуатации; это занимает много времени, стоит больших денег, а выгода косвен
ная, и бизнесу было трудно ее увидеть. Кроме того, трудно понять ход миграции.
Оrкат? Сложно, болезненно.
Зеленая миграция
(green migrations).
Учитывая, что мы работаем в другой среде,
код не ломается повсеместно, он выполнен прозрачно или в пределах разумного и
контролируемого радиуса действия, а изменения минимальны; обнаружено очень
мало ошибок, и часто очень рано, мало ошибок на продуктиве, преимущества для
бизнеса ясны, видимы и имеется кристально ясное понимание прогресса. Оrкат?
Управляемый.
Какой из них лучше: красная или зеленая миграция? Зеленая миграция, не так ли?
Проблема с красной миграцией заключается в том, что она создает проблемы как
для инженерных групп, так и для бизнеса. Красная миграция является источником
сбоев и нарушает бизнес-процессы. Красные миграции, как правило, приостанав
ливаются, имеют длинные хвосты и встречают сопротивление со всех сторон.
Иногда невозможно сделать миграцию на
100 %
зеленой. Но ваша цель
-
сделать
ее максимально зеленой и работать таким образом, чтобы ваши миграции со време
нем улучшались и становились более эффективными, а вы более качественно их
выполняли.
Как вы можете видеть на рис.
9.3,
переход от красной к зеленой миграции
-
это
спектр. Теперь давайте рассмотрим все действия, которые можем предпринять,
чтобы сделать миграцию как можно более зеленой.
Миграция кода
Красная
■
409
Зеленая
........... ........................ .........
миграция
миграция
(-) Огромный радиус поражения
(-) Множество критических изменений
(-) Медленная, запоздалая и дорогостоящая
(+) Контролируемый радиус поражения
(+) Меньше критических изменений
(+) Быстрая, своевременная и недорогая
обратная связь
обратная связь
(-) Ошибки на поздних этапах
(-) Косвенная, скрытая ценность для бизнеса
(-) Плохая видимость , трудности с мониторингом
(-) Болезненный откат
Рис.
9.3.
(+) Выявление ошибок на ранних этапах
(+) Прямая и понятная ценность для бизнеса
(+) Отличная видимость, легкий мониторинг
(+) Управляемый откат
Красная миграция в сравнении с зеленой
Элементы надлежащей миграции кода
Сейчас самое время обсудить возможные варианты миграции кода; здесь есть не
сколько компромиссов и вариантов. Мы разделяем их на четыре категории: цель
переноса, сложность, влияние на клиента и исполнение.
Цель миграции
Первая категория касается цели миграции
(migration target).
Здесь у нас есть три
подэлемента: Тип, Что и Как. Тип и Что очень похожи. Можно даже утверждать,
что они довольно искусственные и оба могут быть объединены в один. Давайте
начнем с Типа. Вы переносите несколько целевых объектов. У вас будет несколько
различных типов целевых объектов (компонентов), таких как:
♦
веб-приложения с пользовательским интерфейсом;
♦
приложения для настольных компьютеров;
♦
серверная часть для интерфейсов
♦
микросервисы;
♦
решения сторонних производителей;
♦
классические монолиты;
♦
распределенные монолиты;
♦
один или все из вышеперечисленных.
(BFF),
часто это приложения
NodeJS;
Что общего у всех этих элементов? Такими компонентами могут быть модули раз
вертывания, которые могут находиться на одном сервере (Ьig Ьох) или на несколь
ких серверах. Часто классические монолиты и распределенные монолиты содержат
несколько типов компонентов, объединенных в одном целевом объекте.
Классические монолиты могут иметь несколько серверов для обеспечения масшта
бируемости и отработки отказа, но представляют собой один большой блок, в то
время как распределенные монолиты будут иметь больше серверов и будут логиче
ски распределены вне зависимости от масштабируемости и отработки отказа.
Классический монолит содержит множество различных типов компонентов, объ
единенных в одном модуле развертывания; в
Java
это может быть
JAR, EAR
или
Глава 9
■
410
Классический монолит
Распределенный монолит
1 сервер , 1О приложений
1О серверов , 1О приложений
...
1 _______
t 1
t
1
з_
-.
1
L.
rL----------~-
:~-----------1
~
~·
1
1
-~----------
·- - -
-.
1
t
1~
~------------ ----------- -,
-
- - - -
- - -
Рис.
WAR.
-
- -
- -
9.4.
1
1
- - -
-
..!1
i
- - --- " ------- --~- --- -- -- -.
1
Общая реляционная БД
- - -
• Г
11
''
., L----
1
11
,
1
-
1
t.
, ____________
- 1
1
•
L _________
1 - -
~--- --- - '
""
1
..!
_____ _
1
-
:
,-------.!!.:
t I
r_1
'----------1 1
1
••
- ,
1
1 1
1
-
1
,..: ______ ,. ___________
1
' 1
.JJ.11----------- ·-1
1 1
1
1
1 --------
1
Общая реляционная БД
1
1
~-------------------------:
- -'
Классический монолит по сравнению с распределённым
Базы данных часто являются еще одним компонентом; для наглядности все
они объединены в этом примере (рис .
Рассматривая пример на рис.
монолитом является
Java,
9.5,
9.4).
вы можете видеть, что нашим классическим
но давайте предположим, что это
момент вы должны использовать
Java 19
Java 1.6,
и на данный
или новее. Здесь тип представляет собой
классический монолит, но это не что-то одно, а несколько вещей, потому что у нас
есть сг.едующее: два разных интерфейсных приложения, одно из которых написано
на Apache Wicket, куча Jаvа-сервисов, некоторые веб-сервисы
на JSF, а другое с
SOAP,
другие просто
RPC
с
RMI,
для отчетов в
Java
использует
Jasper,
внутрен
ние общие библиотеки и большая общая реляционная база данных, которая содер
жит множество функций и даже объектов Java, запущенных на стороне базы дан
ных.
Классический монолит
---------------------г--------------------1
,,
Веб-интерфейс (JSF)
:
::
Веб-интерфейс (Apache Wicket)
:
1
•'
1
·---------------------·~---------------------·
r----"" - -- - - -,, - - - - - - -- -- -1,...------ - -- - - IJ
lt
•
1
: Сервис Java
11
:: Сервис Java
11
: : Сервис Java
• -----------~• ___________ lt _________________:
-------------- ,.. --------------------------.
1
1
1
1
tl
"
: Отчеты Jasper
:: Сервис Java
:
1
11
1
'-= -- -
Общие библиотеки
·-------------------------_-,,.-:_ ":.--:.-:- - -:. ":. ""':. -:.-: -:. ~
:
' ~акетные процессы : ' ... ???
_ ,_ ava __________ ,,_____________ 1
----- --- ------- r---------1
,
Реляционная БД
1
,
:
'
Объекты
1
1
Java :
Функции БД
1
1__ - - - - - - - - - - - - - - - - - - · - - - - - - - - - - - ' - - - - - - - - -
Рис.
9.5.
Пример миграции кода классического монолита
Миграция кода
Следующий элемент
-
■
411
это модуль компонента (вид или тип компонента), который
и необходимо собственно мигрировать, и иногда одновременно изменяются не
сколько элементов. Таким образом, это может быть один модуль, одна библиотека
Java
или комбинация нескольких модулей: библиотека
Java,
задание
Jenkins
и про
цедура доступа к базе данных. Модуль компонента дает вам некоторое представле
ние о том, что изменяется в коде, например:
♦
конфигурация;
♦
библиотеки;
♦
фреймворки;
♦
JDK-
♦
операционная система;
♦
языки программирования;
♦
базы данных, которые будут рассмотрены в следующей главе
и SDК-пакеты;
10 «Миграция
дан-
ных».
Ну и последний элемент
-
это Как. Как мы собираемся это сделать? Переносим ли
мы всё как есть, с минимальными изменениями, что облачные провайдеры называ
ют «подъемом и сдвигом». Нужно ли нам перестраивать архитектуру и в целом пе
реосмысливать все? Можем ли мы провести некоторые изменения в вендорах про
зрачно? Например, можем ли мы перейти с
Orac\e JDK 11
на А WS
Corretto JDK 11?
Какие изменения нам нужно внести сейчас, а какие можно внести позже? Будет ли
интерфейс сохранен на
TypeScript
и
Java
с помощью
JSF
или он будет перенесен, например, на
9.6)?
Что мигрируется в первую очередь?
React?
Много возможностей, не так ли (рис.
С чего мы начнем? Мы ответим на этот вопрос в следующей главе по мере того, как
вы будете узнавать больше вариантов, техник и компромиссов.
• Веб-припожение с пользо вательски м интерфейсом
• Приложение дпя настольно го комьютера
• Серверная часть дпя интерфейсеров (BFF)
часто испопьзует NodeJS
• Приложения
• Классические монолиты
• Микросервисы
• Распределенные монолиты
• Решения сторонних производителей
Рис.
9.6.
• Библиотеки
• Фреймворки
• JDK- и SDК-пакеты
• Операционная си сте ма
• Язы ки пр о граммирования
• Баз ы данн ых
Цель миграции: Тип, Что и Как
На данный момент вот некоторые рекомендации: возвращаясь к вашему инвентар
ному списку, вы можете добавить несколько дополнительных столбцов, чтобы
классифицировать тип, какие работы будут выполняться и как они будут выпал-
412
Глава 9
■
няться. Вы можете и должны рассмотреть различные стратегии для каждого ком
понента. Миграция кода может быть выполнена разными способами, и, как видите,
нет правильного или неправильного. Вот несколько советов, которые следует учи
тывать, чтобы определить приоритетность для вашей цели миграции .
♦
Критичность. Возникают ли у нас проблемы с доступностью из-за критичности
или влияния на бизнес?
♦
Стоимость. Можно ли добиться существенной экономии?
♦
Низко висящие плоды. Можно ли легко выполнить миграцию кода?
Поставщики облачных вычислений , такие как А WS, классифицируют некоторые
стратегии Как как
7Rs.
г-----~----------~
(Rehost)
Передвинуть
-------------~
_ _.,...,..,./ Поднимите и переместите, т. е. перенесите на ЕС2
--------------------------------~
-------- .
r-------------
1 -------------- ------- ---------·
Переместить
(Relocate)
~f
t---,►
Сменить платформу
1
Поднимите и сдвиньте + измените форму, т. е. из Oracle RAC в RDS Oracle
-- -------•1
l _____________________
(Replatform)
г----
Купить заново
(Repurchase) 1----1>1
-------- ---
Удаление и закупка , т. е. новый поставщик, торговая площадка
L-"'"""- ----~~-- -----
г--------
Оставить
L
---------9.7.
На рис.
9.7
'
___ ;i1
-------- --------------1
_
-------- ----- ---
Цель миграции: Тип, Что и Как. Источник:
j
--- ..
-----
~: Вывод из эксплуатации. Может спровоцировать миграцию
t---,►
(Retire)
Рис.
--
► ~о~~~~е~, пото:у:~ ~1~е м~ж~те миrриро~ть
(Retain)
г-
Списать
1
Поднимите и сдвиньте , т. е. запустите VMware на AWS
L ________ .._. __ ,_ _____ ------- ----- •1
:
-------------~
https://docs.aws.amazon.com/prescriptiveguidance/latest/large-migration-guide/migration-strategies.html
показаны некоторые варианты Как для переноса в облако. Теперь да
вайте перейдем к следующему разделу, который посвящен трудностям.
Сложность
Миграция кода может осуществляться с незначительным или значительным воз
действием на людей или технологии. Изменения в коде могут быть очень простыми
в том смысле , что вы можете просто изменить номер версии в своем
вая, что
Java
использует
другой, например
Java
p om. xml ,
учиты
Maven, и, возможно, заменить импорт из одного пакета на
Jakarta ЕЕ . Изменения в коде также могут быть жест
ЕЕ на
кими и вынудить вас изменить бизнес-логику. Из-за удаления функции может на
рушится текущая работа (рис.
9.8).
В то время как самый важный фактор, который приведет к миграции кода на прак
тике или при передаче, заключается в том, есть ли у вас обратная совместимость
Миграция кода
■
413
или нет. Как видно из спектра обратной совместимости, она может составлять от О
до
100 %.
Некоторые или все ваши методы или операции могут быть обратно со
вместимы, что упростит миграцию.
В ручном режиме
(-) Изменения,
Рис.
9.8.
•• •• •••• •• •••• •• •• •• •• •••••• ••••••••• •• •• •• •
\
нарушающие целостность
В автоматическом
режиме
(+) Обратная
совместимость
Миграция в ручном режиме в сравнении с миграцией в автоматическом режиме
Допустим, ваш подход имеет обратную совместимость на О
%;
это не значит, что
вы не можете автоматизировать изменения. Вы могли бы написать программу, ко
торая внесет необходимые правки в код, и она бы хорошо работала для:
♦
импорта кода;
♦
имен классов и методов;
♦
удаления классов.
Там, где это было бы непросто (в случаях, когда порядок следования параметров
меняется
или бизнес-логика нуждается в переосмыслении), это действительно
должно быть сделано вручную. Кроме того, для автоматизации миграции кода не
обходимо учитывать затраты на автоматизацию всех возможных сценариев и изме
нений кода, которые иногда не окупаются.
Давайте вернемся к сравнению
Ehcache
и
Redis для
сценария миграции кода.
Контракт
Ehcache
+ Получение строки
(строковый ключ)
Интерфейс
+ Void put (строковый ключ , строковое значение)
Контракт на обслуживание кеша
Сервис кеширования
v1
Контракт на обслуживание кеша
v1
~
lmp-v1
§
Рис.
Сервис кеширования
lmp-v2
--
9.9.
Контракт в интерфейсе
Миграция с
REST
Ehcache
(рис.
на
Redis -
~
.....
......
реализация создают и используют
операции: PUT -
Ehcache отображается как REST + JSON
.-,,
Redis
~
сервисный сценарий
9.9), открытый по протоколу НТТР 1.1, и
JSON; поддерживаемые операции - это
его
две
где вы передаете ключ и значение, которые будут храниться на
сервере кеширования, и
GET -
где вы передаете ключ для выполнения поиска.
414
■
Глава 9
Учтите, что в первой реализации у вас есть простой сервис кеширования. Однако
текущее решение работает неидеально.
Вам нужно хранить больше объектов,
и каждый раз, когда сервис не работает, кеш теряется. В результате возникает про
блема с холодной загрузкой, которая создает некоторые всплески задержки, когда
кеш пуст. В этом примере в реализации версии
решила перейти на
Redis.
1 используется Ehcache,
и команда
Таким образом, можно было бы использовать возможно
сти кластера и даже перейти на А WS
Elasticache Redis
в будущем. Вы проводите
инвентаризацию и анализ кода, а затем обнаруживаете, что сервисом кеширования
пользуются более
100
пользователей.
Эту миграцию кода можно выполнить с помощью обратной совместимости, по
скольку мы знаем контракт. Даже если контракт связан с интерфейсом
Ehcache,
было бы возможно реализовать этот интерфейс и сохранить контракт, чтобы все
вызовы
REST
не прерывались. Однако в реальной реализации (версия
вался бы не встроенный
Ehcache
в
а
Java,
2)
использо
Redis.
Теперь миграция не только прозрачна, но и стало возможным внедрить «зеленую»
миграцию с помощью:
♦
Тестирования. Всестороннее и автоматизированное тестирование публичного
контракта.
♦
Возможности отката. Внедрение может быть очень прозрачным на сетевом
уровне. Легко переключать всех пользователей. Повторное развертывание не
требуется.
♦
Обратной совместимости. Позволяет избежать сложных проблем с рефакто
рингом благодаря подходу обратной совместимости.
Давайте рассмотрим другой сценарий миграции, более сложный, где кеш
это
-
внутренняя общая библиотека, а не сервис.
1
1
1
1
1
1
1
1
-.. ..
1
-
Библиотека кеширования,
версия
1
1
кеширования, версия
Библиотека кеширования,
Контракт на библиотеку
кешиоования веосия
Контракт на библиотеку
Контракт на библиотеку
кеширования, версия
L Ehcache
версия
1
1 Ehcache
""
..
версия
2
1~
~
1С
l
Рис.
На рис.
1
Библиотека кеширования,
9.1 О
9.10.
Миграция с
Ehcache
на
Redis -
Ehcache
на
Redis.
J
библиотечный сценарий
представлен несколько иной сценарий: более
прежнему переходят с
Redis
100
пользователей по
Сохраняются те же ограничения и пробле
мы. Цель по-прежнему заключается в зеленой миграции и обеспечении обратной
Миграция кода
■
415
Распределенные
монолиты
Классические
монолиты
Внутренние общие
библиотеки
ВремяNсилия
Рис.
9.11.
Сложность/размер в зависимости от времени/усилий
для различных целей миграции
совместимости. Однако в этом случае у нас нет сервиса, а есть внутренняя общая
библиотека.
Мы бы по-прежнему применяли обратную совместимость аналогичным образом.
Однако теперь у нас нет интерфейса
фейсу
♦
Ehcache,
нет
JSON.
REST,
есть
Java JAR
и прямой доступ к интер
Это создает дополнительные сложности:
Распространение. Более чем в
нить версию библиотеки с
100 различных репозиториях потребуется изме
v 1 на v2. Вы можете и даже должны автоматизиро
вать этот процесс.
♦
Многократное развертывание. Развертывание не может быть выполнено так
же просто, как развертывание сервиса; потребуется повторное развертывание.
♦ Последствия отката. Выхода нет; есть последствия отката, о которых мы поговорим позже в этой главе.
Нам, как команде по миграции, предстоит проделать еще большую работу, но мы
всё еще можем добиться зеленой миграции. Классические монолиты и распреде
ленные монолиты гораздо сложнее; о них будет рассказано позже в текущей главе.
Учитывая, что вы будете стремиться задействовать все доступные ресурсы для
обеспечения обратной совместимости, можно говорить о том, что задача по мигра
ции кода является масштабной, трудоемкой и продолжительной по времени.
Надлежащие сервисы проще поддерживать и переносить (рис.
9.11).
Экономичные
внутренние общие библиотеки также проще в обслуживании. Тем не менее класси
ческие внутренние общие библиотеки намного сложнее, чем сервисы, по причинам,
которые мы уже обсуждали. Два других типа мы рассмотрим позже.
У старевшие приложения часто намного сложнее, и у вас может не быть возможно
сти обеспечить 100%-ную обратную совместимость с новыми версиями. Вам всё
равно могут потребоваться следующие изменения:
416
♦
■
Глава
9
Существенное изменение
пользовательского
интерфейса:
от
настольного
к веб- или от веб- к мобильному.
♦
Масштабный языковой сдвиг: переход с одного языка на другой, например
с
♦
Delphi
на
Java.
Масштабное изменение хранилища данных: вынужденная смена базы дан
ных, например с
♦
Sybase
на
Postgres.
Масштабное обновление платформы: пришлось значительно изменить на-
стройки и нарушить обратную совместимость, например с
Hibemate 3 на 6.
Даже имея хотя бы один пункт из этого списка, вы уже столкнетесь с множеством
трудностей. Миграция кода никогда не заканчивается. Даже если вы вынуждены
выполнять переход в красном режиме, можно предпринять действия, которые со
временем упростят и сделают его более зеленым, например:
♦
Упрощение. Упростите свою экосистему, используйте меньше вариантов, ис
пользуйте стандарты.
♦
Меньше внутренних библиотек. Используйте меньше внутренних общих биб
лиотек, несколько библиотек вместо сотен.
♦
Надлежащие сервисы. Следуя принципам, изложенным в этой книге, предос
тавляйте надлежащие сервисы и используйте изоляцию как способ обеспечения
параллельной миграции. Гибкость, изоляция и надлежащие контракты влияют
на производительность.
♦ Жизненный цикл разработки. Наличие определенного жизненного цикла, пу
ти вывода приложений и сервисов из эксплуатации.
♦
Минимальный стек. Используйте минимальный стек и по возможности избе
гайте бинарных связей.
♦
Следите за общими глобальными компонентами. Тщательно изучайте гло
бальные изменения с большим радиусом распространения по всем сервисам. Это
могут быть как внешние сервисы, так и внутренние библиотеки.
♦ Больше инкрементных миграций. Применяйте больше инкрементных и постоянных миграций, чтобы уменьшить отклонения и упростить процесс.
В зависимости от состояния ваших устаревших приложений, возможно, придется
выполнить несколько повторных миграций, прежде чем удастся перейти на более
зеленый режим. Сложность и влияние на команду
-
ключевой аспект миграции
кода. Теперь давайте обратим внимание на еще одну важную форму воздействия,
но не на внутреннюю команду, а на клиентов и конечных потребителей.
Влияние на клиентов
-
онлайн и офлайн
Зеленая миграция не оказывает никакого влияния на конечных пользователей, ва
ших
клиентов
(рис.
9 .12).
Правильная
архитектура
программного
обеспечения
с использованием надлежащих сервисов позволяет нам вносить изменения в очень
прозрачной форме. Прозрачные изменения
-
это отлично, потому что они позво
ляют конечным пользователям нормально пользоваться вашим продуктом/реше-
Миграция кода
..._О_Ф_л_ай_н_
__,,- • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • 1
(-) Вынужденный
Рис.
простой
9.12.
■
417
Онлайн
(+)
Нет простоя
Влияние на потребителя: офлайн- и онлайн-спектр
нием, не замечая никаких перемен. Такой подход ведёт нас к переходу в онлайн.
У нас также есть офлайн-решения, которые находятся на другом конце спектра.
Онлайн-режим миграции
Как следует из названия, нет простоев или простоев, заметных для клиентов (ко
нечных пользователей).
Онлайн
-
это действительно здорово, ведь он открывает множество преимуществ,
таких как:
♦
Прозрачность. А кто-нибудь вообще заметил, что происходит миграция кода?
♦
Отсутствие простоев. Никаких финансовых потерь, никаких объяснений, ника
кой драмы.
♦
Зрелость. технологическая организация уверенно справляется с онлайн-пере
ходами и, скорее всего, делает это на высоком уровне.
♦
Потрясающий опыт. Укрепление доверия к бренду; идеально подходит для получения удовольствия от использования продукта.
Звучит заманчиво, не так ли? Да, но за это приходится платить. Работать онлайн
намного сложнее, потому что:
♦
многое может пойти не так;
♦
миграция кода может стоить дороже;
♦ тестирование и откат станут более дорогостоящими.
Офлайн-режим миграции
Режим офлайн может показаться неразумным вариантом, но в некоторых случаях
он вполне приемлем. То, что компонент находится в автономном режиме, не обяза
тельно означает, что с точки зрения потребителя у вас будут простои. Всё зависит
от того, как работает компонент. Например, если целевым типом переноса кода
является веб-интерфейс, ориентированный на клиента, то когда этот веб-интерфейс
недоступен, возникает время простоя.
Теперь давайте рассмотрим другой тип цели переноса кода, например пакетное за
дание. Для пакетного задания, которое выполняется в фоновом режиме асинхрон
но, может потребоваться пара секунд, а иногда и минут. Итак, здесь, как вы можете
видеть, мы разделили работу офлайн и время простоя. Однако не все миграции
кода и не все типы компонентов допускают такой подход.
Офлайн-режим имеет преимущества (рис.
9.13).
Но, как и в любой архитектуре
программного обеспечения, здесь есть свои компромиссы:
418
■
Глава 9
Веб-
интерфейс
"'~
Мобильное
приложение
\,:
"'gQ)
.
О
•
•
Сервисы
с::
"'
:х:
Q)
s
:х:
"'s
Пакетные
,j§
задания
Внутренняя общая
библиотека
Время работы офлайн
Рис.
9.13.
Влияние режима офлайн на разные виды компонентов
♦ Проще, меньше проблем может возникнуть. Устраняется множество сложно
стей, меньше возможностей для сбоев и все упрощается. Вам не нужно беспоко
иться о проблемах синхронизации.
♦
Стоимость ниже. Процесс может стоить дешевле, но всё будет зависеть от ма
тематических расчетов
♦
-
при снижении производительности снизится и доход.
Возможно, это единственный способ. Из-за технических ограничений могут
быть задействованы некоторые устаревшие приложения.
В зависимости от типа бизнеса и предоставляемых сервисов у вас будут разные
уровни критичности. Один из полезных методов, который используют компании,
-
это создание уровней. Уровни позволяют понять, какие компоненты могут выдер
живать меньшее время простоя. Каждый бизнес индивидуален и может иметь свои
целевые показатели уровня обслуживания
(Service Level Objectives, SLO) 1
для
обеспечения доступности.
Один из возможных примеров представлен в табл.
9.1 .
Таблица
Доступность:
Уровень
Уровень
время безотказной работы
1
Время безотказной работы:
Время простоя:
Уровень
2
4
99,671 %
99,741 %
часа в год
Время безотказной работы:
Время простоя:
1
22
время простоя
Компонент
База данных
MySQL
часа в год
Время безотказной работы:
Время простоя:
Уровень З
28,8
/
9.1. Уровни
99,982 %
Redis:
Веб-интерфейс: продажи
часа в год
Определение целевых показателей уровня обслуживания в Википедии :
https://en. wikipedia.oгg/wiki/Seгvice-level_objective.
кеширование категорий
товаров
Миграция кода
Таблица
Уровень
Доступность:
время безотказной работы
Уровень
Время безотказной работы:
4
Время простоя:
26,3
Наличие целей и уровней
/
время простоя
(табл.
9.1)
419
(окончание)
Компонент
Сервис продаж, база данных
99,995 %
минуты в год
SLO
9.1
■
Cassandra
для всех ваших компонентов упрощает
планирование миграции кода и дает вам четкое представление о том, что должно
быть подключено к сети и насколько автономно вы можете работать с каждым
компонентом.
Команда сервисов
по сравнению с командой платформы
Чтобы выполнить миграцию кода, нам необходимо приложить усилия проектной
команды. Не все миграции полностью автоматизированы, особенно когда есть
много критических изменений. Иногда приходится идти на компромисс между
автоматизацией и ручной миграцией. Автоматизация экономит время, но требует
затрат на разработку. Ручная миграция может быть быстрой, но ее результаты
могут привести к повторной миграции.
Когда автоматизации недостаточно, возникает целый спектр задач, которые в ос
новном могут быть выполнены командой сервиса на одной стороне спектра или
командой разработчиков платформы на другой стороне спектра (рис.
кают трения. Мы обсуждали эту тему в главе
2
9.14).
Возни
«Антипаттерны: отсутствие изо
ляции».
Команда сервиса
Гибридная команда
Рис.
9.14.
Команда платформы
Спектр реализации миграции кода
Команды сервисов. Гораздо лучше знают бизнес по сравнению с платформенными
командами и находятся в наилучшем месте для тестирования решения с точки зре
ния его влияния на бизнес. Бизнес-знания команды сервиса важны для классиче
ских монолитных и устаревших решений, где нет четких границ владения. Они
распределяются между несколькими командами, а автоматизация тестирования на
ходится на низком уровне или не внушает доверия. Однако сервисные команды
могут не быть экспертами в области миграции. На них будут оказывать давление
бизнес и продукт, требуя повышения эффективности. Команды сервисов могут от
казаться от миграции, т. к. она не имеет прямой ценности для бизнеса.
Платформенные команды. Они мало знают о бизнесе или о правильном тестиро
вании сервисных компонентов. Однако это можно исправить, если автоматизиро
вать тестирование на должном уровне и доверять его результатам. Классические
монолитные и устаревшие системы часто не имеют достаточного охвата тестиро-
420
■
Глава 9
ванием и требуют миграции кода. Таким образом, преимущество использования
платформенных команд заключается в том, что вы получаете техническую экспер
тизу.
Трения между командами сервисов и платформы часто возникают из-за неопреде
ленных границ ответственности, а также из-за сложных взаимоотношений, дина
мики и ожиданий. Присутствуют следующие факторы:
♦
Неясность владения. Сервисные команды ожидают, что все миграции будут
выполняться платформенными командами, поскольку сервисные команды хотят
сосредоточиться на бизнес-функциях и прямой ценности.
♦
Недостаток осмотрительности. Сервисные команды предпочитают свободно
выбирать библиотеки и фреймворки, уникальные для их задач, при этом ожида
ют, что другие команды помогут им с миграцией.
♦
Основатели. Разработчики платформы ожидают, что сервисные команды будут
владеть их базой кода и техническими решениями. Они хотят, чтобы сборка вы
полнялась успешно, а тесты оставались стабильными.
♦
Вовлеченность в миграцию. Команды разработчиков платформы стремятся
к быстрому внедрению новых технологий и повышению эффективности. Однако
создать что-то проще, а вот перенести всех пользователей довольно сложно. Та
ким образом,
команды разработчиков платформы
ожидают, что сервисные
команды будут мигрировать чаще и оперативнее.
Гибридная команда. Это временная команда, состоящая из инженеров по плат
форме и сервисам, которые сочетают в себе обе сильные стороны. Гибридные ко
манды могут стать связующим звеном между двумя мирами, где мы сочетаем биз
нес-знания и ноу-хау в области тестирования с техническим опытом и крутыми
способностями к миграции.
Аналогичную идею можно найти в книге Мэтью Скелтона
нуэля Паиса
(Manuel Pais)
(Matthew Skelton)
и Ма
«Командные топологии: организация бизнес- и техноло
гических команд для быстрого потока»
(Team Topologies: Organizing Business and
Technology Teams for Fast Flow), опубликованной в 2019 r. Между командами
Команды , ориентированные на поток
Команды поддержки
Команда
сложной подсистемы
Команды платформы
Рис.
9.15.
Топологии команд
Миграция кода
■
421
платформы и сервисов, называемыми командами, ориентированными на поток,
существуют команды сложных подсистем и группы поддержки, которые будут по
хожи на нашу гибридную команду, представленную здесь (рис.
9.15).
Шаблоны миграции кода
Теперь давайте разберемся, как можно выполнить миграцию кода. Мы рассмотрим
несколько шаблонов. Порядок расположения шаблонов довольно искусственно
сгруппирован, но направлен на то, чтобы идти от простого к сложному в смысле
усилий по реализации и трудоемкости. Наша классификация моделей не подразу
мевает, что одни из них лучше или хуже других. Думайте о них как о различных
инструментах, которые вы можете и должны иметь в своем арсенале.
Обратная совместимость
Шаблон обратной совместимости уже рассматривался в главе
6
«Принципы надле
жащего предоставления сервисов». Напомним, что мы не нарушаем интерфейсы,
методы и вызовы функций, что сводит к минимуму требуемый рефакторинг. Мы
вернемся к вопросу обратной совместимости в контексте откатов с использованием
подхода
Amazon 2 «двусторонние двери».
Отложенная миграция
Отложенная миграция
(lazy migrations) -
это форма прозрачной миграции, при ко
торой миграция интегрируется в работу программного компонента. Давайте рас
смотрим несколько примеров. Прежде всего, представьте, что у вас есть идентифи
катор профиля, который представляет собой сложную строку типа:
Profile ID Vl = ТУРЕ - PHONE- STATUS
Where:
ТУРЕ: regular, politician, reporter, or celebrity.
PHONE: the phone nwnЬer
STATUS: Active or Deactivated
Теперь представим, что это хранится в
показано на рис.
MySQL,
а также кешируется в
Redis,
как
9.16.
Теперь предположим, что нам нужно внести следующие изменения в код.
Нам нужно добавить код страны как часть телефонного номера. К сожалению, мы
не предполагали, что решение будет работать в нескольких странах. Это устранит
возможную
коллизию,
когда
два
человека
с
одинаковыми
номерами
находятся
в разных странах. Какие изменения нужно внести в код? Можем ли мы сделать его
обратно совместимым? Да, можем! Но мы сделаем еще один шаг за пределы обрат
ной совместимости, поэтому сначала давайте разберемся с общими изменениями
в коде.
2
Запрещен на территории РФ.~ Ред.
■
422
Глава 9
Мобильное
Веб
приложение
интерфейс
Контракт
Реализация
сервиса профилей
БД профилей
на
Рис.
9.16.
MySQL
Пример отложенной миграции в сервисе профилей
Рассмотрим:
Profile ID V2 =
ТУРЕ
-
COUNTRY- CODE- PHONE- STATUS
что означает:
♦
Контракт не изменится, потому что идентификатор был отображен как строка.
♦
Тесты контракта теперь будут прерваны, потому что потребуется новый формат
с добавлением кода страны.
♦
Вам нужно изменить внутренний
♦
Изменения доступа к БД, как в ваших сопоставлениях
POJO,
который будет представлять профиль.
♦ Миграция данных, которая будет рассмотрена в главе
SQL, так
и в
JPA.
10 «Миграция данных».
Теперь сервис может в принципе реализовать оба шаблона идентификаторов
и внутренне перенаправить к нужному коду (рис.
9.17).
Теперь представьте, что вместо полного переписывания кода для поддержки шаб
лона
ID
версии
с версиями
2 вы либо дублируете
1 и 2. Кроме того, мы бы
код, либо рефакторите его, чтобы он работал
ввели шаблон маршрутизатора (роутера), ко
торый представляет собой класс, который будет анализировать идентификатор
профиля и определять, перенаправить его к реализации версии
кая маршрутизация
1 или
версии
2.
Та
это условие if, основанное на строковом поле идентифика
-
тора профиля, который может быть выполнен несколькими различными способами,
такими как:
♦
Проверьте размер
♦
Найдите_, т. к. в профиле
♦
Обратите внимание на наличие кода страны.
♦
Все варианты, указанные выше.
-
в профиле
V2
V2
размер больше, чем в профиле
их больше, чем в профиле
V 1.
V 1.
Миграция кода
Мобильное
Веб-
приложение
инте
■
423
и
V2),
йс
Контракт
Redis
Реализация
сервиса профилей
БД профилей
на
Рис.
9.17.
MySQL
Маршрутизация к двум различным реализациям
Хитрость здесь в том, что, поддерживая оба идетификатора шаблона
(V l
мы можем позволить пользователям , скажем, веб-интерфейса считывать данные
с помощью шаблона V l . При сохранении данных мы можем преобразовать их
в шаблон
V2
внутри системы и вообще отказаться от сохранения шаблона
Итак, мы будем считывать оба шаблона, но сохранять только
ГОРЯЧИЕ данные (рис.
9.18)
V l.
V2.
означают, что они постоянно считываются (получа
ются или выбираются) и записываются (вставляются или обновляются). В конеч-
Потребитель
(пишет)
Потребитель
(читает)
Контракт
Redis
Реализация
сервиса профилей
БД профилей
на MySQL
.........................
Рис.
9.18.
Пути чтения и записи
424
■
Глава 9
нам итоге все потребители будут использовать шаблон
нить весь код, который обрабатывает
Vl.
V2,
и можно будет отме
Останутся сценарии, в которых только
некоторые идентификаторы будут ХОЛОДНЫМИ. Не стоит беспокоиться о них
сейчас. Мы вернемся к этому шаблону в контексте миграции данных в главе
1О
«Миграция данных».
Здесь следует иметь в виду важную идею: мы можем совместить две совершенно
разные концепции (идентификаторы
Vl
и
V2)
и постепенно переходить от старого
способа к новому. Это позволяет избежать немедленной миграции данных и ис
пользования только одного шаблона идентификатора в коде. Такой подход является
отложенной миграцией. Каждый раз, когда пользователь выполняет операцию за
писи, система делает больше, чем ожидается, и меняет внутренний шаблон иден
тификатора. Это удобно для потребителей, поскольку они могут постепенно пере
ходить на шаблон
V2,
имея время для адаптации и работы над своими измене
ниями.
Strangler Fig
Strangler Fig -
это усовершенствованная модель, позволяющая разделить на части
классические и распределенные монолиты. Идея создания
Strangler Fig
происходит
от рода растений-паразитов, которые душат другие, более старые и крупные рас
тения,
(рис.
высасывая
Источник:
Идея
питательные
вещества,
пока
растение-хозяин
не
погибнет
9.19).
Рис. 9.19. Фикус Уоткинсиана, Австралия.
https://en.wikipedia.org/wiki/File:Ficus_watkinsiana_on_Syzygium_hemilampra-lluka.jpg
Strangler Fig
сом Стивенсоном
была перенесена в программное обеспечение и предложена Кри
(Chris Stevenson) и Энди Полсом (Andy Pols) на конференции
Extreme Programming (ХР) в 2004 г. как гибкий подход к устаревшим системам.
■
Миграция кода
Теперь давайте посмотрим, как шаблон
Strangler Fig
425
на практике применяется
к классическому монолиту и антипаттерну «распределенный монолит».
Преобразование классического монолита в надлежащий
SOA
В классическом монолите приложение часто представляет собой единую базу кода
с одним или несколькими модулями развертывания. Это напоминает структуру,
изображенную на рис.
Потребитель
1
9.20.
Потребитель
Потребитель
2
3
Классический монолит
Потребитель
Потребитель
4
5
(-)
Нет четких границ
(-)
Нет четких интерфейсов/контрактов
ОбщаяБД
Рис.
9.20.
Straлgler
Fig -
классический монолит, шаг
1
Итак, на первом этапе у нас есть сценарий, где несколько потребителей обращают
ся к классическому монолиту и несколько раз классический монолит вызывает
себя сам. В нашей ситуации, скорее всего, не будет четких границ и контроля
видимости, все может быть общедоступным. Кроме того, чистые и четко опреде
ленные контракты и интерфейсы у классического монолита могут вообще отсутст
вовать. Итак, вам нужно будет либо выбрать какой-то интерфейс для запуска, либо
создать новый интерфейс или контракт. Вот некоторые рекомендации:
♦
Подмножество: выберите бизнес-область или ее часть, например изображения,
платежи, профили, продажи и т. д.
♦
Общие функциональные возможности: если у вас есть общие функциональ
ные возможности, такие как аутентификация, авторизация, права доступа или
безопасность, это также может быть хорошим вариантом.
♦
Вначале контракт: создайте контракт, добавьте новый интерфейс и предос
тавьте его как НТТР.
■
426
Глава 9
Допустим, мы хотим извлечь функциональность работы с
рис.
9.21
изображениями,
на
показано, как это будет выглядеть. Контракт очень компактный, и никто
не требует использовать новый контракт, это нормально. Теперь мы будем перево
дить всех потребителей, которым нужен новый контракт, по одному за раз.
Потребитель
1
Потребитель
2
Потребитель
3
Потребитель
Потребитель
4
5
Контракт
Классический монолит
(-)
Нет четких границ
(-)
Нет четких интерфейсов/контрактов
ОбщаяБД
Рис.
Вот пример (рис.
быть
100
9.22):
9.21. Strangler Fig -
классический монолит, шаг
в вашей реальности у нас
5
2
потребителей; у вас могло бы
потребителей, так что это простой подход, но он может занять много вре
мени; как только вы выделите одного потребителя, вы можете перейти к следую
щему потребителю и повторить.
Одно важное соображение заключается в том, что, если у всего классического мо
нолита
5 потребителей,
это не означает, что у вашего нового контракта будут те же
потребители. Вам следует избегать переноса поддельных потребителей, а перено
сить только тех, которым действительно необходимо использовать новый контракт
(рис.
9.23).
Как только вы достигните цели, вы можете перенести код на другую
кодовую базу и в автономный сервис.
Наконец, мы достигли конечного состояния (рис.
9.24),
и классический монолит
стал меньше. Теперь вы можете повторить весь этот процесс для следующего ин
терфейса/контракта. Если продолжать в том же духе, то можно высушить весь
классический монолит и избавиться от него.
Миграция кода
Потребитель
1
Потребитель
2
Потребитель
3
Потребитель
Потребитель
4
■
427
5
Контракт
Классический монолит
(-)
Нет четких границ
(-)
Нет четких интерфейсов/контрактов
ОбщаяБД
Рис.
Потребитель
1
9.22. Strangler Fig -
Потребитель
2
классический монолит, шаг
Потребитель
3
Потребитель
3
4
Потребитель
5
Контракт
Классический монолит
(-)
Нет четких границ
(-)
Нет четких интерфейсов/контрактов
Общая БД
Рис.
9.23. Strangler Fig -
классический монолит, шаг
4
■
428
Глава 9
Потребитель
Потребитель
1
2
Потребитель
3
Потребитель
Потребитель
4
5
Контракт для изображений
Классический монолит
Реализация
сервиса изображений
(-)
Маленький
(-)
Больше никаких функций
чтения/записи изображений
Хранилище
изображений
Рис.
Общая БД
9.24. Strangler Fig -
классический монолит, шаг
5
Преобразование классического монолита
в модульный монолит
Итак, теперь давайте предположим, что мы хотим сохранить монолитную архитек
туру, но сделать ее современной и модульной. Наш процесс тот же, но с одним
большим отличием: мы можем не предоставлять новую функциональность в каче
стве публичного контракта. Это может быть внутренний закрытый модуль. У нас
Н Нет четких
Классич.
Н Нет четких границ
монолит
Н Нет четких
границ
Классич. Н Нет четких
монолит
интерфейсов/
Н Нет четки~
интерфейсов/
интерфейсов/
контрактов
контрактов
контрактов
0
Н Нет четких
(+) Четкие
границ
Н Нет четких
интерфейсов/
границы
(+) Связность и
модульность
контрактов
0
4
Рис.
9.25. Strangler Fig -
модульный монолит, этапы с
1-ro
по 5-й
Миграция кода
наверняка будуr интерфейсы
конечная точка
REST,
Java,
■
429
представляющие контракт, но не обязательно
что будет зависеть от варианта использования (рис.
9.25).
Как вы можете видеть, механика очень похожа, но здесь цель состоит в том, чтобы
сделать монолит модульным. В ходе процесса вам нужно будет определить, какие
модули будут общедоступными, а какие
-
приватными.
Здесь применимы те же принципы, которым мы научились при работе с надлежа
щими стабильными сервисами. Единственная разница в том, что теперь у нас есть
два типа контрактов
-
публичные и частные. Имеется то, что является общедос
тупным для пользовательских приложений, и то, что является приватным для поль
зовательских приложений, но общедоступным для других модулей. Например,
функциональность изображений в модуле профиля может быть абстрагирована
ко1,1трактом с профилем и не обязательно должна быть общедоступной.
Преобразование распределенного монолита
в надлежащий
Применение
SOA
Strangler Fig
к распределенному монолиту отличается. Мы применяем
несколько стратегий: шлюз и слияние.
Стратегия «шлюз»
заключается
в том, чтобы
объединить отдельные сервисы
в единый сервис высшего уровня, и этот сервис высшего уровня может быть реали
зован с помощью:
♦
нового контракта и сервиса, которые объединят и абстрагируют другие сервисы;
♦
решений для АРI-шлюза, таких как
GraphQL
AWS API Gateway, Kong API gateway, Nginx,
и многих других технологий;
♦ это также можно было бы сделать с помощью
Kubemetes lngress,
бессерверных
и многих других подходов.
Стратегия слияния заключается в том, что мы, по сути, объединяем сервис и рекон
струируем монолит, применяя обратный подход, у нас будет, например, 5 репози
GitHub, которые будут объединены в один репозиторий. Здесь нам не
ториев на
требуется никаких специальных технологий; это просто миграция кода.
Давайте сначала углубимся в каждую стратегию, рассмотрим подход со шлюзом
(рис.
9.26).
Этот подход позволяет нам скрыть распределенный монолит; у компа
ний могут быть сотни и тысячи микросервисов. Размещая АРI-шлюз наверху, мы
абстрагируемся от всех базовых сервисов. Здесь мы применим шаблон
Strangler Fig,
поэтому шаги будуr такими же, как и раньше.
♦
Шаг первый: добавьте АРl-шлюз поверх имеющихся у вас распределенных мо
нолитов.
♦
Шаг второй: определите первый контракт, который будет перенесен в АРI
шлюз. Если чистых, стабильных контрактов нет или они не подходят, создайте
новые.
♦
Шаг третий: настройте АРI-шлюз для вызова экземпляра сервиса.
♦
Шаг четвертый: рефакторинг всех потребителей, обращающихся к сервису
через АРI-шлюз.
430
■
Глава 9
Репозиторий
АРl-шлюз (контракт)
Распреде•
Распреде•
Распреде•
ленный
ленный
ленный
монолит
монолит
монолит
2
Репозиторий
Распреде
Распреде
Распреде
ленный
ленный
монолит
монолит
монолит
3
слить
Модульный
Единый
монолит
репозиторий
Общая база данных
:
Шлюз
♦
Репозиторий
ленный
Общая база данных
Рис.
1
9.26. Stranger Fig -
Слияние
распределенные монолиты: шлюз против слияния
Повторяйте до тех пор, пока все обращения к сервисам распределенного монолита не будут проходить через АРI-шлюз.
Как только этот последний шаг будет выполнен, вы можете приступить к упроще
нию базовых сервисов путем их объединения, вывода из эксплуатации, рефакто
ринrа, перезаписи, разделения базы данных и т. д. Именно такой подход
Uber при
(Domain Oriented
Uber DOMA можно
менил к доменно-ориентированной архитектуре микросервисов
Microservice Architecture, DOMA,
рис.
9.27).
Сообщение об
резюмировать следующим образом:
♦ Более
♦
2200 критически
важных микросервисов в
Устранение неполадок стало более сложным: для расследования одной пробле
мы потребовалось просмотреть более
♦
Uber.
По данным
Uber,
50 сервисов
в
12 различных
командах.
срок службы микросервиса составляет полтора года. Это озна
чает, что каждые полтора года
50 % наших
микросервисов выходят из строя, что
приводит к миграционному аду.
♦
С внедрением
Uber
DОМА время внедрения новой функции сократилось на
25-
50 %.
Airbnb вой
еще одна компания из Кремниевой долины, которая использует шлюзо
подход
однако у них
(https://www. infoq.com/presentations/airbnb-scalabllity-transition/),
не один шлюз, а несколько уровней. Подход Airbnb можно резюмиро
вать следующим образом.
♦
Извлечены четыре важных урока: инвестируйте в общую инфраструктуру на
раннем этапе, упрощайте зависимости от сервисов, обновляйте данные плат
формы и унифицируйте
API,
ориентированные на клиента.
Миграция кода
♦
■
431
Пользовательский интерфейс, управляемый сервером, отображает интерфейс на
основе серверного сервиса.
♦
Уровни сервисов, сервисы презентаций, сервисы передачи данных .
♦
АРl-шлюз.
грс
1
...
Сервис шлюза
'
~
с
о
-.
rpc
1
1
б
-
~
с
ы
о
т
б
и
е
О Публич ный интерфейс
онлайн
за п рос
1
r
Сервисы
1
т
и
е
.,,,"'
1'-...
О Частнь 1й интерфейс
,,.,,.,
ы
•-
'--
Базы
данных
ETL
·····--~
~з
--
.,,,1.,,'
а
-
n
р
_
..,,,.J__
-----------------------------------
-
офлайн
з
а
--
n
р
о
о
с
---с
т
Рис.
9.27.
Архитектура
Uber DOMA.
Источник: https:llwww.uber.com/Ыog/microservice-architecture/
Теперь давайте поговорим о другом подходе. Слияние может показаться странным,
но иногда это еще один приемлемый вариант. Здесь мы буквально возвращаемся
к классическому монолиту и переносим всю базу кода, представляющую собой не
сколько репозиториев на
GitHub,
в один репозиторий на
GitHub.
Как только весь
код будет собран в одном месте, вы сможете превратить классический монолит
в современный разделенный на модули монолит и начать исправлять ошибки там.
Одним из больших преимуществ является то, что можно будет загрузить весь код
в вашу
IDE
и воспользоваться инструментами рефакторинга.
Подход, который становится очень популярным в наши дни ,
-
переход от бессер
верных или микросервисных решений к модульному монолиту. Именно так посту
пил
Amazon
Prime
Video
(рис.
9.28,
https://www.primevideotech.com/video-
432
■
Глава 9
streaming/scaling-up-the-prime-video-audio-video-monitoringservice-and-reducingcosts-by-90). У Amazon Prime Video было бессерверное решение, которое было пе
ренесено на архитектуру в стиле монолит, где его можно кратко охарактеризовать
следующим образом:
♦
Amazon Prime Video
преодолел жесткие ограничения по масштабируемости без
сервера с ожидаемой рабочей нагрузкой в
♦
Переход с функций А WS
♦
Prime Video по-прежнему
щью ЕС2 и ECS.
Step
5 %,
функциями
(бессерверных) на ЕС2 и
Lambda/Step.
ECS.
позволяет масштабировать рабочие нагрузки с помо
♦ Значительное преимущество
-
снижение затрат на
90 %.
§--~
Amazon ECS
Информирование клиента
Начать
в режиме реального времени
анализ
Поток
аудио/видео
!
:
Результаты поиска
'
реального времени
в режиме
'
'
~
Amazon ECS
Кластер
Переслать запрос
Кластер
ECS
Сервис Amazon
для детекторов
ECS
1и 2
Сервис Amazon
для детекторов
ECS
ECS
3, 4 и 5
Обобщенные результаты
:
'
поиска по каждому детектору
•
~
Список результатов поиска
Amazon SЗ
Рис.
Источник:
9.28. Архитектура Amazon Prime Video -
от бессерверной архитектуры до монолитной.
https:/'-.primevideotech.com/video-streaming/scaling-up-the-prime-video-audio-videomonitoring-serviceand-reducing-costs-by-90
■
Миграция кода
Двусторонние двери
У
Amazon
интересный подход к миграции. У
Amazon
433
Amazon
есть принцип лидерства, ко
торый называется «избегать односторонних решений», т. е. решений, которые не
возможно откатить. Такой принцип применяется и в инженерном деле, особенно
при миграции кода. У А WS есть замечательный ресурс под названием Amazon
Builders' Library (https://aws.amazon.com/builders-library/), где они публикуют
отличные статьи, в которых делятся уроками, извлеченными из того, как они созда
вали
В
А WS.
статье
«Обеспечение
отката
безопасности
при
развертывании»
(https://aws.amazon.com/Ьuilders-library/ensuringrollback-safety-during
deployments) Amazon
советует учитывать возможность отката при миграции; необ
ходимо иметь возможность вернуться к предыдущим настройкам (рис.
Активация
Подготовка
Vl
Чтение
Запись
Источник:
vз
V2
Чтение
XML
XML
9.29).
Чтение
XML и JSON
XML
XML и JSON
JSON
Запись
Запись
Рис. 9.29. Библиотека Amazon Builders - избегайте односторонних дверей.
https://aws.amazon.com/builders-library/ensuring-rollback-safety-during-deployments/
В статье на
Amazon
советуют не менять код сразу, чтобы перейти с
XML
на
JSON,
потому что такой переход будет необратимым, а восстановление станет сложной
задачей. Вместо этого предполагается разбить процесс на несколько этапов и сде
лать больше проб. Например, сначала можно читать данные в обоих форматах, но
записывать только старый
XML.
Затем в какой-то момент нужно читать данные
в обоих форматах, но записывать только новый формат. В итоге на финальном эта
пе следует читать и записывать данные уже в формате
JSON.
Препятствия при миграции
До сих пор в этой главе мы изучали разницу между красной и зеленой миграциями.
Настало время перейти к инвентаризации, вариантам использования и проверке
концепций. Мы рассмотрим компромиссы между миграциями в зависимости от це
ли, сложности, влияния на клиента и исполнения. В этом последнем подразделе мы
обсудили шаблоны миграции кода, такие как обратная совместимость, отложенные
миграции,
Strangler Fig,
а также и их применение к классическим монолитам,
модульным монолитам, распределенным монолитам (шлюз против слияния) и дву
сторонним дверям
Amazon.
Теперь давайте поговорим о некоторых препятствиях,
возникающих при миграции кода, и предложим несколько советов, как их преодо
леть.
Препятствие
-
остаточные явления
Красные миграции· происходят еще и потому, что, как только вы начнете мигра
цию, то столкнетесь со всеми видами препятствий, такими как:
434
■
Глава 9
♦
остаточные явления
♦
техническая задолженность;
♦
сложность.
(leftovers) -
прошлые незавершенные миграции;
У нас есть несколько различных способов решения этих проблем.
Удвоение усилий по инвентаризации и проверке концепций
Еще одна причина для проведения анализа кода и составления описей заключается
в том, что эти меры помогут выявить проблемы. Проводя проверку концепций
(Proof of Concept,
РОС), вы можете прощупать почву и снизить риск возникновения
препятствий во время миграции. Чем точнее ваш инвентарный список и выше уро
вень в РОС, тем меньше вероятность того, что вы столкнетесь с этими препятст
виями.
Распределенные миграции и зависимость от команды
Если вы решили выполнить миграцию кода несколькими распределенными коман
дами, а не централизованной командой (из инженеров платформы и сервисов),
перечислим несколько действий, которые вы можете предпринять, для снижения
количества препятствий.
♦
Централизованный канал: создайте центральный канал
♦
Wiki:
slack для
миграции.
убедитесь, что вы создаете общую вики-страницу, поскольку у команд,
скорее всего, будут одинаковые проблемы с кодом.
♦
Рабочее время: решайте проблемы с исключениями или сложными сценариями
с помощью совещаний в рабочее время, гибридных команд и видеороликов,
в которых рассказывается об извлеченных уроках.
Повторение,повторение,повторение
В случае распределенной команды попробуйте повторить одно и то же
lО
раз. Лю
ди работают над несколькими проектами одновременно; они будут сбиваться
с толку. Чем чаще вы будете повторять задание, тем лучше они его освоят.
Препятствия -трения и энтропия
Самые серьезные препятствия для миграции кода. Трения возникают из-за того, что
в работе задействовано несколько команд, которые часто работают над нескольки
ми проектами одновременно.
Что может быть хуже трений, так это энтропия, когда инерция убивает импульс,
который вы набираете в проектах. Энтропия замедляет миграцию, замораживает, а
затем прекращает существование. Энтропия возникает из-за того, что вещи теряют
контроль, а правила потребления часто не определены из-за слабых границ и отсут
ствия принципов, которые мы неоднократно видели в этой книге. Итак, проблема
с энтропией заключается в том, что создать что-то новое лучше существующего
Миграция кода
■
435
просто; сложнее всего перенести это на всех пользователей и удалить старый код.
Часто инженеры не удаляют код, из-за чего миграции выполняются частично. Дли
тельные миграции, как правило, отменяются, что также приводит к образованию
остаточных явлений.
Вот как можно справиться с этими препятствиями:
♦
Сопоставление зависимостей. Четко обозначьте зависимости команды и, на
сколько это возможно, сообщайте о них на всех совещаниях.
♦
Оценка на основе данных инвентаризации. Убедитесь, что вы рассчитали
время для надлежащей миграции.
♦
Набор навыков имеет значение. Подумайте о том, чтобы иметь подходящую
команду с нужными навыками и опытом для выполнения миграций.
♦
Обратная совместимость. Используйте обратную совместимость для снижения
энтропии.
♦
Упрощение. Упростите свой технологический стек и количество внутренних
общих библиотек, чтобы уменьшить радиус переноса кода.
♦ Частые небольшие миграции. Выполняйте миграции кода чаще; небольшие
отклонения, как правило, менее рискованны и позволяют вам двигаться быстрее.
♦
Не пропускайте этап вывода нз эксплуатации. Разработайте план и стратегию
вывода компонентов из эксплуатации, ведь если вы просто добавите новое про
граммное обеспечение и не удалите старое, ваша проблема только усугубится.
♦
Подход к продукту. Заставьте инженеров думать о продукте: осознать, что ско
рость, ошибки, надежность и доступность
-
это часть работы с клиентами. Ин
женеры также работают над улучшением продукта.
♦ Послабление. Убедитесь, что у команд есть достаточно свободного времени.
Зарезервируйте
20 %
свободного места во всех спринтах, чтобы было время для
адаптации к изменениям кода и устранению препятствий.
♦
Управляемые сервнсы. Используйте управляемые сервисы и SааS-решения,
где вы выполняете меньше операций и, следовательно, меньше переносов кода.
Препятствия
-
высокие WIР-лимиты,
давление бизнеса, соблюдение требований
и другие ловушки
Еще одним распространенным препятствием, заставляющим команды опускать
руки, являются слишком высокие WIР-лимиты 3
(WIP limits).
Это может произойти
из-за того, что одна команда одновременно работает над несколькими разными
проектами или выполняет множество многосоставных задач в рамках одного. Часто
такое происходит из-за давления бизнеса и/или комплаенс-давления, которое может
3
WIP (work in progress)- это то. сколько задач у команды одновременно находится в работе. - Пер.
436
■
Глава 9
исходить от какого-либо регулирующего органа, информационной службы, обще
ственности и других источников давления.
Чтобы преодолеть это препятствие, вы можете сделать следующее:
♦
Смотрите в целом. Используйте принцип бережливого производства. Убеди
тесь, что видите всю работу, которую необходимо проделать вашей команде.
♦ Скажите «нет», скажите «позже». Подумайте о том, чтобы отложить проекты
на более позднее время, и будьте честны.
♦ Правильный размер команды. Попросите привлечь больше персонала, воз
можно, рассмотрите возможность привлечения подрядчиков.
Красные миграции страдают от описанной проблемы гораздо больше, чем зеленые.
Пост-миграционный период
Пост-миграция
(post-migration) -
заключительный раздел этой главы. Теперь нам
нужно рассмотреть, что происходит после миграции кода и когда миграция в целом
выполнена. Двумя важными элементами миграции кода являются тестирование и
наблюдаемость. Они помогают убедиться, что миграция кода не создает проблем.
Тестирование
-
это первый шаг, а наблюдаемость
-
второй. Мы более подробно
обсудим тестирование, наблюдаемость и все, что вам нужно знать о последующей
миграции как кода, так и данных, в главе
10 «Миграция данных».
Наблюдаемость имеет большое преимущество, поскольку ее можно использовать
после миграции как еще одну возможность лучше понять, что делают ваши серви
сы. Настоятельно рекомендуем использовать инструменты для публикации показа
телей, которые дадут четкий сигнал о том, что ваша миграция проходит успешно,
например:
♦
Счетчики операций, доступа: общее количество счетчиков операций.
♦ Возможность обнаружения ошибок: счетчики ошибок/исключений.
♦
Процентили задержки: индикаторы задержки с процентилями р50, р75, р90,
р95, р99.
♦ Централизованное ведение журнала: обязательно. Централизованное ведение
журнала для реальных ошибок.
Очень важно выполнить проверку при миграции кода с одной версии на другую.
Например, если вы переносите код с версии
1 на
версию
2
или с
Arch 1 на Arch 2,
как убедиться, что весь код успешно перенесен? Иногда эту проверку можно вы
полнить с помощью журналов, метрик и статистических данных из обеих систем.
Например, если у нас есть Система
набор из
V 1 и Система V2, можем ли мы запустить
5 тысяч тестов для обеих систем и получить одинаковые результаты?
наш
Стратегии отката
Наилучшие стратегии отката реализуются за счет обеспечения обратной совмести
мости и соблюдения принципа
Amazon
«избегайте односторонних дверей». Откат
Миграция кода
■
437
может быть автоматическим или ручным. Для отката вручную рассмотрите воз
можность использования
♦
runbook4,
подобного этому:
Аномалии. Как обнаружить аномалии? Используйте панель мониторинга
+ опо
вещение.
♦
Процедуры отката. Как выполнить откат? Верните последнюю фиксацию или
используйте старый
♦
JAR.
Проверка работоспособности. Как убедиться, что все в порядке? Запустите
тесты еще раз и проверьте отсутствие ошибок в наблюдаемости.
Хотя весь этот процесс можно автоматизировать, современные решения, такие как
Spinnaker
и
Argo CD,
уже реализуют этот шаблон. Они проводят автоматизирован
ный анализ и откаты с помощью технологии
Canary.
Что нужно запомнить
Поздравляем! Вы дочитали до конца главу
9.
Перечислим несколько моментов,
о которых следует помнить.
♦
Не принимайте миграцию кода как должное.
♦
Несколько различных причин могут вынудить вас решиться на миграцию кода:
♦
♦
4
•
У программного обеспечения истекает срок службы.
•
Поставщик прекращает свою деятельность.
•
Соответствие требованиям, например информационной безопасности.
•
Инфраструктура, например облачные миграции.
•
Модернизация: нарезка ломтиками и кубиками монолита.
•
Завершение работы устаревшего компонента.
•
Новые потребности и возможности бизнеса.
•
Консолидация в связи с приобретением компании.
Существуют два вида миграций:
•
КРАСНАЯ: полная проблемных моментов.
•
ЗЕЛЕНАЯ: плавная миграция благодаря надлежащей проверке.
Красная миграция:
•
Огромный радиус действия.
•
Множество кардинальных изменений.
•
Медленная, запоздалая и дорогостоящая обратная связь.
В компьютерной системе или сети runbook представляет собой компиляцию рутинных процедур и опера
- Пер.
ций, выполняемых системным администратором или оператором.
■
438
♦
Глава 9
•
Ошибки на поздних этапах.
•
Косвенная и скрытая ценность для бизнеса.
•
Плохая видимость, которую трудно отследить.
•
Болезненные откаты.
Зеленая миграция:
•
Контролируемый радиус действия.
•
Меньшее количество критических изменений.
•
Быстрая, своевременная и недорогая обратная связь.
•
Выявление ошибок на ранних этапах.
•
Прямая и понятная ценность для бизнеса.
•
Отличная видимость, которую легко отслеживать.
•
Управляемые откаты.
♦
Инвентаризация и проверка концепций
♦
Инвентаризация важна, потому что:
-
это ключ к зеленой миграции.
•
Позволяет вам понять масштабы миграции.
•
Позволяет получить важную информацию о ваших потребителях, зависимо
стях и ограничениях.
♦
♦
•
Обеспечивает централизованное представление о ходе выполнения.
•
Позволяет разработать стратегию и спланировать миграцию.
Компромиссы при миграции делятся на четыре категории:
•
Цель миграции: тип компонента, что это такое и как это будет осуществляться.
•
Влияние на команду.
•
Влияние на клиентов.
•
Реализация.
Надлежащие сервисы позволяют выполнять миграцию намного проще, чем рас
пределенные монолиты.
♦
Влияние на клиентов зависит от того, находятся они онлайн или офлайн.
♦ Выполнение может осуществляться командой разработчиков платформы, сер
висной командой или гибридной командой.
♦ Шаблоны переноса кода:
•
Обратная совместимость.
•
Отложенная миграция.
Миграция кода
■
439
• Strangler Fig.
•
♦
Двухсторонние двери
Шаблон
Strangler Fig,
Amazon.
применяемый к распределенным монолитам, отличается
от них двумя стратегиями:
•
•
Шлюз: оставить как есть, добавить шлюз верхнего уровня.
Слияние: упростить проблему, превратив распределенный монолит в мо
дульный.
♦
Наличие остаточных явлений и других препятствий может быть устранено с по
мощью надлежащих инвентаризаций и проверки концепций.
ГЛАВА
10
Миrрация данных
Некоторые люди видят вещи такими, какие они
eCTh,
и спрашивают: почему?
Я мечтаю о вещах, которых никогда не было, и спрашиваю, почему бы и нет?
Дж. Ф. Кеннеди
Это должно быть очевидно: невозможно модернизировать монолит, не исправив
его хранилища и модели данных. Глава
8 «Внедрение
новых технологий» научила
вас правильно выбирать инструмент для работы, и одним из основных инструмен
тов является ваша база данных. Миграции кода будет недостаточно; вам также по
требуется перенести данные. Миграция данных повсеместно необходима для раз
деления классических монолитов, исправления распределенных монолитов, любой
формы облачной миграции, модернизации или цифрового преобразования, а также
для обновления постоянного хранилища для обеспечения надлежащего предостав
ления сервисов.
Да, миграция данных сложна. Однако ее можно выполнить должным образом и
сделать все правильно. В этой главе мы поделимся общими рецептами, шаблонами
и способами успешного выполнения миграции данных. Ваш этап оценки и плани
рования важен для поиска общих шаблонов и подходов. Мы еще раз рассмотрим
два шаблона переноса кода и их значение в контексте миграции данных
женную миграцию и
Strangler Fig.
-
отло
Наконец, мы рассмотрим аспекты, связанные
с пост-миграцией, такие как тестирование и мониторинг, чтобы убедиться, что все
предусмотрели, а затем проведем очистку и вывод из эксплуатации. Давайте нач
нем.
Структура главы
В этой главе мы рассмотрим следующие темы:
♦
Риски миграции данных.
♦
Подготовка миграции данных.
•
Инвентаризация и анализ.
•
Планирование и определение быстрых выигрышей.
Миграция данных
♦
•■
441
Шаблоны миграции данных.
•
Повторный просмотр отложенных миграций.
•
Экспорт и импорт.
•
Репликация базы данных.
•
Сравнение таблиц.
•
Триггеры.
•
Захват изменения данных.
•
Двойная запись.
0
Незавершенные данные.
0
Сбой при выполнении одной операции записи.
0
Задержка и сложность транзакций.
♦ Стратегии миграции данных.
•
Онлайн или офлайн.
•
Вначале схема или несколько миграций.
•
Пересмотр:
0
♦
Strangler Fig.
Классические монолиты,
Strangler Fig и
миграция данных.
Выполнение миграции.
•
Тестирование.
•
Проверка работоспособности перед миграцией.
•
Тестирование производительности.
•
Практическое тестирование производительности базы данных с помощью
NDBench.
♦
♦
•
Проверка работоспособности: структура и данные после миграции.
•
Наблюдаемость.
После миграции данных.
•
Охота на призраков.
•
Очистка и вывод из эксплуатации.
Что нужно запомнить.
Риски миграции данных
Все основано на данных. Данные
-
это источник жизненной силы большинства
современных компаний. По определению миграция данных является более сложной
задачей, чем миграция кода, из-за связанных с ней высоких рисков:
442
♦
■
Глава 10
Потеря данных, их повреждение. В случае потери данных можно потерять
весь бизнес, пострадать от ущерба бренду или столкнуться с проблемами с регу
лирующими органами.
♦
Серьезные сбои. Если какой-либо сервис не работает, всегда можно восстано
вить его; но, если ваши данные будут потеряны из-за неправильной миграции,
это может нарушить работу с клиентами в целом.
♦
Финансовые потери. Потеря данных означает потерю продаж или дальнейшие
финансовые последствия.
♦
Сложный откат. Хранилища данных содержат сложные представления состоя
ния; откат поврежденной базы данных
-
это чертовски трудная задача; и это
сложнее, чем вернуться к своему резервному, скрытому пулу сервис-вокеров 1
(service worker).
Чтобы миграция данных была успешной, необходимо тщательно спланировать и
выполнить ее. Давайте рассмотрим подготовку, которую должны выполнить все
команды перед началом работы.
Подготовка миграции данных
Любая эффективная миграция начинается с надлежащей оценки; это способ разо
браться в существующем ландшафте, который вы можете использовать для созда
ния эффективного плана миграции ваших данных. Давайте начнем с анализа и про
ведения эффективной инвентаризации.
Инвентаризация и анализ
Перед началом любой миграции данных крайне важно провести инвентаризацию;
вернитесь к главе
5
«Оценки» и перечитайте методы составления общего инвентар
ного списка, которые вы обсуждали с инженерами и архитекторами. Если вы зани
маетесь миграцией данных, в инвентарном списке могут содержаться дополнитель
ные материалы. Возможно, вам потребуется собрать такую информацию, как:
♦
Владелец. Кому принадлежат данные? Существует ли в вашей компании про
цесс управления данными? Знаете ли вы, кто управляет данными?
♦
Средства чтения/записи и приложения. Какие приложения выполняют чтение
и запись для конкретной цели миграции? Есть ли у вас конечные пользователи,
например общий поток базы данных или процесс обработки больших данных
(big data)?
1
Сервис-воркер -
ло скрипт, который работает в фоновом режиме независимо от веб-страниuы. Он по
зволяет выполнять за;щчи. которые не требуют взаимодействия с пользователем или даже находиться
в активной вкладке браузера. Например: кеширование ресурсов для работы в офлайн-режиме, получение и
отправка рush-уведомлений, синхронизация данных в фоновом режиме. Сервис-воркер
клиентом и сервером, пропускающий через себя все запросы к серверу.
-
Пер.
-
посредник между
Миграция данных
♦
■
443
Критичность. Насколько важны эти данные? Является ли это хранилище досто
верным источником данных или это просто копия или альтернативное представ
ление? Сколько времени простоя может выдержать организация?
♦
Объем работ. Какие кластеры, схемы, таблицы, столбцы и даже строки особен
но важны для реляционных баз данных?
♦
Возможности очистки и вывода из эксплуатации. Действительно ли все дан
ные необходимы и активно используются предприятием? Есть ли вероятность
вывода из эксплуатации вместо миграции?
Вы можете собрать нужную информацию, обратившись к персоналу. Попросите
архитекторов, ведущих инженеров, администраторов баз данных и инженерных
менеджеров заполнить инвентарные списки и ответить на вопросы. Используйте
инструменты, автоматизацию или их сочетание (рис.
10.1). Можно анализировать
Hibemate/JP А или анализи
информацию из своих кодовых баз, считывать объекты
ровать прямой
SQL
в своей кодовой базе. Например, получив запросы, вы можете
извлечь таблицы и столбцы с помощью синтаксического анализатора
как
SQL,
такого
JSqlParser (https://github.com/JSQLParser/ JSqlParser).
Здесь важную роль может сыграть наблюдаемость, поскольку используются инст
рументы для получения информации о том, что происходит в операционной сис
теме;
инструменты профилирования и АРМ, такие как
стеки ведения журнала, такие как
Dynatrace,
ELK
или
Datadog, New Relic и
Graylog, и многие другие ме
тоды для выявления горячих точек использования базы данных.
,-------------,
0
1
1
1 Анализ результатов
1
., ____________
,...------------1
1
0
1
1
1
..,1
,-------------1
0
Сбор данных
0
1
с помощью инженеров
1
______________1
,-------------1
0
1
1
1
1
1._
1
Рис.
0
Подготовка
инвентарного списка
_____________
1 Привлечение персонала
10.1.
.. _____________
1
Сбор запросов
1
Сбор данных
1
с помощью кода ,
1
1 с помощью инструментов 1
1
1
"------------,-------------,
1
1 Подготовка
ин струмента
или базы да нн ых
1
' _____________
1 инвентарного списка
._
'
Инструментальный подход
1
Подготовка к миграции данных
1
1
,-------------1
1
1
1
1
1...
1
1
1 Анализ результатов
1
1
-
инструментальные подходы и привлечение персонала
Сбор информации для поддержки миграции данных может осуществляться различ
ными способами; нет правильного или неправильного соотношения между исполь
зованием персонала и инструментов. Вот некоторые рекомендации:
♦
Периодичность. Если это единовременное мероприятие, люди могут работать
быстрее. Хорошая ручная работа отличается тем, что выполняется единожды и
используется многократно. Плохая ручная работа требует постоянного повторе-
444
■
Глава 10
ния. Само собой разумеется, что важно минимизировать проекты и избегать
плохой ручной работы.
♦ Размер и объем. Если у вас обширная сеть команд, сервисов и хранилищ дан
ных, автоматизация с помощью инструментов имеет больше смысла. Нет необ
ходимости
опрашивать сотню
человек,
если
ответ
может дать
автоматизация.
Что касается вариантов использования фиксированных монолитов и распреде
ленных монолитов, то иногда у команд нет ответов из-за размывания команды,
и автоматизация является более эффективным и быстрым решением.
♦
Оцените свои инструменты. Если у вас уже есть хорошие инструменты веде
ния журнала
SQL
и обеспечения наблюдаемости или ваша база данных поддер
живает наблюдаемость при выполнении запросов, хорошим решением будет ис
пользование имеющихся инструментов. Вы можете быть удивлены количеством
данных и информации, доступных с помощью инструмента
CLI, API,
скрипта
или даже какого-либо пользовательского интерфейса администратора, о котором
вы не знаете.
♦
Не бойтесь социализации. На самом деле, нет ничего плохого в том, чтобы по
просить разные команды прочитать код и разобраться в том, как использовать
данные. Откровенно говоря, миграция ваших данных будет непростой задачей;
лучше всего привлечь к ней команды и начать с энтузиазмом воспринимать пре
имущества изменения технологических стеков.
В хороших базах данных часто есть таблицы метаданных. В них можно увидеть
текущие запросы, как показано в табл.
Таблица
10.1.
10.1. Реляционная БД и таблицы наблюдаемости
Система управления БД
Таблица/вьюшка
Postgres 2
pg_stat_activity
MySQL3
INFORMATION_SCHEMA.PROCESSLIST
Oracle 4
v$sqlarea, v$session and v$sql
Запрос к таблицам метаданных
недостатком
является
то,
что
-
это непростое решение проблемы. Ключевым
приложения
и
сервисы
должны
использоваться
ко
нечными пользователями в рабочей среде, в наборах тестов или при синтетической
загрузке. Если ваши приложения работают в режиме ожидания, вы не увидите ни
каких запросов. И если запросы появляются редко, это не значит, что они неважны;
2
Представление pg_stat_activity в PostgreSQL: https://www.postgresql.org/docs/current/
monitoring-stats.html#MONIТORING-PG-ST А T-ACTIVIТY-VI EW.
3
Список процессов MySQL:
https://dev.mysql.com/doc/refman/8.0/en/information-schema-processlist-taЫe.html.
Ключевые системные команды Oracle: https://web.archive.org/weЬ/20150217062227/http://www.
databasejournal.com/features/oracle/article.php/3375351/Watching-SQL-Execute-on-Oracle--Part-ll.htm.
4
Миграция данных
■
445
представьте, что у вас сложный, но важный бизнес-процесс, который выполняется
всего
1 раз
в месяц. Если вы не запросите таблицы метаданных в этот конкретный
день, в этот конкретный момент, ваша база данных не выдаст запросы, и вы про
пустите их. Однако хорошей новостью здесь является то, что, если вы видите
запрос при обращении к таблицам метаданных, это означает, что приложение ис
пользует его.
Давайте рассмотрим варианты инструментария для разбора кодовой базы. Допус
тим, ваша база кода находится в удаленной системе управления версиями, такой
как
git,
с использованием
GitHub
или
GitLab.
Вы можете написать поисковый
скрипт для сканирования всей вашей базы кода, извлечения запросов и отправки их
в
JSqlParser для
извлечения таблиц и столбцов. Разбор кодовой базы -дело нетри
виальное и непростое.
♦
Сложные сценарии. Синтаксический анализ может быть сопряжен с трудно
стями; код не всегда прост, ведь приложение может формировать динамические
SQL-запросы.
♦
Мертвый код. То, что вы видите
SQL
в коде, еще не означает, что он использу
ется; это может быть мертвый код, на поиск которого вы можете потратить
месяцы.
Hibemate/JPA, Spring Data
или, честно говоря, любой хороший ОRМ регистрирует
SQL-запросы с помощью простого изменения конфигурации; часто это простое
свойство
Java,
как в табл.
10.2.
Таблица
10.2. Конфигурации Java ORMs для регистрации запросов
Фрейм вор к/решение
Конфиrурация 5
Spring Data JPA
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.foпnat_sql=true
Hibernate
log4j.logger.org.hibernate.SQL=debug
log4j.logger.org.hibernate.type.descriptor.sql=trace
Ведение журнала SQL-запросов в ваших приложениях сопряжено с теми же огра
ничениями, что и чтение таблиц метаданных или использование любого другого
инструмента обеспечения наблюдаемости базы данных; вам необходимо запустить
код для выполнения запросов либо с реальным трафиком, либо с наборами тестов.
По сравнению со сканированием кода, протоколирование запросов будет работать
лучше для динамических запросов, поскольку ОRМ 6 разрешит окончательный
динамический запрос и зарегистрирует его (рис.
10.2).
5
Spring Data Configuration https://springhow.com/spring-boot-show-sql/.
6
ОRМ (Object-Relational Mapping, объектно-реляционное отображение, или преобразование) -
технология
программирования, которая связывает базы данных с концепциями объектно-ориентированных языков про
граммирования, создавая «виртуальную объектную базу данных».
-
Пер.
■
446
Глава 10
1
:
1
1
: Java ORM регистрирует ,
1,
SQL-зanpocы
,_____________
,---------------,
: Использование инструмента :
1
1 Observab1lity АРМ,
: например журнала данных :
0
,...------------,
,-------------,
,
: Сканирование и анализ 1
:
, кодовой базы
1
1
1
1
Чтение кода
1
1
1
1
1
1 Привлечение персонала
Рис.
10.2.
1
0
0
0
Инструментальный подход
Краткое описание вариантов извлечения информации из базы данных
Конечно, простое понимание источника не позволяет определить цель миграции;
для этого требуется архитектура программного обеспечения, понимание сферы
вашей деятельности и дальнейший анализ компромиссов. У вас есть несколько
вариантов.
♦ Простое разбиение. Разделите классические монолиты, превратив одну боль
шую базу данных в более мелкие независимые базы данных.
♦ Сложное разбиение. Примените шаблон
Strangler Fig:
распутайте связанные
таблицы, упорядочите их по бизнес-областям и создайте специализированные
сервисы с изолированными базами данных по бизнес-областям.
♦
Слияние. Объединение сервисов распределенного монолита в сервисы по биз
нес-областям с надлежащей степенью детализации базы данных.
♦
Эволюция на месте. Эволюция схемы, изменение модели данных, но сохране
ние хранилища данных.
♦
Миграция хранилища данных. Измените базовое хранилище сохраняемости
Oracle на А WS Aurora или
Postgres, Kafka и ElasticSearch.
данных; перейдите с
с
SQL Server на
примените
CQRS
и перейдите
Располагая всеми этими сведениями в виде нашего инвентарного списка, мы можем
приступить к составлению плана. Если повезет, сможем найти несколько быстрых
выигрышей, также известных как низко висящие плоды.
Планирование и определение быстрых выигрышей
Наличие хорошего инвентарного списка является важным фактором для правиль
ного планирования миграции данных. С его помощью можно распределить воз
можные миграции данных по группам и бизнес-областям, которые будут организо
ваны по степени важности, бизнес-подразделениям или технологиям. Вы можете
определить концепции, которые вам необходимо проверить (РОС), чтобы подтвер-
Миграция данных
■
447
дить жизнеспособность определенных целей миграции, или тесты производитель
ности, которые доказывают, что ваша конфигурация
RDS Oracle7
будет соответст
вовать вашему локальному физическому оборудованию или превзойдет его. Задача
убедить бизнес в необходимости миграции данных выходит за рамки данной книги.
Однако хороший план поможет продемонстрировать вашу осведомленность и ор
ганизованность.
Если вам повезет, инвентаризация может дать быстрые выигрыши или низко вися
щие плоды. Возможно, в общей базе данных есть независимые схемы с минималь
ным количеством зависимостей между собой; или в рамках одной схемы у вас есть
наборы таблиц, явно независимых друг от друга.
Чтобы более подробно показать вам, как можно добиться быстрого результата, да
вайте рассмотрим сценарий, в котором у вас есть классический монолит и большая
общая центральная реляционная база данных с несколькими схемами. В нашем
сценарии быстрого выигрыша вы обнаружите три изолированные схемы, которые
используют один и тот же физический кластер, но не имеют связи между собой.
Все, что вам нужно сделать, это создать три отдельных экземпляра базы данных, по
одному на схему (рис.
10.3).
Конечно, легче сказать, чем сделать; вскоре мы рас
смотрим практические методы выполнения этой миграции.
Классический монолит
Контракт
ввв
Общая БД
Рис.
10.3.
Контракт
Контракт
Реализация
Реализация
Реализация
сервиса
сервиса
сервиса
Изолированная
Изолированная
Изолированная
БД
БД
БД
Разделение общей базы данных на три экземпляра с одной схемой в каждом
Давайте не будем забывать, что разделение на три отдельных кластера баз данных
подразумевает
наличие
соответствующих сервисов,
изолированных
контрактов
и
изолированного развертывания сервисов. Возможно, вам не удастся сделать все это
одним движением. Вероятно, придется сначала переместить базу данных, а затем
разделить служебный код. Или же вы сможете выполнить оба действия одновре
менно.
RDS Oracle - это сервис для реляционных баз данных Oracle, разработанный компанией Amazon Web
Services (А WS). С помощью RDS можно устанавливать, эксплуатировать и масштабировать развертывания
Oracle. Сервис позволяет операторам управлять трудоемкими задачами администрирования базы данных
и фокусироваться на инновациях и разработке приложений. - Пер.
7
448
■
Глава 10
Вторая возможность, которую мы обсуждали, заключается в том, что у вас есть
одна схема, но при анализе использования таблиц вы понимаете, что существуют
три набора независимых таблиц (рис .
10.4).
Представьте, что, купив лотерейный
билет, вы только что сорвали джекпот. Вы можете сделать то же самое, что описано
в предыдущем подходе, и сразу перейти к созданию более подходящих сервисов
с изолированными базами данных.
Классический монолит
Контракт
таблиц
1
Реализация
Реализация
сервиса
сервиса
сервиса
Изолированная
Изолированная
Изолированная
БД
БД
БД
таблиц З
2
Общая БД
Рис.
Реализация
Набор
Набор
Набор
таблиц
Контракт
Контракт
10.4.
Создание новых схем из изолированных наборов таблиц
Быстрые выигрыши доступны не всегда; если у вас их нет, пусть так и будет. Но
если у вас есть такая возможность, быстрые выигрыши должны быть приоритет
ными при миграции данных. Демонстрация реального, немедленного прогресса
в вашем бизнесе
-
это всегда отличный исход. Ваш проект по миграции данных
может быть длительным, и ожидание результатов до конца проекта
-
рискованная
стратегия . Но даже если вы быстро добьетесь желаемых результатов, проблем не
избежать. В конечном итоге вам придется проделать тяжелую работу, о которой мы
расскажем позже в этой главе.
Шаблоны миграции данных
Итак, с простыми вещами покончено. Теперь давайте рассмотрим, как можно пра
вильно выполнить миграцию данных.
Повторный просмотр отложенных миграций
Отложенная миграция
(Lazy migration)
была рассмотрена в предыдущей главе
9
«Миграция кода». Давайте теперь немного расширим этот шаблон в контексте ми
грации данных .
На рис .
VI
10.5
показан сценарий отложенной миграции сервиса профилей с версии
на версию
V2,
который мы подробно обсуждали в главе
9
«Миграция кода». На-
Миграция данных
■
449
помним, что отложенная миграция выполняется в процессе выполнения, когда код
сервиса переносит данные на стороне приложения по мере того, как сервис обра
батывает новые данные. В нашем примере мы выполняем перенос данных из иден
тификатора профиля в формате версии
версии
ко
V2;
V2.
V I в идентификатор профиля в формате
V 1, так и V2, но может записывать толь
Наш код может считывать как
со временем, по мере доступа пользователей или сервисов к данным профи
ля, все данные в
и кешированные в
MySQL
Redis
будут прозрачно перенесены
в новый формат. Количество хранилищ данных, используемых сервисом, не имеет
значения; здесь мы аккуратно обрабатываем два хранилища данных, но их может
быть любое количество.
Потребитель
Потребитель
(чтение)
(запись)
Контракт
Redir
Реализация
сервиса профилей
MySQL
БД профилей
. . . . . . . . . . . ..
Рис.
10.5.
Отложенная миграция, повторение
Надлежащие сервисы являются ключом к отложенной миграции, поскольку они
обеспечивают четкую границу обслуживания, отделяющую интерфейс от реализа
ции. Ваши потребители не знают специфики работы сервиса, что позволяет выпол
нять миграцию данных и рефакторинr базы данных в целом прозрачно. Огложен
ные
миграции
позволяют использовать
несколько сценариев, все
из которых кон
тролируются сервисом.
♦
Рефакторннr столбцов. Преобразование данных, запись их в другой столбец,
объединение или разделение столбцов.
♦
Рефакторннr таблиц. Полное преобразование таблицы в другую структуру
таблицы.
♦
Рефакторннr схемы. Переместите схемы в другой кластер, как мы видели
в наших примерах про быстрые выигрыши ранее в этой главе.
450
♦
■
Глава 10
Миграция хранилища данных. Запись в другое постоянное хранилище; на
пример, переход с
MySQL RDS
на А WS
Aurora.
♦ Рефакторинг формата данных. Полностью измените формат данных и их зна
чение, как мы видели в примере идентификатора профиля в формате версии
или версии
1
2.
Отложенная миграция выполняется во время работы приложения, связывая преоб
разование данных с чтением и записью, вследствие чего она происходит медленно.
В связи с этим возникают некоторые очевидные проблемы и недостатки:
♦
Сроки выполнения. Миграция данных не обязательно завершится в установ
ленные сроки и может занять больше времени, чем хотелось бы.
♦ Незавершенные данные. Если некоторые идентификаторы никогда не считы
ваются и не записываются, они никогда не переносятся. Возможно, вам потре
буется написать отдельное пакетное задание для переноса оставшихся иденти
фикаторов; мы вернемся к незавершенным данным позже в текущей главе, когда
будем обсуждать двойную запись.
♦
Задержка. Вы выполняете больше кода и получаете доступ к большему количе
ству данных во время выполнения, и поэтому можете увеличить задержку, вы
полнив функцию
♦
+ миграцию одновременно.
Ошибки. Что происходит, когда у вас возникают ошибки? Следует ли прервать
миграцию?
Из-за этих недостатков при переносе данных шаблон отложенной миграции может
оказаться недостаточным. Помимо отложенных миграций, существуют и другие
шаблоны, которые могут нам помочь.
Экспорт и импорт
Схема экспорта и импорта проста для понимания, и, вероятно, это первая схема,
о которой вы подумали, когда читали название этой главы: экспортируйте базу
данных в файл, содержащий SQL-команды, а затем импортируйте этот SQL-файл
в другую базу данных (рис.
Как правило, загружаемый файл содержит
SQL
с использованием синтаксиса языка описания данных (Data Description Language,
DDL) и языка манипулирования данными (Data Manipulation Language, DML)8.
10.6).
Другими словами, структуру таблицы и данные. Для большинства баз данных эти
скрипты могут быть автоматически сгенерированы с помощью инструмента дампа,
такого как
MySQL dump
или
Oracle Data Pump
(табл.
10.3), а
сами файлы дампа уже
настроены на быстрое получение результата. Экспорт и импорт
-
это один из
самых быстрых способов перемещения данных, если только вы не меняете техно
логию постоянного хранилища.
DDL и DML подробно описаны в Википедии: https://en.wikipedia.org/wiki/Data_definition_language и
https://en.wikipedia.org/wiki/Data_manipulation_language.
8
Миграция данных
: SQL-ФАЙЛ (DDL и SML)
EJEJEJ
10.6.
451
:
Изолированная
БД
Общая БД
Рис.
■
Экспорт и импорт данных с использованием
SQL, DDL
и
DML
Таблица 10.3. Инструменты экспорта и импорта по базам данных
База данных
Инструмент
MySQL9
mysqldump
Postgres 10
pg_dump
Огасlе 11
SQL Developer,
Огасlе
Data Pump
Экспорт и импорт имеют несколько очевидных недостатков:
♦
Офлайн. Как правило, сгенерированные инструкции являются деструктивными;
они блокируют таблицы и могут потребовать много физических ресурсов для
выполнения. Кроме того, вы не хотите добавлять или изменять новые записи во
время импорта. Для обеспечения максимальной безопасности вам необходимо
перевести обе базы данных в офлайн.
♦
Технология сохранения заблокированных данных.
SQL
универсален, но не
все базы данных работают одинаково. Вы не можете просто импортировать дан
ные, экспортированные из
MySQL
в
Oracle.
Если вы также хотите изменить базу
данных, вам потребуется преобразовать файл.
Если планируете полагаться только на простой экспорт и импорт, вы ограничены
в способах выполнения переноса данных. Экспорт и импорт часто наиболее эффек
тивны в сочетании с другими стратегиями. Например, представьте, что вы экспор-
9
MySQL: mysqldump: https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html.
10
PostgreSQL dp _ dump: https://www .postgresql.org/docs/current/backup-dump.html.
Oracle SQL Developer: https://www.oracle.com/database/technologies/appdev/sqldev/export-intro1.html#:-:text=1.lsing%20the%20main%20menu%2C%20select,a%20directory%20and%20file%20name.
11
452
■
Глава 10
тируете данные, преобразуете
DML
или
DDL
в SQL-дампе, чтобы изменить данные
или структуру данных или даже цель постоянного хранилища, затем импортируете
данные в новую базу данных, и все это в режиме онлайн, а затем применяете стра
тегию отложенной миграции, двойную запись или даже захват изменения данных,
чтобы наверстать упущенное и завершить работу. Экспорт и импорт могут быть
гибкими инструментами при разумном использовании.
Репликация базы данных
Большинство баз данных поддерживают возможности репликации данных, которые
необходимы для создания высокодоступных и надежных систем. Самые простые
версии позволяют создавать выделенные реплики для чтения, при этом транзакции
записи выполняются только на одном или нескольких главных узлах. Продвинутые
реляционные базы данных и решения
NoSQL
позволяют полностью запускать базы
данных в конфигурации с несколькими ведущими узлами 12
актив-актив
(active-active).
(multi-master)
или
Здесь все узлы могут выполнять операции чтения и за
писи, будучи синхронизированы благодаря репликации базы данных. Репликация
данных может быть использована для получения различных преимуществ и вари
антов использования:
♦ Масштабирование. Реплики чтения распределяют нагрузку на чтение базы
данных приложения по нескольким компьютерам, чтобы повысить производи
тельность. Базы данных с несколькими главными объектами выполняют те же
функции, но также могут обрабатывать операции записи; стратегии реплик чте
ния предполагают, что одна главная запись выполняется на одном узле, а опера
ции чтения выполняются в репликах.
♦ Отказоустойчивость и аварийное восстановление. Чтобы избежать возникно
вения единой точки сбоя в вашей базе данных, реплицируйте данные на не
сколько узлов. В случае сбоя на одном узле вы можете восстановиться, пере
ключившись на другой узел. Аналогичным образом репликация данных на дру
гой сайт или регион может позволить вам восстановиться после полного сбоя
сайта. Репликация является важным инструментом для аварийного восстановле
ния и общей отказоустойчивости.
♦
Аналитические рабочие нагрузки. Создавайте выделенные реплики для чте
ния, чтобы справляться с большими аналитическими нагрузками, в то время как
оперативная обработка транзакций выполняется только на главном сервере.
♦
Резервное копирование. Сервисы резервного копирования могут работать на
репликах, не нарушая работу главного сервера, а также приложений и сервисов,
выполняющих чтение и запись на главном сервере.
12
Базы данных с несколькими ведущими узлами могут содержать более одного ведущего узла; в некоторых
случаях все базы данных имеют равные права доступа ко всем данным, или, в качестве альтернативы, узлы
в
кластере
по
отдельности
выступают
в
качестве
ведущих
Более подробное обсуждение приведено на странице Википедии:
https://en.wikipedia.org/wiki/Мulti-master_replication.
узлов
для
определенных
точек
данных.
Миграция данных
♦
■
453
Миграция данных. Репликация данных может сыграть важную роль в обеспе
чении
миграции данных.
Команды
могуr использовать репликацию данных
в качестве механизма для синхронизации данных и последующей миграции из
одной среды в другую или даже просто с одного компьютера на другой. Мигра
ция данных позволяет реплицировать данные с использованием множества раз
личных методов, с помощью встроенных инструментов базы данных, программ
ного обеспечения сторонних производителей или даже на стороне приложе
ния/сервиса.
На рис.
10.7
показан пример перехода от классического монолита к полноценному
сервису. Здесь у вас есть один общий кластер баз данных с множеством таблиц
и схем. Ваша команда хочет перенести один набор схем в новую изолированную
базу данных, которая
(master/replica)
в настоящее время находится в режиме мастер/реплика
с Мастер
1 (М 1),
Реплика
1 (R 1)
и Реплика
2 (R2).
Мы можем ис
пользовать репликацию базы данных, чтобы скопировать данные из старого общего
кластера в новый изолированный кластер. Вы начинаете с репликации М 1 в новый
кластер базы данных с тремя выделенными репликами для чтения:
R3, R4
и
RS.
Как
только все реплики в изолированной базе данных синхронизируются, вы назначае
те одну реплику в качестве новой главной, затем переключаете источник досто
верности на новый кластер, отключая доступ из изолированной базы данных к М 1,
R1
и
(рис.
R2, очищая
10.8).
и выводя из эксплуатации старые данные в старом кластере
Классический монолит
Контракт
Реализация
сервиса
Мастер
Ремика
1
1
Общая БД
Рис.
10.7.
Репликация данных из классического монолита в соответствующий сервис
Хотя здесь это проиллюстрировано двумя простыми шагами, на самом деле это
долгая и трудная задача, на выполнение которой могуr уйти месяцы или годы,
в зависимости от взаимосвязи и сложности ваших систем. Мы рассмотрим эти шаги
более подробно, когда вернемся к шаблону
Strangler Fig позже
в текущей главе.
454
■
Глава 10
Контракт
Реализация
серв иса
Изолированная БД
Рис.
10.8.
Переключение источника достоверных данных с классического монолита
на надлежащий сервис
Сравнение таблиц
Другой простой метод, который дополняет сценарии экспорта и импорта или реп
ликации базы данных, заключается в запуске сравнения таблиц (tаЫе
diff).
После
перемещения данных вы сравниваете их в исходной и целевой таблицах, опреде
ляя отклонения, которые есть в исходной таблице, но отсутствуют в целевой
(рис.
10.9).
Исходная
таблица
10 записей
-
Исходная
таблица
Дельта
5 записей
..-
Разница между исходной
и целевой таблицами .
5 записей
Рефакторинг данных в той же базе данных
или перенос в другую базу данных.
ОбщаяБД
Рис.
10.9.
Подход, основанный на сравнении таблиц
Сравнение таблиц помогает убедиться в успешной миграции или выполнить неко
торые миграции данных, в основном в режиме онлайн, а функция получения дель
ты помогает восстановить упущенные записи. Вы можете создать таблицу, распро-
Миграция данных
■
455
страняющую данные, с помощью инструментов, описанных в разделе «Экспорт и
импорт», или путем написания кода для вашего небольшого приложения. Вы также
можете периодически запускать сравнение таблиц перед переключением. Но имей
те в виду, что сравнение таблиц требует больших ресурсов и не будет масштабиро
ваться для больших таблиц.
Подход, основанный на сравнении таблиц, может быть использован для двух раз
ных вариантов переноса данных:
♦ Рефакторннг базы данных. Перенос схем, таблиц или столбцов; например
когда вы хотите использовать новую таблицу с новым столбцом, но вам нужно
скопировать данные из исходной таблицы.
♦
Миграция хранилища данных. Полный переход на другую базу данных, на
пример с
MySQL
ных
напрямую сопоставимы. Поэтому, если вы преобразуете классический
SQL
на
Postgres.
Большинство простых структур таблиц базы дан
монолит в надлежащий сервис, для синхронизации данных может быть доста
точно простого сравнения таблиц.
Сравнение таблиц имеет ограничения при работе с большими таблицами или набо
рами данных, поскольку вам необходимо время от времени считывать исходную
таблицу. Можно уменьшить некоторые последствия этого метода, получив данные
из реплики, предназначенной для чтения. Однако существуют более эффективные
методы.
Триггеры
Многие современные базы данных поддерживают использование триггеров
gers ):
тия.
(Trig-
код базы данных, который выполняется в ответ на предопределенные собы
Триггеры также
могут использоваться для
поддержки миграции данных.
В простом сценарии триггер может срабатывать при вставке, обновлении и удале
нии исходной таблицы или группы таблиц, а затем записывать эти изменения
в таблицу журнала. Позже таблица журнала может использоваться в качестве ис
точника для репликации изменений в друтие таблицы или даже базы данных.
На рис.
10.1 О
триггерный подход показан более подробно. Таблица журнала изме
нений создается с помощью триггеров, которые срабатывают при внесении изме
нений в исходные таблицы. Затем функция считывает таблицу журнала изменений
и отправляет данные в другую таблицу в другой базе данных. Это изображается как
функция базы данных в общей базе данных. Но на самом деле функция может на
ходиться в изолированной базе данных, быть даже в виде независимого скрипта
или бессерверной функции. Всё будет хорошо работать, если новая изолированная
база данных будет иметь ту же технологию работы с базами данных, что и исход
ная база данных. Если изолированная база данных использует другую технологию
сохранения и команда, например, переходит с
Postgres
на
MySQL,
то функция чте
ния журнала изменений должна будет преобразовать один формат базы данных в
другой.
Самая большая проблема с триггерами заключается в том, что они могут влиять на
производительность, задерживая транзакции. Кроме того, в некоторых технологиях
456
■
Глава 10
баз данных вы не сможете использовать один и тот же триггер для всех таблиц,
и/или, возможно, потребуется объединить их с другими решениями, такими как
хранимые процедуры и функции. Что делать, если появилась новая таблица? Будет
ли это включено в триггер? Таким образом, вам могут понадобиться дополнитель
ные скрипты и код, чтобы продолжать генерировать триггеры для новых таблиц.
Исходная
таблица
Триггер
10 записей
Целевая таблица
5записей
Общая БД
Изолированная БД
Рис.
10.10. Триггерный
подход
Захват изменения данных
Захват изменения данных
(Change Oata Capture,
СОС) является идеальным решени
ем для переноса данных, особенно если вам требуется перемещение данных прак
тически в режиме реального времени. При захвате изменения данных вы считывае
те журнал всех изменений исходной базы данных и используете этот журнал для
применения изменений к новой целевой базе данных. Многие базы данных исполь
зуют ту или иную форму СОС для реализации репликации данных, поскольку для
синхронизации систем достаточно просто читать журналы СОС. Таким образом,
стратегии СОС и репликации взаимосвязаны. Миграция данных с помощью СОС
напрямую использует журнал репликации данных для выполнения действий, что
полезно, когда требуется полное преобразование, например, в совершенно новое
хранилище данных. Стратегии СОС могут быть реализованы с помощью
Kafka,
Apache
который выступает в качестве канала связи между исходной и целевой база
ми данных. В зависимости от характера вашего бизнеса и общих требований к дос
тупности простои могут быть критичны, а при масштабной работе объем ваших
данных может быть значительным. В таких случаях СОС
-
оптимальное решение.
Реализация СОС может показаться более сложной, но, в свою очередь, вы получае
те большую гибкость. На рис.
10.11
показан наш классический монолит, в который
вставляются, обновляются и удаляются исходные таблицы. Когда изменения обра
батываются, они записываются в журналы транзакций локальной базы данных. Эти
Миграция данных
журналы считываются и отправляются в такой канал, как
Apache Katka.
■
457
Потреби
тель подписывается на эти изменения. Это может быть простое Jаvа-приложение,
бессерверная функция или даже какой-нибудь простой Jаvа-код, который находит
ся внутри соответствующего сервиса.
Kafka
Подписчик
Исходная
Транзакция
таблица
Журнал
изменений
10 записей
Целевая таблица
5 записей
Общая БД
Изолированная БД
Рис.
Подход
10.11.
CDC
для перехода от классического монолита к надлежащей изолированной БД
Хорошей новостью является то, что для СОС существуют платные варианты и ва
рианты с открытым исходным кодом. Например, у
Debezium (https://debezium.io/) -
Oracle
есть
Golden Gate 13 ,
а
отличное решение для СОС с открытым исход
ным кодом.
В
Debezium
есть исходные коннекторы, которые вы будете использовать для под
ключения к исходным базам данных, из которых собираетесь извлекать данные,
таким как
MySQL, Postgres, Oracle, Cassandra, MongoDB, SQL Server, D82, Vitess и
l 0.12). Debezium также позволяет отправлять события измене
ний в Katka, затем вы можете использовать коннектор Katka для отправки данных
в различные источники, такие как ElasticSearch, Infinispan и ваше хранилище дан-
многие другие (рис.
1
~
::=~=~=.:-=~=====;:=;-·='-~
:§
Debezium
PostgreSQL
j;Э
111
Apache Kafka
Kafka Connect with
DeЬez11.1 m
:::::::::::::::::::::;:::::~:::':::1~'
source connectors
Рис.
10.12. CDC -
общая архитектура
ОО
r.
W
~::~:;, ......
ElastкS•arch
~
Connector
~
кafka Connect with
s1nk connectors
§Д
.._" '
it1
Debezium.
Источник: https://debezium.io/documentation/reference/staЫe/architecture.html
13
Oracle Golden Gate: https://docs.oracle.com/en/middleware/goldengate/index.html.
;.•elastic
hfp,
Data
Warehouse
■
458
Глава 10
ных. Также вы можете зарегистрировать своего подписчика как часть соответст
вующего сервиса.
Двойная запись
Двойная запись
это еще один активный способ , позволяющий при
(dual writing) -
ложениям напрямую обрабатывать
миграцию данных (рис. 1О.13 ).
В сценарии
двойной записи команды одновременно выполняют запись в две разные базы дан
ных. Эти базы могут иметь как одинаковую, так и разную структуру данных . Над
лежащие сервисы
-
отличный способ реализовать двойную запись, поскольку они
имеют изолированные базы данных и нет риска, что другой сервис будет записы
вать данные только в одну базу данных. Двойная запись также известна как дробо
вик
(shotgun).
Контракт
Реализация
сервиса
Сервис производит двойную запись
в две различные базы данных .
Старая БД
Новая БД
Рис.
10.13.
Шаблон двойной записи
Двойная запись может поддерживать множество вариантов использования
при
переносе данных :
♦ Нарезка кубиками и ломтиками. Разделение классического монолитного кода
на части.
♦ Рефакторинr базы данных. Реорганизация базы данных и эволюция схемы
в целом.
♦
Миrрация хранилища данных. Переход с одной системы управления баз дан
ных на другую, например с
♦
Oracle на MySQL.
Эволюция кластера. Вы используете
Cassandra 3 .х
Apache Cassandra
2 .х и хотите перейти на
или хотите остаться на той же версии, но перейти на новый кла
стер с более совершенным оборудованием.
Основное различие между двойной записью и репликацией базы данных заключа
ется в том, что двойная запись выполняется только на стороне приложения, т. е. на
стороне сервиса. Когда вы запрашиваете у сервиса выполнение операции записи,
вы выполняете запись в две разные таблицы или базы данных . Сама база данных
ничего не знает и не играет прямой роли.
Миграция данных
■
459
Двойная запись также имеет свои недостатки:
♦
Незавершенные данные. Как и при отложенной миграции, двойная запись вы
полняется только для данных, которые сервис активно обрабатывает. Это не
сработает для «холодных» данных, которые обновляются редко.
♦
Сбои. Что произойдет, если в одной из баз данных произойдет сбой записи? Как
восстанавливать данные?
♦
Задержка. Две базы данных должны подтвердить запись, что приводит к неко
торым задержкам и усложнению транзакции в целом.
Давайте обсудим эти недостатки более подробно.
Незавершенные данные
Данные, которые являются актуальными, будут перенесены. Однако что происхо
дит с точечными данными, которые никогда не считывались или не записывались?
Ну, они никогда не будут перенесены. Таким образом, шаблон двойной записи не
может работать сам по себе. К счастью, в нем есть несколько простых исправлений.
Вы можете сравнить таблицы и определить недостающие данные, а затем запустить
свой сервис для обработки значений в реальном времени. Можно считывать данные
из
сервиса,
затем
выполнять
запись
в
сервис
или
потенциально
предоставлять
выделенную конечную точку, предназначенную только для миграции, которая вы
полняет то же самое в локальной транзакции. Вы можете быстро обрабатывать
промежуточные данные вне рабочего времени вашего приложения или медленно,
выстраивая идентификаторы записей в очередь для последующей обработки.
Почему бы не прочитать все записи в первую очередь и просто не написать скрипт,
который принудительно запускает все записи с помощью двойной записи? Потому
что двойная запись имеет ключевое преимущество в том, что вы можете наблюдать
за выполнением кода вашего приложения в реальном времени, прежде чем пере
ключиться на него. Что делать, если в коде сервиса есть ошибка, которая проявля
ется только при высокой нагрузке, ошибка, которую вы увидите только в рабочей
среде? Мы рассмотрели преимущества тестирования в рабочей среде в аналогич
ных сценариях в главе
7
«Надлежащее тестирование сервисов». Двойная запись
позволяет вам убить двух зайцев одним выстрелом: перенести данные и протести
ровать код до того, как он повлияет на клиентов.
Сбой при выполнении одной операции записи
Что ж, в данном случае у нас есть два варианта: либо вы полностью игнорируете
сбой и позволяете компоненту сравнения таблиц справиться с этим, либо вам нуж
но повторить попытку. Ожидание завершения сравнения таблиц приводит к вре
менной рассинхронизации двух баз данных. В конечном итоге они все равно станут
согласованными. Если вы просто ждете повторной попытки, вы задерживаете пре
образование. Вы не можете повторять попытки вечно. И что вы будете делать после
трех попыток? Можно занести ошибки в отдельную таблицу, чтобы выполнить не
которую ручную корректировку, или же просто проигнорировать сбой и позволить
460
■
Глава 10
сравнению данных решить проблему. А затем ваши инженеры отладят то, что по
шло не так.
Задержка и сложность транзакций
Несмотря ни на что, вы выполняете больше работы, что приведет к некоторой за
держке выполнения основной транзакции, потребляя больше ресурсов на стороне
приложения и усложняя работу сервиса с ней. Сложность должна где-то присутст
вовать. Когда вы используете репликацию базы данных, сложность переносится
в базу данных. При двойной записи сложность остается в сервисе.
Возможно, вы подумаете, что у меня есть монолит, который я нарезаю на кусочки.
Я не хочу писать какой-либо прикладной код, который будет подключаться к моей
новой изолированной базе данных. Именно так в конечном итоге мы разделяем ба
зы данных! Итак, давайте будем полагаться на природу соответствующих сервисов;
пусть монолитное приложение записывает данные как в эту базу данных, так и
в соответствующий сервис (рис.
10.14).
Перенесите все варианты использования
и средства записи в новый сервис. Единственное различие между рис.
10.13
и
10.14
заключается в том, что двойная запись выполняется путем вызова сервиса вместо
прямого вызова монолитом изолированной базы данных.
Монолит осуществляет запись
в две разные базы данных .
Одна из записей выполняется
Классически й монолит
через вызов сервиса.
Реализа ция
сервиса
ОбщаяБД
Изолированная БД
Рис.
10.14.
Схема двойной записи с классическим монолитом
Стратегии миграции данных
На данный момент мы узнали о важности проведения оценки и составления надле
жащего
перечня
для
поддержки
миграции
ваших
данных,
а
также
исследовали
закономерности для подхода к переносу отдельных данных. Давайте углубимся и
разберемся в некоторых более широких стратегиях миграции данных, таких как
онлайн или офлайн, вначале схема, а также пересмотрим
Strangler Fig.
Миграция данных
■
461
Онлайн или офлайн
В зависимости от вашего бизнеса простой может быть нежелательным. Но если
у вас есть такая возможность, воспользуйтесь ею! Перенос данных в автономном
режиме намного проще. Огкровенно говоря, некоторые базы данных справляются
с переносом данных лучше других, поэтому, насколько возможно, старайтесь мак
симально упростить задачу. Например, если можно обойтись только экспортом и
импортом, сделайте это. Именно в тех случаях, когда существует высокая степень
сцепления и большая степень запутанности, используйте такие шаблоны, как СОС,
и более продвинутые стратегии, такие как
Strangler Fig,
к которым мы вскоре вер
немся. Вам необходимо разобраться в своих инструментах и проверить свои пред
положения. Проанализируйте ожидаемые сроки простоя ваших решений для ми
грации. Например, при рассмотрении репликации
подобные приведенным в табл.
Oracle
можно получить цифры,
10.4.
Таблица 10.4. Пример решений Oracle 14 и ожидаемых простоев
Решение
Ожидаемое время простоя
Oracle Golden Gate
От нуля до нескольких секунд
Oracle Data Guard
Менее
5
Oracle Recovery Manager
Менее
2 часов
минут
Если ваш бизнес не терпит простоев или предъявляет жесткие требования к надеж
ности,
возможно,
вам
следует рассмотреть
возможность
перехода
на
высокодос
тупные базы данных, подобные рассмотренным в главе
технологий, таких как
Cassandra, ScyllaDB 15
или
8, с использованием новых
А WS Aurora. Высокодоступные
базы данных часто работают в конфигурации с несколькими ведущими устройст
вами, о чем было сказано в нашем разделе о репликации баз данных. Базы данных
с несколькими ведущими устройствами идеально подходят для многорегиональных
рабочих нагрузок, которым требуется конфигурация «актив-актив». Если вы не ис
пользуете высокодоступную базу данных с несколькими основными базами дан
ных, но она необходима вашему бизнесу, вы можете позволить себе некоторое вре
мя простоя, чтобы перейти на более совершенную базу данных.
Вначале схема или несколько миграций
Итак, вы планируете преобразовать существующую базу данных и структуру таб
лиц в новую базу данных с совершенно другой структурой таблиц. Но как лучше
поступить: сначала обработать данные, а затем преобразовать их, или сделать и то
и другое сразу? У каждого подхода к переносу данных есть свои компромиссы.
14
Пример ожидаемого времени простоя Oracle: bttps://docs.oracle.com/en/solutions/гeduce
databasemigгation-downtime/index.Ьtml#GUID-03575843-7008-4919-А 1Cl-523E4 l С 11 С3 Е.
15
с
ScyllaDB - это столбчатая база данных с открытым исходным кодом, которая обратно совместима
Cassandra: bttps://www.scylladb.com/.
462
■
Глава 10
Преобразование данных и схемы одновременно
-
это подход, основанный на по
строении схемы. Давайте определим новую схему с новым дизайном таблиц или
даже отойдем от реляционной модели и перейдем к
NoSQL,
и сразу перейдем к ней
во время миграции данных. Второй подход состоял бы в том, чтобы сначала перей
ти к новому кластеру баз данных, используя ту же схему или как можно более
близкую к ней, а позже реорганизовать ее, эффективно выполнив несколько мигра
ций.
Помните, что здесь нет правильного или неправильного пути, есть только компро
миссы (рис.
10.15).
Шалон «вначале схема» интересен тем, что, когда вы закончите,
вы полностью завершите работу, т. е. одним махом и перенесете данные, и перей
дете на новый кластер или даже на новую технологию. Недостатком является
больший риск; это сложнее, т. к. вы делаете две вещи одновременно и многое мо
жет пойти не так.
Изменить схему
Сначала выполнить миграцию
прямо во время миграции
(новый источник достоверности),
(новый источник достоверности)
затем изменить схему
Несколько миграций
Вначале схема
(-) Сложнее
(+) Только одна
(+)Лef\je
Н Много миграций
миграция
Рис.
10.15.
Спектр миграции и изменения схемы
Однако при многократной миграции у нас есть преимущество в том, что мы снача
ла переключаемся на новый источник достоверности, а затем фокусируемся на раз
витии схемы. Такой процесс немного проще, но означает большее количество эта
пов. В конечном итоге вы будете выполнять более одной миграции, что является
недостатком. Критически важно, что множественные миграции не могут работать
при
переходе
с СУБД на
на совершенно
другую
технологию
сохранения
Если вы переходите с MySQL на Cassandra,
MySQL в Cassandra приведет к неудаче, в то
MySQL на Postgres всё может быть нормально.
NoSQL.
ровать вашу схему
реходе с
данных,
например
попытка реплици
время как при пе
Учитывая методы и шаблоны, которые мы рассмотрели до сих пор: отложенные
миграции, экспорт и импорт, репликация базы данных, сравнение таблиц, триггеры
базы данных или двойная запись, вы можете использовать любой из этих шаблонов
миграции данных, используя подход «вначале схема» или «множественные мигра
ции». Решать вам.
Пересмотр:
Strangler Fig
Мы подробно рассмотрели шаблон
Strangler Fig
в главе
9
«Миграция кода»; он яв
ляется важным для расширенной миграции кода и ничем не отличается от шаблона
миграции данных, который рассматриваем в текущей главе. Именно так следует
поступать, когда вам нужно нарезать классический монолит на кусочки. Независи-
Миграция данных
мо от того, как вы планируете миграцию
-
■
463
переходите ли вы с классических или
распределенных монолитов на надлежащие сервисы, вам потребуется перенести
данные.
Strangler Fig
является мощной стратегией для такой миграции. Давайте
начнем с рассмотрения классического монолита (рис.
Классические монолиты,
Strangler Fig
10.16).
и миграция данных
Прежде всего, вам нужно определить концепцию того, как вы хотите разделить мо
нолит, что можно сделать, сосредоточившись на конкретных критериях группиров
ки, таких как:
♦
Бизнес-область. Как мы уже говорили в главе
нес-областей
♦
-
5
«Оценки», сопоставление биз
лучший способ организации программного обеспечения.
Функции. Функции часто пересекаются с бизнес-областями; это не идеально , но
возможно.
♦
Таблицы. Существующая организация данных, скорее всего, не соответствует
вашей текущей бизнес-структуре, далека от идеала, но лучше, чем ничего.
□
Классический
монолит
□□
□
□
Рис.
10.16.
Классический монолит
-
шаг
1
Давайте вернемся к вашему описанию. Предположим, вы решили разбить свою ба
зу данных по бизнес-областям и начинаете с выделения области продаж . Вам необ
ходимо идентифицировать всех читателей и авторов таблиц в этой бизнес-области.
Вы можете и должны провести инвентаризацию, подобную приведенной в табл.
Таблица
10.5.
10.5. Инвентарный список писатепей/читатепей
Имя таблицы
Читатель
Автор
Перешел на новый сервис?
Sales
SalesDAO.java
-
ДА
Users
UserController.java
-
НЕТ
Sales
-
UserAnalytics.java
НЕТ
JSP_page_users.jsp
НЕТ
Users
464
■
Глава 10
Как и в случае с любым инвентарным списком, ваш список может оказаться очень
длинным, поэтому мы всегда рекомендуем использовать общую электронную таб
лицу, такую как
Microsoft Excel
или
Google Sheets.
Получив эту информацию, вы
можете приступить к разработке нового сервиса, определению нового контракта
и реализации (рис.
10.17).
Сервис продаж (надлежащий сервис)
□ Классический монолит
□□
Контракт
Реализация
сервиса
g~cg~
lc
Учитывая
10.17.
.......
~
□
......
ОбщаяБД □
Рис.
'
__,
Изолированная БД
От классического монолита к надлежащему сервису- шаг
Strangler Fig,
2
рекомендуется сначала перемещать средства записи, а за
тем средства чтения. Вам нужно будет перемещать каждое средство записи по оче
реди. Как и ранее, вы должны выбрать, будете ли вы выполнять шаблон «вначале
схема» или же несколько миграций. Давайте предположим, что вы вначале перей
дете к новой схеме. Итак, теперь нужно применить двойную запись к классическо
му монолиту и перевести одно из устройств записи на новый надлежащий сервис
(рис.
10.18).
Здесь мы сначала выполняем миграцию кода, а затем данных, сначала создаем сер
вис, а затем меняем данные одни за другими. Старый код пока удалять нельзя. Этот
процесс вы повторяете до тех пор, пока все средства записи и чтения не будут
переключены на новый надлежащий сервис. На этом работа не заканчивается: вы
должны удалить неработающий код и данные из старой базы данных в приоритет
ном порядке, чтобы избежать путаницы и неработающего кода (рис.
10.19).
Теперь вы можете перейти к следующей бизнес-области, функции или группе таб
лиц и повторить весь этот процесс.
Strangler Fig также
может быть применен к рас
пределенным монолитам. Основное отличие здесь заключается в том, что вместо
того, чтобы хранить весь код в одном репозитории на
по нескольким репозиториям.
GitHub,
вы распределяете код
Миграция данных
■
465
Сервис продаж (надлежащий сервис)
□ Классический монолит
□□
Контракт
Реализация
сервиса
B~cg~
□
ОбщаяБД □
Рис.
10.18.
Изолированная БД
От классического монолита к надлежащему сервису
Классический монолит □□
-
шаг
3
Сервис продаж (надлежащий сервис)
□
Контракт
Реализация сервиса □
1J
с.
.....
□□□
=,
J
Изолированная БД
Рис.
10.19.
От классического монолита к надлежащему сервису
-
шаг
4
Выполнение миграции
Разработка и планирование миграции базы данных
-
это только первая часть. Что
бы успешно выполнить их, вам нужно знать, что они работают. Здесь на помощь
приходят тестирование и наблюдаемость. Они не прекращаются в момент мигра
ции, а продолжают приносить пользу вашему программному обеспечению на про
тяжении всего его будущего жизненного цикла.
■
466
Глава 10
Тестирование
Тестирование
-
это важный инструмент для эффективного выполнения кода и ми
грации данных. Существуют различные категории и виды тестов, которые вы, воз
можно, захотите выполнить. Но как минимум должно быть сделано следующее
(рис.
♦
10.20):
Проверка работоспособности перед миграцией. Функциональное тестирова
ние перед переносом данных: все ли в порядке или у нас есть проблемы, прежде
чем мы начнем? Важно знать, является ли ваша миграция причиной проблем или
они уже существовали до ее старта.
♦
Тестирование производительности приложения. Производительность прило
жения
следует
измерять
и
тестировать
с
помощью
такого
инструмента,
как
Gatling.
♦
Тестирование производительности базы данных. Функциональность доступа
к БД также необходимо протестировать, возможно, с помощью такого инстру
мента, как
NDBench.
♦ Проверка работоспособности после миграции. Тестирование нужно прово
дить не только в начале, но и в конце. Проверьте структуру и данные на работо
способность после миграции.
Тестирование производительности
с точки зрения приложения
Тестирование производительности
с точки зрения БД
Проверка работоспособности тестирование перед миграцией
Проверка работоспособности
-
тестирование после миграции
структуры и данных
Рис.
10.20.
Тестирование миграции базы данных
Проверка работоспособности перед миграцией
Перед началом любой миграции рекомендуется убедиться, что приложение и ис
ходная база данных находятся в хорошем состоянии. Как минимум вам необхо
димо:
♦
Проверить сборку. Убедитесь, что все связанные проекты кода прошли проце
дуру сборки.
Миграция данных
♦
■
467
Проверить уровень прохождения тестов. Убедитесь, что все наборы тестов
проекта успешно пройдены на
100 %.
Если тесты не проходят, то почему? Вос
пользуйтесь возможностью исправить ошибки: исправьте или удалите.
♦
Проверить централизованные журналы логов. Убедитесь, что ни приложе
ния, ни базы данных не регистрируют ошибки, необработанные исключения или
другие неожиданные сообщения. Если у вас еще нет централизованного реше
ния для регистрации сообщений из нескольких систем, сделайте шаг назад. Как
еще вы сможете обнаружить непредвиденные проблемы в приложениях? Важно
знать о существующих неполадках.
♦
Проверить панели мониторинга. Убедитесь, что все панели мониторинга
работоспособности вашего приложения в исправном состоянии и оповещения не
срабатывают. Проверяя панели мониторинга на наличие предупреждений, про
анализируйте стратегию переноса данных, которую вы используете. Не вызовет
ли это ложных срабатываний? Возможно, вам придется отключить некоторые из
них на время миграции.
Тесты должны существовать до того, как вы начнете проверку работоспособности,
и должны быть неотъемлемой частью процесса поддержки и выпуска приложений.
Однако классические и распределенные монолиты могут быть сложными, а тесты
в них могут отсутствовать.
Добавление тестов перед началом миграции может показаться лишним, но это
очень важная и отличная идея. Ведь если при переносе данных возникают ошибки,
вы можете здраво рассуждать о том, была ли ошибка вызвана переносом или уже
происходила до миграции. Если вы запустили все тесты перед началом миграции и
i-,
с::>
П роисходит
миграция се рве р а
V
~ Исправление ошибок
Фун кция
п ере кр естны х
прода ж
Классический монолит □□
Сервис продаж
( надлежащий сервис)
Контракт
Происходит
миграция
Реализация
JDK
сервиса
□
□
□□□
Происходит
миграция
базы данных
Изол и рованная БД
Общая БД
Операционная система
(Ubuntu)
Происходит миграция
операционной системы
Рис.
10.21.
Фактическая миграция
468
■
Глава 10
все они прошли без ошибок, то это говорит о том, что ошибка, как вы подозреваете,
была вызвана миграцией.
Причина, по которой мы говорим «ключ к разгадке», а не «абсолютное доказатель
ство»,
заключается
в том,
что
мир
продолжает меняться,
пока
вы
планируете
и
выполняете миграцию данных; команды разрабатывают и выпускают функции, а
другие миграции происходят параллельно (рис.
вашего неисправного
монолита,
вы уверены,
1О .21 ).
что
не
Независимо от состояния
сможете
потратить
время на
исправление тестов и ошибок до начала миграции? Поверьте нам, мы знаем из опы
та: правильное тестирование экономит многие часы жизни, паническое устранение
неполадок и отладку.
Тестирование производительности
Необходимо понимать, как ваши миграции повлияют на производительность при
ложения, и тестирование производительности
-
лучший инструмент для этого.
Проведите базовый тест производительности перед началом миграции и еще один
после ее завершения, чтобы подтвердить правильность миграции. Для сценариев
отложенной миграции или двойной записи может оказаться хорошей идеей запус
тить тест во время самой миграции.
Тестирование производительности важно. Все ваши функциональные тесты могут
быть пройдены успешно. Но отсутствие индекса или плохо спроектированная
функция означают низкую производительность под нагрузкой и возможные по
следствия для потребителей. Приложения изменят свои схемы доступа к данным
в результате миграции данных, особенно при смене технологий сохранения дан
ных. Необходимо выявить антипаттерны до их запуска. Например, если вы вне
дряете новую базу данных, знаете ли вы, как она будет работать под нагрузкой?
Возможно, для новой технологии ожидается высокая загрузка процессора, но это
является тревожным сигналом для вашего предыдущего стека.
На практике вы будете проводить две формы тестирования производительности:
♦
Тестирование в режиме черного ящика (Ыасk Ьох
testing).
Создание нагрузки
на ваше приложение и проверка задержки и времени отклика. Взгляните шире,
посмотрите не только на компоненты вашего приложения, но и на весь график
зависимостей. В главе
Gatling
7 «Надлежащее
тестирование сервисов» мы рассмотрели
как эффективный способ проведения тестирования производительности.
Используйте
Gatling
для проведения нагрузочного теста, моделирования ожи
даемого производственного трафика, чтобы оценить поведение сервиса и убе
диться, что производительность соответствует ожиданиям после миграции.
♦ Тестирование в режиме белого ящика
(white
Ьох
testing).
Взгляните на это
с точки зрения базы данных; убедитесь, что целевое оборудование соответствует
вашим
потребностям,
проверьте
производительность запросов,
индексацию,
планы выполнения и многие внутренние детали и параметры.
Давайте подробнее рассмотрим специализированный инструмент, помогающий
в тестировании в режиме белого ящика/ производительности базы данных:
NDBench.
Миграция данных
■
469
Практическое тестирование
производительности базы данных с помощью
NDBench
Теперь нам нужно провести эффективное тестирование производительности базы
данных, для чего нужен инструмент, который может измерять производительность
запросов,
план
выполнения
и
время выполнения
запросов к различным
хранили
щам данных. Использование такого инструмента становится еще более важным,
когда вы переходите с одного ядра базы данных на другое, например с
Oracle на
MySQL. У Nettlix есть интересный инструмент под названием NDBench (https://
github.com/Netflix/ndbench), с помощью которого можно выполнить тестирование
NoSQL на стороне базы данных для: Cassandra, Redis, Elasticsearch, Elassandra,
Amazon DynamoDB, JanusGraph, Netflix Dynomite.
Netflix использовал NDBench для облегчения перехода с Cassandra 2.0 на 2.1
(https://github.com/Netflix/ndbench/wiki/NDBench-at-Netflix). На рис. 10.22 пока;-~
NDBench Runner
1. Select
а
--
Cluster
lnstance Statistics
loc.alhoSI
- tudL.8tAvo- rмdRPS -
мtt.utAYV - wm.RPS
2. Connect а Driver
tn~Ttst
~7nll'!uglll-eortl«IICR,\fo
НЮЕ SETTO<GS
lлlttal
Sett1ngs
~_,,..IIQl'I
"
~Кеу~О
BiFll 'IIЫНI
Run\ime Sett1ngs
15;63.ЭО
155'
tSS-:30
.. --..
..
_,
-·
НЮ€ SТАТS
1555
1555.30
а,-.
Swnl.UU.YQ
...........
JSON
•ci,et,ett1t1ta11•lnt": 2f.
•ск~&t,•
27'1,
С.К~\11·
ММ,
•,,--,,ti.,r,•.1
1t•t11te1•tFr• ~
2't
1t•1.uiмf•t"r~8"d•
$
-'"':==~
---------· -----· ---·----·
о
il')'Dlcti.n.}НЬМor!!
(;(),,_,',о,~
.,.....,u.vv·
·,ua,tN'
2
1
.,....,,tm·,
., ..... , ..... 1
·r111CL1tMS".1,
-, .....,t'""" J,
.,....,. 25
"
·r1кS,,cc,11•: •~•·••ttafitlur ■•
1,
••ri\~ltAVt"• J,
"•r1teL.ltl'S8"; J.
•~it81...1tfltS"- 5,
• •1t8',.1~·: ' ·
••r11.t.t"'"5"
1.
...,iteL.lt""9",.
11,
-.,11..,,--
"••it•b~•••
7267
3. Run Load Tests
RANOOМ
8acW
0
о
Rнds
• 0
--
Рис.
Источник:
wr.1н
• 0
о
о
10.22. Интерфейс NDBench от Netflix.
https:/lgithub.com/Netflix/ndbench/wiki/NDBench-UI
н..s.
15~15:57
470
■
Глава 10
зан инструмент
NDBench Runner,
с помощью которого вы можете выбрать свой
кластер, подключить и настроить драйвер базы данных, выбрать стратегию тести
рования и запустить; статистика экземпляров позволяет вам понять влияние ваших
тестов на общую производительность базы данных.
Проверка работоспособности:
структура и данные после миграции
Отлично, вы завершили начальный этап миграции данных, и все индикаторы на
информационных панелях загорелись зеленым. Теперь нужно проверить работо
способность и согласованность вашей новой структуры базы данных и данных, со
держащихся в ней. Допустим, вы переносите реляционную базу данных, такую как
автономный кластер
♦
Postgres,
в
RDS Postgres.
Вам нужно будет проверить:
Исправность таблиц. Все таблицы были перенесены:
100
таблиц в
RDS Postgres.
100
таблиц в
Postgres ==
Все столбцы, строки, индексы и конфигурации при
сутствуют, как и ожидалось.
♦ Целостность данных. Все данные бьmи перенесены; если в таблице А
лиона строк, то и в таблице В
Проверка работоспособности
-
80,124 мил-
80, 124 миллиона строк.
это один из последних тестов, которые мы прово
дим при миграции данных. Для выполнения этих тестов вам необходимо уметь
подсчитывать и сравнивать количество таблиц и столбцов с обеих сторон, а также
экспортировать свою схему для сравнения инструкций
SQL DDL.
Сравнивать дан
ные в большом объеме очень сложно. Еще один эффективный метод- выборочная
проверка
строк
с
использованием
контрольных
сумм
с
помощью
хеширования.
Если они совпадают, данные верны. А если нет, может потребоваться расследо
вание.
Наблюдаемость
Наблюдаемость жизненно важна для миграции кода и данных. Наблюдаемость
это способ понять, что происходит в ваших системах, сервисах
(observability) -
и базах данных, а также оценить общее состояние ваших данных (рис.
мы рассказывали о тестировании. Тестирование
наблюдаемость
-
-
10.23).
Ранее
это форма наблюдаемости, но
это гораздо больше.
Суть наблюдаемости заключается в понимании того, что происходит с нашим про
граммным обеспечением во время эксплуатации. Возможно, в вашей среде уже есть
инструменты, которые помогут ответить на этот вопрос. Централизованное ведение
журнала логов в настоящее время довольно популярно, но само по себе ведение
журнала
-
не самый эффективный способ понять, что происходит в вашей систе
ме, или устранить ошибки. Информационные панели и оповещения важны для
обеспечения надежности и операций на продуктиве, но они также важны для
успешной миграции кода и данных. Как правило, командам необходимы инстру
менты для кодирования и публикации таких показателей клиентов, как:
Миграция данных
Рис.
10.23.
■
471
Наблюдаемость
♦
Счетчики успешных операций. Подсчитывают все успешные операции.
♦
Счетчики ошибок. Подсчитывают все операции с ошибками
-
наблюдаемость
ошибок.
♦
Процентили задержки. Измеряйте производительность с помощью проценти-
лей задержки: показатели для Р50, Р70, Р75, Р90, Р95, Р99.
Ваши тесты являются частью наблюдаемости системы. Тесты также должны пуб
ликовать показатели. Публикация показателей в системе мониторинга производи
тельности приложений
(Application Perfonnance Monitoring, АРМ) 16 ,
Prometheus (https://prometheus.io/), является отличным решением,
такой как
поскольку
в этом случае вы можете сопоставлять события в центральной базе данных вре
меннь1х рядов с изменениями базы данных, журналами и другими системными
данными. Отслеживание вызовов отдельных процессов в вашем стеке также очень
важно. Особенно важна распределенная трассировка 17 , потому что один вызов мо
жет объединить множество сервисов, и вам нужно видеть поток вызовов во всех
сервисах. Распределенная трассировка/ АРМ также может быть использована для
всех миграций путем определения:
♦
Общей производительности: ключевые показатели, такие как процессор, па
мять, дисковый ввод-вывод и размер очереди.
♦
Наиболее часто используемых запросов: наиболее часто выполняемые запросы в системе.
♦
Медленных запросов: самые медленные запросы.
♦
Времени выполнения: время выполнения транзакции, запроса или процесса.
Во время любой миграции необходимо следить за тем, чтобы не возникали узкие
места в производительности и возможные сбои в работе пользователей. Дпя под
тверждения
того,
что
миграция
дает
приемлемые
результаты,
важно
следить
16 Определение АРМ от компании Amazon:
https://aws.amazon.com/what-is/application-performance-monitoring/.
17
Определение трассировки от Open Telemetry: https://opentelemetry.io/docs/concepts/signals/traces/.
за
■
472
Глава 10
производительностью базы данных и выполнять мониторинг запросов или транзак
ций.
В табл.
10.6
приведены некоторые инструменты обеспечения наблюдаемости, ко
торые вам следует рассмотреть для использования.
Таблица
10.6. Решения для обеспечения наблюдаемости, которые следует учитывать
Инструмент обеспечения наблюдаемости
Утилита
https://docs.datadoghq.com/
database_monitoring/query_metrics/
Datadog - АРМ
и SQL Server
https://newrelic.com/lp/mysql
New Relic - АРМ
+ 600 интеграций
https://www.solarwinds.com/databaseperformance-monitoring-software
SolarWinds -АРМ
https://grafana.com/
Альтернативный инструмент мониторинга
дпя запросов к
MySQL, Postgres
дпя запросов к
MySQL
и мониторинг
производительности дпя Огасlе
с открытым исходным кодом
Мы только начали касаться того, как наблюдаемость может помочь вам. Всё, что
вы можете измерить, можете и наблюдать. Наблюдаемость может и должна исполь
зоваться во многих, самых разных контекстах, чтобы увидеть, что используется
активнее:
♦ Аппаратные показатели. Все компоненты приложения (пользовательский ин
терфейс, сервисы, веб-сайты, мобильные приложения и т. д.) должны публико
вать базовые показатели, такие как загрузка процессора, памяти, использование
диска, дисковый ввод-вывод, сетевой ввод-вывод.
♦ Таблицы. К каким таблицам осуществляется доступ; счетчики чтения, записи.
♦
Столбцы. Какие столбцы используются для чтения и записи.
♦ Классы и методы. Какие классы в вашем коде используют больше памяти или
вызываются чаще?
♦
Функции. Используйте в своем мобильном приложении аналитику, такую как
Mixpanel (https.//mixpanel.com/),
и узнавайте,
используются ли
когда-либо
определенные функции.
♦ Пользовательский интерфейс приложений. Сколько запросов обслуживает
ваш веб-сайт в день, в час, в минуту? Какие страницы наиболее популярны
в вашем приложении и каково время их отображения? Классифицируйте и пред
ставляйте эту информацию по продуктам, бизнес-областям или организациям.
♦ Конфигурации. Все ли конфигурации программного обеспечения на самом де
ле используются вашим приложением? Какие конфигурации используются чаще
всего?
♦ Задания
Jenkins.
Когда в последний раз выполнялось задание? Каков средний
процент неудачных или успешных заданий в ваших проектах? Насколько быст
ро или медленно выполняется задание?
Миграция данных
♦
■
473
Тесты. Сколько тестов выполняется по сравнению с тем, сколько их определено
в кодовой базе? Сколько из них пройдено успешно? Сколько завершено неудач
но? Какова частота их прохождения? Есть ли среди них ошибочные? Классифи
цируйте и представляйте эту информацию по продуктам, бизнес-областям или
организациям.
♦
Сервисы. Как часто вызывается сервис? Кто его вызывает и какие операции или
данные запрашивают?
♦
Бессерверные функции. Сколько функций активно вызывается, а сколько про
сто определено? Как часто они выполняются успешно или с ошибками? Можете
ли вы разобраться в них; правильно ли они помечены для идентификации вари
антов использования?
♦
Пакетные задания. Сколько пакетных заданий выполняется в сравнении с тем,
сколько из них определено? Как часто они выполняются? Каково время выпол
нения? Как часто они завершаются ошибкой или выполняются успешно? Опре
делите график зависимостей ваших пакетных заданий, если он существует.
♦
Средства балансировки нагрузки и АРI-шлюзы. Сколько конечных точек
определено и сколько из них активно используется? Сколько транзакций обра
батывается в час, в минуту, в секунду? Классифицируйте и представляйте эту
информацию по продуктам, бизнес-областям или организациям.
♦
DNS-имена. Сколько DNS-имен у вас в рабочем состоянии? Как часто добавля
ются новые DNS-имена или меняется их разрешение? Сколько у вас СNАМЕ
по сравнению с несколькими записями? Перегружены ли ваши DNS-cepвepы?
В целом это помогает иметь правильную структуру
DNS
для анализа данных
о наблюдаемости. Существует достойный и предсказуемый шаблон, такой как:
$app_name.$business_domain.$cloud_az.$cloud_region.
♦
Группы
безопасности.
Какое
количество
групповых
правил
безопасности
в среднем используется в ваших сервисах? Какие сервисы или ресурсы не соот
ветствуют требованиям? Найдите сервисы, которые допускают слишком боль
шое количество абонентов и могут нарушать изоляцию.
♦ Кластеры. Где установлены ваши серверы:
EMR,
ЕС2,
ECS
или
EKS?
Кому
принадлежат кластеры? Сколько они стоят?
♦
Серверы. Сколько у вас серверов? Правильно ли они помечены, чтобы иденти
фицировать варианты использования? Кому они принадлежат? Каково соотно
шение использования и простоя их ресурсов? При недостаточном или избыточ
ном использовании экземпляры нужного размера автоматически преобразуются
в более подходящий тип.
Наблюдаемость очень важна как для миграции кода, так и данных, поскольку клас
сические и распределенные монолиты, как правило, содержат мертвый код. На
блюдаемость позволяет легко обнаруживать и удалять неработающий код, не толь
ко упрощая миграцию, но и снижая затраты за счет очистки неиспользуемых ресур
сов, снижения сложности, сокращения масштабов будущих миграций и просто
улучшения работы.
Всё должно быть наблюдаемым.
474
■
Глава
10
После миграции данных
Как только вы закончите, вам нужно будет очистить и по-настоящему вывести из
эксплуатации старый код. Но вы не завершите работу, пока не отключите всех по
требителей. Вы уверены, что всё зафиксировали? Некоторые из практик, которые
мы опишем далее, предназначены не только для периода после миграции; охота на
призраков принесет вам пользу как до миграции, так и во время нее.
Охота на призраков
Наши миграции выполняются успешно, и теперь пришло время отказаться от ста
рых решений и баз данных. Не так быстро
-
нам нужно решить некоторые задачи
аудита, чтобы убедиться, что мы не пропустили ни одного пользователя или при
ложения. Проверка важна, поскольку при отключении серверов могут возникнуть
перебои в работе или нарушится работа пользователей и разработчиков.
Мы называем этот процесс охотой на призраков. Охота на призраков означает про
ведение анализа в сочетании с инвентаризацией вашего программного обеспечения,
чтобы подтвердить, что все потребители, включенные в первоначальную инвента
ризацию, являются полноценной совокупностью реальных потребителей. Вот не
сколько вариантов, которые легко могут быть реализованы:
♦ Отсутствующие потребители. Не хватает некоторых потребителей, которые не
записаны в вашем обычном стеке. То есть ваш сервис написан на
потребитель являлся приложением на С#, работающим в
сом на
♦
Visual Basic,
Развертывание
Java, но этот
Windows, или макро
от которого сильно зависит работа в бухгалтерии.
Soowflake. Некоторые приложения были развернуты вручную,
CVCD. Не забудьте, что ноутбук, засунутый под стол, поддер
минуя конвейеры
живает работу всей компании.
♦ Разные команды и организации. Приложение из другой организации, с кото
рой вы не знакомы, и у вас нет доступа к исходному коду в вашем общем храни
лище.
♦ Новый компонент. После завершения инвентаризации и запуска процесса ми
грации появляется новый сервис или приложение, созданные без вашего ведома.
Как мы можем обнаружить призраков? Воспользуйтесь теми же ресурсами, людьми
и инструментами, что и для проведения инвентаризации в начале (рис.
.
Офлайн
При
Онлайн
~
Поспрашивать
10.24).
Чтение кода
окружающих
Рис.
Разобраться в своих
Подключение
инструментах
к сети
10.24. Спектр
охоты на призраков
Наблюдаемость
Миграция данных
переходе с
Postgres
на
MySQL
■
475
можно охотиться на призраков следующими спосо
бами:
♦ Поспрашивать окружающих. Спросите своих архитекторов, администраторов
баз данных и технических руководителей; возможно, они знают то, чего вы не
знаете. Возможно, приложение Х и сервис
Z
будут выведены из эксплуатации
в следующем месяце и вам не нужно будет заботиться о них как о потребителях.
Может быть, вы узнаете о новом приложении, запущенном в производство пере
груженной командой, или даже о каком-то скрытом инструменте наблюдения,
о существовании которого вы не подозревали и который откроет целый мир но
вых возможностей, потребителей, которых вы упустили.
♦ Чтение кода. Выполните поиск по репозиториям и ознакомьтесь с исходным
кодом, например найдите JАR-файл драйвера
Postgres JDBC.
Что бы вы ни дела
ли, всегда читайте код.
♦ Разобраться в своих инструментах. Возможно, вам не хватает ключевых пока
зателей, о которых команды не знают и которые могут быть использованы для
выявления скрытых потребителей. В достойных решениях всегда есть пользова
тельский интерфейс администратора, АРI-интерфейсы и другие показатели или
способы понять, что происходит. Прочтите официальную документацию и изу
чите свои инструменты, прежде чем прийти к выводу, что вы знаете предел того,
что они могут вам сообщить.
♦ Подключение к сети. Проверьте свою сеть с помощью журналов доступа switch
или А WSELB/ ALB. Перечислите все IР-адреса, попадающие в базу данных
Postgres,
которые вы хотите удалить, и отследите приложения оттуда. Не забы
вайте, что у большинства сервисов приложений, таких как
Tomcat,
также есть
журналы доступа.
♦ Наблюдаемость. Проверьте свои инструменты наблюдаемости/АРМ, чтобы
получить список всех приложений или пользователей баз данных для вашего эк
земпляра
Postgres в
рабочей среде.
Как правило, поиск призраков следует выполнять несколько раз в течение проекта,
независимо от того, идет ли речь о миграции кода, данных или о любом другом ви
де миграции. Проекты по миграции могут занимать много времени, и ситуация ме
няется. Если у вас есть возможность автоматизировать процесс охоты на призраков,
то и отлично. В противном случае делайте это вручную. Вам следует постоянно
консультироваться и использовать охоту на призраков для улучшения своего ин
вентарного списка, чтобы перепроверять, включены ли в него все приложения, да
же после того, как вы закончите создавать его в первый раз! Охота на призраков
-
отличный способ социализировать свою миграцию. Вы можете проинформировать
менеджеров о том, что происходит, и использовать эти точки соприкосновения для
предупреждения команд, которым, возможно, потребуется действовать в рамках
миграции.
Полезно практиковаться в охоте на призраков на ранних этапах процесса миграции.
Java, а затем обнаруживае
ASP.NET. Что ж, ваше решение мо-
Представьте, что вы планируете разработать решение на
те, что у вас есть пользователи, работающие с
476
■
Глава 10
жет не подойти этим пользователям, и вам, возможно, потребуется применить со
вершенно другой подход! Теперь представьте себе еще более страшный сценарий:
вы находите потребителя
Snowtlake -
проприетарноrо решения, написанного на С,
без исходного кода, только с двоичными файлами. Возможно, вам потребуется соз
дать специальное решение. И лучше обнаружить это раньше, чем позже, чтобы из
бежать неожиданных сбоев в работе, которые убивают миграцию.
Очистка и вывод из эксплуатации
Наконец, после охоты на призраков пришло время вывести из эксплуатации старую
систему, заархивировать старый код, выключить серверы и объявить о победе. Вот
несколько советов по выводу систем из эксплуатации:
♦ Коммуникация. Заблаговременно уведомляйте свои команды о выводе данных
из эксплуатации, по крайней мере за
2--4
недели до этого.
♦ Хаос. Оrключите сервисы перед выводом из эксплуатации; если вы правильно
выполнили свою работу, жалоб быть не должно.
♦
Архивируйте код. Не удаляйте код полностью; заархивируйте репозиторий,
например, в
git, GitHub
или
GitLab.
♦ Полное резервное копирование данных. Не просто выключайте серверы и вы
брасывайте данные, создайте полную резервную копию старых данных и заар
хивируйте их в
S3/Glacier 18 •
♦ Удалите пользовательский код. Не оставляйте после себя мертвый код; выведите из эксплуатации пользовательский код, удалив его и очистив зависимости.
Очистка кода и данных, вероятно, является одним из самых неэффективных видов
деятельности в нашей отрасли. Люди не удаляют код, и это неправильно. Нерабо
тающий код приводит к путанице, ненужным миграциям и усложняет поиск и
устранение неисправностей. Неработающий код и неработающие данные ведут
к потере персонала и инфраструктуры. Миграция не заканчивается, когда вы запус
каете последний
PR
и развертываете последний сервер; она будет продолжаться
до тех пор, пока вы не очистите и не удалите ненужный код и данные. Так что не
стесняйтесь.
Что нужно запомнить
Поздравляем! Вы дочитали до конца главу
10.
Вот несколько моментов, о которых
следует помнить.
♦
Миграция данных сопряжена с большими рисками:
•
•
потеря данных, их повреждение;
нарушение качества обслуживания клиентов, возможные проблемы с брен
дом;
18
АWS Glacier: https://docs.aws.amazon.com/amazonglacierЛatest/dev/introduction.html.
Миграция данных
♦
•
финансовые потери;
•
откат
-
■
477
наиболее сложный процесс.
Оценка, инвентаризация и надлежащий анализ имеют решающее значение при
миграции данных.
♦
Инвентаризация в виде таблицы должна отвечать на следующие вопросы.
•
Кто владелец данных?
•
Какие приложения выполняют чтение и запись для конкретной цели миграции?
♦
•
Насколько важны данные? Сколько времени простоя мы можем выдержать?
•
О какой схеме, таблицах и столбцах мы говорим?
•
Можем ли мы вывести из эксплуатации какие-либо данные?
Существуют два подхода к сбору данных для инвентаризации:
•
люди: проводите собеседования и задавайте вопросы;
•
инструменты: сканируйте и анализируйте базу кода, используя инструменты
наблюдаемости АРМ или ОRМ.
отличный инструмент для планирования.
♦
Инвентаризация
♦
Вам может повезти, и вы сможете получить быстрый выигрыш, например:
•
•
-
несколько схем, которые можно разделить на несколько экземпляров;
изолированные наборы таблиц, которые можно разделить на независимые
схемы.
♦
Отложенные миграции позволяют приложению обрабатывать варианты исполь
зования для рефакторинга базы данных, такие как:
♦
♦
•
рефакторинг столбцов;
•
рефакторинг таблиц;
•
рефакторинг схем;
•
миграция хранилища данных;
•
рефакторинг формата данных.
Однако у отложенных миграций есть такие недостатки, как:
•
задержка сроков доставки;
•
обработка «холодных» данных;
•
увеличение времени ответа за счет введения нового кода;
•
способы устранения ошибок.
Экспорт и импорт
-
это простой и эффективный способ переноса данных за
исключением того, что:
■
478
Глава 10
•
их необходимо выполнять в режиме офлайн;
•
сложнее изменять технологии сохранения данных.
♦ Репликация базы данных может пригодиться в нескольких вариантах использо
вания:
♦
•
масштабирование;
•
отказоустойчивость и аварийное восстановление;
•
аналитические рабочие нагрузки;
•
резервное копирование;
•
миграция данных.
Репликация базы данных может использоваться для синхронизации двух разных
баз данных.
♦
Сравнение таблиц и триггеры
-
это два разных способа поддержки миграции
данных.
♦ Сбор данных об изменениях
(Change Data Capture, CDC)
является предпочти
тельным способом обработки сложных миграций данных.
♦
Debezium -
хороший вариант с открытым исходным кодом для СОС.
♦
При двойной записи вы записываете данные как в исходную, так и в целевую
базу данных из своего приложения.
♦
Двойная запись имеет такие недостатки, как:
•
обработка «холодных» данных;
•
случаи сбоя;
•
повышенное время ответа.
♦ Миграция офлайн проще, но ваш бизнес может не согласиться с простоем.
♦ При миграции данных «вначале схема» все данные сразу переносятся в новую
схему.
♦
Стратегия множественной миграции сначала перемещает данные, а затем преоб
разует их в новую схему.
♦
Strangler Fig
является идеальным шаблоном для разделения классических и рас
пределенных монолитов.
♦
Надлежащее тестирование важно как для миграции кода, так и для миграции
данных.
♦
Надлежащее тестирование миграции состоит из:
•
тестирования работоспособности перед миграцией;
•
тестирования производительности приложений;
•
тестирования производительности базы данных;
•
тестирования работоспособности после миграции.
Миграция данных
♦
■
479
Тесты на работоспособность перед миграцией включают:
•
проверку прохождения сборки;
•
проверку 100%-ного успешного прохождения всех тестов;
•
проверку наличия ошибок в системах ведения логов.
•
проверку всех информационных панелей на чистоту и отсутствие ложных
оповещений.
♦
Тестирование производительности при переносе выполняется в двух вариантах:
•
в
тестирование
режиме
ящика,
черного
которое
проверяет
производитель
ность с точки зрения приложения;
•
тестирование в режиме белого ящика, которое проверяет производительность
с точки зрения базы данных.
♦
NDBench -
хороший инструмент для тестирования производительности базы
данных.
♦
Проверяется правильность структуры базы данных и корректность самих дан
ных после переноса.
•
Все ли таблицы, столбцы, индексы и конфигурации перенесены правильно?
•
Все ли элементы данных перенесены успешно?
♦
Наблюдаемость
♦
Системы
-
это то, как вы понимаете всю свою систему в целом.
производительности
мониторинга
mance Monitoring,
АРМ)
-
приложений
(Application Perfor-
отличный способ фиксировать показатели наблю
даемости и составлять отчеты о них.
♦
Подсчитывать использование всех ресурсов и публиковать показатели исполь
зования для ключевых элементов, таких как аппаратные показатели, таблицы,
столбцы, классы и методы, функции, пользовательские интерфейсы, конфигура
ция, задания
Jenkins,
тесты, сервисы, бессерверные функции, пакетные задания,
балансировщики нагрузки и шлюзы
API,
DNS-имена, группы безопасности, кла
стеры и серверы.
♦
Такие действия после миграции данных, как охота на призраков, очистка и вы
вод из эксплуатации, необходимы для завершения любой миграции.
♦
Охота на призраков
-
это форма аудита, которая позволяет выявить отсутст
вующих пользователей, используя такие методы, как:
•
расспросить окружающих;
•
прочитать код;
•
узнать свои инструменты;
•
подключение к сети;
•
наблюдаемость.
480
■
Глава 10
♦
Охоту на призраков следует проводить несколько раз в процессе миграции.
♦
Рекомендации, которым необходимо следовать перед выводом из эксплуатации:
•
коммуникация;
•
хаос;
•
архивный код;
•
полное резервное копирование данных;
•
удаление пользовательского кода.
♦ Сохранение устаревшего кода является неправильным и стоит организациям как
денег, так и времени.
♦
Не стесняйтесь удалять неиспользуемый код и данные.
ГЛАВА
11
Эпилоr
В конце концов, этому нет конца
Роберт Лоуэлл
Вы добрались до конца книги! Однако на этом ваше пугешествие не заканчивается.
Здесь мы хотим подкрепить некоторые идеи и принципы и еще раз указать направ
ление. Поехали!
Структура главы
В этой главе мы рассмотрим следующие темы:
♦
На бис!
♦
Принципы важнее всего.
♦
Образование.
♦
Городское планирование.
♦
Концепция.
♦ Далее.
На бис!
Разработка программного обеспечения
-
сложная область. Возможно, вы этого не
осознаёте, но мы каждый день совершаем невозможное.
Эффективный инженер-программист владеет не одной профессией, а целым мно
жеством:
♦ Супергерой, обладающий навыками, умениями и скрытыми преимуществами,
о которых он и не подозревал, когда записывался на курс Computer Science l О l .
♦ Пожарный, бегущий на пожар, чтобы справиться с производственными инци
дентами.
♦ Частный детектив, непревзойденный сыщик, изучающий логи и строки кода,
чтобы найти корень проблемы.
482
♦
■
Глава 11
Врач, быстро диагностирующий работоспособность системы, выявляющий про
белы в дизайне и предлагающий как долгосрочные, так и краткосрочные реше
ния.
♦
Ученый, создающий и проверяющий гипотезы и обращающий внимание только
на реальные данные.
♦
Археолог, исследующий пыльные старые кодовые базы, разбирающийся в зага
дочных архитектурах, программном обеспечении и коде.
♦
Преподаватель и студент, изучающие бизнес и технологии для решения про
блем, обучающие инженеров правильным практикам и принципам, которым не
обходимо следовать.
♦
Юрист, отстаивающий правильные решения и проекты так, как будто завтраш
него дня не существует, убеждающий архитекторов, менеджеров и предприни
мателей добиваться наилучших результатов.
♦
Специалист, создающий красивое и надежное программное обеспечение, быст
рые, эффективные, безопасные, изолированные решения, которые выдержат ис
пытание временем.
♦
Бегун, иногда участвующий в забеге, чтобы снизить нагрузку на производство,
или завершающий годовой марафон, чтобы завершить болезненную миграцию.
♦
Художник, создающий красивые, элегантные впечатления, которые радуют его
клиентов.
♦ Шеф-повар, усердно работающий в команде над приготовлением вкусных блюд
и обеспечивающий лидерство на протяжении всего процесса.
В довершение ко всему технологии стремительно развиваются, а их сложность по
стоянно растет. Мы живем в мире старых решений, которые когда-то были велико
лепны, но теперь устарели, и новых решений, которые команда спешно создает,
чтобы дополнить свое резюме новейшими и наилучшими технологиями. Мы без
мерно сложны, а борьба со сложностями
-
это бесконечная битва. Проблемам нет
конца, и можно спросить себя: если участвовать в бесконечной игре, зачем беспо
коиться? В конце концов, зачем заботиться о классических и распределенных мо
нолитах, если мы все могли бы сидеть на пляже и пить мохито, верно? Гораздо
проще просто смотреть в другую сторону.
Мы здесь, чтобы сказать вам: вы можете играть лучше, вы можете бороться и вы
можете побеждать! Не смотрите в другую сторону! Независимо от того, через что
вы проходите, не сдавайтесь; единственный путь
-
это двигаться вперед, постоян
но совершенствуясь, делая мир лучше для себя и своей команды, даже если никто
этого не видит. Помните: правильный поступок
-
это правильный поступок, даже
если никто другой его не совершает, а неправильный поступок
-
это неправиль
ный поступок, даже если это делают все. Стремитесь к лучшему, потому что это
правильно.
Вы не одиноки. Вы можете читать, изучать, переучиваться и всё улучшать, если
просто будете верить. Потому что мы должны, можем и будем! Страсть зарази
тельна. Если вы сможете повлиять на двух человек, а они повлияют еще на двоих,
Эпилог
■
483
то вскоре вас будут окружать удивительные люди, и вы измените мир. Наберитесь
терпения, но не останавливайтесь на достигнутом. Единственный путь
-
двигаться
вперед!
Принципы важнее всего
Принципы не являются чем-то опциональным. Если вы что-то и выносите из этой
книги, так это то, что принципы имеют значение. Всегда используйте свои принци
пы и удваивайте их. Изоляция, стабильные контракты и экономичные библиотеки
должны стать основой вашего мышления на каждый день. Технологии постоянно
меняются, но принципы остаются неизменными.
Рис.
11.1.
Принципы Томаса Джефферсона. Источник:
Внедрение любой
новой технологии
https://www.azquotes.com/quote/145670
означает перемены.
Перемены трудны
и
сопряжены с риском. Когда вы внедряете новую технологию, вы можете и будете
совершать ошибки. Но, ничего не делая, не совершенствуясь, вы не сможете избе
жать своих текущих проблем. Единственный выход
-
продвигаться вперед с по
мощью новых технологий и качественного программного обеспечения. Однако вы
можете и должны следовать следующим принципам.
♦
Изоляция
-
это всё. Изолируйте всё, начиная с бизнес-областей, создавайте
стабильные ограничения, никогда не используйте хранилища данных совместно,
будьте осторожны и следите за внутренними общими библиотеками.
♦
Надлежащие сервисы.
SOA -
это правильный путь! Используйте сервисы вез
де, где только можете. Создавайте их больше, чем других компонентов, и ис
пользуйте как можно меньше библиотек.
♦
Борьба со сложностями. Вам нужно бороться со сложностями постоянно, без
остановочно.
Невозможно
быстро
обеспечить
наилучший
пользовательский
опыт и постоянно повышать ценность бизнеса, если находитесь посреди токсич
ных отходов. Менеджеры могут мешать вам бороться со сложностями, а про
свещение поможет открыть им глаза. Каждый должен осознавать сложность
ситуации.
■
484
Глава 11
♦ Архитектура основана на компромиссах. Ничего не принимайте на веру;
у всего есть плюсы и минусы, сильные и слабые стороны. Если вы считаете, что
ваша любимая новая технология идеальна, подумайте еще раз; если вы не види
те недостатков, значит, вы недостаточно знаете. Ищите проблемы, рассматри
вайте, как что-то может пойти не так, и определяйте основные кейсы.
Не принимайте ни одно технологическое решение как должное. Внимание к дета
лям
-
обязательное условие. Проводите инвентаризацию, следите за тем, чтобы
всё было видно, и обязательно обдумывайте принятые решения. Когда вы хотите
разработать сервис, проведите анализ компромиссов и спросите, должна ли это
быть библиотека. Когда вы разрабатываете библиотеку, проведите анализ компро
миссов и спросите себя, должен ли это быть сервис. Анализ компромиссов
-
это
непрерывная работа, поскольку технологии постоянно меняются. Вчерашние пра
вильные решения могут стать сегодняшними неправильными. Анализ компромис
сов должен быть постоянным, это неотъемлемая часть правильной архитектуры
программного обеспечения. Оrступайте и не плывите по течению, не задумываясь
о последствиях.
Образование
Первый шаг на любом пути разработки программного обеспечения
-
признать
свое невежество; как бы много вы ни знали, вы знаете недостаточно. Слепое следо
вание шаблонам прошлого может завести вас в тупик. Это относится как к вам, так
и ко всей вашей команде. Образование
-
это ключ ко всему; вы не сможете преоб
разовать свою компанию, если люди не узнают, как выглядит оптимальное реше
ние. Не удастся исправить свои плохие монолиты, если команды будут совершать
одни и те же ошибки снова и снова. Обучение должно быть приоритетным делом.
Рис.
11.2.
Болонский университет, Италия: старейший постоянно действующий университет в мире.
Источник:
https://en.wikipedia.org/wiki/Learning
Эпилог
■
485
Недостаточно пройти техническое обучение. Онлайн-тренинги часто не учат вас
принципам. Вам необходимо постоянно понимать и обсуждать принципы, методы
и то, как отделять одно от другого.
Ретроспективы необходимы для формирования культуры обучения и самоанализа.
Ретроспективы должны быть продолжительными и глубокими, чтобы выявить пер
вопричины и способствовать успешному поведению.
Модернизация
-
это слишком серьезная война, чтобы вести ее в одиночку. Пере
станьте думать, что ваши инженеры ничего не понимают, и они это поймут. Верьте
в них, обучайте их принципам и знакомьте с новыми инженерными технологиями.
Обучайте людей и давайте им свободу. Команды, которые знают и применяют
принципы, не ошибутся; жесткий контроль над всем не приведет к улучшению
программного обеспечения. Наличие надлежащих сервисов
-
это создание эффек
тивных команд, которые сделают все возможное, чтобы поступать правильно .
Городское планирование
Мы понимаем, что иногда нужно решать производственные проблемы и бороться
с пожарами, но вы нt; можете жить в кризисном режиме
24/7
и при этом разрабаты
эффективные архитектуры программного обеспечения. Архитектура про
это упреждающее планирование, мышление на два-три
граммного обеспечения -
вать
шага вперед, предвидение успеха, но также и планирование на случай неудачи.
Вместо того чтобы создавать хаос на микроуровне, вам нужно мыслить как город
ской дизайнер; вам нужно заняться зонированием города. Вы хотите, чтобы все
промышленные предприятия были расположены рядом с государственными шко
лами? Где вы хотите, чтобы люди жили, делали покупки и работали? Городской
дизайнер разрабатывает свой план, зонирует кварталы для работы, игр и всего
остального и позволяет строителям строить. Как и в случае с программным обес-
Источник:
Рис. 11.3. Вид Барселоны, Испания , с высоты птичьего полета.
https://www.dreamstime.com/stock-photo-aeria1-view-typical-buildings-eixample-districtbarcelo-residentialbarcelona-spain-image6588051 О
486
■
Глава 11
печением, архитекторы формулируют свои принципы, проектируют систему в це
лом, а затем предоставляют разработчикам пространство для экспериментов и рос
та. Соответствующие команды поймут, активизируются и восполнят пробелы не
обходимыми решениями. Городского дизайнера не волновало, будет ли кофейня на
этом конкретном углу. Он хотел, чтобы люди жили своей жизнью и были счастли
вы. Точно так же эффективное программное обеспечение
-
это баланс между пра
вилами и свободой. Дизайн архитектора воплощается в общей системе, а не в каж
дой детали.
Город
-
это бесконечная игра 1 : каждый день происходят жизнь и смерть, созида
ние и разрушение. Изменения происходят постоянно; города
-
это живые сущест
ва, которые постоянно находятся в цикле подъема и падения, разрушают здания и
строят дома одновременно, постоянно. Как и компании, они со временем будут
расти и сокращаться, компании приобретаются, а подразделения ликвидируются.
Изменения неизбежны, ошибки неизбежны. Вы никогда не сможете переписать все
программное обеспечение за раз. У вас всегда будет сочетание хороших и плохих
сервисов, монолитов и распределенных монолитов.
Можете ли вы заставить всех переехать в другой город, пока будете перестраивать
их город в течение
50 лет?
Нет, это невозможно. Вместо этого часть города строит
ся, часть сносится, а часть постоянно улучшается за счет реконструкции. То же са
мое относится и к программному обеспечению. Вам нужно поставить перед собой
долгосрочную цель; не пытайтесь решить все сразу, но со временем сможете и
будете совершенствоваться. Бережливое мышление
-
это взгляд в будущее, вы
должны думать о долгосрочной перспективе.
Помните о базовых элементах модернизации программного обеспечения: выводите
его из эксплуатации, улучшайте, переписывайте или игнорируйте (рис.
11.4).
Вы не
можете просто выбрать что-то одно. Вам всегда придется выбирать сервисы, кото
рые придется переписывать, и те, которые вы пока не можете заменить. Но это не
значит, что вы остановитесь на достигнутом. Не сидите сложа руки и не ждите,
по-ка их перепишут, и не переписывайте ради того, чтобы переписать! Сервисы
Улучшить
Игнорировать
Рис.
1
11.4.
Переписать
Вывести
из эксплуатации
Основные элементы принятия решений для модернизации
«Бесконечная игра» Саймона Синека: https://tinyurl.com/infinite-game.
Эпилог
■
487
необходимо постоянно совершенствовать. Возможно, это одна из самых важных
вещей, которые вы можете сделать. Исправление монолитов
не бинарный про
-
цесс, это сложный спектр и живая система, которая должна постоянно меняться.
Вы не будете сносить и перестраивать весь город сразу. Можно снести некоторые
здания, другие перестроить и отремонтировать те, которые в этом нуждаются, зону
за зоной, район за районом.
Бизнес
это бесконечная игра. Программное обеспечение постоянно совершенст
-
вуется. Игра в кошки-мышки в сфере безопасности длится вечно. Злоумышленники
никогда не перестанут атаковать вашу компанию, техническое обслуживание нико
гда не закончится, и бизнес постоянно предъявляет новые требования. Вам всегда
нужно будет улучшать программное обеспечение. Люди всегда будут создавать
технологические долги. Ваша компания приобретет другие компании или будет
поглощена ими, что приведет к проблемам, некачественным технологиям и тому,
что кто-то нарушит изоляцию.
Проекты
-
это ошибочный подход2 • Проекты
-
это конечная игра. Проекты пред
полагают, что у них есть конец, и стремятся сбалансировать время, затраты и ре
сурсы. Вы уже знаете эту историю: вы пытаетесь завершить свой проект в нереали
стичные
сроки,
качество
снижается,
вы
поступаетесь
своими
принципами,
нару
шаете изоляцию и часто получаете продукт не лучшего качества, но, несомненно,
получаете больше технических задолженностей.
Проекты модернизации терпят неудачу, потому что являются проектами. По опре
делению
проекты
модернизации
потерпят
неудачу,
потому
что
это бесконечная игра; вы не можете завершить модернизацию за
модернизация
1, 2
или
5 лет.
По
правде говоря, работа никогда не заканчивается, за исключением случаев, когда
ваша компания обанкротится и закроется. Программное обеспечение должно быть
непрерывным, как и его модернизация. Создание монолитов должно быть жизнен
ной философией, а не проектом.
Концепция
Почему вы хотите исправить монолит? Да, у него есть серьезные проблемы. Но
проблемы, которые он создает, связаны не только с программным обеспечением.
Он также влияет на людей и саму организацию, делает ее требующей ненужных
процессов и формирует культуру, которая боится перемен. Монолит
-
это нечто
большее, чем просто технология, он заставляет ваши команды мыслить неправиль
но. Плохое программное обеспечение продолжает работать, отнимая все больше и
больше времени, энергии и мотивации у людей, которым нужно платить за работу
над ним. Компании, которые используют классические и распределенные моноли
ты,
-
это не лучшие места для работы!
Итак, когда вы купили эту книгу, сами того не осознавая, вы вступили на путь,
который заключался не только в рефакторинге кода, но и в изменении культуры
вашей компании. Вы купили книгу о программном обеспечении, а оказалось, что
2
Аллан Келли о #NoProjects: https://www.youtube.com/watch?v=Rzg1ax8LdaM.
488
■
Глава 11
она посвящена философии, изменению образа мыслей и в конечном счете измене
нию жизни.
В конце концов, если вы будете следовать нашим принципам, ваше программное
обеспечt:ние больше не будет навязывать вашим инженерам неправильные реше
ния. Вместо этого у вас будут надлежащие сервисы, квалифицированные команды,
довольные клиенты и успех. Поступая правильно, вы даете своим сотрудникам
возможность учиться, расти, работать над интересными проектами, получать удо
вольствие от своей работы и, в свою очередь, радовать своих клиентов. Вы сможете
сделать свою компанию лучшим местом, где стоит работать. Вы ведь проводите
в ней так много времени! Разве вы не должны любить ее?
Все вы видели рекламный ролик
Apple Think Different:
«За сумасшедших» 3 . Изме
нение культуры вашей компании начинается с одного человека, который искренне
верит в лучшие методы ведения бизнеса, с лидера, видящего светлое будущее.
Этим человеком должны быть вы.
Далее
Делитесь! Обучайте других и помогайте распространять информацию. Вы не може
те ничего изменить в одиночку, внесите свой вклад, убедив других. Когда вы не
.1елитесь, вы не учитесь. Делиться информацией - это не только забота, но и обу
чение.
Создание результатов необходимо для обучения. Как вы учите математику? Зани
маясь математикой! Называйте это домашним заданием, упражнениями или просто
практикой. Какой смысл просто читать что-то и ничего с этим не делать? Рассказы
вайте об этом другим, пишите посты в блогах и применяйте идеи, изложенные
в этой книге, в своей повседневной работе.
Мы не хотим, чтобы вы просто прочитали нашу книгу, мы хотим, чтобы вы эффек
тивно усвоили ее. Вы не сможете учиться без практики. Для практики вам не нужен
это применять это
бизнес-проект; хотя лучший способ научиться чему-либо в своей повседневной работе. Вы можете изучить многие идеи, изложенные в дан
ной книге, с помощью проверки концепций. Наш рецепт обучения следует приме
нять не к этой книге, а к любой другой, если вы стремитесь чему-то научиться.
Теория требует практики, а практика-теории.
Идите и измените мир! Будьте панк-рокером, не принимайте статус-кво, привноси
те в мир новые, удивительные вещи. Не бойтесь, верьте в себя, вы можете это сде
лать, мы можем это сделать. Прочитав эту книгу, вы сделаете первый шаг!
Спасибо, что прочитали такую длинную книгу. Мы ценим ваше время.
«Vamos que vamos!» 4
Диего Пачеко
Сэм Сгро
3
4
Реклама Apple TV, выпьем за сумасшедших: https://www.youtube.com/watch?v=-z4NS2zdrZc.
Давай, давай, давай! (исп.). - Пер.
Предметный указатель
А
Acceptance test 306
ActiveMQ 79, 169
Agile 83
◊ Execution 217
◊ method 26
Airbnb 191, 195
Amazon Web Services (А WS) 38
Amplifier 34, 46, 51, 62, 134
Anti-Pattem 32-34
Anti-science mentality 137
Apache Commons 171
Apache Kafka 80, 89, 127, 374
Apache POI 178
API Gateway 77, 79, 102, 103, 125
АРI-шлюз 77, 79, 102, 103, 125
Application Performance Monitoring (АРМ)
471
Architect 81
Artificial intelligence (AI) 258
Assessments 209,211,214,227, 243
AvailaЬility Zones (AZ) 38
А WS Kinesis 80, 89
А WS X-Ray 233
в
Backend for Frontend (BFF) 73, 77
Backward compatiЬility 93, 175, 225, 272
Bad environment 137, 142
Bad shared libraries 85
Beta users 329
Big Data 43, 88, 90
Big Designs Up Front (BDUF) 62
Binary Coupling 41, 92, 124, 163
Black Ьох testing 468
Breaking changes 272
Broken windows 46, 51, 64, 137
Bulkhead Pattem 107
Bulkheading 107
Business impact 112,240,245
Business pressure 66, 232
Business Process Execution Language (BPEL)
253
с
САР
Theorem 387
Maturity Model lntegration
(CMMI) 227
Cargo cult 119, 167
Cassandra 16, 76
Centralization 27, 81, 84, 101, 169
Centralizing engineering teams 81
Change Data Capture (СОС) 89,456
Chaos testing 306, 333
ChatGPT 47,258
Classical monolith 17, 43--45, 5~56, 65
Classification and judgment 229
Client/Server sidecars 194
Cloud computing 191
Code
◊ analysis 211,225,227
◊ migration 183, 403
◊ reviews 86
◊ smell 27
◊ base 26
Command Query ResponsiЬility Segregation
(CQRS) 80, 374
Complex Event Processing (СЕР) 380
Complexity 234
Cone of Uncertainty 215
Contract 94
Contract tests 306
CoPilot 47
CapaЬility
490
■
Предметный указатель
Сору and paste 47, 51, 197
Core Team 81
Coupling 35
Cycle time 44
D
Oaemon 186
Oata Access Object (ОАО) 37
Oata Oescription Language (OOL} 450
Oata Manipulation Language (OML} 450
Oata Transfer Objects (ОТО) 286
Oecisions and tradeoffs 218
Oefinition of done (000) 304
Oenial of Service (OoS) 111
Oeployment unit 26
Oesign Pattem 33
Oesign Reviews 86
OevOps 45, 81, 82
Oistributed Monolith 118
Oomain Oriven Oesign (ООО) 103,239,259,
358
Oomain Mapping 239
Oomain Oriented Microservice Architecture
(ООМА) 430
Oownstream dependencies 112, 233
Oriver 1 74
Oual writing 458
Е
Edge router 328
End ofLife (EOL) 134,149,219
End to End (Е2Е) 305
Enterprise Service Bus (ESB) 220, 253
Envoy 189
Event Bus 127
Event Sourcing (ES) 77, 79, 379
Expectations 31, 86, 94, 244
Exploratory tests 306
F
Failure isolation 39, 107, 108, 111
Fallback 110,111,126,127
Fear ofchange 51, 55, 137
Features and bugs 138
Fra111ework 161, 165
Functions as а Service (FaaS) 145
Funnel Curve 215
G
Gatling 323
GitHub 21, 83, 136,167,231
Go 168
Google Cloud SOK 168
Granularity 29, 96, 100,177,228
GraphQL 102, 394
gRPC 397
Guava 171
н
Hibemate 92, 122, 164
High coupling 35
Information Security (InfoSec) 130
Integrated Oevelopment Environment (IDE)
53, 162,227
Integration tests 305
Internal shared libraries 161
Inventories 406
lnversion of Control (IoC) 172
Isolation 67, 69, 85, 104
Istio 195, 233
J
Jackson93, 171
Java Oevelopment Kit (JDK) 196
Java SOK 168, 172
Java Virtual Machine (JVM) 385
JDBC 43, 122, 167
JUnit 169, 236
к
Kigali 233
ksqlDB 380
Kubemetes 168, 190, 233, 366
L
Lack of Talent Oensity 56, 63, 166
Landmines 137, 141, 143, 153
Lazy migration 421,448
Lean Library 204
Lean method 26
Leftovers 137,434
Предметный указатель
Library 159
Load tests 306
■
491
Q
Quick win 153, 243
м
Machine leaming (ML) 184
Manual testing 309
Master inforrnation model 90
Maven 114, 144,172,233
Microfrontend 39
Microservice 23
Microservice Envy 49, 55
Microservices Style of Architecture (MSA)
28,82
Migration target 409
Mocking interface 344
Modemization projects 212
Monolith 23
N
NDBench 469
Netflix Simian Arrny 336
Non-breaking changes 272
о
Object Oriented Programming (ООР) 33
Objectives and Кеу Result (OKR) 48, 150,
163, 165
Observabllity 4 70
Online Transaction Processing (OL ТР) 88
Open source software (OSS) 162
Order of events 247
Over-centralization 82
Ownership 40, 51, 81, 135, 136, 151,163,230
р
Pass rate 48, 174, 180
Perforrnance tests 306
Plain Old Java Object (РОЮ) 76, 122, 233
Platforrn team 81
Polyglot Persistence 277
Post-migration 436
Prioritization 214, 244
Product Market Fit (PMF) 134, 213
Proof of Concept (РОС) 154, 406, 434
Proper isolation 71
PuЬ\ic contracts 104, 182, 232
Pull Request (PR) 86, 136, 165, 180
R
Radical change 248
Red, versus green migrations 408
Reddit 47, 167
Regression tests 306
Remote procedure call (RPC) 233
Repack 40
Replaying traffic 332
Representational State Transfer (REST) 392
Resi\iency matrix 338
Rust 168
s
Scala 168
Separation ofConcerns (SOC) 267,392
Serverless 43, 146
Service Level Agreements (SLA) 168
Service Level Objectives (SLO) 168,292,418
Service Mesh 195
Service Oriented Architecture (SOA) 80,
182,253
Sidecar 186
Single Point ofFailure (SPOF) 108, 144
Sitio 195
Smoke tests 306
SOA и изоляция 276
Software architecture 52
Software as а Service (SaaS) 219,362
Software configuration management (SCM)
231,408
Software engineering 23
Software infrastructure 106
SonarQube 235
Spring41, 122,165,231
StaЬ\econtracts 104,119,162,352
StackOverflow47, 167,171
Standardization 84, 161
Strangler Fig 424, 462
Strategy 64, 130,209, 217, 244
Stress tests 306
SuperApp 60
Synthetic data generation 314, 340
492
■
Предметный указатель
т
ТаЫе diff 454
Talent Density 49
Team erosion 81, 86, 134--136, 173
Technology and business needs 212, 216
Temporal coupling 125
Terraform 84, 168
Test coverage 236
Test data setup 343
Test Driven Development (TDD) 307
Testing
О in production 326
О interfaces 314, 341
О Manifesto 318
О pyramid 324
Time То Live (TTL) 111
Toxiproxy 337
Triggers 455
u
Unit tests 305
Upstream dependencies 234
Usabllity tests 306
Use cases 53, 88, 149, 177
User Facing dimension 234
Utils 176
UX isolation 111
А
Автоматизация работоспособности
контрактов
290
Анализ
О
кода
О
проекта
211,225,227
289
Антинаучное мышление
Архитектор
32-34
81
Архитектура
О
Kafka 376
О
программного обеспечения
Аудит в реальном времени
52
330
Б
Базы данных
NoSQL 386
Бережливые методы разработки
26
Бессерверность 3р 1
43, 146
159
Бизнес-код 197
Бинарная СВЯЗЬ 41, 92, 124, 163
Быстрый выигрыш 153, 243, 446
Бессерверный
Библиотека
в
Вариант использования
Виртуальная машина
V
137
Антипаттерн
53, 88, 149, 177
367
О
Java 385
40, 51, 81, 135, 136, 151,163,230
Влияние на бизнес 112,240,245
Внутренняя общая библиотека 161, 360
Воспроизведение трафика 332
Временная взаимосвязь 125
Владелец
Value Objects (VO) 286
Virtual Machines (VM) 367
Vulnerabllities 162
w
Webpack40
White Ьох testing 468
WIP limits 435, 435
Wrappers 177
у
YouTube 167
z
Zipkin 233
Время
О
жизни
О
цикла разработки
111
44
Выполнение миграции
465
Высокая степень связности
35
234
Вышестоящие зависимости
г
Генерация синтетических данных
Гибкие методы разработки
Гибкие модели данных
26
386
Гибкий процесс разработки
Граница сервиса
261
217
314, 340
Предметный указатель
д
493
Когда следует
Давление бизнеса
66, 232
Двойная запись 458
Двусторонние двери Amazon 433
микросервисов
использовать сервисы
◊
отказаться от сервисов
Код с запашком
255
256
27
Код-ревью
26
86
Команда
430
Доступность сервиса
294
174
Дымовые тесты
◊
Кодовая база
Доменно-ориентированная архитектура
Драйвер
■
306
◊
DevOps 81
◊
разработчиков платформы
◊
ядра
81
81
Комплексная обработка событий
Контейнеры
Е
380
366
Контракт94
Единая точка отказа
Конус неопределенности
144
215
Концепция плотности квалифицированных
специалистов
3
Зависть к микросервисам
Запрос на доработку
Зона доступности
4 7, 51, 197
253
Корпоративная сервисная шина
49, 55
Кривая воронки
136
Захват изменения данных
215
Крупный проект на переднем плане
89, 456
Культ карго
38
62
119, 167
л
и
Локальные ресурсы компании
Изменения
◊
нарушающие целостность
◊
не нарушающие целостность
272
272
на пользователя
Макетирование интерфейса
234
Изолированные модули развертывания
366
Изоляция
◊
67, 69, 70, 85, 104
библиотек 279
◊
пользовательского опыта
◊
публичных контрактов
◊
сбоев
SOA 254
тестирования
318
338
184
Миграция
◊
остаточные явления
◊
тестирование
◊
трения и энтропия
434
466
434
183,403
23
Миграция кода
Интегрированная среда разработки
Микросервис
53
130
Инфраструктура программного
Микросервисная архитектура
28
Микросервисный стиль архитектуры
Микрофронтенд
106
Исследовательские тесты
◊
◊
Машинное обучение
39, 107, 108, 111
◊ хранилищ данных 277
Инвентаризация 406
Инверсия управления 172
Интеграционные тесты 305
Мина
Искусственный интеллект (ИИ)
344
Манифест
Матрица отказоустойчивости
111
286
Информационная безопасность
142
м
Измерение,ориентированное
обеспечения
49
Копирование и вставка
258
306
к
Классификация и принятие решений
229
Классический монолит 17, 43-45, 54-56, 65
Клиент-серверная Sidecar 194
39
137, 141, 143, 153
Моделирование
◊
данных
◊
предметной области
386
Модуль развертывания
Модульные тесты
239, 259, 358
26 .
305
Мониторинг производительности
приложений
Монолит
23
471
82
494
■
Предметный указатель
п
н
Наблюдаемость
Переборки
470
Нагрузочное тестирование
107
Пирамида тестирования
322
324
306
Надлежащая ИЗОЛЯЦИЯ 71,353
Настройка тестовых данных 343
Незавершенные данные 459
Плохая среда
Независимость
Подготовка миграции данных
Нагрузочные тесты
137, 142
Плохие общие библиотеки
Повторное использование
Пограничный маршрутизатор
◊
сервисов
Подход
◊
тестов
◊
вначале контракт
◊
сначала реализация
263
310
Нехватка квалифицированных
специалистов
Покрытие тестами
55, 63, 166
Нижестоящие зависимости
85
199
Новые функции и исправление багов
268
268
236
Пользователи бета-версии
112, 233
138
328
442
329
Понимание при тестировании важнее,
чем проверка функциональности
Порядок действий
о
Пост-миграционный период
Обезьянья армия
Обёртка
проектирование
177
поиск
Обработка
ошибок в контрактах
◊
событий
103
Предотвращение ошибок важнее, чем их
191,350
◊
436
Предметно-ориентированное
Netflix 336
Облачные вычисления
319
247
319
Преимущества
293
SOA 256, 265
306
Признаки плохих тестов 307
Принцип разделения задач 392
Приоритеты 214,244
Причины миграции кода 404
Приемочный тест
77, 79
Обратная совместимость
93, 175,225,272
Объект
◊
доступа к данным
◊
значения
◊
передачи данных
37
286
Проверка
286
◊
дизайна
◊
концепций
Одна учетная запись
◊
работоспособности перед миграцией
◊
для всего
◊
работоспособности после миграции
◊
для каждой бизнес-области
◊
на сервис
Объектно-ориентированое
программирование (ООП)
33
359
86
154, 406, 434
Программное обеспечение
358
◊
разработка
◊
как услуга
Онлайн-обработка транзакций
◊
с открытым исходным кодом
Операционная система (ОС)
Продукт, соответствующий рынку
Ожидания
355
31, 86, 94, 244
Организация работы
466
470
88
106
команды 362
23
219
162
134, 213
Проект модернизациии
Основная информационная модель
90
Публичный контракт
212
104, 182, 232
Особенности тестов программного
обеспечения
р
305
Остаточные явления
13 7
Радикальные изменения
Отдельная точка отказа
248
46, 51, 64, 137
Разделение задач 267
Размывание команды 81, 86, 134--136, 173
Отказ в обслуживании
Разработка, основанная на тестировании
Ответственность команды за качество
Разбитые окна
важнее, чем ответственность
тестировщика
320
108
111
Отложенная миграция 421,448
Охота на призраков 474
Оценка 209, 211, 214, 227
Очистка и вывод из эксплуатации
307
Распределенный монолит
118
Расширяемость и адаптивность
476
Регрессионные тесты
306
263
Предметный указатель
Резервный вариант
◊
влияние изменений
Результаты оценки
◊
внутренние состояние
11О, 111, 126, 127
243
Репликация базы данных 452
Решения и компромиссы 218
Риски миграции данных 441
Ручное тестирование 309
35
Сервисный контракт
(API) 270
Сервис-ориентированная архитектура
80,
182,253
Сетка сервисов
195
Синтаксис языка описания данных
450
Система разделения ответственности за
выполнение командных запросов
Сквозные тесты
80, 374
305
Скорость изменений бизнеса
Сложность
◊
222, 231
234
миграции кода
412
Соглашение об уровне обслуживания
168
Создание наилучшей системы важнее, чем
ее разрушение
320
Сокращение
◊
затрат и упрощение обслуживания
◊
сроков вывода на рынок
260
257
Сопоставление бизнес-области
239
383
OpenAPI 270
Сравнение таблиц 454
Срок жизни программного обеспечения
134
Стабильный контракт
104, 119,162,352
84, 161
Степень детализации 29, 96, 100, 177, 183,
228
Стратегия 64,130,209,217,244
Стратегия миграции данных 460
вначале схема или несколько миграций
461
онлайн или офлайн
461
Страх перемен 51, 55, 137
Стресс-тестирование 322
Стресс-тесты 306
Суперприложение 60
производительности
◊
сервисов
326
468
321
Тесты
◊
автономные
◊
быстрые циклы обратной связи
◊
внутренние состояния
◊
зависимость
315
315
314
от данных 309
◊
изоляция зависимости от данных
◊
контрактов
◊
непоследовательная частота отказов
◊
неэффективные циклы тестирования
◊
постоянная вероятность успеха
◊
постоянная настройка тестов
307
309
312
31 О
◊
производительности
◊
прямые входные данные
◊
самостоятельные тесты
◊
устойчивость к рефакторингу
◊
хрупкость при рефакторинrе
306
314
315
312
308
◊
сервисов
◊
тестов
Тригер
254
305
455
у
Управление конфигурацией программного
обеспечения
231, 408
Уровень прохождения тестов
48, 174, 180
Усилитель
34, 46, 51, 62, 134
Утилита 176
У язвим ость 162
ф
161, 165
в режиме белого ящика
Хаотическое тестирование
в режиме черного
Характеристики хороших тестов
468
ящика 468
313
306
х
387
Тестирование
◊
на продуктиве
◊
Фреймворк
т
Теорема САР
◊
Типы
Стандартизация
◊
на всем протяжении важнее, чем в конце
212,216
Спецификация
◊
304
314, 341
корректность 304
Технологические и бизнес-потребности
Спектр языков программирования
◊
готовность к эксплуатации
интерфейсов
318
с
Связность
◊
◊
495
304
339
◊
◊
■
306, 333
3 11
496
■
Предметный указатель
э
ц
Целевые показатели уровня обслуживания
Экономичная библиотека
Экспорт и импорт
168,292,418
Цель миграции
409
27, 81, 84, 101, 169
инженерных команд 81
чрезмерная 82
204
450
Эффективные инженеры
381
Централизация
◊
◊
ю
Юзабилити-тесты
ч
Чрезмерная централизация
306
я
82
Язык
ш
Шаблон
◊
переборки
◊
проектирования
107
33
Шаблоны миграции
◊ данных
◊
448
кода421
◊
выполнения бизнес-процессов
◊
манипулирования данными
◊
программирования
382
253
450