12,99 €
Если вам давно кажется, что вся разработка и развертывание в вашей компании донельзя замедлились – переходите на микросервисную архитектуру. Она обеспечивает непрерывную разработку, доставку и развертывание приложений любой сложности. Книга, предназначенная для разработчиков и архитекторов из больших корпораций, рассказывает, как проектировать и писать приложения в духе микросервисной архитектуры. Также в ней описано, как делается рефакторинг крупного приложения – и монолит превращается в набор микросервисов. В этой книге Как (и зачем!) использовать микросервисную архитектуру. Стратегии декомпозиции сервисов. Управление транзакциями и шаблоны запросов. Эффективные стратегии тестирования. Шаблоны развертывания, включая контейнеры и бессерверные платформы.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 615
Veröffentlichungsjahr: 2023
Переводчики С. Черников, С. Черников
Крис Ричардсон
Микросервисы. Паттерны разработки и рефакторинга. — СПб.: Питер, 2022.
ISBN 978-5-4461-0996-8
© ООО Издательство "Питер", 2022
Все права защищены. Никакая часть данной книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения владельцев авторских прав.
Столкнувшись с неправдой, неравенством или несправедливостью, не молчите, ведь это ваша страна. Это ваша демократия. Будьте ее творцом, защитником и носителем.
Тэргуд Маршалл (Thurgood Marshall), судья Верховного суда США
Будущее уже здесь — оно просто не очень равномерно распределено.
Уильям Гибсон (William Gibson), писатель-фантаст
Это одна из моих любимых цитат. Ее суть в том, что новые идеи и технологии становятся общепринятыми и распространяются в обществе далеко не сразу. Хорошим примером этого может служить мой опыт знакомства с микросервисами. Все началось в 2006 году, когда, вдохновившись выступлением AWS-евангелиста, я вступил на путь, который в итоге привел меня к созданию первой версии Cloud Foundry (хотя с текущей версией ее роднит лишь название). Она представляла собой PaaS (Platform-as-a-Service — платформа как услуга) для автоматизации развертывания Java-приложений в EC2. Как и все другие мои промышленные приложения на Java, Cloud Foundry имело монолитную архитектуру, состоящую из единого файла формата WAR (Java Web Application Archive).
Объединение в монолит разнообразных сложных функций, таких как выделение ресурсов, конфигурирование, мониторинг и управление, привело к проблемам, связанным как с разработкой системы, так и с ее использованием. Например, вы не могли изменить пользовательский интерфейс без тестирования и повторного развертывания всего приложения. А поскольку компонент для мониторинга и управления зависел от системы обработки сложных событий, хранившей свое состояние в памяти, мы не могли запустить больше одного экземпляра Cloud Foundry! В этом стыдно признаться, но я лишь разработчик программного обеспечения, и никто из нас не без греха.
Очевидно, что приложение быстро переросло свою монолитную архитектуру, но какие у нас были альтернативы? В то время подходящее решение уже было известно разработчикам и применялось в таких компаниях, как eBay и Amazon. Например, в Amazon миграция с монолита началась примерно в 2002 году. Новая архитектура состояла из набора слабо связанных сервисов. За каждый сервис отвечала команда «на две пиццы» (в терминологии Amazon) — достаточно компактная для того, чтобы всех ее членов можно было накормить двумя пиццами.
Компания Amazon приняла на вооружение эту архитектуру, чтобы ускорить темпы разработки, активизировать инновации и повысить конкурентоспособность. Результаты оказались впечатляющими: как сообщается, изменения на промышленном уровне в Amazon происходят каждые 11,6 с!
В начале 2010 года, после того как я переключился на другие проекты, будущее программного проектирования наконец стало актуальным и для меня. Именно тогда я прочитал книгу Майкла Т. Фишера (Michael T. Fisher) и Мартина Л. Эббота (Martin L. Abbott) The Art of Scalability: Scalable Web Architecture, Processes and Organizations for the Modern Enterprise (AddisonWesley Professional, 2009). Ее ключевой идеей было трехмерное представление модели масштабирования приложения в виде куба. В соответствии с ним масштабирование по оси Y обозначает разбиение приложения на сервисы. Сейчас такой подход кажется довольно очевидным, но в то время у меня как будто открылись глаза. Наконец-то я мог решить проблемы двухгодичной давности, спроектировав Cloud Foundry в виде набора сервисов!
В апреле 2012 года я впервые описал этот метод проектирования в своем докладе под названием «Декомпозиция приложений для улучшения развертываемости и масштабируемости» (www.slideshare.net/chris.e.richardson/decomposing-applications-for-scalability-and-deployability-april-2012). На тот момент у подобной архитектуры не было общепринятого названия. Иногда я называл ее модульной, многоязычной, поскольку сервисы могут быть написаны на разных языках.
Еще одним примером неравномерного распределения будущего может служить тот факт, что термин «микросервис» (ru.wikipedia.org/wiki/Микросервисная_архитектура) использовался на семинаре по архитектуре программного обеспечения еще в 2011 году, хотя я впервые услышал его во время выступления Фреда Джорджа (Fred George) на конференции Oredev 2013 и мне он пришелся по душе!
В январе 2014 года я создал сайт microservices.io, чтобы описать архитектуру и шаблоны проектирования, с которыми столкнулся. А в марте 2014-го Джеймс Льюис (James Lewis) и Мартин Фаулер (Martin Fowler) опубликовали статью о микросервисах (martinfowler.com/articles/microservices.html), которая популяризировала этот термин и сплотила сообщество вокруг новой концепции.
Идея небольших слабо связанных между собой команд, которые быстро и надежно разрабатывают и доставляют микросервисы, постепенно набирает популярность в сообществе программистов. Важные промышленные бизнес-приложения сегодня обычно являются монолитными и разрабатываются крупными командами. Выпуск новых версий происходит редко и, как правило, создает проблемы для всех, кто вовлечен в этот процесс. Информационные технологии часто не поспевают за потребностями бизнеса. Как же перейти на микросервисную архитектуру, учитывая сказанное?
Ответом на этот вопрос должна послужить данная книга. Прочитав ее, вы начнете хорошо понимать архитектуру микросервисов, узнаете о преимуществах и недостатках этого подхода, а также научитесь использовать его в подходящих ситуациях. В книге описываются способы решения бесчисленных проблем проектирования, с которыми вы будете сталкиваться, включая работу с распределенными данными. Здесь также рассматриваются методы перевода монолитного приложения на микросервисную архитектуру. Но эта книга не манифест микросервисов. Она организована в виде набора шаблонов проектирования. Каждый шаблон — это универсальное решение проблемы, возникающей в определенном контексте. Красота такого подхода состоит в том, что наряду с преимуществами того или иного решения описываются и его недостатки, которые следует учитывать при работе. По своему опыту могу сказать, что объективность при обдумывании решения дает гораздо лучшие результаты, чем ее отсутствие. Надеюсь, вы получите удовольствие от чтения и научитесь успешно разрабатывать микросервисы.
Труд писателя требует уединения, но, чтобы превратить рукопись в готовую книгу, нужно множество людей.
Прежде всего я хочу поблагодарить Эрвина Тухейя (Erin Twohey) и Майкла Стивенса (Michael Stevens) из издательства Manning за то, что они неизменно одобряют идею написания очередной книги. Также хотел бы сказать спасибо редакторам-консультантам Синтии Кейн (Cynthia Kane) и Марине Майклс (Marina Michaels). Синтия помогла мне начать и поработала над несколькими первыми главами. Дальше эстафету приняла Марина, и с ней мы дошли до конца. Я всегда буду ей признателен за скрупулезную и конструктивную критику написанного. Хотел бы выразить благодарность и остальным сотрудникам Manning, которые работали над изданием этой книги.
Спасибо научному редактору Кристиану Меннерику (Christian Mennerich), корректору Энди Майлзу (Andy Miles) и всем внештатным рецензентам: Энди Киршу (Andy Kirsch), Антонио Пессолано (Antonio Pessolano), Арегу Мелик-Адамяну (Areg Melik-Adamyan), Кейджу Слагелю (Cage Slagel), Карлосу Куротто (Carlos Curotto), Дрору Хелперу (Dror Helper), Эросу Педрини (Eros Pedrini), Хьюго Крузу (Hugo Cruz), Ирине Романенко (Irina Romanenko), Джесси Росалье (Jesse Rosalia), Джо Джастесену (Joe Justesen), Джону Гатри (John Guthrie), Кирти Шетти (Keerthi Shetty), Мишель Мауро (Michele Mauro), Полу Гребенцу (Paul Grebenc), Петуру Раджу (Pethuru Raj), Потито Колучелли (Potito Coluccelli), Шобхе Айер (Shobha Iyer), Симеону Лейзерзону (Simeon Leyzerzon), Срихари Сридгарану (Srihari Sridharan), Тиму Муру (Tim Moore), Тони Суитсу (Tony Sweets), Тренту Уайтли (Trent Whiteley), Весу Шаддиксу (Wes Shaddix), Уильяму И. Уилеру (William E. Wheeler) и Золтану Хамори (Zoltan Hamori).
Я хотел бы также поблагодарить всех, кто купил MEAP и оставил свои отзывы на форуме или связался со мной напрямую.
Спасибо организаторам и участникам всех конференций и встреч, на которых я выступал, за шанс представить и проверить мои идеи. И спасибо моим клиентам по всему миру, для которых я проводил консультации и тренинги, за возможность им помочь и претворить мои задумки в жизнь.
Хочу выразить благодарность моим коллегам по Eventuate, Inc., Эндрю, Валентину, Артему и Станиславу, за их вклад в продукт, над которым работает Eventuate, и проекты с открытым исходным кодом.
Наконец, я хотел бы сказать спасибо жене Лауре и детям Элли, Томасу и Джанет за поддержку и понимание на протяжении последних 18 месяцев. Будучи прикованным к своему ноутбуку, я не мог ходить на футбольные матчи Элли, наблюдать за тем, как Томас учится летать на авиасимуляторе, и посещать новые рестораны вместе с Джанет.
Спасибо вам всем!
Цель этой книги — научить вас успешно разрабатывать приложения с использованием микросервисной архитектуры.
Здесь обсуждаются не только преимущества, но и недостатки микросервисов. Вы узнаете, в каких ситуациях имеет смысл применять их, а когда лучше подумать о монолитном подходе.
Основное внимание в книге уделяется архитектуре и разработке. Она рассчитана на любого, в чьи обязанности входят написание и доставка программного обеспечения, в том числе на разработчиков, архитекторов, технических директоров и начальников отделов по разработке.
Акцент здесь делается на шаблонах микросервисной архитектуры и других концепциях. Я старался сделать материал доступным вне зависимости от того, какой стек технологий вы используете. Вам лишь нужно познакомиться с основами архитектуры и проектирования приложений уровня предприятия. В частности, понадобятся понимание таких концепций, как трехуровневая архитектура, проектирование веб-приложений, реляционные базы данных, межпроцессное взаимодействие на основе обмена сообщениями и REST, а также базовые знания программной безопасности. Код примеров создан на языке Java. Чтобы извлечь из примеров максимальную пользу, вы должны быть знакомы с фреймворком Spring.
Книга состоит из 13 глав.
• Глава 1 описывает симптомы монолитного ада, которые проявляются, когда монолитное приложение перерастает свою архитектуру, и дает советы относительно того, как выйти из этой ситуации путем перехода на микросервисную архитектуру. В ней также предоставлен краткий обзор терминов, которые используются в шаблонах проектирования микросервисов и упоминаются на протяжении почти всей книги.
• Глава 2 объясняет, почему программная архитектура имеет большое значение, и описывает шаблоны, с помощью которых приложение можно разбить на отдельные сервисы. Кроме того, в ней показаны способы преодоления проблем, с которыми разработчики обычно сталкиваются на этом пути.
• В главе 3 описываются разные шаблоны для организации надежного межпроцессного взаимодействия в рамках микросервисной архитектуры. Из нее вы узнаете, почему асинхронное взаимодействие, основанное на обмене сообщениями, часто наилучший выбор.
• В главе 4 показано, как поддерживать согласованность данных между сервисами с помощью шаблона «Повествование» (Saga). Повествование (иногда встречается термин «сага») — это последовательность локальных транзакций, которые координируются с помощью асинхронного обмена сообщениями.
• Глава 5 описывает процесс построения бизнес-логики сервиса с использованием предметно-ориентированного проектирования, шаблонов агрегирования и доменных событий.
• Глава 6 является логическим продолжением главы 5. В ней рассказывается, как разработать бизнес-логику с помощью шаблона порождения событий, который представляет собой метод структурирования бизнес-логики и постоянного хранения доменных объектов.
• Глава 7 посвящена реализации запросов для извлечения данных, разбросанных по разным сервисам. Мы рассмотрим два разных шаблона: объединение API и CQRS (command query responsibility segregation).
• Глава 8 охватывает шаблоны проектирования внешних API для обработки запросов от разного рода клиентов, таких как мобильные приложения, браузерные JavaScript-приложения и сторонние программы.
• Глава 9 — первая из двух глав, посвященных методикам автоматического тестирования микросервисов. В ней вы познакомитесь с такими важными понятиями, как пирамида тестирования, описывающая относительные пропорции каждого из типов тестов в вашем тестовом наборе. Вы также научитесь писать модульные тесты, которые станут фундаментом пирамиды тестирования.
• Глава 10 — логическое продолжение главы 9. Она посвящена написанию тестов других типов, входящих в пирамиду тестирования, включая интеграционные и компонентные тесты, а также проверку потребительских контрактов.
• В главе 11 освещаются различные аспекты разработки сервисов промышленного уровня, включая безопасность, шаблон вынесения конфигурации вовне и шаблоны наблюдаемости сервисов. В число последних входят агрегация журналов, метрики приложения и распределенная трассировка.
• В главе 12 описываются различные методы развертывания сервисов, включая виртуальные машины, контейнеры и бессерверные платформы. В ней также раскрываются преимущества использования сети сервисов — слоя сетевого программного обеспечения, который служит посредником при взаимодействии в рамках микросервисной архитектуры.
• В главе 13 объясняется, как шаг за шагом превратить монолитную архитектуру в микросервисную путем применения шаблона «Подавляющее приложение» (Strangler application). Это подразумевает реализацию новых возможностей в виде сервисов и извлечение модулей из монолитной системы с их последующим преобразованием в сервисы.
По мере чтения вы познакомитесь с разными аспектами микросервисной архитектуры.
Эта книга содержит множество примеров исходного кода в виде пронумерованных листингов и небольших фрагментов-вставок. В обоих случаях для форматирования используется такоймоноширинныйшрифт, позволяющий отделить код от остального текста. Во многих случаях оригинальный исходный код был переформатирован — издатель добавил переносы строк и убрал отступы, чтобы оптимально использовать место на странице. Кроме того, из большей части листингов были удалены комментарии, если код описывается в тексте. Нередко код содержит пояснения, которые выделяют важные концепции.
Все главы, кроме 1, 2 и 13, содержат код из сопутствующей демонстрационной программы, которая находится в репозитории GitHub: github.com/microservices-patterns/ftgo-application.
Еще одним отличным ресурсом для изучения микросервисной архитектуры является мой сайт microservices.io. Он содержит не только полный набор шаблонов проектирования, но и ссылки на другие ресурсы, включая статьи, презентации и примеры кода.
Крис Ричардсон (Chris Richardson) — разработчик, архитектор и автор книги POJOs in Action (Manning, 2006), в которой описывается процесс построения Java-приложений уровня предприятия с помощью фреймворков Spring и Hibernate. Он носит почетные звания Java Champion и JavaOne Rock Star.
Крис разработал оригинальную версию CloudFoundry.com — раннюю реализацию платформы Java PaaS для Amazon EC2.
Ныне он считается признанным идейным лидером в мире микросервисов и регулярно выступает на международных конференциях. Крис создал сайт microservices.io, на котором собраны шаблоны проектирования микросервисов. А еще он проводит по всему миру консультации и тренинги для организаций, которые переходят на микросервисную архитектуру. Сейчас Крис работает над своим третьим стартапом Eventuate.io. Это программная платформа для разработки транзакционных микросервисов.
Рисунок на обложке называется «Одеяние раба-мориска в 1568 году»1 и позаимствован из четырехтомника Томаса Джеффериса (Thomas Jefferys) A Collection of the Dresses of Different Nations, Ancient and Modern («Коллекция платья разных народов, старинного и современного»), изданного в Лондоне в 1757–1772 годах. На титульном листе говорится, что это гравюра, раскрашенная вручную с применением гуммиарабика.
Томаса Джеффериса (1719–1771) называли географом при короле Георге III. Он был английским картографом и ведущим поставщиком карт своего времени. Он чертил и печатал карты для правительства и других государственных органов. На его счету целый ряд коммерческих карт и атласов, в основном Северной Америки. Занимаясь картографией в разных уголках мира, он интересовался местными традиционными нарядами, которые впоследствии были блестяще переданы в данной коллекции. В конце XVIII века заморские путешествия для собственного удовольствия были относительно новым явлением, поэтому подобные коллекции пользовались популярностью, позволяя получить представление о жителях других стран как настоящим туристам, так и «диванным» путешественникам.
Разнообразие иллюстраций в книгах Джеффериса — яркое свидетельство уникальности и оригинальности народов мира в то время. С тех пор тенденции в одежде сильно изменились, а региональные и национальные различия, такие значимые 200 лет назад, постепенно сошли на нет. В наши дни бывает сложно отличить друг от друга жителей разных континентов. Если взглянуть на это с оптимистичной точки зрения, мы пожертвовали культурным и внешним разнообразием в угоду более насыщенной личной жизни или в угоду более разнообразной и интересной интеллектуальной и технической деятельности.
В то время как большинство компьютерных изданий мало чем отличаются друг от друга, компания Manning выбирает для своих книг обложки, основанные на богатом региональном разнообразии, которое Джефферис воплотил в иллюстрациях два столетия назад. Это ода находчивости и инициативности современной компьютерной индустрии.
Ваши замечания, предложения, вопросы отправляйте по адресу [email protected] (издательство «Питер», компьютерная редакция).
Мы будем рады узнать ваше мнение!
На веб-сайте издательства www.piter.com вы найдете подробную информацию о наших книгах.
1Habit of a Morisco Slave in 1568.
В этой главе
• Симптомы монолитного ада и их устранение путем перехода на микросервисную архитектуру.
• Неотъемлемые характеристики микросервисной архитектуры, ее достоинства и недостатки.
• Каким образом микросервисы позволяют разрабатывать крупные сложные приложения в стиле DevOps.
• Язык шаблонов проектирования микросервисов, и почему вы должны его использовать.
Понедельник превосходно начался для Мэри, технического директора компании Food to Go, Inc. (FTGO), но уже к обеденному перерыву она почувствовала разочарование. Мэри провела предыдущую неделю вместе с другими архитекторами и разработчиками программного обеспечения на отличной конференции, знакомясь с последними веяниями в мире программирования, включая непрерывное развертывание и микросервисную архитектуру. Она встретилась с сокурсниками по университету Северной Каролины и поделилась с ними историями о борьбе за технологическое лидерство. Конференция укрепила ее в желании улучшить процесс разработки в FTGO.
К сожалению, это чувство быстро испарилось. Она только что потратила первое утро новой недели на неприятное совещание с бизнес-руководством и старшими разработчиками. На протяжении двух часов они обсуждали очередную задержку в выпуске критически важной версии продукта. Увы, но последние несколько лет подобного рода совещания проходили все чаще и чаще. Несмотря на использование гибких методик, темп разработки продолжил замедляться, делая бизнес-требования почти невыполнимыми. И что хуже всего, простого решения, по всей видимости, не было.
Благодаря конференции Мэри осознала, что ее компания столкнулась с проблемой монолитного ада и что панацеей станет переход на микросервисную архитектуру. Но такой подход и сопутствующие ему новейшие методики разработки казались недостижимой мечтой. Мэри сложно было представить, как она будет исправлять текущую ситуацию и одновременно улучшать процесс разработки в FTGO.
К счастью, как вы вскоре сможете убедиться, это можно сделать. Но сначала рассмотрим проблемы, с которыми сталкивается компания FTGO, и попытаемся понять, что их вызвало.
С момента основания в 2005 году компания FTGO демонстрировала стремительный рост. Сейчас она входит в число лидеров на американском рынке доставки еды. У руководства даже имеются планы расширения за рубеж, но они находятся под угрозой срыва из-за задержек в реализации необходимых возможностей.
По своей сути приложение FTGO довольно простое. Клиенты заказывают еду в местных ресторанах на сайте компании или с помощью мобильного приложения. FTGO координирует сеть курьеров, которые доставляют заказы. Компания также отвечает за оплату услуг курьеров и ресторанов. Последние с помощью веб-сайта FTGO редактируют меню и управляют заказами. Приложение использует различные веб-сервисы: Stripe для платежей, Twilio для обмена сообщениями и Amazon Simple Email Service (SES) для электронной почты.
Как и многие другие устаревающие промышленные приложения, FTGO представляет собой монолит, состоящий из единого файла в формате Java WAR (Web Application Archive). С годами это приложение стало большим и сложным. Несмотря на все усилия команды разработчиков, оно превратилось в живую иллюстрацию антишаблона под названием «большой комок грязи» (Big Ball of Mud; www.laputan.org/mud/, https://ru.wikipedia.org/wiki/Большой_комок_грязи). Цитируя Фута и Йодера, авторов этого антишаблона, это «беспорядочно структурированные, растянутые, неряшливые, словно перемотанные на скорую руку изоляционной лентой и проводами, джунгли спагетти-кода». Темпы выпуска новых версий замедлились. Но что еще хуже, приложение FTGO было написано с использованием устаревших фреймворков. Налицо все симптомы монолитного ада.
В следующем подразделе описывается архитектура приложения FTGO. В нем также объясняется, почему монолитная архитектура хорошо себя проявляла в самом начале. Мы поговорим о том, как приложение FTGO переросло свою архитектуру и каким образом это привело к монолитному аду.
FTGO — это типичное Java-приложение уровня предприятия. Его архитектура, выполнена в виде шестиугольника (рис. 1.1). Мы подробнее обсудим этот архитектурный стиль в главе 2. В гексагональной архитектуре ядром приложения является бизнес-логика, которую окружают различные адаптеры, реализующие пользовательский интерфейс и выполняющие интеграцию с внешними системами.
Рис. 1.1. Приложение FTGO имеет гексагональную архитектуру. Оно состоит из бизнес-логики, окруженной адаптерами, которые реализуют пользовательские интерфейсы и взаимодействуют с внешними системами, например мобильными клиентами и облачными сервисами для платежей, электронной почты и обмена сообщениями
Бизнес-логика состоит из модулей, каждый из которых представляет собой набор доменных объектов. В качестве примеров модулей можно привести управление заказами, управление доставкой, биллинг и платежи. Здесь также есть несколько адаптеров, взаимодействующих с внешними системами. Некоторые адаптеры направлены вовнутрь и обслуживают запросы путем обращения к бизнес-логике — это относится к REST API и пользовательскому веб-интерфейсу. Остальные адаптеры направлены вовне, позволяя бизнес-логике получать доступ к MySQL и работать с такими облачными сервисами, как Twilio и Stripe.
Несмотря на то что приложение FTGO имеет логически модульную структуру, оно упаковано в единый WAR-файл. Это пример широко распространенного монолитного стиля программной архитектуры, в соответствии с которым система структурируется в виде одного исполняемого файла или развертываемого компонента. Если бы приложение FTGO было написано на языке Go (GpLang), это был бы один исполняемый файл. В случае с Ruby или NodeJS это было бы единое дерево каталогов с исходным кодом. В монолитной архитектуре как таковой нет ничего плохого. Разработчики FTGO приняли верное решение, выбрав ее для своего приложения.
На ранних этапах развития приложение FTGO было относительно небольшим, поэтому монолитная архитектура давала ему множество преимуществ.
• Простота разработки — IDE и другие инструменты разработки сосредоточены на построении единого приложения.
• Легкость внесения радикальных изменений — вы можете поменять код и структуру базы данных, а затем собрать и развернуть полученный результат.
• Простота тестирования — разработчики написали сквозные тесты, которые запускали приложение, обращались к REST API и проверяли пользовательский интерфейс с помощью Selenium.
• Простота развертывания — разработчику достаточно было скопировать WAR-файл на сервер с установленной копией Tomcat.
• Легкость масштабирования — компания FTGO запускала несколько экземпляров приложения, размещенных за балансировщиком нагрузки.
Однако со временем разработка, тестирование и масштабирование существенно усложнились. Посмотрим почему.
К своему сожалению, разработчики FTGO обнаружили, что у такого подхода есть огромный недостаток. Успешные приложения, такие как FTGO, имеют склонность вырастать из монолитной архитектуры. Каждый раз команда разработчиков FTGO реализовывала несколько новых возможностей, увеличивая тем самым кодовую базу. Более того, успех компании постепенно приводил к росту числа программистов. А это не только ускорило темпы разрастания кодовой базы, но и повысило накладные расходы на администрирование.
Как видно на рис. 1.2, с годами небольшое простое приложение FTGO превратилось в чудовищный монолит. Точно так же некогда компактная команда разработчиков теперь состоит из нескольких scrum-команд, каждая из которых работает над конкретной функциональной областью. Переросшее свою архитектуру приложение FTGO попало в монолитный ад. Разработка стала медленной и мучительной. Разрабатывать и развертывать код с применением гибких методов больше невозможно. Посмотрим, почему так получилось.
Рис. 1.2. Пример монолитного ада. Большая команда разработчиков FTGO сохраняет свои изменения в едином репозитории исходного кода. Между сохранением и попаданием кода в промышленную среду лежит длинный и тяжелый путь, который подразумевает ручное тестирование. Приложение FTGO стало большим, сложным, ненадежным и трудным в обслуживании
Основная проблема приложения FTGO заключается в его чрезмерной сложности. Оно слишком большое для того, чтобы один разработчик мог его понять. В итоге исправление ошибок и реализация новых возможностей усложнились и стали занимать много времени. Разработчики не успевали в срок.
Усугубляет проблему то, что сложность, и так чрезмерная, обычно повышается экспоненциально. Если кодовая база плохо поддается пониманию, разработчик не сможет внести изменения подходящим образом. Каждое изменение усложняет код и делает его еще менее понятным. Элегантная модульная архитектура, показанная на рис. 1.1, не отражает действительности. Приложение FTGO постепенно превращается в большой комок грязи.
Мэри вспомнила, что на конференции, где недавно присутствовала, она встретила разработчика, который писал инструмент для анализа зависимостей между тысячами JAR-файлов в приложении, состоящем из миллиона строчек кода. Тогда ей показалось, что этот инструмент можно будет применить для FTGO. Теперь она в этом не уверена. Что-то подсказывает Мэри, что лучшим решением будет переход на архитектуру, более приспособленную к крупным приложениям, — микросервисы.
Помимо борьбы с чрезмерной сложностью, разработчикам FTGO приходится иметь дело с замедлением ежедневных технических задач. Большое приложение перегружает и замедляет их IDE. Сборка кода занимает много времени. Более того, из-за своей величины приложение долго запускается. В итоге затягивается цикл написания — сборки — запуска — тестирования кода, что плохо сказывается на продуктивности.
Еще одна проблема с приложением FTGO состоит в том, что доставка изменений в промышленную среду является долгим и тяжелым процессом. Команда разработчиков обычно развертывает обновления раз в месяц, как правило в ночь пятницы или субботы. Мэри постоянно читает о том, что новейшим подходом к обслуживанию приложений типа SaaS (Software-as-a-Service) является непрерывное развертывание: доставка изменений в промышленную среду многократно в течение суток и в рабочее время. Как сообщается, по состоянию на 2011 год компания Amazon.com развертывала изменения каждые 11,6 с, никак не затрагивая при этом конечного пользователя! Для разработчиков FTGO обновление продукта чаще чем раз в месяц кажется несбыточной мечтой. А использование непрерывного развертывания выглядит чем-то нереальным.
Компания FTGO частично применяет гибкую методологию разработки. Команда разработчиков делится на группы и выполняет двухнедельные «спурты». К сожалению, путь готового кода к промышленной среде оказывается длинным и тяжелым. Работа такого большого количества программистов над одной и той же кодовой базой часто приводит к тому, что сборку нельзя выпустить. Разработчики FTGO пытались решить эту проблему, создавая отдельные ветви для новых возможностей, но это вылилось в затяжные и мучительные слияния кода. Как следствие, по окончании «спурта» следует длительный период тестирования и стабилизации кодовой базы.
Еще одна причина того, почему изменения так долго доходят до промышленной среды, связана с длительным тестированием. Код настолько сложен, а эффект от внесенного изменения так неочевиден, что разработчикам и серверу непрерывной интеграции (Continuous Integration, CI) приходится выполнять весь набор тестов. Некоторые участки системы даже требуют ручного тестирования. Кроме того, значительное время затрачивается на диагностику и исправление причин проваленных тестов. В итоге на завершение цикла тестирования требуется несколько дней.
Команда FTGO испытывает проблемы и с масштабированием своего приложения. Дело в том, что требования к ресурсам разных программных модулей конфликтуют между собой. Например, данные о ресторанах хранятся в большой резидентной базе, которую желательно развертывать на серверах с большим объемом оперативной памяти. Для сравнения: модуль обработки изображений сильно нагружает ЦПУ и в идеале должен работать на серверах с большими вычислительными ресурсами. Но, поскольку эти модули входят в одно и то же приложение, компании приходится идти на компромисс при выборе серверной конфигурации.
Еще одна проблема с приложением FTGO заключается в его недостаточной надежности. В результате в работе промышленной среды часто возникают перебои. Одна из причин — то, что из-за большого размера приложения его сложно как следует протестировать. Недостаточное тестирование означает, что ошибки попадают в итоговую версию программы. Что еще хуже, приложению не хватает локализации неисправностей, поскольку все модули выполняются внутри одного процесса. Время от времени ошибка в одном модуле (например, утечка памяти) приводит к поочередному сбою всех экземпляров системы. Разработчикам FTGO не очень нравится, когда их вызывают посреди ночи из-за поломки в промышленной среде. Недовольно и руководство, ведь при этом страдают доходы и доверие к компании.
И последнее, с чем столкнулась команда FTGO, — то, что архитектура, обусловившая монолитный ад, заставляет использовать постепенно устаревающий стек технологий. При этом разработчикам сложно переходить на новые фреймворки и языки программирования. Переписать все монолитное приложение, применив новые и, предположительно, лучшие технологии, было бы чрезвычайно дорого и рискованно. Как следствие, программистам приходится работать с теми инструментами, которые они выбрали при запуске проекта. Из-за этого они часто обязаны поддерживать код, написанный с помощью устаревших средств.
Фреймворк Spring продолжает развиваться, поддерживая обратную совместимость, поэтому теоретически у команды FTGO должна быть возможность перехода на новые версии. К сожалению, в приложении используются версии фреймворков, несовместимые с новейшими выпусками Spring. Разработчики так и не нашли времени для их обновления. В итоге существенная часть кода написана с применением устаревших технологий. Кроме того, программистам хотелось бы поэкспериментировать с языками, не основанными на JVM, такими как GoLang или NodeJS. К сожалению, монолитная архитектура исключает такую возможность.
Вполне вероятно, что вы разработчик, архитектор, технический директор или начальник отдела разработки. И отвечаете за приложение, которое переросло монолитную архитектуру. Как и Мэри из FTGO, вы испытываете сложности с доставкой программного обеспечения и хотите узнать, как уйти из монолитного ада. Или, возможно, боитесь, что ваша организация уже на пути к монолитному аду, и хотите как-то изменить курс, пока еще не слишком поздно. Если вы хотите избежать такой ситуации или выбраться из нее, эта книга для вас.
Большое внимание здесь уделяется концепциям микросервисной архитектуры. Я стремился сделать материал доступным вне зависимости от того, какой стек технологий вы используете. Но нужно, чтобы вы были знакомы с основами архитектуры и проектирования приложений уровня предприятия, в частности знали:
• трехуровневую архитектуру;
• проектирование веб-приложений;
• разработку бизнес-логики в объектно-ориентированном стиле;
• применение реляционных СУБД — SQL- и ACID-транзакции;
• межпроцессное взаимодействие с использованием брокера сообщений и REST API;
• безопасность, включая аутентификацию и авторизацию.
Примеры кода в этой книге выполнены на языке Java с применением фреймворка Sping. Поэтому вы должны быть знакомы с этим фреймворком, чтобы извлечь максимальную пользу из представленного кода.
Дойдя до последней страницы, вы усвоите такие темы.
• Основные характеристики микросервисной архитектуры, ее достоинства и недостатки, а также сценарии, в которых ее следует использовать.
• Методы работы с распределенными данными.
• Эффективные стратегии тестирования микросервисов.
• Варианты развертывания микросервисов.
• Стратегии перевода монолитного приложения на микросервисную архитектуру.
Вы также получите следующие навыки.
• Проектирование приложений с применением микросервисной архитектуры.
• Разработка бизнес-логики для микросервисов.
• Использование повествований для обеспечения согласованности данных между сервисами.
• Реализация запросов, охватывающих несколько сервисов.
• Эффективное тестирование микросервисов.
• Разработка безопасных, настраиваемых и наблюдаемых сервисов, готовых к промышленному применению.
• Разбиение существующих монолитных приложений на сервисы.
Мэри пришла к выводу, что ее компания должна перейти на микросервисную архитектуру.
Что интересно, программная архитектура имеет мало общего с функциональными требованиями. Вы можете реализовать набор сценариев (функциональных требований к приложению) с использованием любой архитектуры. На самом деле таким успешным приложениям, как FTGO, свойственно быть большими и монолитными.
Конечно, архитектура тоже важна, ведь она определяет так называемые требования к качеству обслуживания, известные также как нефункциональные требования или атрибуты качества. Рост приложения FTGO сказался на различных его атрибутах качества, особенно на тех, которые влияют на скорость доставки программного обеспечения: обслуживаемости, расширяемости и тестируемости.
С одной стороны, дисциплинированная команда способна замедлить процесс скатывания в монолитный ад. Программисты могут усердно поддерживать модульность своего приложения. А еще — написать комплексные автоматические тесты. С другой стороны, у них не получится избежать проблем, свойственных большим командам, которые работают над одной монолитной кодовой базой. Они также не смогут ничего поделать с постоянно устаревающим стеком технологий. В их власти лишь отсрочить неизбежное. Чтобы убежать из монолитного ада, придется мигрировать на новую, микросервисную архитектуру.
Сегодня все больше специалистов сходятся на том, что при построении крупного, сложного приложения следует задуматься об использовании микросервисов. Но что именно мы имеем в виду под микросервисами? К сожалению, само название мало о чем говорит, так как основной акцент в нем делается на размере. У микросервисной архитектуры есть бесчисленное количество определений. Одни понимают название слишком буквально и утверждают, что сервис должен быть крошечным, например состоять из 100 строчек кода. Другие считают, что на разработку сервиса должно уходить не более двух недель. Адриан Кокрофт (Adrian Cockcroft), ранее работавший в Netflix, определяет микросервисную архитектуру как сервис-ориентированную, состоящую из слабо связанных элементов с ограниченным контекстом. Это неплохое определение, но ему недостает ясности. Попробуем придумать что-нибудь получше.
Мое определение микросервисной архитектуры навеяно прекрасной книгой Мартина Эбботта (Martin Abbott) и Майкла Фишера (Michael Fisher) The Art of Scalability (Addison-Wesley, 2015). В ней описывается практичная трехмерная модель масштабирования в виде куба (рис. 1.3).
Эта модель определяет три направления для масштабирования приложений: X, Y и Z.
Рис. 1.3. Модель определяет три направления для масштабирования приложения: масштабирование по оси X распределяет нагрузку между несколькими идентичными экземплярами, по оси Z — направляет запросы в зависимости от их атрибутов, ось Y разбивает приложение на сервисы с разными функциями
Масштабирование по оси X часто применяют в монолитных приложениях. Принцип работы этого подхода показан на рис. 1.4. Запускаются несколько экземпляров программы, размещенных за балансировщиком нагрузки. Балансировщик распределяет запросы между N одинаковыми экземплярами. Это отличный способ улучшить мощность и доступность приложения.
Масштабирование по оси Z тоже предусматривает запуск нескольких экземпляров монолитного приложения, но в этом случае, в отличие от масштабирования по оси X, каждый экземпляр отвечает за определенное подмножество данных (рис. 1.5). Маршрутизатор, выставленный впереди, задействует атрибут запроса, чтобы направить его к подходящему экземпляру. Для этого, к примеру, можно использовать поле userId.
Рис. 1.4. Масштабирование по оси X связано с запуском нескольких идентичных экземпляров монолитного приложения, размещенных за балансировщиком нагрузки
Рис. 1.5. Масштабирование по оси Z связано с запуском нескольких идентичных экземпляров монолитного приложения, размещенных за маршрутизатором, который направляет запросы в зависимости от их атрибутов. Каждый экземпляр отвечает за подмножество данных
В данном сценарии каждый экземпляр приложения отвечает за подмножество пользователей. Маршрутизатор проверяет поле userId, указанное в заголовке запроса Authorization, чтобы выбрать одну из N идентичных копий программы. Масштабирование по оси Z отлично помогает справиться с участившимися транзакциями и растущими объемами данных.
Масштабирование по осям X и Z увеличивает мощность и доступность приложения. Но ни один из этих подходов не решает проблем с усложнением кода и процесса разработки. Чтобы справиться с ними, следует применить масштабирование по оси Y, или функциональную декомпозицию (разбиение). То, как это работает, показано на рис. 1.6: монолитное приложение разбивается на отдельные сервисы.
Рис. 1.6. Масштабирование по оси Y разбивает приложение на отдельные сервисы. Каждый из них отвечает за определенную функцию и масштабируется по оси X (а также, возможно, по оси Z)
Сервис — это мини-приложение, реализующее узкоспециализированные функции, такие как управление заказами, управление клиентами и т.д. Сервисы масштабируются по оси X, некоторые из них могут использовать также ось Z. Например, сервис Order имеет несколько копий, нагрузка на которые балансируется.
Обобщенное определение микросервисной архитектуры (или микросервисов) звучит так: это стиль проектирования, который разбивает приложение на отдельные сервисы с разными функциями. Заметьте, что размер здесь вообще не упоминается. Главное, чтобы каждый сервис имел четкий перечень связанных между собой обязанностей. Позже мы поговорим о том, что это означает.
Теперь рассмотрим микросервисную архитектуру как разновидность модульности.
Модульность является неотъемлемой частью разработки крупных сложных приложений. Современные приложения, такие как FTGO, слишком велики для разработки в одиночку и слишком сложны для того, чтобы в них мог разобраться отдельный человек. Приложения следует разбивать на модули, которые разрабатывают и в которых разбираются разные люди. В монолитном проекте модули представляют собой сочетание концепций языка программирования, таких как пакеты в Java, и ресурсов, участвующих в сборке, таких как JAR-файлы. Но, как выяснили разработчики FTGO, этот подход обычно не очень практичен. Монолитные приложения с длинным жизненным циклом, как правило, превращаются в «большие комки грязи».
В микросервисной архитектуре единицей модульности является сервис. Сервисы обладают API, которые служат непроницаемым барьером. В отличие от пакетов в Java API нельзя обойти, чтобы обратиться к внутреннему классу. В долгосрочной перспективе это намного упрощает поддержание модульности приложения. Использование сервисов в качестве строительных блоков имеет и другие преимущества, например, каждый из них можно развертывать и масштабировать отдельно.
Ключевой особенностью микросервисной архитектуры является то, что сервисы слабо связаны между собой и взаимодействуют только через API. Слабой связанности можно достичь за счет выделения каждому сервису отдельной базы данных. Например, в онлайн-магазине сервисы Order и Customer могли бы иметь собственные базы данных с таблицами ORDERS и CUSTOMERS соответственно. Структуру данных сервиса можно менять на этапе разработки, не координируя свои действия с разработчиками других сервисов. На этапе выполнения сервисы изолированы друг от друга — ни одному из них, например, не придется ждать из-за того, что другой сервис заблокировал БД.
Не волнуйтесь, Ларри Эллисон не наживается на слабой связанности
То, что каждый сервис имеет собственную БД, вовсе не означает, что ему выделяется целый сервер баз данных. То есть вам не нужно тратить в десять раз больше на лицензии для Oracle RDBMS. Подробнее об этом — в главе 2.
Разобравшись с тем, что такое микросервисы и каковы их ключевые характеристики, можем посмотреть, как это все относится к приложению FTGO.
В дальнейшем на страницах книги мы будем подробно обсуждать микросервисную архитектуру приложения FTGO. Но сначала взглянем на то, как в этом контексте выглядит масштабирование по оси Y. Применив к FTGO декомпозицию, мы получим архитектуру (рис. 1.7). Разбитый на части код состоит из многочисленных сервисов, как клиентских (фронтенд), так и серверных (бэкенд). Мы можем также провести масштабирование по осям X и Z, чтобы на этапе выполнения каждый сервис имел несколько экземпляров.
Рис. 1.7. Некоторые из сервисов в микросервисной версии приложения FTGO. API-шлюз направляет запросы мобильных клиентов к сервисам. Сервисы взаимодействуют между собой через API
Клиентские сервисы включают в себя API-шлюз и пользовательский веб-интерфейс для ресторанов. API-шлюз, который, как вы увидите в главе 8, играет роль фасада, предоставляет интерфейсы REST API, применяемые в мобильных приложениях для заказчиков и курьеров. Веб-интерфейс используется ресторанами для управления меню и обработки заказов.
Бизнес-логика приложения FTGO состоит из многочисленных бэкенд-сервисов. У каждого из них есть REST API и собственная приватная база данных. В их число входят такие сервисы:
• Order — управляет заказами;
• Delivery — управляет доставкой заказов из ресторана клиентам;
• Restaurant — хранит информацию о ресторанах;
• Kitchen — отвечает за подготовку заказов;
• Accounting — управляет биллингом и платежами.
Многие сервисы являются аналогами модулей, описанных ранее в этой главе. Разница в том, что все сервисы и их API имеют четкие определения. Каждый из них можно разрабатывать, тестировать, развертывать и масштабировать независимо от остальных. Такая архитектура помогает поддерживать модульность. Разработчик не может обратиться к внутренним компонентам сервиса, минуя его API. В главе 13 вы узнаете, как преобразовать существующее монолитное приложение в микросервисы.
Некоторые критики микросервисов утверждают, что в этом подходе нет ничего нового и что это всего лишь разновидность сервис-ориентированной архитектуры (service-oriented architecture, SOA). Действительно, на самом высоком уровне существует некоторое сходство. И SOA, и микросервисная архитектура — это стили проектирования, которые структурируют систему как набор сервисов. Но при более детальном рассмотрении можно обнаружить существенные различия (табл. 1.1).
Таблица 1.1. Сравнение SOA и микросервисов
Параметр
SOA
Микросервисы
Межсервисное взаимодействие
Умные каналы, такие как сервисная шина предприятия, с использованием тяжеловесных протоколов вроде SOAP и других веб-сервисных стандартов
Примитивные каналы, такие как брокер сообщений, или прямое взаимодействие между сервисами с помощью легковесных протоколов наподобие REST или gRPC
Данные
Глобальная модель данных и общие БД
Отдельные модель данных и БД для каждого сервиса
Типовой сервис
Крупное монолитное приложение
Небольшой сервис
SOA и микросервисная архитектура обычно используют разные стеки технологий. В приложениях на основе SOA, как правило, применяются тяжеловесные стандарты веб-сервисов наподобие SOAP. Им часто нужна сервисная шина предприятия (Enterprise Service Bus, ESB) — умный канал, который интегрирует сервисы с помощью бизнес-логики и кода для обработки сообщений. Приложения, спроектированные в виде микросервисов, обычно задействуют легковесные технологии с открытым исходным кодом. Сервисы взаимодействуют через примитивные каналы, такие как брокеры сообщений или простые протоколы, подобные REST или gRPC.
SOA и микросервисная архитектура также по-разному обращаются с данными. SOA-приложения обычно имеют глобальную модель данных и общую БД. Для сравнения: как уже упоминалось, у каждого микросервиса есть собственная база данных. Более того, в главе 2 вы увидите, что каждому сервису, как правило, отводится отдельная доменная модель.
Еще одно важное различие между двумя архитектурами заключается в размере сервисов. SOA обычно используется для интеграции крупных, сложных, монолитных приложений. В микросервисной архитектуре сервисы не всегда являются крошечными, но почти всегда они оказываются намного меньше. Так что большинство SOA-приложений состоит из нескольких больших частей, а микросервисные проекты чаще всего разбиты на десятки или сотни мелких сервисов.
Начнем с достоинств, а затем рассмотрим недостатки.
Микросервисная архитектура имеет следующие преимущества.
• Она делает возможными непрерывные доставку и развертывание крупных, сложных приложений.
• Сервисы получаются небольшими и простыми в обслуживании.
• Сервисы развертываются независимо друг от друга.
• Сервисы масштабируются независимо друг от друга.
• Микросервисная архитектура обеспечивает автономность команд разработчиков.
• Она позволяет экспериментировать и внедрять новые технологии.
• В ней лучше изолированы неполадки.
Рассмотрим каждое из этих преимуществ.
Главное достоинство микросервисной архитектуры — возможность непрерывных доставки и развертывания крупных, сложных приложений. Как вы увидите в разделе 1.7, непрерывные доставка и развертывание входят в DevOps — набор методик для быстрого, частого и надежного выпуска обновлений. Организации с высокопроизводительным DevOps обычно не испытывают больших проблем с развертыванием изменений в промышленной среде.
Три свойства микросервисной архитектуры делают возможными непрерывные доставку и развертывание.
• Она обеспечивает уровень тестируемости, необходимый для непрерывных доставки и развертывания. Автоматическое тестирование — ключевой аспект непрерывных доставки и развертывания. Поскольку все сервисы в микросервисной архитектуре относительно небольшого размера, написание автоматических тестов значительно упрощается, а их выполнение занимает меньше времени. В результате приложение будет содержать меньше ошибок.
• Она обеспечивает уровень развертываемости, необходимый для непрерывных доставки и развертывания. Каждый сервис может быть развернут независимо от других. Если разработчикам, которые занимаются сервисом, нужно выкатить изменение, затрагивающее только этот сервис, они могут не координировать свои действия с другими командами. Так что частое развертывание изменений в промышленной среде намного упрощается.
• Она позволяет сделать команды разработчиков автономными и слабо связанными между собой. Вы можете организовать отдел разработки в виде набора небольших команд (например, по принципу двух пицц). В этом случае каждая команда полностью отвечает за разработку и развертывание одного или нескольких связанных между собой сервисов. Она может разрабатывать, развертывать и масштабировать свои сервисы независимо от остальных разработчиков (рис. 1.8). Это значительно ускоряет темп разработки.
Возможность выполнять непрерывные доставку и развертывание обеспечивает несколько бизнес-преимуществ.
• Сокращается время выхода на рынок, что позволяет компании быстро реагировать на отзывы своих клиентов.
• Компания обеспечивает уровень надежности своих услуг, соответствующий современным ожиданиям.
• Работники довольны, поскольку вместо тушения пожара они уделяют больше времени выпуску новых возможностей.
Как результат, микросервисная архитектура стала неотъемлемой частью любой компании, зависящей от программных технологий.
Еще одним преимуществом микросервисной архитектуры является то, что каждый сервис получается сравнительно небольшим. Разработчикам проще разобраться в таком коде. Компактная кодовая база не замедляет работу IDE, что повышает продуктивность. К тому же все сервисы запускаются намного быстрее, чем большой монолит, что тоже делает разработку более продуктивной и ускоряет развертывание.
Рис. 1.8. Приложение FTGO, основанное на микросервисах, состоит из набора слабо связанных сервисов. Каждая команда разрабатывает, тестирует и развертывает сервисы независимо от других
Каждый сервис в микросервисной архитектуре можно масштабировать отдельно, используя клонирование (ось X) и секционирование (ось Z). Кроме того, любой сервис можно развернуть на оборудовании, которое лучше всего отвечает его требованиям к ресурсам. Для сравнения: в монолитной архитектуре компоненты с разным потреблением ресурсов (например, одним нужен мощный процессор, а другим — много памяти) должны развертываться вместе.
В микросервисной архитектуре лучше изолированы неполадки. Например, утечка памяти у сервиса затронет только его, другие сервисы продолжат обрабатывать запросы в обычном режиме. В монолитной же архитектуре вышедший из строя компонент поломает всю систему.
Последним, но немаловажным аспектом является то, что микросервисная архитектура устраняет любую долгосрочную зависимость от стека технологий. В принципе, при создании нового сервиса разработчики могут выбрать наиболее подходящие язык и фреймворки. Во многих организациях этот выбор ограничен, но смысл в том, что вы не зависите от принятых ранее решений.
Более того, поскольку сервисы невелики, вполне реально переписать их с помощью лучших языков и технологий. Если новая технология не оправдала ожиданий, вы можете просто выбросить сделанное, не ставя под угрозу весь проект. При использовании монолитной архитектуры все иначе: технологии, выбранные в самом начале, существенно ограничивают возможность перехода в дальнейшем на другие языки и фреймворки.
Очевидно, что идеальных технологий не существует и у микросервисной архитектуры тоже есть ряд существенных недостатков и проблем. На самом деле большая часть книги посвящена борьбе с этими изъянами. Но пусть они вас не смущают — позже я объясню, как с ними справиться.
Далее приведены основные недостатки и проблемы микросервисной архитектуры.
• Сложно подобрать подходящий набор сервисов.
• Сложность распределенных систем затрудняет разработку, тестирование и развертывание.
• Развертывание функций, охватывающих несколько сервисов, требует тщательной координации.
• Решение о том, когда следует переходить на микросервисную архитектуру, является нетривиальным.
По очереди рассмотрим каждую из этих проблем.
Одна из проблем, возникающих при использовании микросервисной архитектуры, связана с отсутствием конкретного, хорошо описанного алгоритма разбиения системы на микросервисы. Как и многое в профессии разработчика, это сродни искусству. Но что еще хуже, если вы неправильно разделили систему, у вас получится распределенный монолит — набор связанных между собой сервисов, которые необходимо развертывать вместе. Распределенному монолиту присущи недостатки как монолитной, так и микросервисной архитектуры.
Еще один недостаток микросервисной архитектуры состоит в том, что при создании распределенных систем возникают дополнительные сложности для разработчиков. Сервисы должны использовать механизм межпроцессного взаимодействия. Это сложнее, чем вызывать обычные методы. К тому же ваш код должен уметь справляться с частичными сбоями и быть готовым к недоступности или высокой латентности удаленного сервиса.
Реализация сценариев, охватывающих несколько сервисов, требует применения незнакомых технологий. Каждый сервис имеет собственную базу данных, что затрудняет реализацию комбинированных транзакций и запросов. Как описывается в главе 4, приложение, основанное на микросервисах, должно использовать так называемые повествования (или саги), чтобы сохранять согласованность данных между сервисами. В главе 7 объясняется, что такие приложения не могут извлекать данные из нескольких сервисов с помощью простых запросов. Вместо этого их запросы должны задействовать либо комбинированные API, либо CQRS-представления.
IDE и другие инструменты разработки рассчитаны на создание монолитных приложений и не обеспечивают явной поддержки распределенных приложений. Написание автоматических тестов, затрагивающих несколько сервисов, — непростая задача. Все эти проблемы характерны для микросервисной архитектуры. Следовательно, для успешного применения микросервисов программисты вашей компании должны иметь отточенные навыки разработки и доставки кода.
Вдобавок микросервисная архитектура существенно усложняет администрирование. В промышленной среде приходится иметь дело с множеством экземпляров разнородных сервисов. Для успешного развертывания микросервисов требуется высокая степень автоматизации. Вы должны использовать технологии следующего плана:
• инструменты для автоматического развертывания, такие как Netflix Spinnaker;
• общедоступную платформу PaaS, такую как Pivotal Cloud Foundry или Red Hat OpenShift;
• платформу оркестрации для Docker, такую как Docker Swarm или Kubernetes.
Подробнее о вариантах развертывания я расскажу в главе 12.
Еще одна проблема микросервисной архитектуры связана с тем, что развертывание функций, охватывающих несколько сервисов, требует тщательной координации действий разных команд разработки. Вам необходимо выработать план «выкатывания» обновлений, который запрашивает развертывание сервисов с учетом их зависимостей. Для сравнения: в монолитной архитектуре вы можете легко выпускать автоматические обновления для нескольких компонентов.
Еще одна трудность связана с решением о том, на каком этапе жизненного цикла приложения следует переходить на микросервисную архитектуру. Часто во время разработки первой версии вы еще не сталкиваетесь с проблемами, которые эта архитектура решает. Более того, применение сложного, распределенного метода проектирования замедлит разработку. Для стартапов, которым обычно важнее всего как можно быстрее развивать свою бизнес-модель и сопутствующее приложение, это может вылиться в непростую дилемму. Использование микросервисной архитектуры делает выпуск начальных версий довольно трудным. Стартапам почти всегда лучше начинать с монолитного приложения.
Однако со временем возникает другая проблема: как справиться с возрастающей сложностью. Это подходящий момент для того, чтобы разбить приложение на микросервисы с разными функциями. Рефакторинг может оказаться непростым из-за запутанных зависимостей. В главе 13 мы поговорим о стратегиях перехода с монолитной архитектуры на микросервисную.
Как видите, несмотря на множество достоинств, микросервисы обладают и существенными недостатками. В связи с этим к переходу на них следует отнестись очень серьезно. Но обычно для сложных проектов, таких как пользовательские веб- или SaaS-приложения, это правильный выбор. Такие общеизвестные сайты, как eBay (www.slideshare.net/RandyShoup/the-ebay-architecture-striking-a-balance-between-site-stability-feature-velocity-performance-and-cost), Amazon.com, Groupon и Gilt, в свое время перешли на микросервисы с монолитной архитектуры.
При использовании микросервисов приходится иметь дело с множеством проблем, связанных с проектированием и архитектурой. К тому же многие из этих проблем имеют несколько решений со своими плюсами и минусами. Единого идеального решения не существует. Чтобы помочь вам сделать выбор, я создал язык шаблонов микросервисной архитектуры и буду ссылаться на него на страницах книги. Посмотрим, что представляет собой этот язык и почему он вам пригодится.
Архитектура и проектирование в конечном итоге сводятся к принятию решений. Вам нужно решить, какая архитектура лучше всего подходит для вашего приложения — монолитная или микросервисная. Делая этот выбор, вы должны взвесить большое количество за и против. Если остановитесь на микросервисах, вам придется столкнуться с множеством вызовов.
Язык шаблонов — хороший способ описания архитектурных и проектировочных методик и помогает принять решение. Сначала поговорим о том, зачем нужны шаблоны проектирования и соответствующий язык, а затем пройдемся по языку шаблонов микросервисной архитектуры.
В 1986 году Фред Брукс (Fred Brooks), автор книги The Mythical Man-Month (Addison-Wesley Professional, 1995)2, высказал мнение, что при разработке программного обеспечения не существует универсальных решений. Это означает, что нет таких методик или технологий, применение которых повысит вашу продуктивность в десять раз. Тем не менее и по прошествии нескольких десятилетий программисты продолжают рьяно спорить о своих любимых инструментах, будучи уверенными в том, что те дают им огромное преимущество в работе.
Во многих дискуссиях такого рода мнения слишком расходятся. Для этого феномена даже есть специальный термин — Suck/Rock Dichotomy (http://nealford.com/memeagora/2009/08/05/suck-rock-dichotomy.html, Нил Форд (Neal Ford)), который иллюстрирует ситуацию, когда в мире программного обеспечения все либо очень хорошо, либо очень плохо. Такая аргументация имеет следующий вид: если вы сделаете X, произойдет катастрофа, поэтому вы должны сделать Y. Примером может служить противостояние между синхронным и реактивным программированием, объектно-ориентированным и функциональным подходами, Java и JavaScript, REST и обменом сообщениями. В реальности, естественно, все немного сложнее. У каждой технологии есть недостатки и ограничения, ее приверженцы их часто игнорируют. В итоге переход на ту или иную технологию обычно происходит в соответствии с циклом зрелости (https://ru.wikipedia.org/wiki/Gartner#Цикл_хайпа), состоящим из пяти стадий, включая пик чрезмерных ожиданий (мы нашли панацею), избавление от иллюзий (это никуда не годится) и плато продуктивности (теперь мы понимаем все плюсы и минусы и знаем, когда это лучше применять).
Микросервисы в этом смысле не исключение. Подходит ли данная архитектура для вашего приложения, зависит от множества факторов. Следовательно, нельзя воспринимать их как решение на все случаи жизни, равно как и не стоит полностью от них отказываться. Как часто бывает, нужно учитывать конкретную ситуацию.
Основной причиной непримиримых споров о технологиях является то, что людьми зачастую движут эмоции. В превосходной книге The Righteous Mind: Why Good People Are Divided by Politics and Religion (Vintage, 2013) Джонатан Хайдт (Jonathan Haidt) описывает работу человеческого разума на примере слона и наездника. Слон представляет собой эмоциональную составляющую нашего мозга, которая принимает большинство решений. Наездник представляет рациональную часть: иногда он может повлиять на слона, но чаще всего лишь рационализирует то, что слон уже и так сделал.
Мы, как сообщество разработчиков программного обеспечения, должны побороть свою эмоциональность и найти лучший способ обсуждения и применения технологий. Отличным методом обсуждения и описания технологий является формат шаблонов проектирования (ввиду своей объективности). Например, описывая с его помощью инструмент разработки, вы должны упомянуть и о недостатках. Рассмотрим этот формат.
Шаблон проектирования — это многоразовое решение проблемы, возникающей в определенном контексте. Это идея, которая возникает как часть реальной архитектуры и затем показывает себя с лучшей стороны при проектировании программного обеспечения. Концепцию шаблонов предложил Кристофер Александер (Christopher Alexander), практикующий архитектор программных систем. Ему также принадлежит идея языка шаблонов — набора шаблонов проектирования, которые решают проблемы в определенной области. В его книге A Pattern Language: Towns, Buildings, Construction (Oxford University Press, 1977) описывается язык для архитектуры, состоящей из 253 шаблонов. Там можно найти решения и для высокоуровневых проблем, таких как поиск места для города («доступ к воде»), и для узких задач наподобие проектирования комнаты («освещение двух сторон каждой комнаты»). Каждый из этих шаблонов решает проблему путем упорядочения физических объектов, варьирующихся от целых городов до отдельных окон.
Идеи Кристофера Александера помогли концепциям шаблонов проектирования и языков шаблонов стать общепринятыми в среде программистов. Объектно-ориентированные шаблоны собраны в книге Эриха Гаммы (Erich Gamma), Ричарда Хелма (Richard Helm), Ральфа Джонсона (Ralph Johnson) и Джона Влиссидеса (John Vlissides) Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley Professional, 1994)3. Эта книга сделала шаблоны проектирования популярными у разработчиков. Начиная с середины 1990-х программисты задокументировали бесчисленное количество шаблонов. Программный шаблон решает архитектурную проблему, определяя ряд взаимодействующих между собой программных элементов.
Представьте, что вы, к примеру, создаете электронный банкинг, который должен учитывать разнообразные правила превышения кредита. Каждое правило описывает ограничение баланса на счете и комиссию, которая снимается при исчерпании кредитных средств. Эту задачу можно решить с помощью широко известного шаблона «Стратегия» из вышеупомянутой книги. Решение состоит из трех частей:
• интерфейса Overdraft, который инкапсулирует алгоритм превышения кредита;
• одного или нескольких классов-реализаций, по одному для каждого конкретного контекста;
• класса Account, который использует наш алгоритм.
Шаблон проектирования «Стратегия» является объектно-ориентированным, поэтому элементы решения выполнены в виде классов. Позже в этом разделе я опишу высокоуровневые шаблоны проектирования, в которых решения состоят из взаимодействующих между собой сервисов.
Одна из причин, почему шаблоны проектирования так ценятся, — они должны описывать контекст, в котором их можно применять. То, что решение ограничено определенным контекстом и может плохо работать в других ситуациях, — это шаг вперед по сравнению с тем, как обсуждение технологий происходило раньше. Например, решение, которое подходит в масштабах компании Netflix, может оказаться не самым лучшим для приложения с несколькими пользователями.
Необходимость учитывать контекст далеко не единственная положительная сторона шаблонов проектирования. Они заставляют вас описывать другие важные аспекты решения, которые часто упускают из виду. Распространенная структура шаблонов включает в себя три особо важных раздела:
• причины;
• итоговый контекст;
• родственные шаблоны.
Рассмотрим каждый из них, начиная с причин.
Раздел «причины» (forces) в шаблоне проектирования описывает различные аспекты проблемы, которую вы решаете в заданном контексте. Они могут противоречить друг другу, поэтому иногда проблему нельзя решить полностью. То, какие из них более значимы, зависит от контекста, поэтому вы должны расставить приоритеты. Например, код должен быть понятным и производительным. Код, написанный в реактивном стиле, производительнее, чем синхронный код, но зачастую в нем сложнее разобраться. Явное указание причин помогает определиться с тем, какие из аспектов проблемы необходимо решить.
Раздел «итоговый контекст» (resulting context) описывает последствия применения шаблона проектирования. Он состоит из трех частей.
• Преимущества — преимущества шаблона, включая аспекты проблемы, которые он решает.
• Недостатки — недостатки шаблона, включая нерешенные аспекты проблемы.
• Замечания — новые проблемы, появляющиеся в результате применения шаблона.
Итоговый контекст формирует более комплексное и объективное представление о решении, что помогает сделать правильный выбор при проектировании.
Раздел «родственные шаблоны» (related patterns) описывает связь между действующим и другими шаблонами проектирования. Связь бывает пяти типов.
• Предшественник — предшествующий шаблон, который обосновывает потребность в данном шаблоне. Например, микросервисная архитектура — это предшественник всех остальных шаблонов в языке шаблонов, кроме монолитной архитектуры.
• Преемник — шаблон, который решает проблемы, порожденные данным шаблоном. Например, при использовании микросервисной архитектуры необходимо применить целый ряд шаблонов-преемников, включая обнаружение сервисов и шаблон «Предохранитель».
• Альтернатива — альтернативное решение по отношению к данному шаблону. Например, монолитная и микросервисная архитектуры — это альтернативные способы проектирования приложения. Нужно выбрать одну из них.
• Обобщение — обобщенное решение проблемы. Например, в главе 12 представлены разные реализации шаблона «Один сервис — один сервер».
• Специализация — специализированная разновидность шаблона. Например, в главе 12 вы узнаете, что развертывание сервиса в виде контейнера — это частный случай шаблона «Один сервис — один сервер».
Кроме того, можно группировать шаблоны по областям, в которых их применяют. Явное описание родственных шаблонов помогает получить представление о том, как эффективно решить ту или иную проблему.
Пример визуального представления связей между шаблонами приведен на рис. 1.9.
Рис. 1.9. Визуальное представление разного вида связей между шаблонами
На рис. 1.9 представлены следующие типы связей между шаблонами:
• шаблон-преемник решает проблему, возникшую в результате применения шаблона-предшественника;
• у одной и той же проблемы может быть несколько альтернативных решений;
• один шаблон может быть специализированной версией другого;
• шаблоны, решающие проблемы в одной и той же области, можно сгруппировать или обобщить.
Набор шаблонов проектирования, имеющих подобные связи, иногда можно объединить в так называемый язык шаблонов. Шаблоны, входящие в него, совместно работают над решением проблем в определенной области. Например, я создал язык шаблонов микросервисной архитектуры. Это набор взаимосвязанных методик для проектирования микросервисов. Рассмотрим его подробнее.
Язык шаблонов микросервисной архитектуры — это набор методик, которые помогают в проектировании приложений на основе микросервисов. Общая структура этого языка показана на рис. 1.10. Прежде всего он помогает определиться с тем, нужно ли вам использовать микросервисную архитектуру. Он описывает оба подхода, микросервисный и монолитный, вместе с их достоинствами и недостатками. А если микросервисная архитектура подходит для вашего приложения, язык шаблонов поможет эффективно ее задействовать, решая различные проблемы проектирования.
Данный язык состоит из нескольких групп шаблонов. В левой части рис. 1.10 представлена группа шаблонов архитектуры приложения, в которую входят монолитные и микросервисные методы проектирования. Это шаблоны, которые обсуждаются в этой главе. Остальная часть языка содержит группы шаблонов для решения проблем, порожденных микросервисной архитектурой. Шаблоны также делятся на три уровня.
• Инфраструктурные шаблоны — решают проблемы, в основном касающиеся инфраструктуры и не относящиеся к разработке.
• Инфраструктура приложения — предназначены для инфраструктурных задач, влияющих на разработку.
• Шаблоны приложения — решают проблемы, с которыми сталкиваются разработчики.
Шаблоны группируются в зависимости от того, какого рода проблемы они решают. Рассмотрим основные группы шаблонов.
Рис. 1.10. Общая структура языка шаблонов микросервисной архитектуры, описывающая разные проблемные области, на которые рассчитаны шаблоны. Слева находятся методики проектирования приложения — монолитного и микросервисного. Остальные группы шаблонов решают проблемы, возникающие в результате выбора микросервисной архитектуры
Решение о том, каким образом разбить систему на набор сервисов, сродни искусству, но в этом вам может помочь целый ряд стратегий. Два шаблона декомпозиции (рис. 1.11) по-разному подходят к определению архитектуры приложения.
Рис. 1.11. Существует два метода декомпозиции: по бизнес-возможностям (когда сервисы группируются на основе бизнес-возможностей) и по проблемным областям (согласно предметно-ориентированному проектированию)
Эти шаблоны подробно описываются в главе 2.
Приложение, основанное на микросервисной архитектуре, является распределенной системой. Важную роль в этой архитектуре играет межпроцессное взаимодействие (interprocess communication, IPC). Вам придется принять ряд архитектурных решений о том, как ваши сервисы будут взаимодействовать друг с другом и с внешним миром. На рис. 1.12 показаны шаблоны взаимодействия, разделенные на пять групп.
• Стиль взаимодействия. Какой механизм IPC следует использовать?
• Обнаружение. Каким образом клиент сервиса узнает его IP-адрес, чтобы, например, выполнить HTTP-запрос?
• Надежность. Как обеспечить надежное взаимодействие между сервисами с учетом того, что некоторые из них могут быть недоступны?
• Транзакционный обмен сообщениями. Как следует интегрировать отправку сообщений и публикацию событий с транзакциями баз данных, которые обновляют бизнес-информацию?
• Внешний API. Каким образом клиенты вашего приложения взаимодействуют с сервисами?
В главе 3 рассматриваются первые четыре группы шаблонов: стиль взаимодействия, обнаружение, надежность и транзакционный обмен сообщениями. В главе 8 мы остановимся на шаблонах внешнего API.
Рис. 1.12. Пять групп коммуникационных шаблонов
Как упоминалось ранее, для обеспечения слабой связанности каждый сервис должен иметь собственную базу данных. К сожалению, такой подход чреват некоторыми существенными проблемами. Из главы 4 вы узнаете, что традиционная методика с использованием распределенных транзакций (2PC) не подходит для современных приложений. Вместо этого согласованность данных следует обеспечивать с помощью шаблона «Повествование». Шаблоны, связанные с данными, показаны на рис. 1.13.
Все эти шаблоны подробно описываются в главах 4–6.
Рис. 1.13. Поскольку каждый сервис работает с собственной БД, для согласования данных между разными сервисами требуется шаблон «Повествование»
Использование отдельной базы данных в каждом сервисе имеет еще один недостаток: некоторые запросы должны объединять информацию, принадлежащую нескольким сервисам. Данные сервиса доступны только через его API, поэтому вы не можете применять к его БД распределенные запросы. На рис. 1.14 показаны несколько шаблонов, с помощью которых можно реализовать запросы.
Рис. 1.14. Поскольку каждый сервис работает с собственной БД, для извлечения данных, разбросанных по нескольким сервисам, следует использовать один из шаблонов запросов
Иногда можно применять шаблон объединения API, который обращается к API одного или нескольких сервисов и агрегирует результаты. В некоторых ситуациях приходится прибегать к командным запросам с разделением ответственности (command query responsibility segregation, CQRS), которые хранят одну или несколько копий данных и позволяют легко к ним обращаться.
Процесс развертывания монолитного приложения не всегда прост, но он прямолинеен в том смысле, что нужно развернуть лишь одно приложение, многочисленные экземпляры которого будут находиться за балансировщиком нагрузки.
Приложение, основанное на микросервисах, намного сложнее. У вас могут быть десятки и сотни сервисов, написанных на различных языках с использованием разных фреймворков. И придется управлять намного большим количеством элементов. Шаблоны развертывания показаны на рис. 1.15.
Рис. 1.15. Несколько шаблонов развертывания микросервисов. Традиционный подход состоит в развертывании сервисов в формате упаковки определенного языка. У него есть две современные альтернативы. Первая — развертывание сервисов в виде виртуальных машин (ВМ) или контейнеров. Вторая — бессерверные технологии: вы просто загружаете свой код, а бессерверная платформа его выполняет. Следует использовать автоматизированную платформу с поддержкой самообслуживания для развертывания и администрирования сервисов
Традиционный (часто ручной) способ развертывания приложений с применением форматов упаковки, характерных для определенного языка (например, WAR-файлов), нельзя масштабировать для поддержки микросервисной архитектуры. Вам нужна высокоавтоматизированная инфраструктура развертывания. В идеале следует использовать платформу, которая позволяет разработчику развертывать и администрировать свои сервисы с помощью простого пользовательского интерфейса — консольного или графического. Такие платформы обычно основаны на виртуальных машинах (ВМ), контейнерах или бессерверных технологиях. Разные варианты развертывания рассматриваются в главе 12.
Ключевыми моментами администрирования приложения являются понимание того, как оно ведет себя во время работы, и диагностика таких проблем, как неудачные запросы и продолжительное время ожидания. Монолитные приложения не всегда легко анализировать и диагностировать, но относительно простой и прямолинейный механизм обработки запросов облегчает эти задачи. Балансировщик нагрузки направляет каждый входящий запрос к определенному экземпляру приложения, которое выполняет небольшое количество запросов к базе данных и возвращает ответ. Например, если нужно понять, как был обработан тот или иной запрос, вы можете просмотреть журнальный файл того экземпляра приложения, который этим занимался.
Анализ и диагностика проблем в микросервисной архитектуре намного сложнее. Запрос может «прыгать» от одного сервиса к другому, прежде чем клиент получит ответ. Таким образом, вы не можете проследить этот процесс в едином журнальном файле. Точно так же осложняется диагностика времени ожидания, ведь корень проблемы может находиться в разных местах.
Для проектирования наблюдаемых сервисов можно использовать следующие шаблоны.
• API проверки работоспособности. Создайте конечную точку, которая возвращает данные о состоянии сервиса.
• Агрегация журналов. Записывайте поведение сервисов и сохраняйте эти записи на центральном сервере с поддержкой поиска и оповещений.
• Распределенная трассировка. Назначайте каждому внешнему запросу уникальный идентификатор и отслеживайте его перемещение между сервисами.
• Отслеживание исключений. Отправляйте отчеты об исключениях соответствующему сервису, который их дедуплицирует, оповещает разработчиков и отслеживает разрешение каждой исключительной ситуации.
• Показатели приложения. Собирайте количественные и оценочные показатели и делайте их доступными для соответствующего сервиса.
• Ведение журнала аудита. Записывайте в журнал действия пользователей.
Эти шаблоны подробно описываются в главе 11.
По сравнению с монолитными приложениями микросервисная архитектура облегчает тестирование отдельных сервисов, так как их размер намного меньше. Но в то же время важно убедиться в том, что отдельные сервисы хорошо работают вместе, избегая при этом использования сложных, медленных и ненадежных сквозных тестов. Следующие шаблоны упрощают эту задачу, позволяя тестировать сервисы изолированно друг от друга.
• Тестирование контрактов с расчетом на потребителя — проверка того, что сервис отвечает ожиданиям клиентов.
• Тестирование контрактов на стороне потребителя — проверка того, что клиент может взаимодействовать с сервисом.
• Тестирование компонентов сервиса — тестирование сервиса в изоляции.
Эти шаблоны тестирования подробно описываются в главах 9 и 10.
Микросервисная архитектура предусматривает многочисленные аспекты, которые должны быть реализованы в каждом сервисе, включая шаблоны наблюдаемости и обнаружения. Они также должны реализовать шаблон вынесения конфигурации вовне, который предоставляет сервису такую информацию, как параметры подключения к базе данных на этапе выполнения. Написание всех этих функций с нуля для каждого отдельного сервиса заняло бы слишком много времени. Намного лучше применять шаблон шасси микросервисов и строить сервисы на основе фреймворков с поддержкой этих возможностей. Подробнее об этом — в главе 11.
В микросервисной архитектуре аутентификацию пользователей обычно выполняет API-шлюз, который затем должен передать учетную информацию, например идентификатор и роли, вызываемому сервису. Часто для этого применяют токены доступа, такие как JWT (JSON Web token). API-шлюз передает токен сервисам, которые могут его проверить и извлечь из него информацию о пользователе. Шаблон «Токен доступа» подробно обсуждается в главе 11.
Основное внимание в языке шаблонов микросервисной архитектуры уделяется решению задач проектирования, что неудивительно. Очевидно, что для успешной разработки программного обеспечения нужно выбрать подходящую архитектуру, но это еще не все. Вы также должны учитывать такие аспекты, как процесс и организация разработки и доставки.
Микросервисная архитектура обычно становится лучшим решением для крупных и сложных приложений. Но создание успешного продукта требует не только выбора подходящей архитектуры, но и правильной организации и налаживания процессов разработки и доставки. Взаимосвязь между процессом, организацией и архитектурой показана на рис. 1.16.
Рис. 1.16. Регулярный и оперативный выпуск обновлений для крупных и сложных приложений требует сочетания микросервисной архитектуры с DevOps, включая непрерывные доставку, развертывание и небольшие автономные команды
С архитектурой мы уже определились. Рассмотрим организацию и процесс.
Успешная деятельность организации сопряжена с расширением команды разработки. В чем-то это хорошо, ведь чем больше разработчиков, тем больше они могут сделать. Но, как пишет Фред Брукс в книге «Мифический человеко-месяц», затраты на взаимодействие в команде размера N составляют O(N2). Если команда слишком разрастается, она становится неэффективной из-за медленной коммуникации между участниками. Представьте себе ежедневные пятиминутки, на которых присутствуют 20 человек...