Ответ
Чистая функция — это функция, которая обладает двумя ключевыми свойствами:
- Детерминированность (Deterministic): Для одних и тех же входных аргументов всегда возвращает одинаковый результат.
- Отсутствие побочных эффектов (No Side Effects): Не изменяет внешнее состояние (глобальные переменные, параметры-ссылки, файловую систему, БД) и не зависит от изменяемого внешнего состояния.
Примеры:
// ЧИСТАЯ функция
public static int Add(int a, int b) => a + b;
public static string Greet(string name) => $"Hello, {name}!";
// НЕЧИСТАЯ функция (зависит от внешнего, изменяемого состояния)
private static int _counter = 0;
public static int GetNextId() => ++_counter; // Побочный эффект: изменяет _counter
// НЕЧИСТАЯ функция (результат недетерминирован)
public static int GetRandom() => new Random().Next(); // Разный результат при каждом вызове
// НЕЧИСТАЯ функция (выполняет ввод-вывод)
public static void Log(string message) => File.AppendAllText("log.txt", message);
Почему это важно? Преимущества чистых функций:
- Тестируемость: Легко проверить, не требуя сложной настройки окружения (mocks, stubs).
- Предсказуемость и надежность: Поведение функции изолировано и понятно.
- Возможности для оптимизации: Кэширование результатов (мемоизация), параллельное выполнение.
- Упрощение рассуждений о коде: Функцию можно анализировать и понимать в отрыве от контекста выполнения.
Чистые функции являются фундаментальной концепцией функционального программирования и крайне полезны даже в объектно-ориентированном коде для создания более стабильных и поддерживаемых модулей.
Ответ 18+ 🔞
А, слушай, про чистые функции. Ну это вообще, блядь, основа основ, если хочешь код, который не выстрелит тебе в колено в пятницу вечером перед деплоем.
Представь себе, есть у тебя функция. Идеальная, блядь, функция. Как швейцарские часы. Ты ей даёшь одни и те же цифры — она тебе один и тот же результат выплёвывает. Никаких сюрпризов. Это и есть детерминированность, ёпта. Сложил 2 и 2? Получи 4. И завтра, и через год, и на продакшене, и у тебя на ноуте в сортире. Всегда 4. Не "иногда 4, а иногда 5, потому что глобальная переменная _mood устала".
И второе, что ещё важнее — она нихуя снаружи не трогает. Ничего. Полный аскет. Взяла данные на вход, посчитала что-то внутри себя, отдала результат и сдохла. Не пишет в файл, не меняет глобальный счётчик, не шлёт запросы в БД и не красит кнопку в интерфейсе. Никаких побочных эффектов. Чистота, блядь, неземная.
Вот смотри, на C#:
// Это святое, это чистая функция. Как монах в келье.
public static int Add(int a, int b) => a + b;
public static string Greet(string name) => $"Hello, {name}!";
Дал Greet("Вася") — получил "Hello, Вася!". И точка. Никаких танцев с бубном.
А теперь смотри на этого уёбка:
private static int _counter = 0;
public static int GetNextId() => ++_counter; // Побочный эффект: изменяет _counter
Он тебе каждый раз разный результат выдаёт! И главное — он гадит в общее поле _counter. Вызвал его десять раз — он там наворотил, а потом другой модуль смотрит на этот счётчик и охуевает: "А почему у меня тут 10, я же только один раз запросил?". Пиздец, а не функция.
Или вот этот шут:
public static int GetRandom() => new Random().Next(); // Разный результат при каждом вызове
Ну это ваще пиздец. Детерминированность? Да ни хуя подобного! Сегодня 42, завтра 15. На тестах пролетает, на проде — нет. Классика.
А этот вообще, блядь, в файловую систему лезет:
public static void Log(string message) => File.AppendAllText("log.txt", message);
Это не функция, это уже процедура с побочкой. Вызвал — и пошла жара: диск скрипит, права проверяются, место кончается. Чистота? Да какая нахуй чистота!
А зачем это всё, спросишь? Да затем, чувак!
- Тестировать их — одно удовольствие. Не надо поднимать целое окружение, мокать базу или файловую систему. Подсунул входные данные — проверил выход. Всё. Быстро и без нервов.
- Предсказуемость. Ты точно знаешь, что она делает. Не зависит от погоды, фазы луны или значения какой-то переменной в другом потоке. Спать спокойно можно.
- Оптимизация. Раз результат для одних и тех же аргументов всегда одинаковый, его можно закэшировать и не пересчитывать каждый раз. Это называется мемоизация. Или можно несколько таких функций параллельно запустить — они друг другу мешать не будут, ибо ничего общего не трогают.
- Понимание кода. Читаешь такую функцию — и всё ясно. Не надо бегать по всему проекту и искать, кто ещё меняет состояние, от которого она зависит. Всё у неё внутри аргументов.
В общем, это как бы базис функционального подхода, но даже в обычном ООП-коде такие функции — это золотой фонд. Код становится крепче, баги вылавливаются быстрее, и волосы на жопе не шевелятся при каждом рефакторинге. Старайся писать так, где это возможно.
Видео-ответы
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶