Функциональное программирование вряд ли можно назвать новым явлением. Еще в начале 90-х, когда я учился в университете, нам нередко приходилось писать что-то на LISP. Казалось бы, 25 лет прошло – но ведь уже тогда этот язык программирования был старше меня.
Преимущества функционального программирования давно признаны широкой общественностью. Успешное развитие программного обеспечения нередко сводится к максимальному упрощению существующих механизмов, которые позволяют новым приложениям приспособиться к требованиям современных пользователей. А заодно приходится спешить, успевая в сжатые сроки представлять потребителям продукцию с неограниченными возможностями. Гораздо проще справиться с поставленной задачей, когда разрабатываемые приложения можно условно разделить на несколько чистых функций, проверить которые не составляет труда. В таких алгоритмах нет каверзных побочных эффектов и абстрактных формулировок, рассчитанных на результаты в глобальном масштабе.
Но, похоже, ни один функциональный язык не претендует на звание общепризнанного. Я имею в виду своеобразную всемирную гегемонию C в 70-х, который позже передал корону C ++, Java, а со временем и JavaScript. Ни один из претендентов второго эшелона (Python, PHP, Perl, Ruby, C# ...) не попадал в категорию функциональных.
А потом произошло что-то невероятное. Да, я говорю о Clojure.
Шучу! Никто не говорит, что на мировой арене появился новый функциональный язык, мгновенно ставший лидером, просто на этот раз мы явно имеем дело с растущим потенциалом чемпиона, который внезапно вышел на первый план. Сейчас мы работаем над созданием мобильного приложения на React/Redux, и вот как выглядит код, который я пишу:
aliasesList.reduce((allMatching, matching, index) => {
if (matching.count() > 0) {
const expanded = allAliases.take(index)
.concat(List.of(matching))
.concat(allAliases.skip(index + 1))
.filter(aliases => aliases.count())
.reduce((current, aliases) =>
current ? current.flatMap(
i1 => aliases.map(i2 => i1.concat(i2))
) :
aliases.map(alias => List.of(alias)),
null);
return allMatching.concat(expanded);
} else {
return allMatching;
}
}, new List());
Так почему же специалисты так долго упускали функциональное программирование из виду? И почему оно становится столь распространенным явлением сегодня?
Долой существительные
Ответ на первый вопрос во многом определяется одной из основных тенденций в сфере разработки программного обеспечения. После окончания университета меня с головой накрыло волнами объектно-ориентированного цунами, а потому более 20 лет я ни строчки не написал на LISP. Сообщество разработчиков ПО признало данную методологию Истиной в последней инстанции – через несколько лет с появлением Java практика лишь закрепилась — причем коллективный разум почему-то настойчиво игнорировал преимущества функционального программирования.
Вооружившись инкапсуляцией, наследованием и полиморфизмом, ООП дарило надежду на упрощение процесса создания новых программ. Однако, в последнее время недостатки метода становились все очевиднее. Жесткие иерархии объектов и отсутствие четких характеристик классов заметно тормозили эволюцию ООП. Постепенно неопределенность распространяется на все без исключения составные элементы программирования, а, значит, не обходится без нежелательной взаимосовмещаемости и непредсказуемых побочных эффектов. Именно так глаголы функционального программирования вытеснили существительные, на которых зиждилось ООП.
Я слегка пошутил, упомянув Clojure чуть раньше, но ведь именно это диалект способствовал возрождению функционального программирования в последнее время. Если говорить о целом ряде практических вопросов, которые не удавалось решить со старым добрым LISP, вместе с Clojure появилось целое поколение разработчиков-функционалов. Так был создан Оm, без которого невозможно представить эволюцию современной экосистемы JS (подробнее об этом позже).
JavaScript растет на глазах
Помимо разочарования ООП, два озвученных ранее вопроса также связаны в силу нескольких дополнительных тенденций: становления JavaScript в качестве полноценного языка программирования общего назначения и включения методологии функционального программирования в обширную экосистему JavaScript.
На рубеже десятилетий становится очевидно, что ключевую роль в большинстве веб-разработок по-прежнему играет сервер, в то время как клиентские скрипты выполняют вспомогательные функции. Да, отдельные приложения на Ajax, например, Gmail, продемонстрировали, насколько удобно использовать приложения в виде отдельной страницы, работающей в самом браузере, для которой сервер – в первую очередь, централизованное хранилище данных. Быстрые веб-приложения, напоминающие привычные стационарные приложения, оказались на порядок выше громоздких предшественников на CGI.
После выпуска Google Chrome в 2008 году и, в частности, после презентации движка V8 от JavaScript, тенденция только усилилась. Создание сверхскоростного JavaScript стало предварительным условием для разработки полноценных одностраничных приложений. И снова лидирует Google со своим AngularJS. V8 также упрочил позиции в Node.js, отдельной JS платформе, применяемой, в первую очередь, для разработки серверных продуктов.
Внезапно JavaScript перестал казаться детским языком программирования. Благодаря AngularJS и целому семейству аналогичных разработок, а с ними и Node, неимоверно возрос интерес к JS, что обусловило невероятный спрос на этот язык программирования в течение последних нескольких лет.
Функция и форма
И какое отношение все это имеет к функциональному программированию? Брендан Эйч (создатель JS) вспоминает, что в 1995 году его взяли в Netscape для создания схемы браузера. Хотя позже пришлось согласить на уговоры руководства, настроенного получить продукт «похожий на Java», разработка сохранила ряд важных свойств языков функционального программирования (например, функции первого класса). Ее окрестили (пусть и с преувеличением) «LISP с синтаксисом C».
На просторах интернета миллион примеров, благодаря которым становится ясно, что с помощью JS можно написать императивный, объектно-ориентированный или просто отвратительных спагетти-код. Но, если сравнивать JavaScript с другими языками программирования, напоминающими С, именно он может стать отличным прототипом для создания истинного функционального языка.
В 2011 году в JS (технически ECMAScript) были добавлены функциональные команды «stalwarts map» и «reduce». В ECMAScript 2015 (ECMAScript 6) с его лаконичным синтаксисом и совершенно рациональной структурой, появился ряд других функциональных инструментов, включая создание объектов и полюбившуюся пользователям жирную стрелку. Далеко не все функции ES2015 поддерживаются браузерами, но благодаря транскомпилятору Babel это не беда, ведь вы можете использовать функционал ES2015 (и даже ES2016), а затем компилировать полученные результаты в виде универсального ES5.
Нормальная реакция
AngularJS ознаменовал начало бума JavaScript, но поскольку продукт корнями уходит в Java и ООП, не стоит записывать его в ряды функциональных разработок. За пару последних лет Facebook React превратился в отличный быстрый клиентский JS фреймворк. Да, не обошлось без впечатляющих показателей архитектуры Flux и библиотеки Immutable.js, также числящихся среди заслуг команды Facebook (интересно, насколько развитие функционального JS совпадает с тем, как Facebook вытесняет Google с рынка фреймворков JS).
Похоже, React формирует очень функциональный подход к разработке веб-приложений. По сути, последняя версия React представила упрощенный синтаксис для чистых компонентов, интеграция которых не вызывает побочных эффектов.
React специализируется, исключительно, на отображении данных, однако, именно поэтому Facebook рекомендует использовать Flux для расширения архитектуры приложений. Так как Flux — просто набор основных элементов (магазины, действия, централизованная диспетчерская служба, однонаправленный поток данных), одновременно с этой разработкой конкуренты поспешили создать собственные альтернативы, претендовавшие на звание лидера в своей сфере. Причем до появления Redux победителя в столь равном бою так и не было.
В основе механизма Redux лежат следующие принципы: единое централизованное хранилище данных, изменение состояния возможно только в результате конкретных действий и применения чистых функций (редукторов).
При использовании в сочетании с Immutable.js Redux становится едва ли не близнецом Om от Clojure. Теоретически, совместить функциональное программирование и JavaScript можно было всегда, но React, Redux и Immutable.js, наконец, предложили разработчикам JS практическое решение вопроса — разработку чистых редукторов без побочных эффектов, которые позволяют изменять привычное состояние продукта в рамках неповоротливого ES6 синтаксиса — для создания крупномасштабных функциональных приложений. Популярность такого подхода (и, следовательно, широкое распространение функционального программирования) просто поражает: когда я впервые обратил внимание не Redux несколько месяцев назад, у него было около 500 звезд на GitHub. Сегодня – более 11000.
Функциональное будущее?
Пока рано утверждать, что интерес к функциональности JavaScript продолжит расти. В последнее время JS неоднократно сталкивался с периодами нестабильности, а потому внезапное появление бесчисленного множества новых фреймворков, претендующих на исключительность, выглядело довольно забавно. Но богатая родословная функционального программирования и корни сформировавшейся тенденции выглядят весьма убедительно. И пусть отдельные проекты терпят неудачи, кажется, будущее разработки программного обеспечения, все же будет функциональным.
По традиции, немного рекламы в подвале, где она никому не помешает. Наша компания запустила новогоднюю распродажу серверов и VPS, в рамках которой можно получить от 1 до 3 месяцев аренды бесплатно. С подробностями акции вы можете ознакомиться тут.
Автор: ua-hosting.company