UI не повинен думати про валідацію
27 лютого 2026 р.4 хв читанняОновлено 27 лютого 2026 р.
Нещодавно я працював над абстрагуванням шару представлення (presentation layer) від UI-шару. В ідеалі, коли справа доходить до будь-якої не-UI логіки, UI повинен бути максимально «тупим». Проте шар представлення часто страждає від фундаментальної архітектурної вади: він намагається вирішувати, що саме має робити UI.
Це відбувається або прямо (передача конкретного
String з помилкою для відображення), або опосередковано (передача Int ідентифікатора рядкового ресурсу). Останнє створює хибне відчуття слабкої зв'язності (decoupling) — шар представлення все ще диктує точний результат на екрані.Такий підхід порушує принцип розділення відповідальності (Separation of Concerns, SoC). Рішення полягає в тому, щоб надати достатньо контекстної інформації, аби UI міг самостійно вирішити, як відобразити помилку, без витоку логіки представлення чи домену.
Моєю конкретною проблемою була валідація вводу у формах. Мені потрібно було показувати помилки форматування в UI (наприклад, обмеження довжини), при цьому зберігаючи валідацію вводу суворо відокремленою від доменних інваріантів — різниця, яку багато розробників упускають.
Початкове рішення в моїй голові було простим: чому б просто не використати enum-и?
kotlin
Де Input виглядає так:
kotlin
Виглядає чисто, але подальша робота над цим виявила проблему: якщо enum просто каже TOO_LONG, UI все одно повинен обчислити розмір вводу або дістати максимальну довжину з домену, щоб показати змістовне повідомлення про помилку. Це вже не той «тупий» UI, який я хотів бачити.
Enum-и виявилися не найкращим рішенням. Замість них я перейшов на sealed структури для представлення помилок валідації. Ці насичені даними помилки (issues) дають UI достатньо контексту для рендеру, не змушуючи його думати чи щось обчислювати:
kotlin
Тепер UI отримує всі необхідні деталі. Я усунув необхідність «полювання за контекстом» (decision context hunt) у UI-шарі, оскільки йому більше не потрібно знати деталі реалізації шару представлення чи обмеження домену.
Ще однією перевагою такого підходу є композиція валідаторів. Я можу використовувати спільні валідатори на різних екранах, або комбінувати їх з кастомними валідаторами під конкретний екран, коли бізнес-логіка відрізняється. Хтось може сказати, що це призводить до дублювання коду, але суворий SoC (як на рівні шарів, так і локально) завжди вартий цього компромісу. До того ж, я не думаю, що це великий боттлнек в епоху ШІ (хоча, чесно кажучи, навіть без нього це не займає багато часу).