Перейти до вмісту
Telegram[email protected]

Архітектура для команди з трьох людей

Євгеній24 червня 2026 р.11 хв читання

Архітектурні поради зазвичай пишуть люди з великих компаній для людей з великих компаній. Для команди з трьох це не просто надлишок — це прямий шлях зупинити розробку. Ось що працює на цьому масштабі.

Справжня ціна мікросервісів

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

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

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

Робочий варіант — один застосунок, розділений усередині на модулі з явними межами. Один деплой, одна база, один лог. Але код усередині впорядкований так, що з нього можна виділити сервіс, коли з’явиться причина, а не бажання.

Ознаки, що межі справжні, а не намальовані:

  • Модуль має публічний вхід (сервіс) і не дозволяє лізти у свої внутрішні класи.
  • Модулі не імпортують одне з одного напряму, окрім явно оголошеного API.
  • Кожен модуль володіє своїми таблицями. Сусід читає їх через сервіс, а не через JOIN.
  • Схему бази можна прочитати й зрозуміти, до якого модуля належить таблиця.

Останній пункт — найдешевший тест. Якщо в схемі є таблиця, яку правлять три модулі, межа проходить не там.

Один пакет контрактів

Найбільша щоденна біль малої команди — фронтенд і бекенд, які розходяться в уявленнях про дані. Лікується це не документацією, а спільним пакетом типів і схем валідації, від якого залежать обидві сторони.

Практично: одна zod-схема на правило, з неї виводиться TypeScript-тип, бекенд робить із неї DTO, фронтенд — валідацію форми. Правило описане один раз. Якщо ви змінили його, обидва застосунки перестають компілюватись — і це саме те, що потрібно. Помилка має вилізти на збірці, а не в проді.

Дублювання правила валідації в двох місцях — це не дублювання коду. Це дві різні системи, які поки що збігаються.

База: одна, але з правилами

Спільна база між модулями — нормально, поки дотримано три речі:

  1. Констрейнти в базі, а не лише в коді. NOT NULL, CHECK, унікальні індекси. Валідація в застосунку захищає користувача, констрейнт захищає дані від застосунку.
  2. Індекси під реальні запити. Не «на всяк випадок», а під ті, що видно в повільних логах.
  3. М’яке видалення там, де дані цінні. deletedAt замість DELETE перетворює катастрофу на непорозуміння.

Мінімум експлуатації, який окупається

Мала команда не може дозволити собі повноцінний SRE-стек, але чотири речі окупаються майже одразу:

  • Аудит-лог. Хто, що, коли змінив. Перше питання при будь-якому інциденті з даними.
  • Черга фонових задач. Пошта, вебхуки й важкі обчислення поза запитом користувача. Інакше падіння SMTP стає падінням форми.
  • Outbox. Повідомлення пишеться в базу в тій самій транзакції, що й подія, а воркер його розсилає. Заявка не губиться, навіть якщо пошта лежить.
  • Бекап із перевіркою відновлення. Бекап, який жодного разу не відновлювали, — це файл невідомого призначення.

Коли все-таки ділити

Виділяйте сервіс, коли з’явився хоча б один із цих сигналів:

  • Частина системи має принципово інший профіль навантаження (обробка відео поруч із формою зворотного зв’язку).
  • Частина має інші вимоги до доступності або до регуляторики.
  • З’явилась друга команда, і релізи почали блокувати одна одну.

Зверніть увагу: жоден із сигналів не звучить як «так правильніше». Якщо модулі всередині моноліту чесні, виділення сервісу — це переміщення папки й додавання HTTP-шару. Якщо межі намальовані — жодна кількість сервісів не допоможе.

Коротко

Троє людей — це не «маленька версія великої команди». Це інший режим роботи, де кожна одиниця інфраструктури віднімає час у продукту. Модульний моноліт, спільні контракти, констрейнти в базі й чотири речі з експлуатації дають більшу частину переваг «дорослої» архітектури за частку її вартості.

Головне
  • Мікросервіси розв’язують організаційну проблему, якої в малої команди немає
  • Межі модулів справжні лише тоді, коли кожен володіє своїми таблицями
  • Одна zod-схема на правило: помилка контракту має ламати збірку
  • Аудит-лог, черга, outbox і перевірений бекап окупаються майже одразу
Коротко — питання й відповіді
Коли моноліт стає проблемою?

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

Чи можна перейти на мікросервіси пізніше?

Так, якщо модулі мають чесні межі: власні таблиці, публічний сервіс на вході й жодних прямих імпортів усередину. Тоді виділення — це папка плюс HTTP-шар.

Євгеній
Фронтенд і фулстек, інтерфейси, продуктова розробка
Потрібен такий пайплайн