Skip to main content

YAGNI (вам це не знадобиться)

YAGNI (You Aren't Gonna Need It) - принцип розробки, який каже: реалізуй лише те, що вимагає поточна специфікація, і додавай більше лише тоді, коли реальна потреба з'являється.

Теорія

Коротко

  • Аналогія: будуй кухню зараз, а не преміальну кулінарну студію, яка "може знадобиться".
  • Головне правило: "Чи вимагає специфікація цього сьогодні?" Якщо ні - пропускаємо.
  • Ціна ігнорування: команди витрачають 20-30% часу на функціонал, яким ніхто не користується.
  • YAGNI проти DRY: DRY прибирає поточне дублювання; YAGNI зупиняє спекулятивний код.
  • Виняток: основи безпеки та перевірені структурні патерни, як MVC-скелет.

Швидкий приклад

javascript
// Завдання: фільтрувати користувачів за активним статусом. Більше нічого. // Порушення YAGNI - сортування і пагінація додані "на потім" function getActiveUsersBad(users, page = 1, sortBy = 'name') { return users .filter(u => u.active) // потрібно .sort((a, b) => a[sortBy].localeCompare(b[sortBy])) // ще не потрібно .slice((page - 1) * 10, page * 10); // ще не потрібно } // YAGNI: робимо рівно те, що каже специфікація function getActiveUsers(users) { return users.filter(u => u.active); } // Результат: [{ name: 'Alice', active: true }, { name: 'Bob', active: true }]

Погана версія це не просто зайвий код. Це код, який ніхто не тестуватиме, не підтримуватиме і, швидше за все, ніколи не викличе.

Чому це важливо

Спекулятивні фічі коштують двічі: спочатку на написання, потім на підтримку, коли реальні вимоги змінюються. Другий удар болючіший, бо ти рефакториш код, який ніколи не служив жодному користувачу. Бачив, як таблицю ролей побудували до релізу і видалили через два тижні - жоден користувач її так і не торкнувся, два дні роботи у смітник. Оцінка 20-30% витраченого часу - консервативна. Хто чистив кодову базу, повну "про запас" абстракцій, знає, наскільки гірше буває.

Важливий нюанс: YAGNI не означає "ніколи не плануй наперед". Це означає: не пиши код, поки потреба не доведена.

Коли застосовувати

  • Специфікація не містить фічі: пропускаємо, пишемо коли прийде тікет.
  • User story каже "можливо пізніше": реалізуємо мінімум, який працює зараз.
  • Фаза прототипу: найменше, що перевіряє гіпотезу.
  • Рефакторинг: додаємо фічу лише якщо метрики показують реальне вузьке місце.

Типові помилки

Зайві параметри "на всякий випадок"

javascript
// Неправильно - три параметри, яких ніхто не просив function filterUsers(users, active = true, minAge = 0, country = '') { return users.filter( u => u.active && u.age >= minAge && (country ? u.country === country : true) ); } // Правильно - специфікація сказала "лише активні" function filterUsers(users) { return users.filter(u => u.active); }

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

Надмірні абстракції для гіпотетичних плагінів

javascript
// Неправильно - базовий клас для плагінів, яких не існує class UserFilter { process(users) {} // порожній метод в очікуванні "колись" } // Правильно - просто функція function filterUsers(users) { return users.filter(u => u.active); }

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

Інфраструктура "для масштабування" без доведеної потреби

Redis-черга для сервісу з 10 користувачами на день дає негайні операційні витрати без жодного гарантованого виграшу. Послідовність правильна: спочатку масив у пам'яті, потім база даних, потім черга - і лише після того, як навантажувальний тест покаже необхідність.

Спекулятивні стани UI

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

Реальне застосування

  • React: create-react-app постачається з мінімальними налаштуваннями. Без TypeScript, Redux і роутингу - поки вони реально не знадобляться.
  • Express: починаємо з базового роутера. Rate limiting додаємо після реального аудиту безпеки, а не наперед.
  • Redux: actions тільки для живих фіч. Жодних "майбутніх offline mode" саг одразу.
  • CLI на Node.js: fs.readFileSync добре працює, поки профілювання не покаже вузьке місце. Тоді переходимо на async.

Питання на співбесіді

Q: Що таке YAGNI?
A: Принцип, який каже: будуй лише те, що вимагає поточна специфікація. Якщо потреба не доведена, коду не існує.

Q: Чим YAGNI відрізняється від DRY?
A: DRY прибирає дублювання в коді, який вже існує. YAGNI зупиняє написання коду, якого взагалі не повинно бути.

Q: Коли можна порушити YAGNI?
A: Для перевірених патернів, як MVC-структура, або для санітизації введення. Основи безпеки застосовуються завжди, навіть до того як користувачі про це попросять.

Q: Як зрозуміти, що фіча реально потрібна?
A: Відстежуй тікети та метрики використання. Якщо менше 5% користувачів просять щось протягом трьох місяців, воно, мабуть, не потрапляє в наступний спринт. Senior-розробники прив'язують це до OKR.

Q: Чи може YAGNI конфліктувати з agile-плануванням?
A: Ні, якщо розглядати кожен спринт як MVP-цикл. Spike-сторії для реальних невідомих. Все інше потрапляє в реліз лише коли user story доводить потребу.

Приклади

Базовий: YAGNI в Express-ендпоінті

javascript
// Специфікація: повернути активних користувачів з валідним email. Більше нічого. app.get('/api/users', (req, res) => { const activeUsers = users.filter(u => u.active && u.email); res.json(activeUsers); }); // GET /api/users → [{ id: 1, name: 'Alice', active: true, email: 'a@test.com' }] // Без авторизації, без пагінації - специфікація поки не вимагає.

Цей ендпоінт робить рівно те, що каже поточна специфікація. Авторизація з'явиться, коли прийде відповідний тікет з безпеки, а не раніше.

Середній рівень: сортування за запитом, а не наперед

javascript
// Користувачі попросили сортування після релізу. Не будуємо наперед. function UserList({ users }) { const [sortBy, setSortBy] = useState(null); // null, поки не клацнули const sorted = sortBy ? [...users].sort((a, b) => a[sortBy].localeCompare(b[sortBy])) : users; // логіка сортування не виконується без потреби return ( <div> {sorted.map(u => <div key={u.id}>{u.name}</div>)} <button onClick={() => setSortBy('name')}>Сортувати за іменем</button> </div> ); }

Сортування з'явилось лише тому, що користувачі реально попросили його після релізу. До цього компонент вийшов без нього. Додавання зайняло один день, а не тиждень рефакторингу заздалегідь побудованої системи.

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

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

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

Дочитали статтю?