Десять років «переходимо на мікросервіси» було відповіддю за замовчуванням на будь-яке архітектурне питання. Багато команд заплатили за це розподіленими транзакціями, десятком деплой-пайплайнів, мережевими затримками між сервісами, які колись були викликами методів, і налагодженням по п'яти потоках логів. Відтоді індустрія скоригувала курс: добре структурований модульний моноліт дає більшість переваг чітких меж без операційних витрат. У гайді пояснюємо, коли яка архітектура доречна і як побудувати модульний моноліт на Spring Boot зі Spring Modulith, який за потреби можна буде розділити на сервіси.

Реальні компроміси

Мікросервіси дають незалежний деплой, незалежне масштабування, свободу технологій для кожного сервісу та ізоляцію збоїв. Платите ви складністю розподіленої системи: мережеві збої, eventual consistency, дублювання даних, версіоновані API, розподілений трейсинг і значно більше інфраструктури. Мартін Фаулер описав ці компроміси ще роки тому, і його порада досі актуальна: майже всі успішні історії мікросервісів починалися з моноліту, що виріс завеликим і був розділений (Fowler: MonolithFirst; Microservice trade-offs).

Реальні приклади вказують у той самий бік. Shopify вирішила модуляризувати свій великий моноліт на Rails, а не розбивати його на сервіси (Shopify Engineering). Команда Prime Video в Amazon перенесла сервіс моніторингу аудіо й відео з розподіленої serverless-архітектури в один процес і повідомила про скорочення інфраструктурних витрат на 90% для цього навантаження (Prime Video Tech, 2023).

Чинник Модульний моноліт Мікросервіси
Розмір команди Одна чи кілька команд Багато автономних команд
Деплой Один артефакт Багато, незалежних
Узгодженість даних Локальні транзакції Eventual consistency, саги
Рефакторинг меж Дешевий (одна кодова база) Дорогий (API, міграція даних)
Операційні витрати Низькі Високі
Незалежне масштабування Грубе Точкове
Ізоляція збоїв На рівні процесу На рівні сервісу

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

Що робить моноліт «модульним»

Модульний моноліт — один застосунок для деплою, поділений на модулі з явними межами:

  • Кожен модуль володіє бізнес-можливістю — замовлення, склад, білінг, сповіщення — і своїми даними.
  • Модулі мають невеликий публічний API; усе інше — внутрішнє.
  • Модулі взаємодіють через цей API або через події і ніколи не лізуть у внутрішні класи чи таблиці одне одного.
  • Залежності між модулями свідомі й без циклів.

Без контролю ці правила руйнуються за кілька місяців. Тут і допомагає Spring Modulith.

Spring Modulith коротко

Spring Modulith — проєкт Spring для побудови модульних монолітів на Spring Boot. Версія 2.0, що вийшла в листопаді 2025 року, базується на Spring Boot 4 і Spring Framework 7 та має перероблений реєстр публікації подій (блог Spring, 2025; довідник Spring Modulith).

Його базова конвенція проста: кожен прямий підпакет головного пакета застосунку — це модуль застосунку, і лише типи в кореневому пакеті модуля є його публічним API; підпакети внутрішні (Spring Modulith: fundamentals).

com.acme.shop
├── ShopApplication.java
├── order            ← модуль "order": публічний API в цьому пакеті
│   ├── OrderService.java
│   ├── OrderPlaced.java          (подія)
│   └── internal                  ← недоступно іншим модулям
│       ├── OrderRepository.java
│       └── PricingCalculator.java
├── inventory
│   ├── InventoryService.java
│   └── internal/...
└── notification
    └── internal/...

Перевіряйте межі в тесті

Один тест валить збірку, коли модуль використовує внутрішні класи іншого модуля або коли залежності утворюють цикл (Spring Modulith: verification):

class ModularityTests {
    private final ApplicationModules modules = ApplicationModules.of(ShopApplication.class);

    @Test
    void verifiesModularStructure() {
        modules.verify();
    }

    @Test
    void writesDocumentation() {
        new Documenter(modules).writeDocumentation();   // діаграми модулів у форматах C4 і PlantUML
    }
}

Генератор документації створює діаграми модулів і залежностей прямо з коду, тож архітектурна документація залишається актуальною (Spring Modulith: documentation).

Взаємодійте через події

Прямі виклики між модулями нормальні для запитів даних. Для реакцій — «коли оформлено замовлення, зарезервуй товар і надішли підтвердження» — використовуйте події застосунку, щоб модуль замовлень не залежав від складу і сповіщень (Spring Modulith: events):

// модуль order
@Service
@RequiredArgsConstructor
public class OrderService {
    private final ApplicationEventPublisher events;
    private final OrderRepository orders;

    @Transactional
    public Order place(PlaceOrder command) {
        Order order = orders.save(Order.from(command));
        events.publishEvent(new OrderPlaced(order.getId(), order.getLines()));
        return order;
    }
}

// модуль inventory
@Component
class InventoryListener {
    @ApplicationModuleListener          // асинхронно, транзакційно, після коміту публікатора
    void on(OrderPlaced event) {
        inventory.reserve(event.orderId(), event.lines());
    }
}

Реєстр публікації подій зберігає події в базі в межах транзакції публікатора і позначає їх виконаними, коли слухачі відпрацювали успішно, тож події не губляться, якщо застосунок впаде, — патерн transactional outbox без додаткової інфраструктури. Події також можна передавати назовні в Kafka, AMQP та інші брокери, коли вони потрібні іншій системі чи майбутньому мікросервісу.

Тестуйте модулі ізольовано

@ApplicationModuleTest піднімає лише один модуль (і за бажанням його залежності), а API Scenario дозволяє перевірити, що модуль публікує події чи реагує на них (Spring Modulith: testing). Тести залишаються швидкими навіть зі зростанням застосунку.

Від модульного моноліту до мікросервісів, якщо це знадобиться

Оскільки модулі вже мають явні API, володіють своїми даними і спілкуються подіями, винесення одного з них в окремий сервіс — це обмежений проєкт:

  1. Оберіть модуль із чіткою причиною бути окремим: інше масштабування, окрема команда, інший ритм релізів.
  2. Передайте його події в брокер; інші модулі продовжують їх споживати.
  3. Замініть прямі виклики його API на HTTP- чи messaging-клієнт за тим самим інтерфейсом.
  4. Перенесіть його таблиці в окрему базу.
  5. Деплойте його незалежно; спостерігайте через розподілений трейсинг — див. Observability з OpenTelemetry.

Більшості модулів цей крок ніколи не знадобиться, і в цьому суть: ви платите за розподіленість лише там, де вона щось дає.

Практичні поради

  • Моделюйте модулі за бізнес-можливостями, а не за технічними шарами. «controllers», «services» і «repositories» — не модулі.
  • Окрема схема на модуль в одній базі або хоча б префікси таблиць роблять володіння даними видимим.
  • Тримайте публічний API малим. Якщо іншому модулю потрібні внутрішні класи, межу, ймовірно, проведено неправильно.
  • Поєднуйте з віртуальними потоками для високої пропускної здатності вводу-виводу в одному процесі; див. Віртуальні потоки в Spring Boot.
  • Працює і з Kotlin; див. Spring Boot + Kotlin у 2026.

FAQ

Модульний моноліт — це просто моноліт із папками? Ні. Різниця — у контрольованих межах: API модулів, перевірені залежності й взаємодія через події, що перевіряються тестами на кожній збірці.

Чи масштабується модульний моноліт? Так, горизонтально, як будь-який stateless-сервіс. Ви масштабуєте весь застосунок, а не окремі модулі, і для більшості навантажень цього достатньо.

Чи потрібен Spring Modulith, чи можна обійтися ArchUnit? ArchUnit теж уміє контролювати правила. Spring Modulith додає зверху виявлення модулів з урахуванням Spring, реєстр подій, тести модулів і документацію.

Коли точно варто обирати мікросервіси? Коли кілька команд мають деплоїти незалежно і часто або коли частини системи мають дуже різні вимоги до масштабування, доступності чи регуляторики.

Джерела

  1. Martin Fowler. MonolithFirst і Microservice trade-offs.
  2. Shopify Engineering. Deconstructing the monolith.
  3. Prime Video Tech (2023). Scaling up the Prime Video audio/video monitoring service and reducing costs by 90%.
  4. Spring (2025). Spring Modulith 2.0 GA released.
  5. Довідник Spring Modulith: fundamentals, verification, events, testing, documentation.