Я провів цікавий рефакторинг Aggregate — мого агрегатора контенту. Сервіс збирає публікації з усієї мережі та об'єднує їх в один RSS-фід. Щоб не спамити підписників, я впровадив функцію розкладу: не більше трьох постів на день. Якщо публікацій забагато, вони стають у чергу на наступні дні.
Все починається зі стану поста: PENDING, SCHEDULED або PUBLISHED. Перехід із PENDING — це ручна дія (суть Aggregate у ретельному відборі контенту), а зміна стану зі SCHEDULED на PUBLISHED раніше виконувалася через cron job.
З людської точки зору така логіка виглядає природною: спочатку ми плануємо пост, а потім у потрібний час він публікується. Проте цей автоматичний перехід, прив'язаний до часу, додавав коду зайвої складності:
- Cron job, що періодично шукає
SCHEDULEDпости для публікації; - Консольна команда як місток між системним cron та кодом;
- Логіка для розмежування: коли пост має бути
SCHEDULED, а коли його можна зробитиPUBLISHEDмиттєво (якщо є вільні слоти); - Тести для перевірки переходів станів та коректної взаємодії з ОС.
У такому процесі забагато зайвого «руху». Багато компонентів мають працювати злагоджено: cron, консольна команда, логіка перевірки черги. Це ускладнює тестування, підтримку та дебаг.
Коли я переписував Aggregate на Tempest, я вирішив спростити цей потік. Рішення виявилося елементарним: я видалив стан SCHEDULED і додав поле publicationDate до стану PUBLISHED. Головна хитрість у тому, що publicationDate може бути в майбутньому.
Тепер під час публікації я просто шукаю у базі даних перший вільний слот:
SELECT publicationDate FROM posts WHERE publicationDate > :publicationDate AND state = "PUBLISHED" GROUP BY publicationDate HAVING COUNT(*) >= 3 ORDER BY publicationDate DESC
Запит знаходить найвіддаленішу дату, де вже є три або більше постів, і ми додаємо до неї один день:
$nextAvailableDate = $futureDate->plusDay()->startOfDay();
Ось так ми позбулися зайвого клопоту:
- Більше ніяких cron jobs;
- Жодних автоматичних змін стану;
- Немає потреби перевіряти, чи можна опублікувати пост негайно.
Звісно, є й нюанси: тепер перевірка «видимості» поста залежить не лише від стану, а й від дати. Також постає питання, що робити, якщо запланований пост видаляється і з'являється «вікно» (хоча це можна вирішити коригуванням запиту).
Проте будь-яке архітектурне рішення — це компроміс. Ми обміняли одну складність на іншу, і в моєму випадку вигода очевидна. Як і завжди в розробці — «все залежить від контексту».
Головний урок: моделювання процесу «як у житті» не завжди веде до найкращого технічного рішення. Іноді варто витратити час, щоб адаптувати людську логіку під технічну реалізацію, адже вони не завжди мають збігатися один в один.
Маєте думки з цього приводу? Вперше в історії цього блогу ви можете залишити їх прямо тут, на цій сторінці (просто прокрутіть до коментарів). Якщо щось піде не так (це все ж таки перший запуск 😅) — пишіть мені на email.