- PVSM.RU - https://www.pvsm.ru -
Вы применяете React [1] для создания пользовательских интерфейсов? Автор материала, перевод которого мы публикуем, говорит, что он тоже работает с React. Здесь он хочет рассказать о том, почему для написания React-приложений стоит использовать ReasonML [2].
React — это очень хороший инструмент для разработки интерфейсов. Можно ли сделать его ещё лучше? Для того чтобы улучшить работу с React, сначала надо понять его основные проблемы. В частности, проблему, у истоков которой лежит тот факт, что React — это JavaScript-библиотека.
Если присмотреться к React, то можно заметить, что некоторые из принципов, положенные в основу этой библиотеки, чужды для JavaScript. В частности, мы говорим об иммутабельности, о принципах функционального программирования и о системе типов.
Иммутабельность — это один из базовых принципов React. Мутации свойств компонентов или состояния приложения весьма нежелательны, так как подобное может привести к непредсказуемым последствиям. В JavaScript нет стандартных механизмов для обеспечения иммутабельности. Структуры данных делают иммутабельными либо придерживаясь неких соглашений, либо используя библиотеки наподобие immutable-js [4].
Библиотека React основана на принципах функционального программирования, так как React-приложения представляют собой композиции функций. Хотя в JavaScript имеются некоторые возможности функционального программирования, такие, как функции первого класса, функциональным языком программирования он не является. Если на JavaScript нужно писать хороший декларативный код, приходится прибегать к сторонним библиотекам вроде Lodash/fp [5] или Ramda [6].
А что не так с системой типов? В React имеется концепция PropTypes [7]. Её используют для имитации типов в JavaScript, так как этот язык, сам по себе, не является статически типизированным. Для того, чтобы пользоваться в JS выгодами статической типизации, опять же, приходится прибегать к сторонним инструментам, таким, как Flow [8] и TypeScript [9].

Сравнение React и JavaScript
Как видите, JavaScript не совместим с базовыми принципами React.
Существует ли язык программирования, который лучше JavaScript согласуется с React?
На данный вопрос можно дать положительный ответ. Этот язык — ReasonML [10].
В Reason реализована иммутабельность. Так как он основан на OCaml [11], функциональном языке программирования, соответствующие возможности также оказываются встроенными в Reason. В этом языке, кроме того, присутствует собственная система типов, подходящая для React.

Сравнение React, JavaScript и Reason
Получается, что Reason совместим с базовыми принципами React.
Reason — это не новый язык. Он представляет собой альтернативный, напоминающий JavaScript, синтаксис и набор инструментов для OCaml — функционального языка программирования, который существует уже более 20 лет. Reason был создан разработчиками из Facebook, которые уже использовали OCaml в своих проектах (Flow [12], Infer [13]).

OCaml
С-подобный синтаксис Reason делает OCaml доступным для программистов, которые знакомы с такими распространёнными языками, как JavaScript или Java. Reason даёт разработчику более качественную, в сравнении с OCaml, документацию, вокруг него сложилось постоянно растущее сообщество [14] энтузиастов. Кроме того, то, что написано на Reason, несложно интегрировать с существующими JS-проектами.

Reason
Основой Reason является OCaml. Reason имеет ту же семантику, что и OCaml, различается лишь синтаксис. Это означает, что Reason даёт возможность писать OCaml-код, используя JavaScript-подобный синтаксис. В результате в распоряжении программиста оказываются такие замечательные возможности OCaml, как строгая система типов и механизм сопоставления с образцом (pattern matching).
Взглянем на фрагмент Reason-кода для того, чтобы ознакомиться с его синтаксисом.
let fizzbuzz = (i) =>
switch (i mod 3, i mod 5) {
| (0, 0) => "FizzBuzz"
| (0, _) => "Fizz"
| (_, 0) => "Buzz"
| _ => string_of_int(i)
};
for (i in 1 to 100) {
Js.log(fizzbuzz(i))
};
Хотя в этом фрагменте используется механизм сопоставления с образцом, он остаётся весьма похожим на JavaScript.
Единственным языком, который работает в браузерах, является JavaScript, поэтому, для того, чтобы писать для браузеров на каком бы то ни было языке, нам надо компилировать его в JavaScript.
Одной из интереснейших возможностей Reason можно назвать компилятор BuckleScript, который берёт код, написанный на Reason и преобразует его в читабельный и производительный JS-код, кроме того, неплохо очищая его от неиспользуемых конструкций.

BuckleScript
Читабельность результатов работы BuckleScript придётся кстати в том случае, если вы работаете в команде, в которой не все знакомы с Reason. Эти люди, по крайней мере, смогут читать результирующий JS-код.
Код на Reason иногда так похож на JS-код, что компилятору вовсе не нужно его преобразовывать. Благодаря такому положению дел можно наслаждаться благами статической типизации Reason и писать код, выглядящий так, будто он написан на JavaScript.
Вот пример кода, который будет работать и в Reason и в JavaScript:
let add = (a, b) => a + b;
add(6, 9);
BuckleScript поставляется с четырьмя библиотеками. Это — стандартная библиотека, называемая Belt [15] (стандартной библиотеки OCaml [16] тут недостаточно), и привязки для JavaScript, Node.js и для API DOM.
Так как BuckleScript основан на компиляторе OCaml, компиляция оказывается очень быстрой [17] — гораздо быстрее чем у Babel и в несколько раз быстрее чем у TypeScript.
Скомпилируем с помощью BuckleScript вышеприведённый фрагмент Reason-кода, содержащий функцию fizzbuzz(), в JavaScript.

Компиляция Reason-кода в JavaScript с помощью BuckleScript
Как видите, JS-код оказался вполне читаемым. Выглядит он так, как будто написан человеком.
Программы, написанные на Reason, компилируются не только в JavaScript, но и в нативный код, и в байт-код. В результате, например, можно написать приложение на Reason и запустить его в браузере, на MacOS, на смартфонах, работающих под управлением Android и iOS. Существует игра Gravitron [18], написанная Джаредом Форсайтом на Reason. Её можно запускать на всех вышеупомянутых платформах.
BuckleScript даёт возможность организации взаимодействия [19] Reason и JavaScript. Это означает не только возможность использования рабочего JS-кода в кодовой базе Reason, но и возможность взаимодействия кода, написанного на Reason, с этим JavaScript-кодом. Как результате, код, написанный на Reason, легко поддаётся интеграции в существующие JS-проекты. Более того, в Reason-коде можно использовать JavaScript-пакеты из NPM. Например, можно создать проект, в котором совместно используются Flow, TypeScript и Reason.
Однако всё не так уж и просто. Для того чтобы использовать JavaScript-код или библиотеки в Reason, их сначала надо портировать с использованием привязок (биндингов) Reason. Другими словами, нам, для того, чтобы воспользоваться строгой системой типов Reason, нужны типы для обычного JavaScript-кода.
Если вам нужно воспользоваться какой-нибудь JavaScript-библиотекой в Reason-коде, сначала стоит обратиться к Reason Package Index (Redex [20]) и узнать, была ли эта библиотека уже портирована в Reason. Проект Redex представляет собой каталог библиотек и инструментов, написанных на Reason и JavaScript-библиотек с Reason-привязками. Если вам удалось найти в этом каталоге нужную библиотеку, её можно установить как зависимость и использовать в Reason-приложении.
Если же найти нужную библиотеку не удалось, вам придётся самостоятельно написать биндинги. Если вы только начинаете знакомство с Reason, учтите, что писать биндинги — это задача не для новичка. Это — одна из самых сложных задач, из тех, что приходится решать тем, кто программирует на Reason. На самом деле, это — тема для отдельной статьи.
Если вам нужен лишь некий ограниченный функционал какой-нибудь JavaScript-библиотеки, вам не нужно писать привязки для всей такой библиотеки. Сделать это можно только для необходимых функций или компонентов.
В начале материала мы говорили о том, что он посвящён разработке React-приложений с использованием Reason. Заниматься этим можно благодаря библиотеке ReasonReact [21].
Возможно, сейчас вы думаете: «Мне всё ещё непонятно — почему надо писать React-приложения на Reason». Однако мы уже обсудили основную причину использования связки React и Reason, которая заключается в том, что React лучше совместим с Reason чем с JavaScript. Почему это так? Всё дело в том, что React был создан в расчёте на Reason, или, точнее, в расчёте на OCaml.

Первый прототип React был разработан Facebook и был написан на Standard Meta Language (StandardML [22]), на языке, который является родственником OCaml. Затем React перевели на OCaml, кроме того, React перенесли на JavaScript. Сделано это было из-за того, что весь веб использовал JavaScript и, вероятно, неразумным было бы делать заявления вроде: «А теперь мы будем писать UI на OCaml». Перевод React на JavaScript себя оправдал и привёл к широкому распространению этой библиотеки.
Как результат, все привыкли воспринимать React в виде JS-библиотеки. React, а также другие библиотеки и языки, такие как Elm [23], Redux [24], Recompose [25], Ramda [6], и PureScript [26], способствовали популяризации функционального стиля программирования в JavaScript. А благодаря распространению Flow [8] и TypeScript [9] в JavaScript стала популярна и статическая типизация. В итоге парадигма функционального программирования с использованием статических типов стала главенствующей в мире разработки фронтенда.
В 2006 году компания Bloomberg [27] создала и перевела в разряд опенсорсных проектов компилятор BuckleScript, который преобразует OCaml в JavaScript. Это позволило им писать более качественный и безопасный фронтенд-код, используя строгую систему типов OCaml. Они взяли оптимизированный и очень быстрый компилятор OCaml и заставили его генерировать код на JavaScript.
Популярность функционального программирования и выпуск BuckleScript создали идеальный климат, который позволил Facebook вернуться к исходной идее React — библиотеки, которая изначальна была написана на StandardML.

ReasonReact
Они смешали семантику OCaml с синтаксисом JavaScript и создали Reason. Кроме того, они создали Reason-обёртку для React, представленную в виде библиотеки ReasonReact, которая обладает дополнительными функциями, такими, как инкапсуляция принципов Redux в компонентах с состоянием. Сделав это, они вернули React к его истокам [28].
Когда библиотеку React переводили на JavaScript, возможности языка подгоняли под нужды React за счёт создания различных библиотек и инструментов. Подобный подход, в частности, означает необходимость в большом числе зависимостей для проектов. Уж не будем говорить о том, что подобные библиотеки постоянно развиваются, и в них регулярно происходят изменения, делающие их новые версии несовместимыми со старыми. Как результат, разработчику приходится очень серьёзно и осторожно относиться к обслуживанию библиотек, от которых зависят его проекты.
Это добавляет дополнительный уровень сложности в JavaScript-разработку. Например, типичное React-приложение обычно содержит, как минимум, зависимости, которые можно видеть на следующем рисунке.

Зависимости типичного React-приложения
Вот какие задачи решают эти зависимости:
Теперь воспользуемся, вместо React для JavaScript, библиотекой ReasonReact. Нужны ли нам, при таком подходе, все эти зависимости?

Переход на ReasonReact
Проанализировав тот же список задач, которые раньше решались с помощью дополнительных средств, мы выясним, что все их можно решить с помощью встроенных средств ReasonReact. Подробности о них вы можете почитать здесь [29].
В приложении, подготовленном средствами ReasonReact, все эти и многие другие зависимости не нужны. Дело в том, что множество важнейших возможностей, которые упрощают разработку, уже включены в язык. Как результат — упрощается работа с зависимостями, и, по мере роста и развития приложения, эта работа не усложняется.
Всё это оказывается возможным благодаря использованию языка OCaml, которому уже более 20 лет. Это зрелый язык, базовые принципы и механизмы которого проверены временем и стабильны.

Если вы родом из мира JavaScript, вам будет несложно начать работу с Reason благодаря тому, что синтаксис этого языка похож на JavaScript. Если вы раньше писали React-приложения, перейти на Reason вам будет ещё легче, так как вы можете, при работе с ReasonReact использовать все свои познания в области React. В основе ReasonReact лежит та же модель , что и в основе React, процесс работы с ними так же очень схож. Это означает, что при переходе на Reason вам не придётся начинать с нуля. Вы разберётесь с Reason в процессе работы.
Лучший способ начать использовать Reason в своих проектах заключается в том, чтобы постепенно вводить в них фрагменты, написанные на Reason. Как уже было сказано, Reason-код можно использовать в JS-проектах, равно как и JS-код в Reason-проектах. Этот подход применим и при использовании ReasonReact. Можно взять ReasonReact-компонент и использовать его в традиционном React-приложении, написанном на JavaScript.
Именно такой вот инкрементальный подход был выбран разработчиками Facebook, которые широко использовали Reason при разработке мессенджера Facebook [31].
Если вы хотите написать React-приложение с использованием Reason и на практике изучить основы этого языка, взгляните на этот [2] материал, где пошагово разбирается разработка игры «Крестики-нолики».
У создателей Reason было два варианта действий. Первый заключался в том, чтобы взять JavaScript и как-то его улучшить. Если бы они избрали этот путь — им пришлось бы иметь дело с историческими недостатками JS.
Они, однако, избрали второй путь, связанный с OCaml. Они взяли OCaml — зрелый язык, обладающий отличной производительностью, и модифицировали его так, чтобы он стал похожим на JavaScript.
React тоже основан на принципах OCaml. Именно поэтому писать React-приложения гораздо легче и приятнее с использованием Reason. Работа с React в Reason предлагает более стабильный и безопасный подход к созданию React-компонентов, так как строгая система типов страхует разработчика и ему не приходится сталкиваться с большинством исторических проблем JavaScript.
Уважаемые читатели! А вы пробовали ReasonReact?
Автор: ru_vds
Источник [33]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/294565
Ссылки в тексте:
[1] React: https://reactjs.org/
[2] ReasonML: https://medium.freecodecamp.org/learn-reasonml-by-building-tic-tac-toe-in-react-334203dd513c
[3] Image: https://habr.com/company/ruvds/blog/424965/
[4] immutable-js: https://facebook.github.io/immutable-js/
[5] Lodash/fp: https://github.com/lodash/lodash/wiki/FP-Guide
[6] Ramda: https://ramdajs.com/
[7] PropTypes: https://reactjs.org/docs/typechecking-with-proptypes.html
[8] Flow: https://flow.org/
[9] TypeScript: https://www.typescriptlang.org/
[10] ReasonML: https://reasonml.github.io/
[11] OCaml: https://ocaml.org/
[12] Flow: https://github.com/facebook/flow
[13] Infer: https://github.com/facebook/infer
[14] сообщество: https://reasonml.github.io/docs/en/community
[15] Belt: https://bucklescript.github.io/bucklescript/api/Belt.html
[16] стандартной библиотеки OCaml: https://discuss.ocaml.org/t/what-is-the-preferable-solution-for-the-role-of-standard-library/1092
[17] очень быстрой: https://bucklescript.github.io/docs/en/build-performance
[18] Gravitron: https://github.com/jaredly/gravitron
[19] взаимодействия: https://en.wikipedia.org/wiki/Interoperability
[20] Redex: https://redex.github.io/
[21] ReasonReact: https://reasonml.github.io/reason-react/
[22] StandardML: https://en.wikipedia.org/wiki/Standard_ML
[23] Elm: https://elm-lang.org/
[24] Redux: https://redux.js.org/
[25] Recompose: https://github.com/acdlite/recompose
[26] PureScript: http://www.purescript.org/
[27] Bloomberg: https://www.bloomberg.com/company/announcements/open-source-at-bloomberg-introducing-bucklescript/
[28] истокам: https://news.ycombinator.com/item?id=15209704
[29] здесь: https://codinglawyer.net/index.php/2018/09/11/why-am-i-building-stuff-in-reasonml-and-why-should-you/
[30] мышления: http://www.braintools.ru
[31] мессенджера Facebook: https://reasonml.github.io/blog/2017/09/08/messenger-50-reason.html
[32] Image: https://ruvds.com/ru-rub/#order
[33] Источник: https://habr.com/post/424965/?utm_source=habrahabr&utm_medium=rss&utm_campaign=424965
Нажмите здесь для печати.