EaxCast S02E05 — интервью с Никитой Прокоповым о Clojure, ClojureScript, а также реактивном программировании

16 июля 2014

Темы двенадцатого выпуска: все, что вы хотели знать о Clojure и ClojureScript, но боялись спросить, с чего начать изучение Clojure, кто истинный наследник языка Lisp — Clojure или Haskell, что такое гомоиконность, как по скорости дожать Clojure до уровня Java, реактивное программирование и React, отличия виртуальной машины Erlang-а от JVM, а также какие чудеса позволяют творить макросы в Clojure. Предыдущие выпуски: одиннадцатый, десятый, девятый, восьмой.

Слушать онлайн:
http://eaxcast.podfm.ru/_eaxcast/12/

Скачать файл:
http://eaxcast.podfm.ru/_eaxcast/12/file/podfm_eaxcast__eaxcast_205.mp3

Шоу нотес:

Голоса выпуска: Никита @nikitonsky Прокопов, Сергей @kpy3 Елин, Александр @afiskon Алексеев

Фоновая музыка: The Panets — Winter Beats (Big Power Mix)

 

Александр: Всем привет! EaxCast, второй сезон, пятый выпуск. Я afiskon, это kpy3.

Сергей: Привет.

А: И в гостях у нас Никита Прокопов, также известный, как tonsky.

Никита: Привет.

А: Привет. Расскажи нам о себе.

Н: Живу в Новосибирске, работаю в Новосибирске, программист. Насколько подробно рассказывать?

С: Продолжай.

А: Мы внемлем.

Н: Занимался Java-й долгое время, потом разными эзотерическими языками, типа Питона, Фантома, Erlang-а. В какой-то момент перешел на Clojure и сейчас наиболее активно занимаюсь Clojure, как раз. У меня был проект на Clojure, у меня были курсы по Clojure, блог про Clojure и тд.

С: Как интересно, ты с Erlang-а перешел на Clojure?

Н: Да.

С: Можешь поподробней рассказать? С чем это было связано?

А: Начни с того, что за проект у тебя?

Н: Это была компания Echo, у них был массивный такой, как бы сервис, что называется at scale, по сервингу комментариев. На самом деле, это платформа, на которой строились комментарии, фотогалереи и тд, для всяких крупных медиа издательств, типа Wall Street Journal, ESPN, Washington Post. Wall Street Journal наверно не было, что-то я запутался. Ну, в общем, такая мощная база данных, в которой можно делать запросы со страничек, ну и оформатить это как комментарии, дискуссии, посты, галереи, форумы, еще что-то. Такой большой конструктор.

Проект был на Erlang-е, у них все было относительно хорошо. Echo на правах стартапа просуществовала то ли 7, то ли 8 лет. Пережил две версии этот продукт. Вторая, как раз, на Erlang-е, и, в принципе, все работало. Когда я туда пришел, то какое-то время тоже им занимался. Потом появилась потребность сделать новый продукт, который занимается мониторингом социальных сетей, соответственно, там не было таких требований по совместимости, по переносу кодовой базы и тд. Можно было выбрать любой другой язык. У нас в тот момент возникло небольшое соревнование. Мы попробовали сделать прототип параллельно на Clojure и на Erlang-е. Собственно, на Clojure прототип по совокупности условий, не могу утверждать, что это именно Clojure так хорошо выступила, но, тем не менее, такое соревнование было. Clojure выступила чуть лучше. И в итоге мы решили продолжать на ней, попробовать, что получится. Ничего не получится? Ну, как бы, не страшно. Можно будет переделать обратно. Но, когда уже постепенно там увязли, все стало, в принципе, нормально, не подвела в общем-то.

С: Скажи, ты сейчас употребил слово «был» несколько раз, когда говорил про Echo. Я немножко напуган этим. Ты там больше не работаешь или это то, что я не хочу произносить?

А: Я сразу хочу предупредить, нам сказали, что эта тема, возможно, о которой нельзя говорить. Или можно?

Н: Ну, сотрудникам Echo нельзя, я уже не сотрудник Echo. Да, я какое-то время там не работаю, поэтому я в прошедшем времени о ней говорю. У них там сейчас дела продолжаются, на самом деле, люди там работают, но значительная часть оттуда ушла. Ну, опять же, я тут много не могу рассказать, потому что я даже чисто для себя не очень понимаю, в чем причины были того, что все начало, как-то так катиться под откос. Поэтому особо комментировать не буду. Меня периодически спрашивают, что случилось. Ну, я как бы, сам не знаю. Можно строить гипотезы, но, на самом деле конкретно что произошло не очень понятно.

А: У нас есть версия — чем хорошо вести подкасты, у тебя в послешоу очень интересные обсуждения. Но, раз нельзя, значит нельзя.

С: Почему в итоге ты выбрал Clojure? Чем она тебя так зацепила?

Н: На тот момент, как бы, сложно сказать. Я может под впечатлением от лекции находился Rich Hickey. На самом деле я, как раз с ними познакомился, не с Clojure познакомился, а с лекциями на тему разработки из гамака (Hammock Driven Development), Simple Made Easy и еще всякого другого. И, через то, что это были довольно клевые лекции, они общие, они не привязаны на самом деле к языку, ну и я в какой-то момент решил посмотреть, что же этот чувак сделал. Оказалось, что сделал прикольную штуку, и многие концепции, о которых он говорит, реализованы в Clojure достаточно хорошо. Вот такой простой язык в том смысле, что разные концепты перпендикулярные не намешаны в кучу и не связаны друг с другом внутри, а разделены и можно их использовать независимо. Типа там, в ООП неймспейсы и классы. Классы выполняют роль и неймспейсов, и объектов и еще чего-то. В Clojure неймспейсы отдельно, функции отдельно. И плюс там работа с состоянием, иммутабельность, и все дела, функциональное программирование. Как выяснилось, довольно полезные штуки, что позднее стало понятно.

А: А вот, в этом вашем проекте, какие библиотеки вы использовали? Я, например, знаю, есть в мире Clojure такая известная библиотека Compojure, если я правильно произношу, ну и тд. Вот можешь рассказать, с чем конкретно работали?

Н: Да, ну мы использовали, но там, как бы, никакого особо интересного ничего нет. Ну да, Сompojure, Ring — основа веб-стека Clojure, без них там вообще особо никуда не деться, там альтернатив особо нет. У Compojure есть какая-то альтернатива, но не столь популярная, ну она простые вещи делает, типа роутинг. У нас там всякие там, доступ к Redis, такие вот вещи, какие-то простейшие. Служебные библиотеки, как правило, обертки вокруг Java-вских библиотек. ZooKeeper у нас был тоже через какую-то обертку. В общем, ничего такого принципиального не было. Ну, и в какой-то момент, почти сделали поддержку Datomic — это база данных, написанная на Clojure. Но, не доделали, немножко не успели.

А: А я так понимаю, ты недавно вернулся из штатов? Если это не секрет, что было причиной поездки?

Н: Компания, в которой я сейчас работаю, Мachine Zone, она возила нас на обучение, на тренинг.

А: И у них там тоже Clojure?

Н: Нет, нет. Сейчас я уже не на Clojure пишу. Clojure-ский проект был у Echo, вот там все нормально, настоящий проект. Мы в продакшене использовали. Нет, а здесь другой, Python, Bash — в таком духе. Ну, и Erlang тоже немножко.

А: А в этом проекте на Clojure вы использовали вот этот модуль, который core.typed, который делает gradual typing?

Н: Мы пробовали его использовать в другом немножко проекте, у нас там был 20% time project, который мы начали пилить на Clojure, попробовали его использовать, но что-то, как-то не пошло. Я подробно не смотрел, но ребята когда пытались его использовать, в общем, поначалу хорошо, а потом они больше запутались, потому что там очень многие вещи приходится аннотировать, особенно внутренности там каких-то list comprehention и прочего. И это довольно сложно.

А: Вот, я немного далек от мира Java и Clojure, но у меня есть такое представление, что если тебе нужна строгая статистическая типизация или если по скорости немножко тебе Clojure не хватает, то проще написать код на Java и его заюзать. Это как-то соответствует действительности или не очень?

Н: Ну, в принципе, Clojure, код на Clojure можно дожать по производительности почти до кода на Java. Можно довести его до такого состояния, что он будет компиляться просто в идентичный Java код. Это делается с помощью type annotations — это встроено в язык, для этого не нужна библиотека крутая, более того, она не помогает в этом никак. Вот core.typed — просто для себя, для галочки, что у тебя все нормально. А type annotations — Clojure не типизированный язык, соответственно, если работать с Java-й из нее, вызывать Java методы на Java объектах, там используется reflection. Соответственно, reflection можно убрать, проаннотировав какой конкретно тип в данном месте имеется в виду. Где-то, какие-то вещи уже проаннотированы, в стандартной библиотеке, например, если ты открываешь файл, то она знает, что там результат будет — файл, а входной параметр — строка. Какие-то вещи в собственном коде можно также проаннотировать и в принципе получится по скорости та же Java.

Можно на Java писать, ну, не знаю, кто-то делает, кто-то не делает. Есть такая компания Prismatic они делают машин лернинг на Clojure. И они пишут, у них там 99.9% Clojure, несмотря на то, что у них там числодробление, и прочее, прочее. Они в Java почти не спускаются и довольно успешно. У них есть обертка для математических вычислений, которая сложности с type annotations внутрь как бы заворачивает, а снаружи она такая приятненькая, совсем Clojure, как бы. Ну, все вроде быстро работает.

А: Это интересно, я вот этого не знал. Я то сужу по синтетическим бенчмаркам на шутауте, поэтому да, я не знал, что так можно.

С: Скажи, а в продакшене с сервером на котором Clojure крутится работать приходится, как с Java, то есть java remote interface, там если что-то посмотреть, попрофилировать и тд? Или у него есть свои какие-то свои средства, там для горячего обновления кода, там какой-то remote shell аля Erlang или аналог какой-то? Как вообще это происходит? Вот у тебя есть сервер, там вот что-то случилось, надо посмотреть, что с ним.

Н: Ну, вообще да, он работает как Java-ский сервер, к нему можно подцепиться через консоль вот эту, как она там, JMX что ли называется или JMI? Java-ская консоль, где показываются всякие garbage collection, вот эта вся хрень, можно всякие снапшоты, хипдампы снять. Ну, обычное Java приложение.

У него есть поддержка REPL-а и можно приконектиться REPL-ом, его правда надо включить заранее, ну как бы, если его включить, то можно по порту туда постучаться и получишь REPL на тот процесс, который запущен на продакшене. Ну, а из REPL-а можно делать что угодно. Код загружать, обновлять, какие-то переменные смотреть, что-то еще можно посмотреть. Вот это все есть, но на самом деле, нам не особо это пригодилось, горячее обновление кода мы не использовали, потому что это все-таки процесс, который не так легко сделать правильно, потому что нужно стейт еще обновлять. Код-то ладно обновить, нужно еще как-то стейт мигрировать. Чтоб с этим мозг не греть, мы просто прибивали и запускали заново. И remote shell как-то по факту не особо пригодился, вот Java-ская консоль, да, пригождалась, мы мемори лики там искали, и так далее, и перформанс смотрели с помощью нее, да, использовали.

А: Ну, то есть, это встроенная фича языка, с определенным флагом собираешь приложеньку и у тебя remshell в ней?

Н: Нет, не с флагом, с библиотекой, nrepl.

А: Я просто знаю, что есть фреймворк Immutant, если я правильно помню, вот в нем, это, по-моему, как часть фреймворка идет. А то, что есть какая-то более легкая либа, я не знал, интересно. Слушай, а что на счет макросов? Вам как-то приходится какие-то DSL-и писать, как-то вот, ну знаешь типичный пример с ip адресами, когда ты берешь список ip адресов, парсишь и получаешь код, который тебе говорит, принадлежит ip диапазону или не принадлежит. Вот, какие-то такие вещи на макросах приходилось делать или так особо не пригождалось?

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

А: Если я не ошибаюсь, у Clojure есть биндинги, например к Akka и есть еще библиотека, сейчас я только вспомню ее название…

Н: Pulsar?

А: По-моему, да, Pulsar, с биндингами к Clojure, которая дает модель акторов, распределенщину и тд. С чем-то таким тебе приходилось работать или может просто смотрел?

Н: Я слышал про них, но мы их не использовали на самом деле. У нас обычные Java-ские треды были. Как бы, есть такая возможность, но нам хватило просто Clojure код и очереди сообщений между ними, вот и все, в принципе.

А: А с чем возникают проблемы, когда пишешь на Clojure? Вот, как бы, с чем реально приходилось сталкиваться?

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

А: А вот, у нас один из предыдущих гостей говорил, что у любого языка под JVM, у него обязательно торчат джавные уши и что там, по-любому будет null pointer exception. Как это, справедливо в отношении Clojure или не справедливо?

Н: Ну, да, есть там null pointer exception. А джавовские уши там не то, что торчат, Clojure изначально, как бы, by design, это язык, который хостится на какой-то платформе. Платформа может быть разная, и она и есть разная. Есть для JVM, есть для JavaScript. Но язык не скрывает платформу, он явно говорит, что вот она есть, что мы из платформы, допустим, берем экцепшены, базовые типы, мы своих не придумываем. У них есть хороший интероп, чтобы ходить в платформу, вызывать методы, и поэтому уши не то, что торчат, по сути, они явно декларируются.

А: А вот еще такой глупый вопрос, просто я совсем не специалист в Clojure. В Clojure есть, так называемые агенты. Я так понимаю, это что-то, с одной стороны, что-то вроде атомов, только асинхронные, с другой стороны, как такие недоакторы. Вот ты можешь объяснить, использовали ли вы агенты? И вообще, нужны ли они или это такой странный примитив, который там не понятно как появился?

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

Отличие от актора в том, что он не доступен по сети, ты можешь только локально с ним работать и у него чуть другая семантика. Потому что у агента, у актора у нас есть концепция, что все спрятано внутри, и актор может делать только то, чему его научили. Какие методы на нем определены, вот он их только может исполнять. В этом смысле актор — это классический объект в ООП понимании, это буквально объект из ООП. То же самое в, как там язык называется, SmallTalk, они точно также себя ведут. А агент — это стейт, в который можно кидать функции и он их будет исполнять над этим стейтом. И, естественно, результат будет складывать обратно в свой стейт. Его гарантия — это то, что он, во-первых, будет исполняться в отдельном потоке, а во-вторых, что будет исполнять запросы, которые к нему пришли, он их будет исполнять последовательно. Соответственно, функции могут быть любые, но он не ограничен теми функциями, которые заведены заранее в нем. Плюс, можно в любое время стейт посмотреть, он наблюдаем. У актора, чтобы посмотреть стейт, нужно писать специальную функцию, которая возвращает этот стейт, плюс нужно дождаться, когда актор будет свободен, чтобы тебе там ответить на твой запрос. А у агента это всегда доступно.

А: Да Сереж, какой у тебя был вопрос?

С: А у меня был вопрос про, на самом деле, Common Lisp. Вот скажи, ты, тебе очень нравится Clojure, да? И, в общем-то, не секрет, что эти два языка очень похожи. Приходилось ли тебе писать на Common Lisp, и если приходилось, то что? Какой у тебя опыт с этим языком?

Н: Нет, не приходилось, я сразу нормальному языку учился. Clojure — это мой первый Лисп, который я изучил.

С: А с чем у тебя связана такая нелюбовь к Lisp-у?

Н: Не то, чтобы нелюбовь, просто, как бы, он такой постарей, полохматей язык, чем Clojure.

С: То есть, ты хотел взять какой-то более современный диалект?

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

С: Скажи, а вот некоторые люди утверждают, что современный Lisp — это, на самом деле, не Clojure, а Haskell. Что ты думаешь по этому поводу и приходилось ли тебе писать на Haskell-е?

Н: Нет, на Haskell-е не приходилось. А у них есть там, REPL например? Можно код загрузить в работающее приложение или нет?

А: В Haskell-е нет горячего обновления кода, но есть REPL, да.

Н: Ну, не знаю. В каком смысле? Это явно какая-то метафора. Имеется в виду, что у Haskell-я есть какой-то аспект, присущий Lisp-у? Я просто не знаю, какой именно имеется в виду. Ну наверно не гомоиконность, да?

А: А что такое гмн… вот это вот странное слово, которое ты сказал? Объясни, пожалуйста.

Н: Ну, это значит, что код программы представлен базовыми структурами данных, структура данных и код записаны одним способом. С одной стороны это вызов функции, а с другой стороны это список просто. Соответственно, когда ты пишешь макросы, тебе не нужно отдельно учить API к AST компилятора, у тебя API — это те же функции манипуляции списками и коллекциями. Ты можешь добавить в хвост списка какой-то объект, это то же самое, что дописать к функции в конец аргумент. Ну, в таком духе. Можешь делать map и filter над кодом. Ну, в таком духе. Обход дерева.

А: Тут спорный момент, потому что в Haskell-е есть расширение, его пока не включили в стандарт, Template Haskell, но оно по факту уже почти везде используется. Там ты оперируешь не совсем списками, ты оперируешь AST, но, в целом, оно соответствует тому определению, которое ты дал.

В любом случае, вот ты говоришь, что начал учить Clojure. Расскажи, как ты ее изучал, и что ты посоветуешь нашим слушателям, которые жаждут изучить Clojure? Вот какие книжки почитать, статьи может там? Туториалы?

С: Ресурсы какие-то интересные, видео лекции, может быть даже те лекции, про которые ты упоминал ранее? Если они доступны публично.

Н: Ну да, я вот всем рекомендую лекции Rich Hickey, тем, кто собирается Clojure учить, не собирается Clojure учить, не важно. У него лекции больше про такой общий подход к написанию программ, систем и тд. Ну, кроме тех, которые там, явно на Clojure заточены. Если учить Clojure, то нужно книжку какую-то прочитать, наверное, и попробовать что-нибудь написать. У меня книжка была «Joy of Clojure», это считается как бы advance книгой, ее там желательно второй типа читать. Можно, мне кажется, и первой, если еще параллельно непонятные места где-нибудь смотреть, или если трудностей не боишься. Базовые книжки там тоже есть, называется одна «Programming Clojure», а другая «Clojure Programming» — это разные книги.

С: Как необычно. Оглядываясь на Erlang, где, в общем, это сплошь и рядом.

А: Кстати, «Clojure Programming», она переведена на русский и есть печатное издание от «ДМК-Пресс», вот она у меня прям, я ее сейчас в руках держу. Как раз хотел спросить, ты ее советуешь, или не советуешь?

Н: Ну, наверное, я не читал. Я не знаю, как можно введение в язык особо запороть, или хорошо сделать. Я думаю, пойдет. Все равно это нужно, чтобы с базовыми вопросами разобраться. А второй аспект, ну, вот у меня, когда я активно новые языки учил, у меня было два подхода. Я на Project Euler решал задачи. Берешь язык и начинаешь задачи на нем решать на Project Euler, и к задаче десятой уже более-менее ориентируешься, что там как делается. Они там простые, как бы, каждая задачка, так оно и нужно, пока ты вообще ничего не умеешь делать, тебе нужно просто какой-то код набрать своими руками и понять, как его вообще структурировать и запустить. Либо, вот у меня на Clojure, просто я начал проект, сделал чат ботика и достаточно удачно, потому, что я почти все концепции Clojure разобрал, включая многопоточность, всякие примитивы по синхронизации и бла, бла, бла. Да, довольно удачный получился проект. То есть, что-нибудь пописать.

С: Прости, ты сказал чат ботика?

Н: Да.

С: Это что? У меня мозг сразу перевернул эти два слова наоборот, то есть, ботик для чатика. А что такое чат ботика?

Н: Чат бот, бот для чата.

С: А, то есть, у меня мозг правильно это понял.

А: IRC или ICQ, или что?

Н: Campfire там был, по-моему, и консольный интерфейс еще был у него. У нас запчасти переключались за счет… в Clojure есть мультиметоды, на мультиметодах получалось сделать такого, как бы, куски реализации и в runtime-е можно собрать бота, у которого интерфейс к чату один, интерфейс, допустим, запоминания memory слов другой, интерфейс, там, какой-то еще, общения — третий. Короче, такие штуки переключались, и можно было в runtime-е это все собирать. Я пытался потом придумать, как это в ООП сделать, получалось не так просто.

А: А вот, SICP, например, годный учебный материал по Clojure или так себе?

Н: Не знаю, но наверно годный, как бы, это известная книжка. По-моему, даже есть Clojure версия его или хотя бы частично она есть. Вроде, начинали ее портировать на Clojure, но я не знаком, не знаю.

А: Я о таком не слышал. А в чем ты пишешь, под какой операционкой сидишь, там IDE? Что там у тебя, Git или Mercurial?

Н: Под Mac OS. У меня уже достаточно давно Mac OS, ну как, достаточно давно, ну да, достаточно. Вот, я сначала в Sublime Text писал, что считается не очень удобным, но, в принципе, достаточно удобно. Никаких проблем особо нет, кроме того, что нужно консоль запускать отдельно в терминале. А потом перелез на Light Table, когда они его более-менее допилили, он сейчас вполне юзабельный.

Вот, и в Light Table — это такая IDE, тоже на Clojure написанная, на ClojureScript даже. Там основная его фишка в том, что можно делать live evaluation, то есть в Light Table коннектиться к REPL процесса, вы запускаете его и к evaluation кода прям, встроен в сам редактор, он inline результаты показывает. И это очень удобно, оно очень увеличивает скорость, время разработки. Я, как бы, про это слушал, но особо сам не пробовал. А когда попробовал, я теперь большой фанат этого дела, и очень страдаю, что Erlang-е, например, так нельзя. Надо будет как-нибудь это дело прорекламировать для тех, кто не знает. Аналогично почти можно собрать Emacs. Но я, как бы, Emacs не осилил до сих пор, и вроде, там немножко не так удобно будет это все выглядеть.

С: Скажи, насколько я понимаю, ты являешься фанатом Clojure, фанатом в хорошем смысле этого слова, может даже, правильней сказать, евангелистом языка. Вот, на твоей новой работе, я так понимаю, у тебя Clojure нет. Ты не пытался ее там продвигать или может, пытаешься?

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

С: Ну, ты готовишься.

Н: Конечно.

А: А расскажи про ClojureScript. Приходилось на нем, какие-то фронтенд скрипты писать или не приходилось?

Н: Да, приходилось. ClojureScript — это такой прикольный диалект Clojure, который запускается в браузере и работает в браузере. Пишешь Clojure код, компиляешь его в JavaScript файл. JavaScript файл подключаешь на страничку и у тебя все работает. Мы его использовали постоянно вместо JavaScript. Собственно, удобней, чем на JavaScript писать. У нас там была простейшая какая-то админка, у нас на 20% time проекте был тоже UI вебный, тут тоже его использовали. Это очень прикольно, потому что ты пишешь на той же Clojure, а Clojure — очень хороший язык, по сравнению с JavaScript это вообще космос. В основном поэтому. В этом я ее даже для мельчайших каких-то вещей, уже сейчас использую, которые, буквально десять строчек на JavaScript, проще на ClojureScript писать. Хороший такой язык.

Сейчас у них там отдельная история с React-ом. Тут недавно появился React, и всех убрал. И ClojureScript, там тоже пытается к нему как-то подступиться. И есть вот Om, который как биндинг для React-a, плюс, там немножко менеджмента стейта. Я написал для ClojureScript библиотеку DataScript, который импортирует in-memory часть Datomic базы данных в браузер. В браузере можно создать мини базу данных с простейшими индексами, и по ней делать какие-то запросы datalog-вские. Ну, это такой популярный оказался проект, у него куча звездочек на GitHub. Собственно, концепция такая, что для каких-то более-менее серьезных фронтенд приложений, можно стейт приложения хранить прямо в базе данных. Не мучиться по переменным, спискам, и каким-то словарям, а складывать это в базу данных и потом рисовать UI на основе запросов к этой базе данных. Такая концепция, которая, она еще предстоит, на самом деле, валидировать толком. Ну, такая перспективная штука. С React-ом тоже она вроде изящно комбинируется.

А: А, вот, для людей темных, как я, и может быть, Сережа тоже. Я, извиняюсь, что такое, этот ваш React?

С: Да, да, очень интересно.

Н: React — это Facebook-вская библиотека для вебного UI. Она в основном покоряет тем, что… Ну, как обычно пишется UI? Ты сначала пишешь код который тебе рендерит DOM, а потом на каждое событие ты пишешь код, который этот DOM меняет. Скрыть эту панельку, показать эту панельку, здесь добавить элемент списка и тд. А в React-e немножко другая концепция, ты пишешь функцию, которая из данных рендерит весь DOM. Там, на самом деле, не настоящий DOM, а псевдо DOM, ну, неважно. Ты пишешь ее один раз и она рендерит из стейта весь этот псевдо DOM. Соответственно, если стейт меняется, вызывается твоя функция и рендерится другой псевдо DOM.

После чего React вычисляет между ними дельту и делает в реальном браузере уже минимальные изменения, чтобы предыдущее состояние привести в последующее. Если ты делаешь обычным путем, у тебя получается N2 переходов, которые надо учесть. Если у тебя N стейтов, тебе нужен N2 переходов.

Любой стейт может перейти в любой стейт, и должен быть код, который из одного в другой переводит. В React-e убрана проблема перехода между стейтами. Тебе достаточно уметь генерить стейт с нуля, а между стейтами переключается за счет именно библиотеки. За счет этого удобно всякие штуки делать. Во-первых, меньше писать кода, и код понятней, потому что ты читаешь и видишь его линейно, из этого стейта генерируется такой-то DOM, все, никаких там хитростей нет. А, во-вторых, удобно переключаться там между стейтами, делать какой-нибудь undo допустим. Тебе не важно, как сейчас интерфейс выглядит, если тебе нужно перейти из стейта в X минус 5, который был 5 шагов назад, ты говоришь просто react, вызываешь свою функцию рендеринга на тех данных, и он тебе, соответственно, вычисляет тот DOM и сам вычисляет, как его перевести туда.

А: Это прикольно. Я смотрю вообще в мире UI всякие прикольные вещи происходят, чуваки там изобретают всякие реактивные программирования, как он там? RxJava или Java.Rx? Я их все время путаю. А это вот такой, альтернативный вариант, потому что здесь сразу у тебя есть, грубо говоря, данные, которые ты мэпишь во вью.

Н: Да, реактивное программирование, есть такая тема тоже и на самом деле, в клиентском программировании, в ClojureScript тоже, оно развивается активно. Но, пока не очень понятно, приведет она куда-нибудь или нет. Потому что там есть свои проблемы, у этого реактивного программирования. А React — это, мне кажется, уже состоявшаяся библиотека, причем это достаточно серьезная, очень серьезное явление уровня jQuery примерно. Вот такого плана. Революция в JavaScript. Она там всех покоряет, потому что вот эта штука, она получается очень быстрой. Всякие Angular и прочее, они, во-первых, громоздкие, а, во-вторых, не очень быстрые. А вот такая штука, она получается очень быстрой. Поэтому все потихоньку переписывают на React.

А: У меня для тебя есть вопрос, от нашего постоянного слушателя Василия Д. Василий Д предлагает обсудить отличия виртуальной машины Erlang-а от JVM. Ну, там, в таких моментах, как мутабельность, немутабельность, разделяемое состояние, немутабельное состояние. Вот ты, как человек, который и с JVM поработал и с Erlang-ом, как считаешь, в чем заключает наиболее важные отличия? И я на две минуты отойду, а вы тут пока пообщайтесь, ОК?

Н: Да, как бы, простой вопрос. В Erlang-е сборка мусора идет per process, а процесс это что-то, соответствующее примерно объекту в Java. Там сборка мусора у нас локально, каждый актер за собой подбирает мусор, соответственно, это наиболее быстрая и более дешевая операция. В Java сборка мусора глобальная, поэтому JVM знаменита своими паузами на garbage collection, которые уже все более и более ничтожные, но, как бы, ей все равно это припоминают. Ну да, мутабельность, понятно, в JVM есть мутабельность. В Erlang-е ее нет. Плюс вот эти все прикольные вещи, типа мессадж пассинга, это все встроено в Erlang-вскую машину, а в Java такого нет, там библиотеками и тд.

А, ну, как бы, основное отличие еще — легковесные потоки. В JVM легковесные потоки народ как-то прикручивает, но очень как-то с переподвыподверта, с переписыванием байт-кода твоего. Ты пишешь класс, потом говоришь делать в легковесный поток, он его разбирает, анализирует и там как-то меняет код, чтобы получились типа легковесные потоки. То есть, в Java тред — это реальный поток, в смысле, поток операционной системы. А в Erlang-е они легковесные, соответсвенно, счетчик инструкций, все дела, вытесняющая многозадачность внутри самой виртуальной машины. За счет этого в Erlang-е можно не думая плодить легковесные треды, а в JVM нужно думать, когда их плодить.

С: В самом Clojure есть какие-то средства контроля за этими тредами? Ну, чтобы, вот так вот, не напортачить, мягко говоря, бездумной работой с потоками, с распараллеливанием и тд?

Н: Ну, у них есть пул агентов. Если делать через агента вычисления, он, в принципе, лимитирован и там особо, трудно напортачить. Можно использовать обычные треды, но там это Java-вские будут треды и ими легко, в принципе, напортачить. Есть еще такая штука core.async — это такая библиотека, написанная достаточно недавно, которая приносит нечто подобное таким вот вычислениям в Clojure. На самом деле, это CSP (Communicating Sequential Processes), процессы, которые посылают сообщения друг другу через каналы. И она умеет делать легковесные блоки, которые могут парковаться, не занимать полностью тред, а парковаться, соответственно, передавать управление другим блокам. Вот таких блоков можно создать очень много, go-блоки, так называемые. И они могут, в принципе, параллельно сосуществовать и по мере появления данных, вот в этих каналах (каналы, грубо говоря — это очередь такая, in memory) что-то вычислять. Эта штука сделана на магии метапрограммирования, макросов. Ну, вот это на самом деле, наверное, самый адский пример использования макросов, который есть в Clojure.

Результат довольно впечатляющий, вот такая вот возможность, которая является, допустим, в языке Go — это фича языка, фича runtime. Здесь же она доделана, сделана как библиотека для Clojure. Этой штукой… Ну, я не знаю, у нее такая странная история adoption. Народ, может быть, и разнюхивает, зачем это нужно и как это использовать, но о таких супер популярных применениях я не слышал пока. В принципе, эта штука очень многообещающая, мне кажется, она найдет свое. Она, как бы, на самом деле, уровня приложения. Нет смысла строить библиотеки на ее основе, но вот на уровне приложения, это может быть удобным способом для организации. Когда внутри приложения нужно организовать разные потоки, объекты или еще что-то, юниты какие-то, которые между собой взаимодействуют.

С: Интересно. Скажи, а приходилось ли тебе работать с такой штукой в Clojure, как clojure.logic?

А: Core. Я вернулся.

С: Ну, да, простите, core.logic.

Н: Нет, не приходилось.

А: Ну, это, я так понимаю, чуваки сделали кусок Пролога для Clojure?

Н: Да, да.

А: Кстати, возвращаюсь к core.async. Ты, случайно, не знаешь, там переключение контекста, ну вот этот паркинг, происходит именно в момент когда ты в очередь что-то кладешь или читаешь, или… Когда именно это физически происходит?

Н: Да, когда делаешь какие-то операции с каналами.

А: Если я там, в цикле долго перемножаю матрички и ничего не делаю с очередями, то я, как бы, тред собой занял?

Н: Да, так не надо делать.

А: Ну, ОК. А, вот, один наш с тобой общий знакомый, он говорил, что ты любишь защищать всякие странные вещи и вообще тролль по натуре. Это правда или это все, как это называется… клевета?

С: Гнусные инсинуации.

А: Да, вот мы прямо боялись тебя звать. Думали, сейчас позовем Никиту, а он нас всех как затроллит. Ан нет.

Н: Ну, вы странные вещи пока не вспоминаете. Ну, как бы… Не знаю, если я защищаю какие-то вещи, обычно всерьез их защищаю. Может быть, манера ведения дискуссии, не прямолинейная немножко, но, в принципе, мессадж всегда вроде прослеживается.

А: Ну, Сереж, я считаю это повод позвать Сохацкого в подкаст.

С: Думаешь?

А: Ну, да. Почему нет? Я вот сегодня написал пост про то, что Java не кроссплатформенная, так что я теперь тоже тролль. Хотя, вот ты меня в реале знаешь, что я менее тролль, чем считаюсь.

С: Ну, да, кстати. Надо почитать комментарии к этому посту.

Н: А пост какой имеется в виду?

А: Там про иконку в трее.

Н: Про иконку в трее?

А: Я написал, что в Ubuntu она не прозрачная и выглядит как говно, и куча джавников сагрилось. Мне очень жаль, если я там ранил чьи-то чувства, но для меня, для джавника начинающего очень, действительно, не очевидно, когда ты в книжках по Java читаешь, что у тебя Java такая вся из себя кроссплатформенная, а потом выясняется что она совсем не такая кроссплатформенная, как в книжках написано. Ну вот у меня это реально вызвало шок, как у новичка. Может быть, для хардкорных джавников это вполне очевидно.

Н: Да, есть, на самом деле, поговорка, что Java не кроссплатформенная, Java — это просто отдельная платформа.

А: Вы слушали первую часть интервью с tonsky. Вторая часть интервью появится либо через пару дней, либо на следующей неделе, мы пока сами не знаем. Так что, подписывайтесь, следите за обновлениями и до следующего выпуска!

Дополнение: EaxCast S02E06 — Никита Прокопов, Lambda Architecture, Storm, ZooKeeper и ответы на вопросы слушателей

Метки: .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.