Разговор о чистых функциях часто уходит в теорию, хотя практический вопрос намного проще: можно ли безопасно понимать, тестировать и повторно использовать этот кусок кода, не вспоминая про скрытое состояние вокруг него.

Чистые функции полезны потому, что они предсказуемы. Они не зависят от внешнего мира, не меняют его и возвращают один и тот же результат для одинаковых аргументов. Как только код начинает читать глобальные переменные, генерировать случайные значения или менять внешнее состояние, предсказуемость падает.

Ниже разберем, как быстро различать чистые и нечистые функции на практике и где побочным эффектам вообще место в приложении.

Обновлено 17 марта 2026: материал переписан вокруг инженерных критериев чистоты, а не только вокруг формального определения.

Что делает функцию чистой

У чистой функции есть два признака:

  • одинаковые аргументы всегда дают одинаковый результат;
  • при вызове не происходит побочных эффектов вне самой функции.

Простейший пример:

const increment = (value) => value + 1;

increment(2); // 3
increment(2); // 3

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

Где код становится нечистым

Нечистота бывает не в одной форме. Чаще всего проблема проявляется в одном из четырех сценариев.

1. Зависимость от внешнего состояния

const COST_OF_ITEM = 250;

const totalPrice = (quantity) => COST_OF_ITEM * quantity;

Функция выглядит безобидно, но ее результат зависит не только от quantity. Если глобальная константа или внешняя конфигурация изменится, поведение тоже изменится.

2. Нестабильный результат при одинаковом вводе

const generateId = () => Math.floor(Math.random() * 10000);

Такую функцию нельзя назвать чистой, потому что один и тот же вызов возвращает разные значения. То же самое касается Date.now() и большинства обращений к случайности, времени или сети.

3. Мутация внешних данных

const removeLastItem = (list) => {
  list.pop();
  return list;
};

Проблема здесь не в самом pop, а в том, что функция меняет переданный массив. Это создает скрытый эффект в другом месте программы.

4. Побочные эффекты во внешний мир

const logger = (message) => {
  console.log(message);
};

console.log, запись в localStorage, DOM-обновления, сетевые вызовы и работа с файлами меняют состояние вне функции. Это нормальные операции, но они делают функцию нечистой.

Как сделать код чище на практике

Главная идея не в том, чтобы убрать все побочные эффекты из приложения. Это невозможно. Идея в том, чтобы изолировать их.

Например, генерацию id лучше вынести наружу и передавать результат как аргумент.

const createUser = (id, name, age) => ({
  id,
  name,
  age,
});

const id = Math.floor(Math.random() * 10000);
const user = createUser(id, "Alex", 28);

Теперь сама функция createUser чистая. Нечистая часть осталась на границе, где мы действительно ожидаем side effect.

То же самое работает с конфигами и временем:

  • лучше передать price, чем читать глобальную переменную;
  • лучше передать now, чем вызывать Date.now() глубоко внутри логики;
  • лучше вернуть новый массив, чем мутировать старый.

Почему это важно не только для функционального программирования

Чистые функции полезны даже если ты не пишешь “функциональный” код.

Они:

  • проще тестируются;
  • легче компонуются в pipeline;
  • снижают количество случайных регрессий;
  • лучше подходят для кэширования и memoization;
  • понятнее при ревью, потому что меньше скрытых зависимостей.

Именно поэтому тема чистоты важна не как часть философии, а как инструмент для читаемости и надежности.

Где нечистым функциям нормально жить

Побочные эффекты нужны. Вопрос не в их существовании, а в том, где они расположены.

Лучше всего держать их ближе к границам системы:

  • в обработчиках событий;
  • в сетевом слое;
  • в адаптерах к хранилищу;
  • в точках интеграции с браузером или Node.js.

А внутри доменной логики, вычислений и преобразований данных лучше сохранять функции максимально чистыми. Тогда поведение системы проще проверять и собирать из маленьких частей.

Короткий чеклист

Если сомневаешься, задай функции четыре вопроса:

  • читает ли она что-то, чего нет в ее аргументах;
  • меняет ли она данные, переданные снаружи;
  • пишет ли она что-то во внешний мир;
  • вернет ли она тот же результат завтра при тех же аргументах.

Если хотя бы на один вопрос ответ “да”, функция нечистая или, как минимум, не полностью чистая.

Итог

Чистая функция — это не статус “идеального” кода, а удобный инженерный контракт: все нужное приходит через аргументы, а результат предсказуем. Чем больше таких функций в логике приложения, тем легче код читать, тестировать и безопасно менять.

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