Коротка відповідь. На Senior-раунді перевіряють не «чи знаєш ти патерни», а чи вмієш ти обирати між ними і чесно називати ціну вибору. Сильна відповідь має структуру «контекст → варіанти → вибір → ціна». Слабка – це універсальний рецепт без умов застосування. Нижче – як мислити про межі компонентів, місце для стану й обробку помилок так, щоб це звучало як досвід, а не як конспект.
Що насправді оцінюють на архітектурному раунді
Інтерв'юер ставить відкрите питання: «як би ти організував стан у великому застосунку?», «як структурувати компоненти фічі?». Правильної відповіді не існує – оцінюють процес:
- чи уточнюєш ти контекст перед відповіддю (розмір команди, вимоги, обмеження);
- чи бачиш більше одного варіанта;
- чи називаєш ціну свого вибору сам, до того як спитають;
- чи відрізняєш «так модно» від «так потрібно тут».
Формальний рівень компетенцій за грейдами я розбирав у статті Middle → Senior Frontend – тут зосередимось саме на аргументації.
Межі компонентів і шарів
Базове архітектурне рішення в React – де провести межі. Робочий поділ на три шари:
- UI-компоненти – рендерять пропси, не знають про API і бізнес-правила. Їх легко переносити й тестувати.
- Логіка – хуки з бізнес-поведінкою:
useCart,useCheckoutForm. Тут живуть правила, валідація, оркестрація запитів. - Дані – шар доступу до API: функції запитів, типи відповідей, серіалізація.
Сигнали порушених меж, які варто вміти називати: компонент на 400 рядків із fetch-ами всередині JSX; UI-компонент, що імпортує API-клієнт; бізнес-правило, продубльоване у трьох компонентах. Рефакторинг тут – не «розбити на менші файли», а винести причину зміни в один шар: правило змінюється в одному місці.
Важливий нюанс для співбесіди: поділ на шари – це інструмент, а не догма. Для одноразової фічі з одним екраном три шари можуть бути надлишковими, і сказати це вголос – плюс, а не мінус.
Де жити стану: критерії, а не бібліотеки
Найчастіша помилка кандидатів – відповідати назвою бібліотеки. Сильніша відповідь – критерії вибору місця для стану:
| Тип стану | Де жити | Критерій |
|---|---|---|
| Локальний UI (відкритий дропдаун, значення інпута) | useState у компоненті |
Ніхто інший його не читає |
| Спільний для гілки дерева | Піднятий до спільного предка або context | Читають кілька сусідів |
| Серверні дані (списки, профілі) | Кеш запитів (будь-яка бібліотека кешування або власний шар) | Джерело правди – сервер; потрібні refetch, інвалідація, статуси |
| Справді глобальний клієнтський (тема, auth-сесія) | Глобальний store або context на верхньому рівні | Читається скрізь, змінюється рідко |
Ключова теза, що відрізняє Senior: серверні дані – не клієнтський стан. Складати відповіді API у глобальний store і вручну синхронізувати – це відтворення кешу без інвалідації. Якою бібліотекою користуватись – деталь; розуміння, що це різні категорії стану, – суть.
Помилки й loading як архітектурне рішення
Junior обробляє помилки в кожному компоненті окремо. Senior проєктує політику:
- Межі помилок (error boundaries) на рівні маршруту або великої фічі: падіння віджета не кладе всю сторінку.
- Єдина семантика статусів: кожен запит має явні loading / error / empty / success стани, і компоненти не вигадують їх щоразу заново.
- Розділення відновлюваних і фатальних помилок: 401 → редірект на логін; мережева помилка → retry із повідомленням; помилка рендера → boundary із fallback.
На співбесіді достатньо намалювати це словами: «на рівні маршруту – boundary, на рівні запитів – єдиний хук зі статусами, на рівні форм – локальна валідація». Це показує системне мислення краще за будь-який список бібліотек.
Формат «контекст → варіанти → вибір → ціна»
Приклад повної аргументації на типове питання «винести логіку фільтрів у context чи тримати в компоненті?»:
- Контекст: фільтри читають три компоненти на одній сторінці; інші сторінки їх не використовують; команда – четверо людей.
- Варіанти: (1) підняти стан до спільного предка і передати пропсами; (2) локальний context сторінки; (3) глобальний store.
- Вибір: варіант 2 – context на рівні сторінки: споживачів більше двох, але стан не глобальний.
- Ціна: будь-яка зміна фільтрів рендерить усіх споживачів context; якщо з'явиться дорогий компонент-споживач, розіб'ю context на «значення» і «сеттери» або повернусь до пропсів.
Чотири речення – і інтерв'юер бачить усе: ти зважував альтернативи, обрав під контекст і знаєш слабке місце свого рішення заздалегідь.
Слабкі vs сильні відповіді: приклади
Питання: «Чому ти б використав глобальний store?»
- Слабко: «Бо в великих проєктах завжди потрібен store, це стандарт».
- Сильно: «Якщо є справді глобальний клієнтський стан – сесія, тема, фіча-флаги. Для серверних даних store не потрібен: їх місце в кеші запитів. У поточному проєкті глобального стану в мене два поля, тож вистачає context».
Питання: «Як ти організуєш структуру папок?»
- Слабко: «components, hooks, utils, services – так усі роблять».
- Сильно: «Групую за фічами: усе, що змінюється разом, лежить поруч – компоненти, хуки й запити фічі в одній папці. Спільне виношу лише після другого-третього використання. Ціна: іноді складніше знайти, де межа фічі, тому домовляємось про правила імпортів між фічами».
Різниця не в знаннях – обидва кандидати знають однакові слова. Різниця в тому, що сильна відповідь прив'язана до умов і чесно називає ціну.
Ще один повний приклад: форми
Друге за популярністю архітектурне питання після стану – «як ти працюєш із формами?». Той самий формат:
- Контекст: у застосунку і прості форми (логін, пошук), і складні (багатокрокове оформлення з залежними полями).
- Варіанти: (1) контрольовані інпути з ручним
useStateна кожне поле; (2) неконтрольовані поля + читання значень на submit; (3) бібліотека форм зі схемою валідації. - Вибір: для простих форм – варіант 1 або 2, без залежностей; для складних – варіант 3, бо ручна синхронізація валідації, touched-станів і залежних полів швидко стає джерелом багів.
- Ціна: бібліотека – це залежність і її API, який треба знати всій команді; схема валідації дублюється з серверною, тому домовляємось про спільне джерело правди для правил.
Зверни увагу на структуру: рішення різне для різних частин застосунку. «Одна технологія на всі випадки» – маркер шаблонного мислення; диференціація за складністю – маркер досвіду.
Червоні прапорці у відповідях
Фрази, які на Senior-раунді працюють проти тебе:
- «Так прийнято» / «це best practice» – без пояснення, чому practice став best і чи застосовний тут.
- «Ми завжди використовуємо X» – відсутність варіантів означає, що вибору не було.
- «Це масштабованіше» – без відповіді, яке саме зростання очікується і що конкретно зламається без цього рішення.
- Мовчання про недоліки власного вибору. Якщо ціну рішення першим називає інтерв'юер – ти її не бачив.
Дзеркальне правило: чесне «тут я б не ускладнював» на просте питання – сильна відповідь. Уміння НЕ застосувати патерн цінується не менше, ніж уміння застосувати.
Як тренувати аргументацію
- Візьми будь-яке своє минуле рішення (стан, структура, бібліотека) і письмово розклади за форматом «контекст → варіанти → вибір → ціна».
- Зроби те саме для протилежного рішення – аргументуй, за яких умов правильним був би інший варіант. Якщо не виходить – ти не обирав, а слідував звичці.
- Потренуйся вголос: архітектурні відповіді на письмі й у розмові – різні навички.
Продовження цієї теми в масштабі цілого застосунку – дизайн стрічки, кешування, продуктивність – розбираю в статті про frontend system design. А про те, коли оптимізація стає архітектурним питанням, – у матеріалі про продуктивність React без передчасного useMemo.