Что такое программный компонент

Существует два взгляда на понятие компонента: широкий и узкий. Согласно широкому, компонентом считается любая логически завершённая единица кода: класс, библиотека, архитектурный слой, сервис и т. п. Мы же будем придерживаться более узкого определения:

Компонент — это логически завершённая единица кода с независимым жизненным циклом и чётко определённым интерфейсом.

Основным критерием логической завершённости является не формальный признак, а видение авторов кода. Логически завершённым считается такой фрагмент кода, который с точки зрения автора полностью решает выделенную им задачу. Например, StringUtils из Spring применим для работы со строками, но рассматривать его как логически завершённую единицу нельзя, поскольку разработчики Spring задумывали его как вспомогательный элемент Spring Core. В то же время похожий по функциональности StringUtils из Apache Commons Lang можно рассматривать как логически завершённую единицу кода, поскольку авторы изначально задумывали библиотеку для работы со строками, и их StringUtils делает именно это.

Под жизненным циклом компонента понимается последовательность состояний «остановлен ↔ работает». Это означает, что у компонента должна быть точка запуска, которая переводит его в рабочее состояние. Обратный переход обычно осуществляется остановкой процесса. Только в рабочем состоянии становятся доступны возможности компонента. Подчеркнём, что точка запуска переводит в рабочее состояние сам компонент, а не создаёт его экземпляры, поэтому повторный её вызов либо завершается ошибкой, либо отрабатывает идемпотентно.

Под независимым жизненным циклом подразумевается, что каждый компонент может быть запущен независимо от других. Например, для запуска компонента «база данных» не требуется компонент «приложение». И наоборот, компонент «приложение» может быть запущен без компонента «база данных». Вы можете возразить, что приложение не запустится без базы данных, но причина этого не в принципиальной невозможности существования одного компонента без другого, а в ошибке, возникающей в процессе инициализации (зачастую это ошибка Liquibase или Flyway). Вместо ошибки подключения к базе данных это могла бы быть любая другая ошибка. К тому же отключение базы данных во время работы приложения не приводит к остановке самого приложения.

И функция, и библиотека обладают чётко определённым интерфейсом и представляют собой логически завершённую единицу кода, однако не имеют жизненного цикла. Поэтому они не являются компонентами. Сервис же является частным случаем компонента, поскольку обладает всеми его признаками: он логически завершён, имеет независимый жизненный цикл и предоставляет чётко определённый интерфейс. Однако сервис предполагает взаимодействие через протокол передачи данных и выполняется в отдельном процессе, тогда как несколько компонентов могут работать в рамках одного процесса, коммуницируя напрямую через общую память.

Компонент необязательно является самостоятельным процессом: в одном процессе может быть запущено несколько компонентов. Примером может служить модульный монолит, где компоненты представлены его модулями. Роль протокола в нём играет обычный доступ к методам через общую память. Точка запуска последовательно запускает модули и связывает их между собой.