Главная страница » Что такое чистая функция js

Что такое чистая функция js

  • автор:

Ваши функции действительно чистые?

Что значит «чистая функция» в контексте JavaScript? В программировании в целом, чистота также известна как «referential transparency», иначе говоря “замена выражения или вызова функции ее результатом никогда не изменит поведение программы” или “каждый раз, когда вы передаете те же входные данные, вы всегда получаете тот же результат”.

Кажется интуитивно, и функция вроде x => x * 10 выглядит чистой, т.к. каждый раз, как вы передаете в неё число 3 в качестве аргумента вы получаете 30 на выходе. Так как мы можем определить, что одна функция чистая, а другая — нет? Достаточно ли для этого просто прочитать код?

Давайте посмотрим на мнения людей. Вчера (25 авг 2016) Я запустил в Twitter голосование “Чистая или нет?” с тремя вариантами ответа:

  • Чистая
  • Нечистая
  • Не уверен

Со следующим кодом.

Вот результаты опроса:

  • Целых 74% думают, что она чистая
  • 18% считают, что нет
  • 8% не уверены

Понятно, почему большинство людей думают, что она чистая: даже если используются мутации внутри, получая массив со значениями [1, 2, 3] в качестве аргумента, вы всегда получите 6 на выходе. Каждый. Грёбаный. Раз.

Но также понятно, почему 18% считают, что она не является чистой: тело функции использует грязные выражения с побочными эффектами. В конце концов, я спросил “Чистая или нет?”, а не “эта функция чистая?”.

Удивительно то, что оба лагеря ошибаются. Те самые, «неуверенные» 8% были правы: это зависит от поведения во время выполнения. Просто прочитав функцию, мы не можем быть уверены. В самом деле, 18%, которые думают, что она не чистая, “более правы”, чем 74%, считающих её чистой, потому что бывают случаи, когда sum не будет чистой.

Код обманчиво простой, и в то время как мы читаем его, как люди мы, естественно, делаем предположения. Вот несколько предположений, которые вы сделали, вероятно, без явного понимания:

  • sum означает, что эта функция на самом деле сумма чисел (почему не Suppress Universal Macro?)
  • arr означает “array” (почему не “arrow” или “arrivals”?)
  • arr на самом деле массив
  • arr не null и не undefined
  • Элементы массива — числа
  • Функции valueOf элементов массива не подделаны

Но, вот проблема: все эти предположения могут провалиться, и приведенный выше код не скажет вам об этом. Вот несколько способов, как мы можем сломать функцию и сделать её грязной:

Итак, sum — нечистая функция.

Не так быстро! Все функции JavaScript на самом деле являются “процедурами”. Чистая функция — это просто “процедура”, которая ведёт себя как математическая функция, единственно верная чистая функция. Это и есть разница между функцией и «функцией». Мы можем только сказать, что “моя функция JavaScript, в данном случае, ведет себя как математическая функция”.

Я предполагаю, что вы знаете, о чем я говорю, но даю подсказку: математическая функция — это отношение определенное на множестве, отображаемом в другое множество. Например, мы могли бы сказать, что sum работает только с массивами чисел. Массивы объектов не поддерживаются. 1

Итак, возвращаясь к JavaScript, функция sum будет вести себя как математическая функция, в зависимости от того, как вы используете её. Если это вся ваша программа:

Тогда, конечно, sum будет чистой функцией! Она ведёт себя как математическая функция. Поставьте её в другую ситуацию, и она перестанет вести себя как математическая функция.

Так вот, ответ: зависит от ситуации. Что означает: взяв любую функцию JavaScript, в большинстве случаев Вы не можете знать, чистая она или нет, просто прочитав код. Вы должны знать, как эта функция вызывается и с какими аргументами.

Помните, наши невинные х => х * 10 ? Бедняга. Мы даже не можем сказать, что эта функция чистая. Посмотрите, она не является чистой:

Чёрт возьми! Есть ли вообще что-нибудь чистое в JavaScript? Вы могли бы сказать: “это неважно, потому что на практике мы не встретим этих странных случаев, которые ты придумал”. Действительно, мы не будем valueOf подменять Math.random.

Пока. в один прекрасный день мы это не сделаем. Вы знаете, те самые сложные ошибки, с которыми вы боретесь иногда? Можно подумать, что в JavaScript за этим стоит черная магия. Он проклят. Происходит что-то мистическое. Эти мистические случаи обычно происходят потому, что что-то где-то там случилось, что-то, что вы не предполагали. Да, теперь это кажется знакомым, верно?

Итак, мы прокляты? х => х * 10 — это так мило и просто в использовании, но эта функция также не является чистой абсолютно всегда. Есть ли что-нибудь чистое на JavaScript? Чистота в JavaScript вообще возможна? Этот ваш JavaScript совершенно нечистый?

Ну, нет. Вот как мы можем сделать sum похожей на математическую функцию:

Что, если кто-то подменил Array.isArray?

Ладно, подождите минутку:

Чтобы сделать её чистой, мы в основном перечислили все предположения о входных данных. Кстати, я до сих пор чувствую себя неловко, что кто-то найдет хитрый способ сломать мою “чистую” sum . Список проверок нуден и делает код менее читабельным. Наверное, вы написали такой код для основных аргументов, которые являются недопустимыми. Но как я чувствовал себя неловко, так и вы. Вы уверены, что учли все случаи и возможные ситуации? Она всегда ведёт себя как математическая функция?

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

В TypeScript, мы можем написать наши проверки в сигнатуре:

Тело функции, реализующее тоже самое, что и в JavaScript:

Если вы попробуете использовать эту функцию так:

Это даже не компилируется! Это значит, что ваша программа даже не “ведёт себя” в самом начале. Также и этот код не будет компилироваться:

Впрочем, внимательный читатель увидит, что моя TypeScript’овая sum может быть также сломана:

Компилируется успешно, но возвращает ошибки во время выполнения “TypeError: Cannot read property ‘length’ of null”. Это потому, что TypeScript pre-v2.0 считает, что этот Array<number> включает в себя null. Даже если мы используем TypeScript v2.1, мы можем обмануть TypeScript через приведение типов:

Компилируется, но возвращает различные результаты для sum(arr) .

Итак, TypeScript тоже обречен? Ну, вроде да, но гораздо меньше, чем JavaScript. TypeScript typings добавляет проверки в ваш код, так что он будет отлавливать больше случаев, чем вы обычно отлавливаете при написании наивного кода. Итак, я за TypeScript. Он помогает мне чувствовать себя немного лучше.

Мы действительно можем быть уверены, что функция чиста, просто прочитав её? Ну, в актуальных функциональных языках программирования, таких как PureScript или Haskell — да, мы можем:

Если Вы не понимаете синтаксис, вот важная часть: [Int] -> Int . Это означает, что это функция, которая принимает список Int и возвращает только Int. Список не может быть undefined, не может быть null. И я не думаю, что вы можете изменять числа так, как это возможно в JavaScript. И есть много проверок, встроенных в Int. Это тип, который удовлетворяет многие типоклассы: Num (это число), Ord (целые числа могут быть упорядочены), Eq (числа могут строго сравниваться 2 ), Show (мы можем сделать удобочитаемый формат для целых чисел) и т. д. Все эти проверки отлавливают много крайних случаев. Может быть, есть некоторые ошибки времени выполнения и опасные операции в Haskell, но это чертовски хорошо делает код похожим на математическую функцию.

Заключение

Ок, так что в Haskell функции являются чистыми, и вы можете это узнать просто прочитав код. Но разве название этой статьи не о JavaScript?

Я думал о чистоте в JavaScript некоторое время, потому что недавно я имел дискуссию с людьми о “оператор scan в RxJS чистый?” и я защищал его, настаивая, что он чистый. Я был неправ. На самом деле был. Это зависит от следующих факторов. Если используется вне контекста высшестоящих Observable, как это было в Elm (актуальный функциональный язык программирования, в лиге Haskell и PureScript), то он чист. Он ведет себя словно математическая функция. Но, если вы используете scan в вышестоящих Observable, существует высокая вероятность, что он не будет вести себя как математическая функция.

Почему все это важно? Потому что я надеюсь, что мы можем начать перенос дискуссии из “это чистая функция?” в

“Эта функция ведет себя как математическая во всех ситуациях, с которыми я могу столкнуться в своём коде?”

Я знаю, что это уже приговор. Я знаю, что на этот вопрос трудно найти ответ в большинстве случаев. Однако это единственное, что мы можем сделать для чистоты JavaScript. Мы не можем посмотреть на код и заявить, что он чистый. У нас было много непроверенных предположений. Давайте говорить “ведет себя, как Math, в данной конкретной ситуации” вместо этого.

Фу́нкция (отображе́ние, опера́тор, преобразова́ние) — в математике соответствие между элементами двух множеств, установленное по такому правилу, что каждому элементу одного множества ставится в соответствие некоторый элемент из другого множества.
Математическое понятие функции выражает интуитивное представление о том, как одна величина полностью определяет значение другой величины. Так, значение переменной x однозначно определяет значение выражения x 2 , а значение месяца однозначно определяет значение следующего за ним месяца.
Аналогично, задуманный заранее алгоритм по значению входного данного выдаёт значение выходного данного. — Википедия  ↩

Существуют ли чистые функции в JavaScript?

Недавно я ввязался в дискуссию о том, как определить чистую функцию в JavaScript. Вся концепция чистоты, кажется, расплывается в таком динамичном языке. Следующие примеры показывают, что нам, возможно, придётся пересмотреть термин «чистая функция», или, как минимум, быть очень осторожными, когда мы его используем.

Что такое чистая функция?

Если вы не знакомы с этим термином, то я рекомендую вам сначала прочитать небольшое вступление. Определение «чистая функция» от Alvin Alexander и Мастер JavaScript интервью: что такое чистая функция? от Eric Elliott будут отличным выбором.

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

  1. Функция возвращает точно такой же результат каждый раз, когда она вызывается с тем же набором аргументов.
  2. Выполнение функции не изменяет какое-либо состояние за пределами её области видимости и не оказывает видимого воздействия на внешний мир, кроме возвращения значения (никаких побочных эффектов).

Иногда добавляется третье условие: «не опирается на внешнее изменяемое состояние». Это, по сути, избыточно, поскольку такая зависимость от изменяемой переменной неизбежно приведёт к нарушению первого условия.

Что из этого является чистым?

Здесь я написал четыре примера функций. Прежде чем продолжить, просмотрите их и решите самостоятельно, какие являются чистыми, а какие нечистыми.

Сделали? Отлично, давайте сравним.

Когда я спрашивал, подавляющее большинство ответило, что функция doubleB является единственной нечистой, а функции doubleA , doubleC и doubleD чисты.

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

Первое более интересное. При вызове с теми же аргументами все они возвращают одно и то же значение (используем toEqual для поддержки массивов):

Нуууу, написано так, что да. Однако, как насчет этой части кода, опубликованного моим другом Alexander?

Результат верен. Я дважды запустил функцию с теми же аргументами и получил разное значение. Это делает её нечистой. Независимо от того, что происходило между ними.

Это заставило меня задуматься. Если это подтвердилось, то что насчёт других? Выдержат ли они, если я достаточно постараюсь? Как вы догадались, нет, они этого не сделают. Фактически, я сейчас говорю:

Ни одна из четырёх функций не является чистой.

Функции как объекты первого класса

В JavaScript функции являются объектами первого класса, то есть они могут быть значением переменной, которое может быть передано, возвращено и, да, переназначено. Если я могу изменить переменную two , я могу сделать и следующее:

Важно подчеркнуть, что это не отличается от того, что сделал Alex. Вместо того, чтобы содержать число, переменная содержит функцию.

Map по массиву

«Map, filter, reduce. Повторить». Это было название одной из моих livecoding-сессий. Эти три метода — ядро преобразования данных в функциональном программировании. Поэтому они должны быть безопасными для использования в чистых функциях.

Как выясняется, в JavaScript ничто не высечено в камне. Или я должен сказать в прототипе?

Подождите. Это, конечно, недопустимо. Это неправильно.

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

Всё, что мы делаем, это переопределяем переменные между вызовами функций. Как мы сделали раньше.

Поэтому функция doubleD не является чистой.

Умножение чисто

Однако в JavaScript нельзя динамически переопределять встроенные операторы, как в некоторых языках.

Кроме того, n — локальная переменная, живущая только в области видимости этой функции. Её невозможно изменить извне.

Нет, это действительно невозможно. Вы должно быть невысокого мнения о JavaScript, если у вас есть на это надежда ��.

Но я выдал себя, когда написал, что ни одна из четырех функций не является чистой. Я приберег ещё один трюк в рукаве.

Хоть я и не могу изменить операцию или аргумент после его передачи, у меня есть свобода выбора того, что можно передать. Числа, строки, булевые значения, объекты…

Объекты? Какое применение у них может быть? Число, помноженное на объект, равно, эм… как 2 * <> . NaN . Проверьте это в консоли. Как это сделал я.

Хотя это не поможет. Если бы только был способ заставить среду выполнения преобразовать объект в число при умножении.

toString для чисел

Если объект появляется в контексте строки, например в случае конкатенации со строкой, движок запускает функцию toString объекта и использует результат. Если функция не реализована, он будет возвращаться к известному '[object Object]' , созданному методом Object.prototype.toString .

В то же время JavaScript вызывает метод valueOf объекта, когда он ожидает число (или булевое значение, или функцию). Осталось только сделать так, чтобы эта функция возвращала разные значения при каждом вызове.

Уфф, да. Функция вызывалась дважды с точно таким же (в любом смысле) аргументом, во второй раз она возвращала другое значение. Это не чисто.

Примечание: в предыдущей версии этой статьи использовался @@toPrimitive или, более точно, Symbol.toPrimitive . Как отметил Alexandre Morgaut, valueOf достаточно и он поддерживается с первой версии JavaScript. Если вы не знакомы с @@toPrimitive , вы всё ещё можете прочитать здесь.

И все-таки: что такое чистая функция?

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

Я хочу, чтобы все четыре функции были чистыми, если я так решил. Да, включая функции типа doubleB . Что делать, если эта переменная (в нашем случае, two ) не может изменяться, например это математическая константа e , pi или phi? Она должна быть чистой.

Я хочу иметь возможность доверять встроенным функциям. Какие программы я могу создать, если я предполагаю, что всё что угодно в Array.prototype или Object.prototype может измениться? Всё просто: никто никогда не захочет их использовать.

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

В некотором роде он должен учитывать предполагаемое использование кода. Функция может считаться чистой в одном проекте и нечистой в другом. И это нормально. Пока программа работает. Пока у разработчиков есть уверенность.

У вас есть идеи для определения? Как вы решаете, что функция является чистой? Есть что-нибудь, что я упустил? Вы чему-нибудь научились?

Примечание

Есть несколько способов защиты от некоторых трюков, использованных выше.

Переопределение свободной переменной типа two или getTwo можно избежать, инкапсулируя весь блок в функцию. Либо использовать IIFE или модули:

Лучшим решением было бы использование const, представленного в ES2015:

Предотвращение от злоупотребления valueOf или @@toPrimitive также возможно, но громоздко. Например, вот так:

Можно было обойти трюк с изменением Array.prototype , только избегая таких функций и возвращаясь к циклам for (for . of) . Это уродливо, непрактично и потенциально невозможно. Абстрагирование этого или использование библиотеки имеет свои недостатки.

Не забывайте, что для того, чтобы сделать функцию действительно чистой, нужно было бы объединить все эти анти-трюки вместе. Представьте себе, как будет выглядеть эта элегантная doubleD , какая она будет длинная и как это повредит читаемости.

«Чистые» и «нечистые» функции в JavaScript

Что такое «чистые» и «нечистые» функции в JavaScript, и как их различать.

«Чистые» функции — это любые функции, исходные данные которых получены исключительно из их входных данных и не вызывают побочных эффектов в приложении. Математические функции являются примерами «чистых» функций. «Нечистые» функции бывают разных форм и размеров. Вот некоторые примеры:

  • функции, вывод которых зависит от внешнего / глобального состояния;
  • функции, которые возвращают разные исходные данные при одинаковых входных;
  • функции, которые изменяют состояние приложения;
  • функции, которые изменяют «внешний мир».

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

«Чистая» функция — это функция, которая выводит свои данные основываясь исключительно на свои входные данные и не вызывает побочных эффектов в приложении.

Например у нас есть функция, которая получает одно значение x и возвращает в данном случае x + 1 :

Довольно легко понять, что это «чистая» функция. Мы получаем тот же результат при вызове этой функции, с тем же входным значением; плюс у нас нет внешних зависимостей, которые бы вызывали побочные эффекты. Чтобы понять это далее, давай сравним это с несколькими «нечистыми» функциями.

Первая «нечистая» функция

Первая «нечистая» функция, которую мы собираемся сделать — это та, чей результат не основан исключительно на её входных данных. Например, давай рассмотрим функцию totalPrice . У нас есть глобальная переменная — COST_OF_ITEM , которая содержит цену на товар. Функция totalPrice берет quantity и умножает ее на эту переменную.

На первый взгляд может показаться, что это «чистая» функция, потому что мы всегда получаем один и тот же результат на основе одного и того же входного значения. Это можно увидеть, вызвав её несколько раз с одним и тем же значением, и вывив в консоль. В обоих случаях мы получаем 500.

Хоть мы и получаем тот же результат, но это «нечистая» функция, так как состояние нашего приложения влияет на вывод нашей функции. Мы можем увидеть это, изменив значение COST_OF_ITEM и посмотреть снова в консоль.

Вторая «нечистая» функция

Наш второй пример «нечистой» функции — это функция, которая получает один и тот же аргумент, но возвращает разные результаты. Часто в наших приложениях нам нужно создавать объекты, которые имеют уникальные идентификаторы, такие как id .

Давай создадим функцию generateID . Эта функция будет возвращать целое число в случайном порядке. Это «нечистая» функция, так как вызвав её несколько раз, каждый раз мы получим разный результат.

Давай используем нашу «нечистую» функцию generateID внутри фабричной функции для создания пользовательских объектов. Чтобы создать пользователя, createUser принимает два параметра: name и age , и возвращает объект с id , используя функцию generateID для его создания, а также name и age .

Вызовем createUser несколько раз, с одинаковыми аргументами.

Если посмотрим в консоль, то увидим, что мы получили похожие объекты, но они не одинаковые — id у всех разный.

«Нечистота» функции generateID делает нашу фабричную функцию createUser «нечистой». Для того чтобы исправить это — можно переместить «нечистую» функцию за пределы фабрики и вызвать её где-нибудь, где мы ожидаем побочный эффект, и передать id в качестве параметра в нашу фабрику createUser .

Третья «нечистая» функция

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

Допустим, мы отслеживаем изменяемое значение (в данном случае id ). Если мы создадим функцию, которая изменяет это значение, у нас будет «нечистая» функция. Например фабричная функция createPersone .

Если мы генерируем наш id для этого объекта, изменяя значение глобального id , то это «нечистая» функция. Вызвав эту функции несколько раз с разными name , то увидим, что id увеличился как мы и ожидали, но если мы также выведем в консоль глобальное значение id , то увидим, что оно тоже изменилось.

Javascript и функциональное программирование. Часть 3. Чистые функции

JavaScript

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

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

Так что же это за загадочные чистые функции? Чистая функция отвечает двум основным требованиям:

1. Она детерминирована. Это означает, что при одном и том же вводе функция всегда возвращает одинаковый результат. Если проводить параллель с математическими терминами (я быстро!), то ей соответствует четко определенная функция. Каждый ввод возвращает один и тот же вывод. Каждый раз.

Чистая функция

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

Ну, а как насчет такой?

В чем-то здесь подвох… Функция createMagicPhrase зависит от значения, которое является внешним по отношению к ее области видимости. Значит, она не чистая!

Нечистая функция

Является ли fetchLoginToken чистой функцией? Возвращает ли она каждый раз одно и то же значение? Конечно же, нет! Иногда она выполняется, иногда сервер падает, и мы видим 500-ю ошибку. А когда-то в будущем API может взять и поменяться так, что вызов станет не выполняемым. Так что раз эта функция не детерминирована, то можно с уверенностью сказать, что чистой она не является.

2. Чистая функция не вызывает побочных эффектов. Побочный эффект – это любое изменение в системе, которое заметно внешнему миру.

Является ли calculateBill чистой функцией? Однозначно �� Она отвечает двум необходимым требованиям:

· Функция зависит только от своих аргументов и возвращает значение на основании них.

· Функция не вызывает никаких побочных эффектов.

The Mostly Adequate Guide говорит нам, что побочные эффекты включают в себя (но не ограничиваются!) следующее:

· изменение файловой системы:

· добавление записи в базу данных;

· вывод данных на экран / ведение журнала;

· получение пользовательского ввода;

· доступ к состоянию системы.

Для чего делать функции чистыми?

Читаемость -> С побочными эффектами наш код прочесть достаточно трудно. И так как нечистые функции не являются детерминированными, то для одного ввода они могут возвращать несколько разных значений. В итоге нам приходится писать код, который бы учитывал все возможные вероятности. Давайте посмотрим еще на один пример, теперь на базе http:

В этом сниппете может возникать столько разных ошибок. Что, если id, передаваемый в getTokenFromServer, окажется некорректным? А вдруг сервер упадет и вместо ожидаемого маркера вернет ошибку? Существует огромное количество всевозможных исходов, и все их необходимо учесть, причем забыть про один из них (или несколько!) достаточно просто.

Чистая функция легче читается, т.к. для нее не требуется контекст. Все необходимые параметры она получает заранее и не коммуницирует / не вмешивается в состояние приложения.

Тестируемость -> Все чистые функции по природе своей детерминированы, поэтому писать для них модульное тестирование – сплошное удовольствие. Тут ваша функция либо работает, либо нет ?

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

Модульность и повторное использование -> Чистые функции можно воспринимать как небольшие логические единицы. Раз они зависят только от того, что получают на входе, то их можно повторно использовать в различных частях кода или проекта.

Прозрачность ссылок -> Звучит как-то очень мудрено. Когда мне впервые попалось это словосочетание, то сразу захотелось все бросить! Но в переводе на простой язык, прозрачность ссылок означает то, что вызов функции можно заменить ее выходным значением без сопутствующих корректировок поведения программы в целом. Это очень удобно при продумывании общей концепции в процессе создания чистых функций.

Все чище некуда… но разве есть в этом толк?

Важно понимать, что несмотря на все плюсы, реализовать работающую программу на одних только чистых функциях – практически невозможно. Ведь тогда созданная нами программа не будет иметь побочных эффектов, поэтому не будет выдавать внешнему миру ничего примечательного. Ну, скукотища же . Вместо этого мы постараемся инкапсулировать все сторонние эффекты в определенные части кода. Тогда в случае, если при написании модульного тестирования чистых и работающих (!) функций что-то сломается, то мы с легкостью найдем источник ошибки.

Акцент на чистоту

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

Для начала определим, какая именно перед нами функция. Эта функция является нечистой потому что зависит от А и В, которые являются внешними элементами по отношению к области ее видимости. Кроме того, она также мутирует (изменяет) значения переменных. Самым быстрым способом рефакторинга данной функции будет следующее:

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

· Вместо мутации (манипуляций с) B и С мы можем вернуть новые значения и отразить их.

Заключение

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *