Чистая архитектура [2021] Роберт Мартин.pdf
Мартин Роберт Чистая архитектура.
Искусство разработки программного обеспечения
Первое — разделение на основе действующих лиц согласно принципу
единственной ответственности; второе соответствует правилу зависимости.
Цель обоих — разделить компоненты, изменяющиеся по разным причинам
и с разной скоростью. Причины в данном случае соответствуют действую-
щим лицам, а скорости — разным уровням политик.
=================================================================
Глава 5. Объектно-ориентированное программирование
- Инкапсуляция? Наследование? Полиморфизм?
=================================================================
Возможность зависеть от абстракции
Это означает, что ПИ и база данных могут быть плагинами к бизнес-правилам.
То есть в исходном коде с реализацией бизнес-правил могут отсутствовать
любые ссылки на ПИ или базу данных.Как следствие, бизнес-правила,
ПИ и базу данных можно скомпилировать в три разных компонента или единицы
развертывания (например, jar-файлы, библиотеки DLL или файлы Gem),
имеющих те же зависимости,как в исходном коде. Компонент с бизнес-
правилами не будет зависеть от компонентов, реализующих ПИ и базу данных.
Как результат, появляется возможность развертывать бизнес-правила неза-
висимо от ПИ и базы данных. Изменения в ПИ или в базе данных не должны
оказывать никакого влияния на бизнес-правила. То есть компоненты можно
развертывать отдельно и независимо.
Проще говоря, когда реализация компонента изменится, достаточно повтор-
но развернуть только этот компонент. Это независимость развертывания.
Если система состоит из модулей, которые можно развертывать независимо,
их можно разрабатывать независимо, разными командами. Это независи-
мость разработки
=================================================================
Часть III. Принципы дизайна
Глава 7. Принцип единственной ответственности
Признак 1: непреднамеренное дублирование
Признак 2: слияния
Решения
=================================================================
Сразу после знакомства с принципами SOLID
мы перейдем к их аналогам в мире компонентов, а затем к высокоуровневым
принципам создания архитектур.
=================================================================
Глава 16. Независимость
Варианты использования
Эффективность работы
Разработка
Развертывание
Сохранение разнообразия вариантов
Разделение уровней
Разделение вариантов использования
Режим разделения
Возможность независимой разработки
Возможность независимого развертывания
Дублирование
Режимы разделения (еще раз)
=================================================================
Архитектор может использовать принципы единственной ответственности и согласо-
ванного изменения для отделения друг от друга всего, что изменяется по
разным причинам, и объединения всего, что изменяется по одной причине.
Пользовательский интерфейс изменяется по причинам, не име-
ющим ничего общего с бизнес-правилами. Все варианты использования
включают оба этих элемента. Очевидно, что поэтому хороший архитектор
отделит часть, отвечающую за пользовательский интерфейс, от части, реа-
лизующей бизнес-правила, так, что их можно будет изменять независимо
друг от друга, сохраняя при этом ясную видимость вариантов использо-
вания.
Сами бизнес-правила могут делиться на более или менее тесно связанные
с приложением. Например, проверка полей ввода — это бизнес-правило,
тесно связанное с приложением. Вычисление процентов по вкладу и подсчет
запасов, напротив, — это бизнес-правила, более тесно связанные с пред-
метной областью. Эти два разных вида бизнес-правил будут изменяться
с разной скоростью и по разным причинам, поэтому их следует разделить
так, чтобы их можно было изменять независимо.
База данных, язык запросов и даже схема — все это технические детали,
которые не имеют ничего общего с бизнес-правилами и пользовательским
интерфейсом. Они будут изменяться со скоростью и по причинам, не за-
висящим от других аспектов системы. Следовательно, в архитектуре они
должны отделяться от остальной системы, чтобы их можно было изменять
независимо.
То есть систему можно разделить на горизонтальные уровни: пользователь-
ский интерфейс, бизнес-правила, характерные для приложения, бизнес-пра-
вила, не зависящие от приложения, и база данных — кроме всего прочего.
=================================================================
Глава 17. Границы: проведение разделяющих линий
Пара печальных историй
FitNesse
Какие границы проводить и когда?
О вводе и выводе
Архитектура с плагинами
Аргумент в пользу плагинов
=================================================================
Менее важный компонент зависит от более важного компонента.
Компонент Database знает
о существовании компонента BusinessRules . Компонент BusinessRules не
знает о существовании компонента Database . Это говорит о том, что интер-
фейсы DatabaseInterface находятся в компоненте BusinessRules , а классы
DatabaseAccess — в компоненте Database .
Оно показывает, что компонент Database
не имеет значения для BusinessRules , но Database не может существовать
без BusinessRules .
Проведя границу между двумя компонентами и направив стрелку в сторону
BusinessRules , мы видим, что компонент BusinessRules мог бы использовать
базу данных любого типа. Компонент Database можно заменить самыми
разными реализациями — для BusinessRules это совершенно неважно.
А это означает, что выбор базы данных можно отложить и сосре-
доточиться на реализации и тестировании бизнес-правил.
Возьмем, например, видеоигру.
Интерфейс не важен для модели — для бизнес-правил.
Что еще важнее, эта модель не нуждается в интерфейсе. Она
благополучно будет решать свои задачи, моделируя все игровые события
даже без отображения игры на экране.
GUI можно заменить интерфейсом какого-то другого вида — для BusinessRules это не важно.
Прежде чем провести линии границ в архитектуре программного обеспече-
ния, систему нужно разделить на компоненты. Некоторые из этих компо-
нентов реализуют основные бизнес-правила; другие являются плагинами,
содержащими функции, которые не имеют прямой связи с бизнес-правила-
ми. Затем можно организовать код в компонентах так, чтобы стрелки между
ними указывали в одном направлении — в сторону бизнес-правил.
В этом без труда можно заметить принципы инверсии зависимостей
(Dependency Inversion Principle) и устойчивости абстракций (Stable
Abstractions Principle). Стрелки зависимостей направлены от низкоуров-
невых деталей в сторону высокоуровневых абстракций.
=================================================================
Глава 18. Анатомия границ
Пересечение границ
Ужасный монолит
Компоненты развертывания
Потоки выполнения
Локальные процессы
Службы
=================================================================
Когда требуется организовать вызов низкоуровневой службы из высо-
коуровневого клиента, для обращения зависимости потока управления
используется динамический полиморфизм. Зависимость времени выпол-
нения в этом случае имеет направление, противоположное зависимости
времени компиляции.Т.е. доступ от высокоуровневых компонентов к низкоуровневым
только через интерфейс находящийся в верхнем уровне,а не нижнем, интерфейс дает
высший уровень,а низший уровень его реализует и ети методы дергает высший уровень.
Высокоуровневые компоненты остаются независимыми от низкоуровневых
деталей.
Взаимодействия между компонентами в монолите протекают быстро и эф-
фективно. Обычно они сводятся к простым вызовам функций. Как след-
ствие, взаимодействия через границы, проведенные на уровне исходного
кода, могут быть очень обширными.
=================================================================
Глава 19. Политика и уровень
Уровень
Заключение
Глава 20. Бизнес-правила
Сущности
Варианты использования
Модели запросов и ответов
=================================================================
Политики, изменяющиеся по одинаковым причинам и в одно
время, находятся на одном уровне и принадлежат одному компоненту. По-
литики, изменяющиеся по разным причинам или в разное время, находятся
на разных уровнях и должны помещаться в разные компоненты.
В любом случае низкоуровневые компоненты проектируются так, чтобы они зависели от высокоуровневых
компонентов
Чем дальше политика от ввода и вывода, тем выше ее уровень. Поли-
тики, управляющие вводом и выводом, являются самыми низкоуровневыми
в системе.
Чем дальше политика
от ввода и вывода, тем выше ее уровень и тем реже она изменяется и по
более важным причинам. Чем ближе политика к вводу и выводу, тем ниже
ее уровень и тем чаще она изменяется и по более неотложным, но менее
важным причинам.
Высший уровень не зависит от низшего и даже о нем ничего не знает.
Низший уровень использует абстракции высшего уровня для общения с ним.
Высокоуровневые элементы, такие как сущности, ничего не знают о низкоуровневых элементах,
таких как варианты использования.
Напротив, низкоуровневые варианты использования знают все о высокоуровневых сущностях.
Почему сущности относятся к высокому уровню, а варианты использования
к низкому? Потому что варианты использования характерны для един-
ственного приложения и, соответственно, ближе к вводу и выводу системы.
Сущности — это обобщения, которые можно использовать в множестве раз-
ных приложений, соответственно, они дальше от ввода и вывода системы.
Варианты использования зависят от сущностей; сущности не зависят от
вариантов использования.
Отмечу также, что варианты использования не описывают пользователь-
ский интерфейс, они лишь неформально определяют входные и выходные
данные, поступающие и возвращаемые через интерфейс. По вариантам
использования нельзя определить, является ли данная система веб-приложением,
толстым клиентом, утилитой командной строки или чистой службой.
Класс варианта использования принимает простые структуры данных на
входе и возвращает простые структуры данных на выходе. Эти структуры
данных ни от чего не зависят. Они не связаны со стандартными интерфейса-
ми фреймворков, такими как HttpRequest и HttpResponse .
В идеале код, представляющий бизнес-правила, должен быть
сердцем системы, а другие задачи — просто подключаться к ним. Реализация
бизнес-правил должна быть самым независимым кодом в системе, готовым
к многократному использованию.
=================================================================
Глава 21. Кричащая архитектура
Тема архитектуры
Цель архитектуры
А что насчет Веб?
Фреймворки — это инструменты, а не образ жизни
Тестируемые архитектуры
=================================================================
Архитектуры не связаны (и не должны быть связаны) с фреймворками.
Архитектура не должна определяться фреймворками.
Если ваша архитектура опирается на фреймворки, она не сможет опираться на
варианты использования.
Хорошие архитектуры опираются на варианты использования и помогают
архитекторам описывать структуры, поддерживающие эти варианты ис-
пользования, не связывая себя фреймворками, инструментами и окружени-
ями.
Хорошая архитектура позволяет отложить решение о выборе фреймворков,
баз данных, веб-серверов и других инструментов и элементов окружения.
Фреймворки относятся к возможностям, которые должны оставаться от-
крытыми.
Веб — это архитектура? Зависит ли архитектура системы от того факта, что
свои услуги она предоставляет через Веб? Конечно нет! Всемирная паутина
(или Веб) — это механизм доставки, устройство ввода/вывода. И архитек-
тура вашего приложения должна интерпретировать его именно так, а не
иначе. Факт предоставления услуг через Веб — это деталь, и она не должна
определять структуру системы.
У вас должна иметься возможность реализо-
вать систему в форме консольного приложения, веб-приложения, толстого
клиента или даже веб-службы без чрезмерного усложнения или изменения
основной архитектуры.
Тестируемые архитектуры.Если архитектура вашей системы основана исключительно на вариантах
использования и вам удалось удержать фреймворки на расстоянии, у вас
должна иметься возможность протестировать все эти варианты использо-
вания без привлечения фреймворков.Вы не должны испытывать потреб-
ности в веб-сервере для выполнения тестов. Вы не должны испытывать
потребности в подключении к базе данных для выполнения тестов. Ваши
сущности должны быть самыми обычными объектами, не зависящими от
фреймворков, баз данных или чего-то другого. Ваши объекты вариантов
использования должны координировать действия сущностей. Наконец,
должна иметься возможность протестировать их вместе без привлечения
любых фреймворков.Бизнес-правила можно тестировать без поль-
зовательского интерфейса, базы данных, веб-сервера и любых других
внешних элементов.
=================================================================
Глава 22. Чистая архитектура
Правило зависимостей
Типичный сценарий
=================================================================
Чистая архитектура
Несмотря на различия в деталях, все эти архитектуры очень похожи. Они
все преследуют одну цель — разделение задач. Они все достигают этой цели
путем деления программного обеспечения на уровни. Каждая имеет хотя
бы один уровень для бизнес-правил и еще один для пользовательского
и системного интерфейсов.
Независимость от фреймворков.Простота тестирования бизнес-правил.
Независимость от пользовательского интерфейса.Например, веб-интерфейс можно заменить консольным интерфейсом,
не изменяя бизнес-правил.Независимость от базы данных.Ваши бизнес-правила ничего
не знают об интерфейсах, ведущих во внешний мир.
Слоеная архитектура,в центре сущности бизнес-правил это самый высокий уровень,по краям это уровень презентации
он самый низкий уровень.Зависимости направлены от низкого уровня к высокому, высокий уровень ничего не знает о низком
уровене,а низкий уровень наоборот знает о высоком.
Чем ближе к центру, тем выше уровень. Внешние
круги — это механизмы. Внутренние — политики.
Программное обеспечение на уровне адаптеров интерфейсов — это набор
адаптеров, преобразующих данные из формата, наиболее удобного для
вариантов использования и сущностей, в формат, наиболее удобный для
некоторых внешних агентов, таких как база данных или веб-интерфейс.
Именно на этом уровне целиком находится архитектура MVC графического
пользовательского интерфейса. Презентаторы, представления и контрол-
леры — все принадлежат уровню адаптеров интерфейсов. Модели — часто
лишь структуры данных, которые передаются из контроллеров в варианты
использования и затем обратно из вариантов использования в презентаторы
и представления.
Самый внешний уровень модели на рис. 22.1 обычно состоит из фреймвор-
ков и инструментов, таких как база данных и веб-фреймворк.
На уровне фреймворков и драйверов сосредоточены все детали. Веб-
интерфейс — это деталь. База данных — это деталь. Все это мы храним во
внешнем круге, где они не смогут причинить большого вреда.
Пересечение границ
Допустим, что вариант использования должен вызвать презентатора. Такой
вызов нельзя выполнить непосредственно, потому что иначе нарушится
правило зависимостей: никакие имена, объявленные во внешних кругах,
не должны упоминаться во внутренних. Поэтому вариант использования
должен вызвать интерфейс (на рис. 22.1 подписан как «Порт вывода вари-
анта использования»), объявленный во внутреннем круге, а презентатор во
внешнем круге должен реализовать его.
Т.е. если необходимо пересечь границу зависимостей в направлении неизвестности,
внутренний слой вызывает внешний слой, тогда внутренний слой должен обьявить интерфейс
и вызывать абстрактный обьект на своей стороне,а реализация этого интерфейса должна быть во внешнем слое.
Если необходимо пересечь границу зависимостей в направлении известности т.е. с внешнего слоя во внутренни
то тут все естественно просто, внешний слой знает о наличии во внутреннем слое нужных методов,
но вызов все равно происходит через интерфейс предоставленный внутренним слоем.
Тот же прием используется для всех пересечений границ в архитектуре. Мы
используем преимущество динамического полиморфизма, чтобы обратить
зависимости в исходном коде в направлении, противоположном потоку
управления, и тем самым соблюсти правило зависимостей при любом на-
правлении потока управления.
Какие данные пересекают границы
Обычно через границы данные передаются в виде простых структур. При
желании можно использовать простейшие структуры или объекты переда-
чи данных (Data Transfer Objects; DTO)
Например, многие фреймворки для работы с базами данных возвращают
ответы на запросы в удобном формате. Их можно назвать «представлением
записей». Такие представления записей не должны передаваться через гра-
ницы внутрь. Это нарушает правило зависимостей, потому что заставляет
внутренний круг знать что-то о внешнем круге.
Итак, при передаче через границу данные всегда должны принимать форму,
наиболее удобную для внутреннего круга.
=================================================================
Глава 23. Презентаторы и скромные объекты
Шаблон «Скромный объект»
Презентаторы и представления
Тестирование и архитектура
Шлюзы к базам данных
Преобразователи данных
Службы
================================================================
Шаблон «Скромный объект»
Для отделения границы зависимостей.
Шаблон проектирования «Скромный объект» первоначально предлагался
для использования в модульном тестировании как способ отделения поведе-
ния, легко поддающегося тестированию, от поведения, с трудом поддающе-
гося тестированию. Идея очень проста: разделить поведение на два модуля
или класса. Один из модулей, который называется «скромным», содержит
все, что с трудом поддается тестированию, в виде, упрощенном до предела.
Второй — все, что было выброшено из «скромного» модуля.
Например, графические пользовательские интерфейсы сложны для мо-
дульного тестирования, потому что трудно писать тесты, которые могут
видеть изображение на экране и проверять присутствие соответствующих
элементов. Однако в действительности большая часть поведения пользо-
вательского интерфейса легко тестируется. Используя шаблон «Скромный
объект», можно разделить два вида поведения на два разных класса, которые
называют Презентатором (Presenter) и Представлением (View).
Представление (View) — это «скромный» объект, сложный для тестиро-
вания. Код в этом объекте упрощается до предела. Он просто переносит
данные в графический интерфейс, никак не обрабатывая их.
Презентатор (Presenter) — это легко тестируемый объект. Его задача — полу-
чить данные от приложения и преобразовать их так, чтобы Представление
(View) могло просто переместить их на экран. Например, если приложе-
нию потребуется отобразить дату в некотором поле, оно должно передать
Презентатору объект Date . Презентатор затем должен преобразовать дату
в строку и поместить ее в простую структуру данных, которую называют
Моделью представления (View Model), где Представление сможет найти ее.
Если приложению потребуется отобразить на экране денежную сумму, оно
может передать Презентатору объект Currency . Презентатор должен преоб-
разовать этот объект в строковое представление десятичного числа с соот-
ветствующим количеством десятичных знаков и знаком валюты и поместить
полученную строку в Модель представления.
Где должны находиться такие системы ORM? Конечно, на уровне базы
данных. В действительности инструменты ORM представляют еще одну
разновидность границы «Скромный объект» между интерфейсами шлюза
и базой данных.
Практически на каждой архитектурной границе можно найти возможность
применить шаблон «Скромный объект». Взаимодействия через границу поч-
ти всегда осуществляются с применением некой простой структуры данных,
и граница часто делит что-то на сложное и простое для тестирования. При-
менение этого шаблона для организации архитектурных границ значительно
улучшает возможность тестирования системы в целом.
==============================================================
Глава 24. Неполные границы
Пропустить последний шаг
Одномерные границы
Фасады
==============================================================
Полноценные архитектурные границы обходятся дорого. Они требуют
определения двусторонних пограничных интерфейсов, структур для вход-
ных и выходных данных и управления зависимостями для выделения двух
сторон в компоненты, компилируемые и развертываемые независимо. Это
требует значительных усилий для создания и сопровождения.
Один из способов сконструировать неполную границу — проделать все,
что необходимо для создания независимо компилируемых и развертывае-
мых компонентов, и затем просто оставить их в одном компоненте. В этом
компоненте будут присутствовать парные интерфейсы, структуры входных
и выходных данных и все остальное, но все это будет компилироваться
и развертываться как один компонент.
Для оформления полноценной архитектурной границы требуется создать
парные пограничные интерфейсы для управления изоляцией в обоих на-
правлениях. Поддержание разделения в обоих направлениях обходится
дорого не только на начальном этапе, но и на этапе сопровождения.
Шаблоны Стратегия и Фасад помогают создать неполную границу зависимостей.
Мы также должны помнить, что
полная реализация границ обходится дорого.
В то же время мы должны помнить, что игнорирование границ может вы-
звать сложности в будущем — даже при наличии всеобъемлющего набора
тестов и жесткой дисциплины рефакторинга.
Вы должны
взвесить все за и против, определить, где пролегают архитектурные границы
и какие из них должны быть реализованы полностью, какие частично, а ка-
кие можно вообще игнорировать.
==============================================================
Глава 26. Главный компонент
Конечная деталь
Заключение
Глава 27. Службы: большие и малые
Сервисная архитектура?
Преимущества служб?
Проблема с животными
Спасение в объектах
Службы на основе компонентов
Сквозные задачи
===============================================================
Архитектура
системы определяется границами, отделяющими высокоуровневые по-
литики от низкоуровневых деталей, и следованием правилу зависимостей.
Архитектура системы определяется границами, проводимыми внутри этой
системы, и зависимостями, пересекающими эти границы. Архитектура не
определяется физическими механизмами, посредством которых элементы
взаимодействуют и выполняются.
===============================================================
Глава 28. Границы тестов
Тесты как компоненты системы
Проектирование для простоты тестирования
Программный интерфейс для тестирования
Безопасность
===============================================================
Тесты
Первое правило проектирования программного обеспечения —
идет ли речь о тестируемости или о чем-то еще — всегда одно: не зависеть
ни от чего, что может часто меняться.
Пользовательские интерфейсы
переменчивы. Наборы тестов, осуществляющие проверки посредством
пользовательского интерфейса, должны быть хрупкими. Поэтому система
и тесты должны проектироваться так, чтобы работу бизнес-правил можно
было проверить без пользовательского интерфейса.
Для достижения этой цели следует создать специальный программный
интерфейс для тестов, чтобы дать им возможность проверить все бизнес-
правила. Этот API должен защищать тесты от проблем с ограничениями
безопасности, не использовать дорогостоящие ресурсы (таких, как базы дан-
ных) и заставлять систему входить в особые тестируемые состояния. Такой
API должен быть надмножеством интеракторов и адаптеров интерфейсов,
которые используются пользовательским интерфейсом.
Цель API тестирования — отделить тесты от приложения. Под отделением
подразумевается не только отделение тестов от пользовательского интер-
фейса: цель — отделить структуру тестов от структуры приложения.
Роль API тестирования — скрыть структуру приложения от тестов. Это по-
зволит развивать прикладной код, не влияя на тесты. Это также позволит
развивать тесты, не влияя на прикладной код.
Такая возможность независимого развития абсолютно необходима, потому
что с течением времени тесты становятся все более конкретными, а при-
кладной код, напротив, — все более абстрактным и обобщенным. Тесная
структурная зависимость препятствует такому развитию — или, по меньшей
мере, затрудняет его — и мешает прикладному коду становиться все более
обобщенным и гибким.
==============================================================
Глава 29. Чистая встраиваемая архитектура
Тест на профпригодность
Привязка к оборудованию — узкое место
Заключение
Часть VI. Детали
Глава 30. База данных — это деталь
Реляционные базы данных
Почему системы баз данных настолько распространены?
Сохранятся ли диски?
Детали
А производительность?
==============================================================
Многие фреймворки доступа к данным позволяют передавать записи и та-
блицы из базы данных в виде объектов через всю систему. Но такой способ
действий является архитектурной ошибкой. Он связывает варианты ис-
пользования, бизнес-правила, а в некоторых случаях даже пользовательский
интерфейс с определенной реляционной структурой данных.
=============================================================
Глава 31. Веб — это деталь
Бесконечный маятник
Вывод
Заключение
Глава 32. Фреймворки — это деталь
Авторы фреймворков
Неравный брак
Риски
Решение
Объявляю вас
=============================================================
Когда вы используете фреймворк, вы читаете до-
кументацию, предоставленную его автором. В этой документации автор
и другие пользователи фреймворка рассказывают вам, как интегрировать
ваше программное обеспечение с фреймворком. Обычно это означает, что
вы должны обернуть фреймворк своей архитектурой. Автор рекомендует
использовать базовые классы и импортировать инструменты фреймворка
в свои бизнес-объекты. Автор настоятельно рекомендует вам привязать
ваше приложение к фреймворку настолько, насколько это возможно.
Для автора тесная связь с его собственным фреймворком не является про-
блемой. Для автора такая связь желательна, потому что он обладает абсо-
лютным контролем над этим фреймворком.
Более того, автор хочет привязать вас к фреймворку, потому что, привя-
завшись, будет очень трудно отвязаться.
Не заключать союзов с фреймворками!
О, вы можете использовать фреймворк — просто не привязывайтесь к нему.
Держите его на расстоянии вытянутой руки. Рассматривайте фреймворк
как деталь, принадлежащую одному из внешних кругов архитектуры. Не
впускайте его во внутренние круги.
Если фреймворк предложит вам породить свои бизнес-объекты от его
базовых классов, скажите «нет»! Определите прокси-классы и держите их
в компонентах, являющихся плагинами для ваших бизнес-правил.
Бизнес-объекты не должны знать о существовании фреймворка.
=============================================================
Глава 33. Практический пример: продажа видео
Глава 34. Недостающая глава
Упаковка по уровням
Упаковка по особенностям
Порты и адаптеры
Упаковка по компонентам
Дьявол в деталях реализации
Организация и инкапсуляция
Другие режимы разделения
==============================================================
Многоуровневая архитектура.
Упаковка - это компилируемая единица развертивания dll, jar.
"Упаковка по уровням" - горизонтальные уровни.
Организация традиционной много-
уровневой архитектуры, в которой код раз-
деляется по функциональному признаку.В такой типичной многоуровневой архи-
тектуре один уровень выделяется для веб-
кода, один уровень — для «бизнес-логики»
и один уровень — для работы с хранилищем
данных. Иными словами, горизонтальные
уровни используются как способ груп-
пировки по подобию. В «строгой много-
уровневой архитектуре» уровни должны
зависеть только от следующего смежного
уровня.
Проблема, как указывает Мартин, в том, что с ростом
масштаба и сложности программного обеспечения трех больших слоев
кода оказывается недостаточно и приходится задумываться о более дроб-
ной организации.
Другая проблема, как уже сказал «дядюшка Боб» 3 , — многоуровневая архи-
тектура не кричит о своем практическом назначении. Поместите рядом код
двух многоуровневых архитектур из разных предметных областей, и они
почти наверняка будут выглядеть пугающе похожими: веб-интерфейсы,
службы и хранилища. Многоуровневые архитектуры страдают еще от одного
большого недостатка
"Упаковка по особенностям" - вертикальные уровни.
Основанное на объединении связанных особенностей, предметных понятий и общих корней.
Все типы помещаются в один Java-пакет, имя которого отражает идею группировки.
Ее легко получить простым рефакторингом из «упаковки по
уровням», но теперь верхнеуровневая структура кричит о предметной области.
Другим преимуществом является относительная простота поиска кода для изменения,
например, когда потребуется изменить вариант использования «просмотр зака-
зов». Весь код сосредоточен вместе, а не разбросан по разным Java-пакетам.
По моему мнению, оба подхода не оптимальны и "Упаковка по компонентам" лучше.
Цель гибридного подхода "Упаковка по компонентам" , — упаковать все обязанности,
связанные с одним крупным компонентом, в единый Java-пакет. Речь идет
о сервис-ориентированном представлении программной системы, что,
собственно, мы наблюдаем в архитектурах микрослужб. Подобно портам
и адаптерам, интерпретирующим Веб как всего лишь еще один механизм
доставки, методика «упаковка по компонентам» помогает отделить пользо-
вательский интерфейс от этих крупных компонентов.
Мое определение компонента немного отличается: «Группа функциональ-
ных возможностей, находящихся за общим чистым интерфейсом, которые
постоянно находятся внутри среды выполнения, такой как приложение»
Ключевое преимущество подхода «упаковки по компонентам» заключает-
ся в размещении всего кода, например, имеющего отношение к обработке
заказов, в одном месте — в компоненте OrdersComponent . Задачи внутри
компонента все еще разделены, то есть бизнес-логика отделена от функций
доступа к хранилищу, но это разделение является уже деталью реализации
компонентов, о которой потребителям знать не обязательно.
Организацию монолитного приложения в виде набора тщательно про-
работанных компонентов можно рассматривать как шаг в направлении
архитектуры микрослужб.
==============================================================