YAGNI (You Ain't Gonna Need It)
YAGNI — принцип экстремального программирования, который гласит: не реализовывай функциональность, пока она реально не понадобилась. Не «может понадобиться» — а уже нужна.
Зачем нужно
Каждая строка кода — это стоимость: написание, тестирование, поддержка, рефакторинг. Код, написанный «на будущее», часто не используется, но всё равно требует поддержки и создаёт сложность.
Где используется
- Планирование фич и спринтов
- Проектирование API и архитектуры
- Выбор зависимостей
- Принятие решений об абстракциях
Предпосылки
Scope creep — ползучее расширение
// Задача: отобразить список пользователей
// ПЛОХО: "а вдруг потом понадобится..."
class UserListManager {
constructor(options = {}) {
this.users = ;
this.sortField = options.sortField || 'name';
this.sortOrder = options.sortOrder || 'asc';
this.filterFn = options.filter || ( => true);
this.pageSize = options.pageSize || 20;
this.currentPage = 0;
this.cache = new Map(); // кэш "на будущее"
this.undoHistory = ; // отмена "на будущее"
this.plugins = ; // плагины "на будущее"
this.eventBus = new EventEmitter(); // события "на будущее"
this.i18n = options.locale || 'ru'; // локализация "на будущее"
}
addPlugin(plugin) { /* ... */ }
undo { /* ... */ }
redo { /* ... */ }
export(format) { /* csv, json, xml "на будущее" */ }
// 200 строк кода для задачи на 20 строк
}
// ХОРОШО: только то, что нужно сейчас
async function renderUserList() {
const users = await fetch('/api/users').then(r => r.json());
const html = users
.map(user => `<li>${user.name} (${user.email})</li>`)
.join('');
document.querySelector('#user-list').innerHTML = html;
}
Feature bloat — раздувание функциональности
// Задача: функция форматирования даты
// ПЛОХО: поддержка 10 форматов "на будущее"
function formatDate(date, format = 'DD.MM.YYYY', locale = 'ru', timezone = 'Europe/Moscow', options = {}) {
const tokens = {
YYYY: date.getFullYear(),
YY: String(date.getFullYear()).slice(-2),
MM: String(date.getMonth() + 1).padStart(2, '0'),
M: date.getMonth() + 1,
DD: String(date.getDate()).padStart(2, '0'),
D: date.getDate(),
HH: String(date.getHours()).padStart(2, '0'),
mm: String(date.getMinutes()).padStart(2, '0'),
ss: String(date.getSeconds()).padStart(2, '0'),
// ... ещё 20 токенов
};
// 50 строк парсинга формата
}
// ХОРОШО: одна конкретная задача
function formatDateRu(date) {
return date.toLocaleDateString('ru-RU'); // "06.04.2026"
}
// Когда РЕАЛЬНО понадобится кастомный формат — тогда и расширите
Когда YAGNI нарушается правильно
Есть случаи, когда стоит планировать наперёд:
| Планировать сейчас | Не планировать |
|---|---|
| Безопасность (хэширование паролей) | Поддержка 5 типов БД |
| Базовая структура проекта | Микросервисы для MVP |
| Валидация входных данных | Мультиязычность без заказчика |
| Обработка ошибок | Плагинная система |
| Логирование | Кэш без нагрузочного тестирования |
// Безопасность — НЕ YAGNI, это нужно СРАЗУ
// Хэшируйте пароли с первого дня
const bcrypt = require('bcrypt');
async function createUser(email, password) {
// НЕЛЬЗЯ откладывать "на потом"
const hashedPassword = await bcrypt.hash(password, 10);
return db.users.create({ email, password: hashedPassword });
}
// Обработка ошибок — тоже нужна сразу
async function getUser(id) {
try {
const user = await db.users.findById(id);
if (!user) throw new NotFoundError('User not found');
return user;
} catch (error) {
logger.error('getUser failed', { id, error });
throw error;
}
}
Стоимость ненужного кода
Каждая «фича на будущее» несёт скрытые затраты:
Написание кода: ~2 часа
Написание тестов: ~1 час
Поддержка при рефакторинге: ~30 мин каждый раз
Когнитивная нагрузка: постоянно
Вероятность использования: ~20%
Итого: 3+ часов на фичу, которая, вероятно, не пригодится
Частые ошибки
- «Потом будет сложнее добавить». Обычно нет. Хорошо структурированный простой код легко расширить
- Путать YAGNI и плохое проектирование. YAGNI не значит «не думай об архитектуре». Означает: не реализовывай пока не нужно
- Добавлять зависимости «на всякий случай». Каждая зависимость — это риск и объём бандла
- Делать универсальное решение вместо конкретного. Универсальность нужна, когда есть 3+ конкретных случая
Практика
- Просмотрите свой текущий проект — есть ли код, который написан, но не используется? Удалите его
- При следующей задаче задайте себе вопрос: «Это нужно прямо сейчас или я фантазирую о будущем?»
- Если хочется написать «на будущее» — запишите идею в TODO и двигайтесь дальше
Связанные темы
Ресурсы
- Martin Fowler — YAGNI (статья на martinfowler.com)
- Extreme Programming Explained (Kent Beck)
- The Pragmatic Programmer (Hunt, Thomas)