<? phpukraine PHP-ПЛАТФОРМА
⌕Пошук по платформі
КОНЦЕПЦІЯ DDD · КРОК 8 З 10

Модульний монолітModular monolith

Один застосунок і один деплой, але код поділено на модулі за предметними областями. Кожен модуль має межу, і інші модулі заходять лише через його публічний вхід.

5 хв читання Middle → Senior
01 · ЩО ЦЕ

Один деплой, кілька модулів

Звичайний Laravel-проєкт ділить код за технічним типом: усі моделі в app/Models, усі контролери в app/Http. Через рік зміна у вакансіях зачіпає десяток папок, а будь-яка модель тягне будь-яку іншу. ділить код за предметними областями: кожен відповідає одному і всередині має власні шари.

СЛОВНИКМодульний моноліт. Один застосунок і один деплой, код якого поділено на модулі з явними межами.
СЛОВНИКМодуль. Код однієї предметної області: Hiring, Content, Projects. Має власні Domain, Application та Infrastructure.
СЛОВНИКBounded context. Межа, всередині якої слова моделі мають одне значення. «Компанія» в найманні й у каталозі може означати різне.

Модуль показує назовні вузький : сценарії, query-сервіси, доменні інтерфейси. Внутрішні класи, особливо Eloquent-моделі, лишаються його справою. Інші модулі звертаються через цей вхід або дізнаються про зміни з подій. Те, що потрібно всім і не містить бізнес-правил, живе в .

СЛОВНИКПублічний вхід модуля. Класи, якими модуль дозволяє користуватися іншим: сценарії, query-сервіси, інтерфейси. Решта внутрішня.
СЛОВНИКСпільне ядро. Shared kernel: невеликий код, від якого залежать усі модулі. У PHP Ukraine це src/Shared: годинник, текстові утиліти й виклик Claude CLI.

Деплой, база й транзакції спільні, тож модулі не платять за мережу між сервісами. Якщо межі тримаються, модуль згодом можна винести в окремий сервіс. Якщо ні, після розділення вийде : ті самі звʼязки, тільки через HTTP.

СЛОВНИКРозподілений моноліт. Сервіси, які не можуть жити один без одного: спільна база, синхронні ланцюжки викликів, спільний реліз.
02 · МЕЖА

Модулі й звʼязки між ними

APP/Laravel: маршрути, контролери, провайдериCONTENTстатті, документаціяSEARCHпошук по всьому сайтуPROJECTSвітрина проєктівІНШІ МОДУЛІHIRINGвакансії, відгуки, компаніїCONTENTOPSчерга задач воркераSHAREDClock · Text · LlmRoadmapTipSearchEngineProjectTrustAnalyticsContactSeoDevelopmentJobApplicationContentTask
APP/Laravel: маршрути, контролери, провайдериCONTENTстатті, документаціяSEARCHпошук по всьому сайтуPROJECTSвітрина проєктівІНШІ МОДУЛІHIRINGвакансії, відгуки, компаніїCONTENTOPSчерга задач воркераSHAREDClock · Text · LlmRoadmapTipSearchEngineProjectTrustAnalyticsContactSeoDevelopmentJobApplicationContentTask
Девʼять модулів у src/ і головні залежності між ними, як вони є в коді. Hiring потрібен Content, Projects, ContentOps і Search, а Search читає Eloquent-моделі Content, Hiring і Projects напряму. Shared використовують усі модулі.
Абстракція Ключовий учасник Домен Інфраструктура Клієнт
  • Content (статті, документація) містить: Roadmap, Tip.
  • Search (пошук по всьому сайту) містить: SearchEngine.
  • Projects (вітрина проєктів) містить: Project, Trust.
  • Інші модулі містить: Analytics, Contact, Seo, Development.
  • Hiring (вакансії, відгуки, компанії) містить: Job, Application.
  • ContentOps (черга задач воркера) містить: ContentTask.
  • Search використовує Content.
  • Search використовує Projects.
  • Search використовує Hiring.
  • Content використовує Hiring.
  • Projects використовує Hiring.
  • ContentOps використовує Hiring.
  1. 1Модуль відповідає предметній області, а не технічному шару.
  2. 2Інші модулі беруть лише публічний вхід. Чужі Eloquent-моделі й таблиці під забороною.
  3. 3Спільне ядро маленьке й без бізнес-правил: час, текст, утиліти.
  4. 4Межі перевіряє тест, а не домовленість.
03 · ЯК У PHP UKRAINE

Де межа тримається, а де ні

Модулі PHP Ukraine це папки в src/: Hiring, Content, Projects, ContentOps, Search та інші, зазвичай з Domain, Application й Infrastructure усередині. Архітектурний тест перевіряє шари всередині модулів і забороняє Shared імпортувати Hiring і ContentOps, але залежності між самими модулями не обмежує. Найпомітніше межу перетинає пошук: EloquentSearchEngine читає Eloquent-моделі трьох інших модулів напряму.

php EloquentSearchEngine.php фрагмент, скорочено
1namespace PhpUkraine\Search\Infrastructure;
2
3use PhpUkraine\Content\Domain\Docs\SectionStatus;
4use PhpUkraine\Content\Infrastructure\Persistence\ArticleModel;← чужа модель
5use PhpUkraine\Content\Infrastructure\Persistence\DocBookModel;
6use PhpUkraine\Content\Infrastructure\Persistence\DocSectionModel;
7use PhpUkraine\Content\Infrastructure\Persistence\QuestionModel;
8use PhpUkraine\Hiring\Domain\Job\City;
9use PhpUkraine\Hiring\Domain\Job\JobStatus;
10use PhpUkraine\Hiring\Infrastructure\Persistence\CompanyModel;← чужа модель
11use PhpUkraine\Hiring\Infrastructure\Persistence\JobModel;
12use PhpUkraine\Projects\Application\Catalog\ProjectCard;← публічний вхід Projects
13use PhpUkraine\Projects\Domain\ProjectRole;
14use PhpUkraine\Projects\Domain\ProjectType;
15use PhpUkraine\Projects\Infrastructure\ProjectModel;← чужа модель
16use PhpUkraine\Search\Application\SearchEngine;← свій порт
17
18final class EloquentSearchEngine implements SearchEngine
04 · ТИПОВІ ПОМИЛКИ

Як модулі зростаються назад

✕ 1

Модулі за шарами

Папки Controllers, Services, Repositories на весь проєкт. Межі між вакансіями й контентом немає ніде, і будь-який сервіс тягне будь-який інший.

Натомість: папка на предметну область, а шари всередині неї.

✕ 2

Чужі таблиці

Модуль робить join по таблицях іншого або бере його Eloquent-модель. Перейменування колонки в одному модулі ламає інший.

Натомість: питайте через публічний вхід: query-сервіс чи інтерфейс. Якщо пошуку потрібна швидка вибірка, її надає модуль-власник.

✕ 3

Shared як смітник

Усе, що не знайшло місця, їде в Shared. Через рік там бізнес-правила, від яких залежать усі модулі.

Натомість: у спільному ядрі лише нейтральне: час, текст, гроші. У PHP Ukraine архітектурний тест забороняє Shared імпортувати Hiring і ContentOps.

05 · ДЕРЕВО РІШЕНЬ

Чи підходить вам модульний моноліт

1
Чи можна назвати в проєкті кілька предметних областей з власними словами?
Вакансії, контент, проєкти: у кожної свої правила й свої «компанії».
НІ →Поки область одна, вистачить шарів в одному модулі.
2
Чи вистачає всім модулям одного деплою й однієї бази?
Жодному модулю не потрібні окремі сервери, мова чи графік релізів.
НІ →Винесіть у сервіс лише той модуль, якому це справді потрібно. Чіткі межі модуля вже підготували його до цього.
3
Чи готові ви перевіряти межі тестом?
Pest arch() або Deptrac у CI.
НІ →Без перевірки модулі за рік зростуться в звичайний моноліт. Почніть з одного правила.
ТАК НА ВСІ →Вам підходить модульний моноліт. Почніть з папки на контекст і тесту на межі.
06 · СЛОВНИК
Модульний моноліт
Один застосунок і один деплой, код якого поділено на модулі з явними межами.
Модуль
Код однієї предметної області: Hiring, Content, Projects. Має власні Domain, Application та Infrastructure.
Bounded context
Межа, всередині якої слова моделі мають одне значення. «Компанія» в найманні й у каталозі може означати різне.
Публічний вхід модуля
Класи, якими модуль дозволяє користуватися іншим: сценарії, query-сервіси, інтерфейси. Решта внутрішня.
Спільне ядро
Shared kernel: невеликий код, від якого залежать усі модулі. У PHP Ukraine це src/Shared: годинник, текстові утиліти й виклик Claude CLI.
Розподілений моноліт
Сервіси, які не можуть жити один без одного: спільна база, синхронні ланцюжки викликів, спільний реліз.
07 · ПЕРЕВІР СЕБЕ

Питання зі співбесід

Усі питання з архітектури →

Модулі живуть в одному процесі, одному деплої й зазвичай одній базі, тому виклик між ними коштує як виклик методу, а транзакція може бути спільною. Мікросервіси розділені мережею й деплоєм, і кожна межа там коштує дорожче.

Архітектурним тестом: Pest arch() з expect(...)->not->toUse(...) для просторів імен інших модулів або Deptrac з описом дозволених залежностей. Тест запускається в CI разом з рештою.

Кожен модуль-власник віддає дані для пошуку через свій публічний вхід або подію, а Search будує власний індекс чи проєкцію. Тоді зміна схеми вакансій зачіпає лише код Hiring, який цей індекс наповнює.