Компонент

Слово “компонент” является чрезвычайно перегруженным термином в индустрии разработки программного обеспечения, но в модели C4 компонент - это совокупность связанных функциональных возможностей, заключенных в четко определенный интерфейс. Если вы используете такой язык, как Java или C#, то самый простой способ представить себе компонент как набор классов реализации, стоящих за интерфейсом.

В модели C4 компоненты не являются отдельно развертываемыми единицами. Вместо этого развертываемой единицей является контейнер. Другими словами, все компоненты внутри контейнера выполняются в одном и том же пространстве процессов. Такие аспекты, как способ упаковки компонентов (например, один компонент или много компонентов в JAR-файле, DLL-библиотеке, общей библиотеке и т.д.), являются ортогональными.

Компоненты против кода?

Компонент - это способ повысить уровень абстракции по сравнению со стандартными блоками на уровне кода, которые есть в используемом вами языке программирования. Например:

  • Объектно-ориентированные языки программирования (например, Java, C#, C++ и т.д.): Компонент состоит из классов и интерфейсов.
  • Процедурные языки программирования (например, C): Компонент может состоять из нескольких файлов C в определенном каталоге.
  • JavaScript: Компонентом может быть модуль JavaScript, который состоит из ряда объектов и функций.
  • Функциональные языки программирования: Компонентом может быть модуль (концепция, поддерживаемая такими языками, как F#, Haskell и т.д.), который представляет собой логическую группировку связанных функций, типов и т.д.

Если вы используете объектно-ориентированный язык программирования, ваши компоненты будут реализованы с использованием одного или нескольких классов. Давайте рассмотрим краткий пример, чтобы лучше определить, что такое компонент в контексте некоторого кода.

Приложение Spring PetClinic представляет собой образец кодовой базы, который иллюстрирует, как создать веб-приложение Java с использованием платформы Spring MVC framework. С нетехнической точки зрения, это программная система, разработанная для воображаемой клиники для домашних животных, которая хранит информацию о домашних животных и их владельцах, посещениях клиники и ветеринарах, которые там работают. Система предназначена только для использования сотрудниками клиники. С технической точки зрения система Spring PetClinic состоит из веб-приложения и схемы реляционной базы данных.

Версия1 веб-приложения, которое мы рассмотрим здесь, представляет собой типичную многоуровневую архитектуру, состоящую из нескольких веб-контроллеров MVC, сервиса, содержащего “бизнес-логику”, и некоторых хранилищ для доступа к данным. Есть также некоторые классы домена и утилиты. Если вы загрузите копию репозитория GitHub2, откроете ее в выбранной вами среде IDE и визуализируете ее путем обратного проектирования диаграммы классов UML из кода, вы получите что-то вроде этого.

Как и следовало ожидать, на этой диаграмме показаны все Java-классы и интерфейсы, составляющие веб-приложение Spring PetClinic, а также все взаимосвязи между ними. Свойства и методы на диаграмме скрыты, поскольку они создают слишком много помех для изображения. Это ни в коем случае не сложная кодовая база, но из-за того, что на диаграмме показаны классы и интерфейсы, на ней слишком много деталей.

Давайте удалим те классы, которые бесполезны для обсуждения “архитектуры” системы. Другими словами, давайте покажем только те классы/интерфейсы, которые имеют некоторое значение с точки зрения статической структуры. В конкретных терминах, для данной конкретной кодовой базы это означает исключение классов model/domain (они являются просто структурами данных) и классов util.

После небольшой реорганизации у нас теперь есть более простая схема, с помощью которой можно рассуждать об архитектуре программного обеспечения. Мы также можем снова увидеть архитектурные уровни (контроллеры, службы и хранилища). Но на этой диаграмме по-прежнему показаны элементы уровня кода (т.е. классы и интерфейсы). Чтобы увеличить масштаб на один уровень, нам нужно определить, какие из этих элементов уровня кода можно сгруппировать вместе, чтобы сформировать “компоненты”. Стратегия группировки элементов на уровне кода в компоненты будет варьироваться от базы кода к базе кода, но для этой базы кода стратегия может выглядеть следующим образом.

Каждый из синих прямоугольников представляет собой “компонент” в этой кодовой базе. Таким образом, каждый из веб-контроллеров является отдельным компонентом, а также результатом объединения остальных интерфейсов и классов их реализации. Если мы удалим шум на уровне кода, мы получим примерно такую картину.

По сути, мы группируем классы и интерфейсы в компоненты, чтобы сформировать модули со связанными функциональными возможностями. Скорее всего, у вас будет общий код (например, абстрактные базовые классы, вспомогательные классы, вспомогательные классы-помощницы и т.д.) которые используются во многих компонентах, таких как JdbcPetVisitExtractor в этом примере. Некоторые из них могут быть переработаны и перенесены “внутрь” конкретного компонента, но некоторые из них неизбежны.

Хотя этот пример иллюстрирует традиционную многоуровневую архитектуру, одни и те же принципы применимы независимо от того, как вы упаковываете свой код (например, по уровням, функциям или компонентам) или используемого архитектурного стиля (например, многоуровневый, шестиугольный, порты и адаптеры и т.д.). Если ваша кодовая база достаточно мала, вы можете выполнить этот процесс вручную. Однако для больших кодовых баз вы, вероятно, захотите рассмотреть возможность автоматической генерации диаграмм компонентов с помощью реверс-инжиниринг вашей кодовой базы (example).

  • 1 приведенные здесь диаграммы не отражают последнюю версию Spring PetClinic, но их достаточно для обсуждения
  • 2 git checkout 95de1d9f8bf63560915331664b27a4a75ce1f1f6 - это версия, на которой были основаны эти диаграммы

Часто задаваемые вопросы (ЧаВо)

Является ли Java JAR, сборка C#, библиотека DLL, модуль, пакет, пространство имен, папка и т.д. компонентом?

Возможно, но, опять же, как правило, нет. Модель C4 предназначена для отображения модулей среды выполнения (контейнеров) и распределения функциональности между ними (компонентами), а не организационных единиц, таких как файлы Java JAR, сборки C#, библиотеки DLL, модули, пакеты, пространства имен или структуры папок.

Конечно, между этими конструкциями и компонентом может быть взаимно-однозначное соответствие; например, если вы создаете гексагональную архитектуру, вы можете создать один файл Java JAR или сборку C# для каждого компонента. С другой стороны, один компонент может быть реализован с использованием кода из нескольких JAR-файлов, что обычно и происходит когда вы начинаете рассматривать сторонние фреймворки/ библиотеки и то, как они встраиваются в вашу кодовую базу.