Декларативный код в JavaScript
Императивный стиль программирования описывает набор шагов, которые нужно выполнить для достижения желаемого результата. Что касается декларативного стиля, то он описывает не конкретные инструкции, а желаемый результат. Примеры часто применяемых декларативных языков — HTML, SQL и даже JSX в React.
Допустим, базе данных не сообщают точные шаги получения данных. Вместо этого применяют SQL для описания того, что надо получить из базы.
SELECT * FROM Users WHERE Country='USA';
Примерно то же самое можно представить и в императивном JavaScript:
let user = null; for (const u of users) { if (u.country === 'USA') { user = u; break; } }
А вот, как это выглядит в декларативном JavaScript, если применять экспериментальный оператор конвейера:
import { filter, first } from 'lodash/fp'; const filterByCountry = country => filter( user => user.country === country ); const user = users |> filterByCountry('USA') |> first;
Предпочтение выражений над операторами
Если наша цель — декларативный код, то выражения должны быть предпочтительнее, чем операторы. Выражения возвращают значение всегда, а операторы применяются для выполнения действий, не возвращая никаких результатов. Это ещё называют побочными эффектами функционального программирования.
Как известно, чаще всего мы используем следующие операторы: for, switch, if, return, while.
Посмотрим на простой пример:
const calculateStuff = input => { if (input.x) { return superCalculator(input.x); } return dumbCalculator(input.y); };
Этот же код мы можем переписать в виде тройного выражения, которое является декларативным:
const calculateStuff = input => { return input.x ? superCalculator(input.x) : dumbCalculator(input.y); };
Если же return — это единственный оператор в лямбда-функции, то язык программирования JavaScript даёт возможность также и полностью избавиться от лямбда-выражения:
const calculateStuff = input => input.x ? superCalculator(input.x) : dumbCalculator(input.y);
При этом тело функции мы можем сократить с 5 строк кода до 2-х.
Есть и другие недостатки применения операторов. К примеру, они вызывают побочные эффекты и изменения, свойственные недетерминизму, в результате чего код делается менее надёжным и читаемым. Также операторы небезопасны и для переупорядочивания, т. к. они полагаются на порядок, в котором были использованы. Кроме того, операторы (в том числе и циклы) трудно распараллелить, т. к. они меняют состояние за пределами своей области видимости. В итоге, при работе с операторами следует понимать, что потребуются дополнительные умственные затраты, что связано с повышенной сложностью.
Что касается выражений, то их можно безопасно переупорядочивать и не вызывать побочных эффектов, также их можно без труда распараллелить.
Декларативное программирование потребует усилий
Декларативное программирование нельзя изучить за одну ночь. Особенно, если учесть, что многие обучались императивному программированию. Декларативное программирование — это, прежде всего, дисциплина и умение мыслить совершенно по-новому. Неплохой первый шаг в декларативном программировании — научиться создавать код без изменяемого состояния, а также не используя ключевое слово let.
Но факт остаётся фактом: если вы сами попробуете декларативное программирование, вы удивитесь тому, насколько элегантным станет код.
Осталось посмотреть на предлагаемую конфигурация ESLint:
rules: fp/no-let: warn fp/no-loops: warn fp/no-mutating-assign: warn fp/no-mutating-methods: warn fp/no-mutation: warn fp/no-delete: warn