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

Предисловие

Я не понял.

Примерно в 2012 году эта штука под названием Clojurescript появилась на моем радаре через js weekly. Какие? Кто-то пытается сделать компилятор lisp-в-javascript? Это почти смехотворно; какой запутанный способ обработки кода на стороне клиента. Функциональное программирование прекрасно во многих контекстах и ​​областях, но клиентский браузер не входит в их число.

Это не сработает

Сама идея lisp-in-a-browser напомнила мне выступление на конференции, которое я когда-то посетил. Во время презентации несколько действительно ярких людей убедительно продемонстрировали мощь и чудеса функционального реактивного программирования. Они установили серию труб, фильтров, узлов, деревьев, стоков и стоков, которые творили чудеса с входными потоками и прекрасно обрабатывали потоки. В последние минуты презентации они перешли в демонстрационный режим и попытались использовать этот метод программирования для обработки событий в браузере. Все прошло не очень хорошо.

У трех докладчиков, каждый из которых был экспертом по FRP, потребовалось более 20 минут, чтобы получить <button> и <input> на странице, которая надежно принимала вводимые пользователем данные. Ой. Слои оберток, адаптеров и преобразователей сигналов оказались слишком глубокими. Докладчики наткнулись на исключения и неопределенные или нулевые ошибки. Было слишком много абстракций, которые нужно было приспособить к существующей среде, чтобы хоть что-то работало, и эти когнитивные издержки оказались слишком большими даже для экспертов.

Нет, спасибо. Я приклею к моему вкусу из месяца javascript фреймворка. Они намного проще, имеют массу полезных функций и мне знакомы. Черт возьми, если мне нужен транспилированный язык, почему бы не взять что-нибудь вроде CoffeeScript? Он сохраняет несколько нажатий клавиш, сглаживает некоторые грубые края javascript и вводит знакомые концепции, такие как классы и наследование. Важно отметить, что он очень легко взаимодействует с [фреймворком месяца], поскольку в конечном итоге это просто javascript в одежде Ruby.

По совпадению, я действительно какое-то время работал с CoffeeScript на своей обычной дневной работе. Он работал точно так, как ожидалось, и, оглядываясь назад, получил код, который был более или менее того же качества, как если бы я вообще не использовал транспилятор.

Время - забавная вещь

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

Среди этих экспериментов, блогов, учебных пособий, уроков, конференций, видео и дискуссий несколько драгоценных камней очень ярко сияли из-под груд грязи. Пожалуй, наиболее влиятельными жемчужинами стали знаменитые Simple Made Easy и The Value of Values. Хотя они были представлены в абстрактном виде, применимым к любому языку или системе, для меня было логичным следующим шагом проверить, с чем работал этот парень Рич Хикки. Конечно, эти фантастические идеи чисто академические и не могут быть надежно применены в реальном мире компьютерных систем, верно? Я не мог ошибиться больше.

Ниже приводится краткое изложение * некоторых * сверхспособностей, предоставляемых Clojure (скриптом), которые я оценил за последние три года регулярного использования.

Игрок 2 вошел в игру

Clojure - это действительно функциональное программирование. Вместе со всеми другими преимуществами функциональной парадигмы есть контекстно-свободное программирование. Это позволяет инженерам работать с небольшими частями системы в полной изоляции.

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

Clojure является выразительным по дизайну. Было сказано, что шепелявя, вы не пишете программное обеспечение; вы пишете язык, на котором собираетесь писать свое программное обеспечение. То же самое и с Clojure. Рассмотрим код ниже; сколько времени нужно, чтобы понять назначение функций? Подход и дизайн исполнителя? Сколько синтаксиса вам пришлось разобрать в своей рабочей памяти, чтобы во всем разобраться?

Простота лежит в основе всего, и сообщество поддерживает этого клиента. Основная единица информации в Clojure - это данные. Встроенная поддержка наиболее распространенных типов данных: карт {:house "stark"}, наборов #{:arya :ned :sansa}, списков ‘("winter" "is" "coming"), векторов ["winter" "finally" "arrived"] и ключевых слов :didnt-see-that-coming.

Библиотеки, системы и API-интерфейсы структурированы вокруг Data > Functions > Macros, что означает, что все составляется, просто используя данные для связи. Как правило, сторонние библиотеки хорошо «делают одно дело» и предоставляют простой API на основе данных. Вы можете построить дерево зависимостей, которое правильно соответствует вашему домену, вместо того, чтобы собирать вместе библиотеки, которые хорошо работают только с конкретными партнерами или «вроде» делают то, что вам нужно. Бонус - вам также доступна вся существующая экосистема java или экосистема javascript, в зависимости от платформы хоста.

Clojure чрезвычайно хорошо разработан. Это размещенный, динамический, функциональный язык общего назначения с неизменяемыми, постоянными структурами данных и надежной инфраструктурой для многопоточности. Язык небольшой (clojure.core составляет около 5 тыс. Локальных мест, или это просто уик-энд чтения), предлагает согласованные абстракции и всегда поддерживает обратную совместимость.

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

Недавняя тенденция в javascript - переход к постоянным структурам с помощью таких инструментов, как immutablejs. Неизменяемый javascript - отличный шаг в правильном направлении, за исключением того, что он создает пару действительно больших проблем: библиотеки предоставляют всеобъемлющий API, который требует целостного участия для приложения, а неизменяемые структуры не взаимодействуют с чем-либо, что также не является неизменным. структура (до свидания lodash, jquery или даже альтернативные неизменяемые реализации.).

Но подождите, можно сказать, мы можем использовать синтаксис ES6 / ES2017 для достижения неизменности! Да, вы можете создавать неизменяемые объекты с помощью новых операторов ... распространения или подобных Object.assign({}, {...old, new: true}) и правильного использования map/filter/reduce. К сожалению, он привнес в javascript еще один острый момент; не забывайте везде использовать неизменяемые операторы. Это нетривиальная задача, особенно когда вы говорите об обновлении индексированных массивов или объектов внутри массивов. Кроме того, теряются преимущества структурного разделения, поэтому ожидайте серьезных последствий для производительности.

Clojurescript стирает почти все беды и подводные камни javascript: несогласованные сравнения типов, правдивое / ложное несоответствие, проблемы с нулевым / неопределенным / NaN, непреднамеренное преобразование типов, мелкое или глубокое копирование, передача значений по сравнению с передачей ссылок , несогласованная проверка равенства и огромные таблицы приоритета операторов, и это лишь некоторые из них. Но просто в кастинге вы обживаетесь наказанием, взаимодействие с хостом проходит без проблем через (js/myFunction args) или (.myFunction js/myModule args). Вызов Clojurescript из javascript - это вопрос ^:export my-function, который предоставляет javascript my_namespace.my_function().

Инструменты Clojure великолепны. Разработка через REPL заслуживает отдельного поста. Просто знайте, что он обеспечивает немедленное выполнение кода под курсором (не требуется тестовых программ), немедленный поиск источника и документации, удаленное внедрение и отладка во время выполнения, а также немедленную обратную связь на всех этапах разработки. Leinengen предлагает строительные леса, строительство, упаковку и развертывание под одной крышей, что означает единообразие и практически полное отсутствие оттока инструмента. Фигвил проложил путь в будущее развития javascript. Монтировать, компонент или интегрировать предлагают возможности настройки / разрыва / остановки / возобновления работы системы во время выполнения. nREPL позволяет осуществлять прямую инъекцию в среду выполнения браузера. Инструменты отладки, такие как re-frame-10x, заставят вас почувствовать себя супергероем с рентгеновским зрением, совершенными знаниями и манипуляциями со временем. Кроме того, при необходимости вы можете обратиться к любым инструментам профилирования, отладки или мониторинга в экосистеме хоста, некоторые из которых были закалены в боях на протяжении десятилетий.

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

Clojurescript использует Google Closure Compiler. Плохо названный GCC выполняет чрезвычайно агрессивную оптимизацию javascript путем переименования, изменения, удаления мертвого кода и встраивания. Это полноценный оптимизирующий компилятор, который понимает среду выполнения javascript, тогда как другие инструменты оптимизации только анализируют и перемешивают AST. Рискуя отбросить чрезвычайно общие и спорные цифры, следует хорошее объяснение мощи GCC: исторически, если доставка javascript и jquery клиенту составляла 1x, Clojurescript плавал примерно в 2 раза. Но в последние несколько лет богатые веб-приложения требовали гораздо большего, помимо javascript и jquery. Благодаря мощности Clojurescript, который не потребовал увеличения количества библиотек, и GCC, он остался на уровне 2x. Между тем, сопоставимое решение javascript, состоящее из [фреймворка месяца] + движка рендеринга реакции + [дополнительных библиотек], достигло 4х.

Clojurescript также легко интегрируется с Библиотекой закрытия Google. По какой-то причине GCL не очень популярен, но он существует уже много лет и уже десять лет используется внутри компании Google в большинстве своих продуктовых линеек: поиск, Gmail, карты, документы, календарь, а также фотографии. Короче говоря, GCL - это отсутствующий std-lib для javascript; он заполняет пустоту, предоставляя стандартные реализации для дат, i18n, математики, стилей, строк, манипуляций с dom и многого другого. Части Clojurescript построены на основе GCL, и любая функциональность, не предоставляемая языком напрямую, находится всего в одном (:import goog.SomeClosureLibrary).

Наконец, опыт разработчиков Clojurescript с точки зрения эргономики, скорости доставки, расширяемости и соотношения количества ошибок и функций феноменален. Это в значительной степени отчасти связано с мощными библиотеками, включенными в функциональный неизменяемый язык. Реагент - это то, чем React надеется когда-нибудь стать. Re-frame - это простая, мощная, расширяемая, однонаправленная, единый источник истины, основанная на событиях система, которая как предшествует, так и превосходит возможности архитектур в стиле Flux / Redux. Библиотеки в целом имеют тенденцию быть одноцелевыми, свободными от зависимостей (или без зависимостей) и компонуемыми. В тех редких случаях, когда в экосистеме Clojurescript еще нет решения, достаточно просто проникнуть в экосистему узлов.

Учитесь на моих ошибках

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

Хотя с тех пор я превратился в яростно любопытного инженера, который приветствует нестандартное, меня беспокоит то, что я, вероятно, упустил много возможностей для изучения отличных идей. Я знаю, что обычно величие где-то прячется по краям. Безопасное плавание между строками корпоративные системы утомительны и ох, черт возьми, это безумие, непрактично и не стоит усилий - это не лучшее место для этого.

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

Куда пойти отсюда

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

Почему clojure (скрипт)
https://m.oursky.com/why-i-chose-clojure-over-javascript-24f045daab7e
https://wit.io/posts/clojure -взрослые
https://hackernoon.com/why-you-should-check-out-clojurescript-f31f64ac7d0e
https://juxt.pro/blog/posts /why-clojurescript-matters.html
https://sekao.net/blog/industry.html
https://www.youtube.com/watch?v=gsffg5xxFQI

Замечательные инструменты
https://github.com/Day8/re-frame
https://purelyfunctional.tv/article/react-vs-re-frame/
https://github.com/Day8/re-frame-10x
http://swannodette.github.io/2016/06/03/tools-for-gotit
https: //github.com/clojure/test.check

React Native
http://cljsrn.org/

Общие ресурсы
https://github.com/mbuczko/awesome-clojure
https://juxt.pro/index.html
https://github.com / matthiasn / Clojure-Resources
http://mattsears.com/articles/2009/06/06/20-clojure-links-to-get-you-up-to-speed/