Перевод очень плохой. Первые две главы читабельны, но дальше наступает такой ужас, что легче переводить онлайн-переводчиком. Существует второе издание этой книги, а также его перевод на русский язык (ISBN: 978-601-08-3643-3), возможно он будет лучше, чем этот.
Книга очень полезная. Особенно удачной получилась седьмая глава с её ловушками и антипаттернами. Не отстает от неё и пятая глава с описанием шаблона безопасного обновления схемы базы данных, которую одновременно используют несколько сервисов. Это особенно полезно для тех, кто проектирует архитектуру с нулевым временем простоя и применяет механизм rolling upgrade для поэтапного обновления сервисов. А восьмая глава просто выдает базу от том, что достижение эффективной масштабируемости невозможно без уменьшения связанности, и квантование монолита избавляет от необходимости поиска компромисса между антогонирующими архитектурными свойствами.
Несмотря на это, есть в книге моменты, с которыми я не согласен и которые вызывают у меня негативные ощущения.
Автор предлагает спорную классификацию архитектурных стилей.
В четвертой главе автор описывает несколько архитектурных шаблонов: ESB-driven SOA, Service-Based Architectures и Microservices, которые он относит к сервис-ориентированным архитектурам. На самом деле сервис-ориентированная архитектура (SOA), архитектура на основе сервисов (SBA) и микросервисная архитектура (MSA) это совершенно разные архитектурные стили. Идеология SOA, централизация управления с целью максимального переиспользования кодовой базы, полностью противоположна идеологии микросервисов, проповедующей децентрализацию и достижение максимальной независимости даже ценой дублирования кода.
Автор размывает разницу между терминами coupling и cohesion.
When developers use layered architectures for separation of concerns (e.g., using a persistence layer to simplify data access), the layer typically exhibits high internal and low external coupling. Within the layer, each component is cooperating towards a single goal, so they tend toward high coupling. In contrast, developers typically define the interfaces between layers more carefully, creating lower coupling between layers. (Chapter 4, page 56)
Coupling характеризует только внешнюю зависимость между модулями, в данном случае между слоями. За обозначение внутренней связности отвечает cohesion. Поэтому вместо "high internal coupling" следовало бы написать "high cohesion". А в фразе "low external coupling" слово "external" лишнее.
Автор размывает разницу между оркестрацией и хореографией.
Например, в контексте описания ESB-driven SOA он пишет и изображает на рисунке 4-10, что сервисная шина занимается оркестрацией и хореографией.
The service bus acts as a mediator for complex event interactions and handles various other typical integration architecture chores such as message transformation, choreography, and so on. (Chapter 4, page 65)
The goal of this team is to create reusable services integration architects can “stitch together” using choreography to form business implementations. (Chapter 4, page 66)
The defining characteristic of an ESB-driven SOA is the message bus architectural component, responsible for a wide variety of tasks as follows: ... Process choreography and orchestration - The message bus composes enterprise services together and manages tasks like invocation order ... (Chapter 4, page 66)
В тексте хореография и оркестрация объединены так, как будто это схожие или одновременно выполняемые функции ESB. В действительности они представляют собой два разных и часто противоположных паттерна интеграции. Оркестрация - это централизованный процесс. Один центральный компонент (оркестратор, который часто является функцией ESB) управляет бизнес-процессом, вызывая различные сервисы в определённом порядке и обрабатывая логику. Это похоже на дирижёра, который указывает каждому музыканту, когда играть. Хореография - это децентрализованный процесс. Здесь нет центрального контроллера. Каждый сервис знает, что делать в ответ на получаемые сообщения, и публикует события, которые могут прослушивать другие сервисы. Это похоже на группу танцоров, которые знают свои шаги и реагируют на движения друг друга без дирижёра. ESB — это в первую очередь инструмент для оркестровки. Хотя она может облегчать взаимодействие в системе, построенной по принципу хореографии, её главная сила и предназначение — выступать в роли центрального контроллера. Поэтому представлять их вместе как единую ответственность логически некорректно.
Автор вводит читателя в заблуждение при описании архитектуры, основанной на сервисах (Service-Based Architecture).
The third difference between microservices and service-based architectures concerns externalized coordination via a mediator like a service bus. (Chapter 4, page 75)
Это утверждение не корректно, так как в Service-Based Architecture (SBA) сервисы не обязаны использовать сервисную шину. Это отличает Service-Based Architecture от классической Service-Oriented Architecture. SOA направлена на интеграцию разнородных сервисов, поэтому ESB является её ключевым признаком. SBA направлена на дробление монолита, поэтому сервисы в этой архитектуре однородны, а следовательно им не нужна высокоинтеллектуальная интеграционная шина.
Автор навязывает читателю спорное утверждение о версионировании исходного кода и миграций схемы базы данных.
Developers and DBAs should version database schemas alongside the code that utilizes it. Source code and database schemas are symbiotic—neither functions without the other. Engineering practices that artificially separate these two necessarily coupled things cause needless inefficiencies. (Chapter 5, page 84)
Здесь автор говорит, что исходный код приложения и миграции схемы базы данных нужно версионировать вместе. Причем он осуждает инженерные практики, которые разделяют эти процессы. Складывается впечатление, что автор настаивает на хранении миграций и кода в одном репозитории. Я считаю, что это очень неудачное решение. Очевидно, что не каждая новая версия исходного кода требует внесения изменений в схему базы данных. С другой стороны, не всякое изменение схемы должно приводить к изменениям в исходном коде. Например, в базах данных часто ограничивают длину текстовой строки, но со временем приходится расширять это ограничение, чтобы в таблицу поместилось какое-то новое значение. В современных языках программирования память для хранения строк выделяется динамически, поэтому зеркалить изменение схемы в исходном коде не потребуется. Если связать исходный код и миграции в одной единице развертывания, то всегда придется обновлять схему базы данных и приложение вместе, вне зависимости есть ли на то необходимость или нет, что безосновательно повышает эксплуатационные расходы.
Автор намеренно подталкивает читателя пренебрегать функционалом отката при создании миграций схемы базы данных.
However, most teams have moved away from building undo capabilities for three reasons. First, if all the migrations exist, developers can build the database just up to the point they need without backing up to a previous version. In our example, developers would build from 1 to 95 to restore version 95. Second, why maintain two versions of correctness, both forward and backward? To confidently support undo, developers must test the code, sometimes doubling the testing burden. Third, building comprehensive undo sometimes presents daunting challenges. For example, imagine that the migration dropped a table—how would the migration script preserve all data in the case of an undo operation? (Chapter 5, page 85)
Возможность откатить изменения схемы базы данных похожа на страховку. Каждый релиз вы платите небольшими затратами времени на создание механизма отката, надеясь, что он никогда не понадобится. Но если вдруг ваш новый релиз положит прод, вы сможете компенсировать всё это потраченное время быстро вернувшись к предыдущей работоспособной версии приложения, чтобы разобраться с проблемой в штатном режиме без переработок и давления руководства.
Автор забывает раскрыть заявленную тему двухфазной фиксации.
В пятой главе автор высказывает идею о том, что границы микросервисов должны проходить по границам транзакций, так как транзакционная связность является самой сильной формой связности. Из этого автор делает вывод, что для сильно транзакционной предметной области мелкогранулированная микросервисная архитектура может принести только вред. В целом, автор излагает правильные мысли, но где, черт-побери, двухфазная фиксация? Кроме как в заголовке автор больше ни разу не упоминает двухфазную фиксацию. В принципе можно было бы догадаться, что транзакции с двухфазной фиксацией - это и есть тот самое зло, которое несет неадекватно мелкое разбиение на микросервисы сильно транзакционной предметной области, но читатель платит деньги, чтобы прочитать этот вывод в книге, а не строить свои догадки.
Автор уходит от темы эволюционной архитектуры в рефлексию над сложностями интеграции с коммерческим программным обеспечением.
Another worrisome coupling point introduced by many package software vendors is opaque database ecosystems. In the best-case scenarios, the package software manages the state of the database entirely, exposing selected appropriate values via integration points. In the worst case, the vendor database is the integration point to the rest of the system, vastly complicating changes on either side of the API. In this case, architects and DBAs must wrestle control of the database away from the package software for any hope of evolvability. (Chapter 6, page 100)
Здесь автор ноет, что покупателям коммерческого программного обеспечения трудно обеспечить его эволюционное развитие: и изменения у него не инкрементальные, и связность необоснованная, и функцию пригодности сложно написать. А бывает, что у такой системы точкой интеграции служит база данных, и в этом случае автор предлагает отнять у этой системы контроль над базой данных. Мне вот только не понятно, как автор собирается объяснять покупателю коммерческой системы, что система, которую он купил, не работает, потому что автор решил, что у этой системы слишком много контроля над базой данных. И вообще, зачем автору понадобилось применять практику построения эволюционных архитектур для программного обеспечения, которое автор не разрабатывает, а тупо покупает готовым?
Автор ошибается в описании шаблона abstraction distraction.
The abstraction distraction antipattern describes the scenario where a project “wires” itself too much to an external library, either commercial or open source. (Chapter 6, page 111)
Это не правда. Термин “abstraction distraction” используют в разработке ПО для описания ситуации, когда разработчики увлекаются созданием абстракций ради самих абстракций, а не ради решения реальной задачи.
Автор ошибается в описании концепции порождающего тестирования.
However, with generative testing, developers run a large number of tests and capture the outcomes then use statistical analysis on the results to look for anomalies. (Chapter 6, page 157)
Порождающее тестирование не предполагает статистический анализ результатов для выявления аномалий. Что нам даст информация о том, что в 1% случаев код работает неправильно? Нам важно знать конкретный набор входных данных, сгенерированных тестом, на которых возникла ошибка.