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+ часов на фичу, которая, вероятно, не пригодится

Частые ошибки

  1. «Потом будет сложнее добавить». Обычно нет. Хорошо структурированный простой код легко расширить
  2. Путать YAGNI и плохое проектирование. YAGNI не значит «не думай об архитектуре». Означает: не реализовывай пока не нужно
  3. Добавлять зависимости «на всякий случай». Каждая зависимость — это риск и объём бандла
  4. Делать универсальное решение вместо конкретного. Универсальность нужна, когда есть 3+ конкретных случая

Практика

  1. Просмотрите свой текущий проект — есть ли код, который написан, но не используется? Удалите его
  2. При следующей задаче задайте себе вопрос: «Это нужно прямо сейчас или я фантазирую о будущем?»
  3. Если хочется написать «на будущее» — запишите идею в TODO и двигайтесь дальше

Связанные темы

Ресурсы

  • Martin Fowler — YAGNI (статья на martinfowler.com)
  • Extreme Programming Explained (Kent Beck)
  • The Pragmatic Programmer (Hunt, Thomas)