В последнее время появляется все больше и больше разных библиотек для создания сложных приложений на js. Оценить масштаб бедствия можно по замечательному сайту TodoMVC, на которой создатели библиотек выкладывают реализации одного и того же приложения, по одной и той же спецификации, но каждый с использованием своего детища для того, чтобы библиотеки можно было бы сравнить между собой на «реальном» примере.
В серии статей я постараюсь сравнить AngularJS (by Google), Knockout, React (by Facebook), RxJs (by Microsoft), Elm и reactive.coffee. В процессе этого я сделаю акцент на идею в основе каждой библиотеки, её происхождение, интересные детали реализации и естественные ограничения. Сравнивать их я постараюсь не на прямую, а оценивая каждую библиотеку с точки зрения composability (возможности к композиции), сложности библиотеки и сложности задач, которые можно решать.
Прежде, чем начать сравнение, я предлагаю окунуться в историю web-приложений, чтобы понять, откуда и для решения каких задач, появились подходы, которые мы сейчас используем. Кроме того, тот, кто не знает историю, обречен повторять ошибки прошлого.
Краткая история web-приложений
Всю историю web-приложений можно описать как стремление сохранить простоту инструментов при постоянном росте сложности задач.
Вначале не было никаких приложений, были только статические документы. Но вместе с ними появились задачи, для решения которых необходима была динамика, например, отделять контент от верстки и хранить его в удобном для манипулирования виде (в базе) или генерировать содержание (меню) и другие вычисляемые элементы документов.
Очевидное решение — CGI скрипты. При HTTP-запросе запускалась программа, которой передавались параметры запроса в виде аргументов. На вывод программа выводила документ, который, в свою очередь, отдавался пользователю.
К сожалению, такой подход оказался несостоятельным, так как сложность инструмента (полноценный язык программирования) была сильно больше сложности задачи (заменять плейсхолдеры в документе на контент из базы); в такой ситуации не удивительно, что скоро появился инструмент попроще.
В основе нового инструмента была идея вкраплять в документ вызовы функций, результат выполнения которых вставлялся бы в документ по месту их вызова. Так появился PHP.
Со временем, сложность продолжала расти, появилась потребность в приложениях, и динамические документы не подошли для данной задачи. Для борьбы со сложностью была предложена идея отделить прикладную логику и данные от представления. Так родилась тройка: код, данные и шаблон (язык для описания преобразования данных в представление). Как и в случае с cgi сложность инструмента возросла, но в отличие от него, она не была отвергнута, так как сложность инструмента росла медленнее, чем сложность задачи.
Теперь отвлечемся немного и заметим, что в истории web-приложений, как, вероятно, и в любой другой истории есть место трагедии. На заре web'а подход к включению разметки в код был заклеймлен (что на тот момент было верно), но затем, когда сложность задач выросла, про него не вспомнили, а придумали кое-что похуже. О чем я? Естественным путем к решению проблем является принцип «разделяй-и-властвуй»: для борьбы со сложной задачей (сложным интерфейсом) мы разбиваем её на независимые маленькие задачи, решаем их и через композицию собираем общее решение. В случае включения разметки в код, за композицию интерфейса отвечали бы привычные средства композиции host языка, такие как композиция функций или композиция объектов, но, следуя стереотипу о том, что разметка в коде это плохо, были придуманы шаблоны. Что такое шаблон? Это нечто, что очень стремится стать ЯП для решения задач композиции (циклы, вычисления выражений есть явно, а также include шаблонов в шаблоны, что есть не что иное, как замаскированный вызов функций), но создатель не может позволить этому случиться ввиду самоцензуры «разметка в коде это плохо». В этом и заключена трагедия: мы не можем использовать разметку в коде, так как это плохо, поэтому мы используем шаблоны, но шаблоны не могут решить нашу задачу достаточно хорошо, потому что тогда они были бы уже ЯП и мы бы от них отказались, так как разметка в коде это плохо:) Следовательно, мы сознательно используем несовершенные инструменты, и, как следствие, держим в голове, помимо целевого языка программирования и языка разметки, еще и язык шаблонов.
Еще замечу, что предубеждение против композиции решения задачи средствами языка (разметки в коде) есть только у web-разработчиков. Производить логическую декомпозицию сложной интерфейсной задачи и композицию решения средствами языка абсолютно естественно для desktop программистов.
Продолжим. В то время, пока шаблоны балансировали на граня ЯП/не ЯП, сложность приложений повысилась еще раз. В 2005 появился AJAX и задача создания приложений легла на плечи javascript. Тогда сложные приложения создавались гигантами вроде Google (gmail), но со временем этим стало заниматься все большее количество людей и компаний. И это приводит нас к ответу на вопрос, почему в последнее время появляется все больше и больше разнообразных библиотек для создания gui.
Очевидно, что применять серверный подход к построению интерфейса на клиенте не верно, так как шаблон на сервере отрабатывает моментально отдавая статический документ, а js приложение живет длительный промежуток времени, следовательно нужно попытаться адаптировать серверный подход для клиента или сменить его. При попытке адаптировать шаблоны (шаблон сам по себе источник трагедии и шизофрении) к продолжительному времени жизни (двухсторонний биндинг) произошел очередной скачек сложности инструментов, который превзошел сложность решаемой задачи, подобно тому, как это ранее случилось с CGI и динамическими документами. Этот скачек сложности создает нишу, которая стремится быть заполненной. Получается, что сейчас мы находимся на пороге появления нового «PHP».
В следующей статье я попытаюсь выделить подходы популярных (или новых) js библиотек и классифицировать их. Препарации будут подвержены AngularJS, Knockout, React, RxJs/Bacon.js, Elm и reactive.coffee.
Автор: shai_xylyd