Skip to main content

Куди варто виносити бізнес-логіку з контролерів?

Коротко: контролер має бути тонким - отримувати вхідні дані, викликати потрібний "use-case/сервіс" і формувати відповідь. Уся бізнес-логіка виноситься нижче по шарах. Ось куди саме:

Куди виносити логіку

  1. Сервіси / Use-cases (Application layer)
  • Що тут: оркестрація сценаріїв, транзакції, виклики репозиторіїв, інтеграції, доменні перевірки високого рівня.
  • Контролер → userService.createUser(dto) → результат/виняток.
  • Іменування за діями: CreateUser, ChangeEmail, PlaceOrder.
  1. Домений шар (Domain layer)
  • Entities/Value Objects з інваріантами й бізнес-правилами (без залежностей від Express/БД).
  • Приклад: User.changeEmail() валідує правило "не можна змінювати e-mail частіше N разів".
  1. Репозиторії / DAO (Data access layer)
  • Інкапсулюють доступ до БД/ORM (Prisma, Sequelize, TypeORM), зберігають лише CRUD і прості вибірки.
  • Інтерфейси в домені, реалізації - в інфраструктурі.
  1. Валідація схем (Validation layer)
  • Схеми вводу/виводу: zod/joi/express-validator.
  • Запускати до контролера (middleware) чи в use-case (якщо залежить від доменних правил).
  • Контролер лишається чистим від дерев if/else.
  1. Авторизація/політики (Policy/ACL)
  • Правила доступу: canUpdateProfile(user, target).
  • Тримати окремо від контролера (policy-функції чи Casbin/Oso).
  1. Мапери/DTO і форматування
  • Перетворення між шарами: запит → DTO → доменна сутність → DTO → відповідь.
  • Прибирає витік деталей БД/ORM назовні.
  1. Крос-нарізні речі - в middleware/інфраструктуру
  • Автентифікація, логування, трейсинг, rate-limit, кеш, CSRF, CORS - не в контролері.
  1. Інтеграції та побічні ефекти
  • Клієнти зовнішніх API, e-mail/SMS, черги/задачі (BullMQ/RabbitMQ), кеш (Redis) - в інфраструктурному шарі, викликаються з use-cases.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.