Разработчики из американской компании Gaslight написали интересный материал о том, почему организация, известная своей любовью к Ruby и Ruby on Rails, решила инвестировать в освоение новых технологий — например, Clojure. Мы в «Латере» развиваем биллинг для операторов связи «Гидра» и тоже работаем с этим языком программирования, поэтому решили выделить главные тезисы команды Gaslight в отдельный материал.
Итак, почему стоит изучать Clojure и использовать его в реальных проектах?
Не только Ruby и RoR
По словам Джеффа Лэйна, написавшего пост в блоге Gaslight, с помощью Clojure его команде удается решать задачи, которые не по плечу Ruby. Он иллюстрирует этот тезис словами одного из основателей Gaslight Дуга Алкорна:
«Я уверен, что нельзя держаться за один язык программирования вечно. Придет время, когда Ruby уступит место новому языку. Потому что изменится сама среда. Я лишь надеюсь, что тот, кто займет этот трон, будет лучше и милосерднее».
Лэйн говорит, что в компании все еще трепетно относятся к Ruby. Здесь все еще считают Rails лучшим решением для написания веб-приложений. Но, как и у любого инструмента, у него есть свои ограничения:
- Ruby — не лучший выбор для многопоточного программировании, несмотря на существование JRuby и наличие библиотек вроде Celluloid.
- Ruby и Rails почти всегда достаточно быстры. Почти, но не всегда.
- Объектно-реляционное отображение (ORM) может не подходить для решения конкретных задач.
- Объектно-ориентированные языки — это в принципе не всегда лучшее решение.
Функциональное программирование как альтернатива
В свою очередь, функциональное программирование — это совершенно иной образ мышления. Заглянем в Википедию:
«Функциональное программирование — раздел дискретной математики и парадигма программирования, в которой процесс вычисления трактуется как вычисление значений функций в математическом понимании последних».
Функциональные языки в отличие от объектно-ориентированных Ruby и JavaScript предлагают совершенно иной подход к решению задач. Изучение этого подхода позволяет приобрести новые знания, которые будут недоступны, если постоянно находиться в комфортных условиях уже знакомых языков программирования, убежден Лэйн.
Clojure работает на сервере
Возьмем описание работы языка с сайта Clojure.org:
«Clojure достигает своих целей, четко следуя стандартам индустрии и используя открытую платформу JVM. Это модернизация хорошо знакомого Lisp. Он обеспечивает функциональное программирование стабильными и устойчивыми структурами данных. Предоставляет встроенную поддержку многопоточного программирования с помощью софта для транзакционной памяти и асинхронных агентов. Clojure — это быстрые и надежные решения ваших задач».
Итак, Clojure работает на виртуальной машине Java (JVM), а значит, обладает несомненными преимуществами, которые предлагает этот инструмент:
- высококачественный сборщик мусора;
- высокопроизводительные встроенные потоки;
- портативность.
Clojure можно использовать везде, где необходимы современные эффективные стабильные структуры данных. Он также вводит новую модель многопоточного программирования с core.async. И потом, сейчас разработаны многие другие полезные библиотеки для логического программирования, сопоставления по образцу, option-типов и многое другое, в чем не лишне было бы попрактиковаться.
Clojure работает в браузере
Еще одна цитата. Вот как описывает преимущества языка ClojureScript Wiki:
«Платформа для разработки с хорошей портативностью, широким охватом и мульти-вендорной поддержкой. Проработанный инструментарий для создания более качественных и надежных приложений, совместимый со всеми новыми устройствами».
ClojureScript легко компилируется в JavaScript и запускается в браузере. Все это обеспечивает совершенно новый подход к созданию клиентских приложений. В сообществе разработчиков JavaScript по многим причинам недолюбливают. Clojure же можно назвать вполне самостоятельным отпрыском Lisp, удобным, лаконичным языком с отличной асинхронной поддержкой, пишет Лэйн. Он может взаимодействовать с другими библиотеками JavaScript. Это позволяет использовать один и тот же язык для клиентской и серверной части, избегая ненужных жертв и потери времени.
Обеспечение полного сохранения текущих состояний (statefullness) в приложениях для клиентов – штука непростая. И пока JavaScript-фреймворки (например, React или Ember) только подступаются к этой проблеме, стоит задаться вопросом – а не сменить ли кардинально сам подход? Возможно, найдется язык в пару к одному из этих фреймворков, способный научить нас лучше управляться с подобными сложностями.
Безусловно, не существует универсального инструмента, который бы подходил для решения всех типов задач. Однако тот факт, что Clojure можно использовать «по обе стороны баррикад» клиент-серверного взаимодействия — его несомненное преимущество.
Игра на опережение
Лэйн цитирует также великого хоккеиста Уэйна Гретцки:
«Как у меня это получается? Я просто всегда стараюсь быть там, где в следующее мгновение окажется шайба, а не там, где она уже побывала».
Clojure позволяет заполнить некоторые пробелы в процессе создания специфических типов приложений. Тех из них, которые нуждаются в высокой скорости обработки больших объемов информации. Эра многоядерных процессоров уже давно началась, но большинство традиционных языков программирования до сих пор не приспособлено к такой архитектуре, убежден Лэйн. Функциональное программирование способно снять эту проблему при написании софта. Clojure обладает всем необходимым инструментарием, для того чтобы позволить программистам эффективно работать с большими массивами данных. Фактически, упорядочивать и преобразовывать данные можно в режиме реального времени.
Без лишней инновационности
В мире технологий иногда возникают вещи настолько передовые и новые, что польза от них не очевидна — хоть когда-то в будущем и может быть существенной — а применение несет в себе большие риски. Для обозначения таких технологий придумали специальный термин — «bleeding edge». Работать с ними комфортно только любителям всего нового.
Clojure нельзя отнести к технологиям переднего края, стабильность работы которых находится под вопросом. Релиз языка состоялся более 5 лет назад, и новый инструмент получил вполне доброжелательные отзывы в сообществе разработчиков. Поэтому самое время познакомиться с ним поближе, не опасаясь подвергнуть себя рискам первопроходцев, считает Лэйн.
Фундамент Clojure — хорошо знакомые технологии, например та же JVM, работа над которой ведется более 15 лет. Поэтому, работая с Clojure, можно использовать и все высококачественные библиотеки Java, существующие на данный момент.
Любопытство — двигатель прогресса
Ну, и самый последний аргумент «за» изучение Clojure — это любопытство и желание узнавать нечто новое. Всегда есть желание быть на передовой, владеть и уметь обращаться с лучшими технологиями на рынке. Clojure идеально подходит для этих целей. Всегда интересно ставить перед собой новые задачи. А находить для них решения – ни с чем не сравнимое удовольствие.
Сейчас в Латере мы используем Clojure выполнения команд по управлению оборудованием. Специфика задачи заключается в требованиях к одновременности при исполнении команд и гибких ограничениях. С одной стороны нельзя «завалить» одно устройство командами, с другой стороны — исполнять все команды последовательно неэффективно, потому что они могут параллельно исполняться на различном оборудовании. Эта задача с легкостью решается библиотекой core.async, которая добавляет поддержку go-блоков и каналов, знакомых по языку Go, где с помощью них реализованы взаимодействующие последовательные процессы (термин, больше известный как CSP).
При этом Сlojure — язык общего назначения, найти ему применение не составляет большого труда. Так как он базируется на JVM, то для него уже фактически существует огромный выбор библиотек, поэтому при его использовании не нужно писать все заново, что сильно снижает порог входа.
Даже если вы на дух не переносите Lisp, вам стоит ознакомиться с концепциями, которые заложены в язык, многие из них заставляют по-новому взглянуть на программирование.
Комментарии (32)
wombtromb
03.04.2016 00:36+7с помощью софта для транзакционной памяти
Звучит очень коряво. Software transactional memory, SТМ, по-русски, обычно называют программная транзакционная память. Не мог не откомментить.
lybin
03.04.2016 10:20+1Статье имхо более подходящее название: "Мнение: Почему стоит уходить с Ruby и RoR на Clojure" :)
getElementById
08.04.2016 15:05Переходить можно с чего угодно, на что угодно. Не нужно быть адептом технологий, нужно знать инструменты. Но в вашей идее есть доля правды: разработчики на RoR зачастую оказываются в ловушке фреймворка, поэтому выход за пределы им «наносит» большую пользу.
PerlPower
03.04.2016 12:40+1Что меня смущает в ClojureScript так это то что несжатый helloworld на нем весит больше мегабайта, в ужатом и гзипнутом виде меньше 100 кб. Ну да ладно, его можно ужать и при росте объема полезного кода поверх рантайма ClojureScript рост размера будет не таким уж серьезным. Но это полбеды, ClojureScript хорош если вы пишите серьезную логику на клиенте, где структуры данных языка и его остальные возможности вам что-то упростят, но если вы как и большая часть людей вокруг делаете фронтенд из кусков всяких фреймворков и компонентов, то есть вероятность что вы просто устанете бороться с тем, что все эти куски заточены под языковые особенности JS а не ClojureScript.
Вот 2 примера кода на ClojureScript и Javascript которые делают одно и то же с использованием фреймворка KnockouJS:
(ns hello-clojurescript) (defn app-view-model [] (this-as this (set! (.-firstName this) (.observable js/ko "Bert")) (set! (.-lastName this) (.observable js/ko "Bertington")) (set! (.-fullName this) (.computed js/ko (fn [] (str (.firstName this) " " (.lastName this))) this)) (set! (.-capitalizeLastName this) (fn [] (.lastName this (-> this .lastName .toUpperCase))))) nil ) (.applyBindings js/ko (app-view-model.))
function AppViewModel() { this.firstName = ko.observable("Bert"); this.lastName = ko.observable("Bertington"); this.fullName = ko.computed(function() { return this.firstName() + " " + this.lastName(); }, this); this.capitalizeLastName = function() { var currentVal = this.lastName(); this.lastName(currentVal.toUpperCase()); }; } ko.applyBindings(new AppViewModel());
SerCe
03.04.2016 16:07Так стоит использовать идеоматичные фреймворки, обычно react-based
https://reagent-project.github.io/
https://github.com/omcljs/om
tkukushkin
03.04.2016 17:44Для ClojureScript есть библиотеки, исполняющие роль «прослойки», такие как Reagent, Om итп.
atc
03.04.2016 17:46Функциональные языки в отличие от объектно-ориентированных Ruby и JavaScript предлагают совершенно иной подход к решению задач.
Но когда JavaScript успел стать объектно-ориентированным, позвольте спросить? Скорее его можно назвать мультипарадигменным, так как он включает неплохой набор инструментов как для функциональной парадигмы, так и для прототипной\объектно-ориентированной.
l27_0_0_1
03.04.2016 17:46+5Почему бы не Elixir?
1) Функциональный
2) Работает в проверенной временем и быстрой Beam VM, как бонус простая и эффективная многопоточность
3) От одного из core разработчиков рельс
4) Phoenix — прекрасный web framework похожий на рельсы, но имхо намного круче
5) ОЧЕНЬ быстрыйgrossws
03.04.2016 21:35простая и эффективная многопоточность
Эффективная — спорно, копирование из кучи в кучу на каждый чих — довольно дорогая операция. Мне куда более импонирует использование immutable-объектов для межакторного взаимодействия, как это делается в akka.develop7
03.04.2016 22:51намекаете ли вы, что в рантайме возрастом 30 лет ничего подобного нет?
grossws
04.04.2016 00:43По тому, что я читал раньше, beam копировал данные из кучи в кучу при отправке сообщений.
Посмотрел на актуальные статьи (2015), пишут что это осталось справедливым для мелких объектов (до 64 байт), что даёт небольшие накладные расходы на копирование. А сообщения с большими объектами содержат только указатель на объект, который хранится отдельно. Так что, сейчас реализация вполне может быть достаточно эффективной.develop7
04.04.2016 10:25«Сейчас», ха. Binaries впилили в BEAM VM в 1995-1996.
grossws
04.04.2016 12:44+2Ну извините. Спеки, которой соответствует beam'а (в отличии от jls/jvms) я не видел, насколько понял её просто не существует. И в куче разных статей про erlang, написанных в нулевых-десятых годах видел упоминания, что при отправке сообщения оно копируется в кучу процесса-получателя.
В erlang efficiency guide написано:
All data in messages between Erlang processes is copied, except for refc binaries on the same Erlang node.
В общем, я в некоторых сомнениях. Если сможете — ткните на какой-нибудь источник или место в исходниках, где описано, что большие сообщения автоматически конвертируются в binaries. В актуальных исходниках R16B03copy_struct
не копирует refc binaries, как и написано в efficiency guide. В erl_message.certs_send_message
используетcopy_struct
. Всё выглядит так, будто сообщение копируется вне зависимости от размера, а binaries используются явно.develop7
04.04.2016 14:19-1Если сможете — ткните на какой-нибудь источник или место в исходниках, где описано, что большие сообщения автоматически конвертируются в binaries.
Автоматической конвертации нет. Но и ваше «копирование из кучи в кучу на каждый чих» несправедливо в случае binaries, которыми пользуются чаще, чем может показаться стороннему наблюдателю.
getElementById
08.04.2016 15:11Библиотеки. Вы же понимаете, что на джаве их больше, а мы тут биллинг делаем. Это все-таки энтерпрайзненько, хоть мы и стараемся не увлекаться.
Saffron
03.04.2016 17:46+2Огромное количество пустых высказываний в духе «никогда не поздно узнавать новое», но самый главный секрет так и не открыт — чем clojure лучше старого доброго вполне зрелого common lisp
anjensan
05.04.2016 11:44Многие считают (я тоже склоняюсь к этому мнению), что Clojure не совсем и лисп. Так что сравнивать напрямую их не совсем корректно.
А так то кложа намертво привязана к платформе. Например, долго не было функций для работы со строками — мол используйте методы java.lang.String. Такой подход дает и плюсы, и минусы. Из минусов, постоянно придется деражать в голове то, что мы работаем под JVM (как таковой абстракции над ВМ нету). Зато интеграция с другими JVM языками прозрачна и легка. Ну и возможности JVM при должном умении можно использовать на всю катушку.
Ну и кложа более ФП-ориентированная — все такое прям неизменяемое и дружелюбное к concurrency.
pav5000
03.04.2016 23:17Есть еще Хаскель ведь, там плюсом статическая типизация, правда, без jvm, но зато рекурсию можно нормально использовать и скобочки на клавиатуре не сотрутся. Хаскельскрипт тоже умеет компилиться в js.
nehaev
04.04.2016 12:51Пожалуй, наиболее близкий вариант на JVM — это Scala. Функциональный язык со статической типизацией, нормальной рекурсией и трансляцией в js.
IvanPanfilov
kotlin лучше
SerCe
Эм? Языки из разных миров, совсем.
solver
Не обращайте внимание на таких, это обычная толстота…
IvanPanfilov
как из разных?
оба крутятся на jvm, и под js kotlin будет скоро тоже
так что кложа остается неудел
и это никакие не «новые технологии» это уже прошлое
anjensan
Толще надо быть, толще.
А по теме, как минимум static vs dynamic typing. Вам этого мало?
vdonich
Так не Лисп же.
[сарказм офф]