Вы все еще помните, что речь идет о производительности?



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

  

С фреймворком понятно, очень сложно и запутано. А сам приложение? Полезли в код приложения.



Получается так, что в коде мало комментариев. Какие-то трудные места не объяснены. Все приложения жестко связаны. Вместо одного класса — длинного, на 2,5 тыс. строк, мы имеем дело обычно с тремя-четырьмя классами по 1000 строк, которые очень жестко знают друг про друга и так по кольцу, общаясь, пересылают себе события, меняют состояния внутри себя. И у нас внутри очень большие проблемы с границами между моделью и бизнес-логикой, и между бизнес-логикой и view. Получается так, что у нас есть view-классы, которые называются как-нибудь типа «волшебная реализующая определенный функционал панель», которая и одновременно отрисовывает себя и отрисовывает дочерние компоненты, и еще у нее до фига бизнес-логики, которая умеет переключать какие-то панели внутри, и которая умеет отсылать уведомления, даже зачастую они из view-классов лазят на сервер.



Поэтому (очень условно) получилось так, что у нас такой не mvc, а M+CV. Т.е. граница между контролем и view очень не определена. Получилось так, что и в моделях есть бизнес-логика, и в контроллерах есть бизнес-логика, и во view есть бизнес-логика, и UI логика, и состояние приложения тоже размазано по всем трем видам классов. Поэтому трудно, например, понять откуда пришли эти данные, или кто является авторитативной точкой, откуда эти данные взялись, и кто хранит на текущий момент самую достоверную копию этих данных, потому что она есть в нескольких частях приложения.



А еще получилось так, что сам фреймворк Ext JS всех очень толкает к архитектуре построенной на publish/subscribe, потому что, в принципе, у него все UI компоненты завязаны на этот механизм, и программисты невольно выбирают то, что предлагает фреймворк. И, вроде как, publish/subscribe — правильный паттерн, но когда ты начинаешь смотреть на приложение, в котором типа 100 страниц, в итоге получается, что ты пытаешься разобраться: «Блин, а к чему же приводит нажатие вот этой кнопки в этой панели, и что же она дергает?».



И выясняется, что, во-первых, события могут неявным образом попадать в родительские классы, которые, в свою очередь, генерят вторичные события, которые попадают в какие-нибудь классы с бизнес-логикой, которые в свою очередь генерят еще события. Затем часть событий игнорируется фреймворком, потом меняется какая-то модель, эта модель генерирует события о том, что «данные во мне поменялись». Появляется еще пяток классов, которые подписаны на ее изменения, и в себе меняют какое-то состояние, которое зависит от состояния этой модели.

В итоге, через три часа ты, наконец, строишь стройную картину и понимаешь, что у всех событий названия очень похожи, и везде есть onclick. И тебе нужно понять, это onclick от этой кнопки, которую ты нажал или onclick от соседней кнопки, которую ты нажал. Потому что фреймворк не запрещает подписку любого компонента на любой. Т.е. ты можешь добраться из кого-нибудь суперконтроллера до кнопки в конкретной панели и подписаться на нее onclick. И это будет просто onclick в кавычках. И такие дела очень трудно дебажить, потому что нет какой-то уникальной селективности этих компонентов. Т.е. там есть свой механизм, называется ComponentQuery, похожий на XPath, в котором можно написать RegEx-запрос, который тебе говорит: «Найди мне там все кнопки, которые вложены в определенную панель с определенным названием». Поэтому, когда ты пытаешься чего-то отрефакторить, очень трудно найти все, вообще, места, где мы реагируем на конкретное событие. Зачастую у нас это даже приводило к циклам событий, когда приложение зависает, потому что постоянно появляются дочерние события, оно начинает их обрабатывать, и этот цикл бесконечен. Пока ты не напишешь какой-нибудь хитрый if типа «если ко мне это событие уже приходило, я его не обрабатываю», то мы дальше его не обрабатываем. Т.е. речь идет о запутанной архитектуре.

Все нормально.



А теперь у меня большой вопрос. В коде крупных приложений с жесткой связанностью между логикой view, между размазанностью функционала по разным классам и очень плохим разграничением зон ответственности между языками, технологиями и прочим, чего обычно нет?



Вот так вот получилось. Причем непонятно, на самом деле, почему получилось. Потому что, на мой взгляд, могло быть лучше. Но, короче, объекты Arrays мы проверили, остальное — как получится. И вечная эта история про то, что когда ты начинаешь писать тесты, ты многое узнаешь про свое приложение, что на самом деле ни фига не надо было делать такое количество связей, потому что замокать 15 объектов ради вызова одной функции, очень геморройно. И в этом плане получили тесты «давай, до свидания».

Какие выводы? Как бы, вот такие, конечно, выводы…



Но на самом деле, настоящие выводы в чем?



Что фреймворк очень сложный для понимания разработчиков, особенно разработчиков, которые до этого не защищали докторскую диссертацию по Java. Во-вторых, код, который получился, очень запутанный. В нем очень много связей, все классы друг про друга знают, и события, которые появляются, никем не контролируются, и это приводит к фейерверко-образным взрывам изменения стейтов приложения, когда 15 мест подписаны на какой-нибудь стейт, события потом генерируют свои дочерние события, и еще какие-нибудь другие места начинают обрабатывать эти события… В этом плане фреймворк жутко асинхронный, и эта асинхронность взрывает мозг. Получается так, что компоненты правят люди, которые понимают одновременно язык шаблонизатора, намешанный JS-код, html, CSS и все это в одном файле. Обычного верстальщика нанять? Я не знаю… Сколько сейчас получает верстальщик? За 40-60 тыс. невозможно найти верстальщика и посадить его за простую рутинную работу «в этой панели убери эту кнопку», потому что сборка всего UI происходит в JS-коде методом созданий инстансов JS-классов. Т.е. ты описываешь большое дерево, какую кнопку в какую панель вложить, какие параметры передать, какие ссылки, на какие события потом подписаться.

Соответственно, главный мой вопрос был — виноват ли в этом фреймворк? На самом деле, конечно, виноват. Частично. Потому что он подталкивает тебя к publish/subscribe, потому что он подталкивает тебя к такому mvс, который они сами делают, псевдо mvc. Потому что в нем нет dependency injection из коробки, потому что он не говорит тебе, как тестировать это все дело…



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

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

Конечно, хочется менее связанную архитектуру, потому что тестировать это нереально, написать тесты для этого очень трудно. Поэтому хочется какой-то изоляции. Понятные микрокомпоненты, каждый из которых ответственен за свой маленький кусочек. И проще UI слой.



К чему главный посыл всей этой презентации (а это самый главный слайд) — что все ваши песни про производительность фронтенда превращаются в лапшевидный код, отсутствие стандартов и «мы наняли нового чувака, а он четыре месяца правит одну багу». Давайте сначала улучшим производительность разработчиков, дадим им в руки нормальные, а не гнутые инструменты, и они сделают код, который будет намного лучше работать, потому что эти задачи были решены на уровне фундамента. Т.е. мы будем стоять на плечах гигантов.

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

Конечно, я полез в Интернет. Ну, а что делать? Тут все бы полезли в Интернет.



Выяснилось, что за пять лет, пока я управлял и работал на PHP, в мире JS многое поменялось, в этом плане пришлось многое выучить заново.

  

И эти тысячи фреймворков, каждый из которых как две капли воды зачастую похож на друг друга, особенно во flux фреймворках — это прямо «придумай свое название точка JS». И из этого ада там, где Google Web Toolkit уже давно умер, надо как-то выбрать. Блин, что делать? Конечно, надо было что-то подумать, как бы посмотреть, как другие где-то что-то выбирают в Интернете, залезть и где-то спереть результат.

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



Именно про компании и сайты я оттуда слайды вырезал, остаются именно честные цифры. Это количество строчек кода, написанных вообще с момента появления Github на разных технологиях. Плюс-минус.



Это слайд рассказывает о том, сколько было докладов по каким технологиям на каких крупных конференциях, посвященных именно фронту, в 2015 году за рубежом.

И везде картинка разная.



На этой картинке тренд популярности запросов в гугле. Их тут несколько… Здесь, если присмотреться, видно, что все технологии идут на самом деле на спад, кроме React js и Angular js.



Если взять какие-нибудь старые более-менее фреймворки дипа Dojo, Yahoo ui и нашего любимого Ext js, то тоже все идет на спад. В этом плане с React js и Angular js никто не поборется, потому что это единственное, что идет вверх.

Мы дальше смотрели такое исследование, где 2,5 тысячи разработчиков было опрошено, каждый из которых выбрал одну технологию.



Это американская компания, которая делает и продает cloud IDE. Получилась вот такая картина, совершенно другая. Т.е. те разработчики, которые поддерживают продукты, у них еще силен, например, Backbone, который по большому счету устарел, но, тем не менее, есть много проектов на нем, которые еще доделывают.



А это уже российский рынок. Мы пытались оценить, кого же мы можем нанять, потому что очевидно, что мы не в космосе работаем, и нам нужно делать продукты в компании, продуктов много и планов — громадье, поэтому кого-то надо нанять. Здесь, вообще, картина другая. Выяснилось, что так или иначе с какой-то из версий ExtJS (поскольку он достаточно долог) и с какой-то из версий Backbone (поскольку он тоже родился в 2008 году) так или иначе кто-то имел дело. Т.е. это никакой гарантии не дает на то, что этот человек прямо сейчас готов чего-то делать realtime на этом фреймворке, но, тем не менее, выяснилось, что среди растущих технологий React js и Angular js, появились внезапно Backbone и ExtJS, причем вакансии по ним есть, и их достаточно много. Вакансий по Backbone больше, чем со знанием React. Вот какая удивительная картина на российском рынке.



В итоге мы все эти исследования максимально скрестили и оставили то, что нам интересно. Туда добавили еще Dojo и добавили ExtJS 6, на который изначально хотели переходить. А Dojo, потому что его используют Parallels, с которым мы тесно интегрируемся, и на котором у них кое-что написано.



Здесь нагло было вырезано пять слайдов. Я не буду рассказывать про то, почему нам это все не подошло, потому что рассказ там очень скучный. Я не буду на этом останавливаться. Если вы полезете изучать для себя, то сформируете и какую-то картину для себя. Мы оценивали, исходя из наших задач. Одна из задач была в том, что технология должна быть более-менее встраиваемой по частям в существующий код, т.е. нам нужен не монолитный фреймворк, а, скорее, набор каких-то методик и библиотек, которые мы можем потихоньку внести. В этом плане оказалось, что Knockout — это вообще не фреймворк, а UI библиотека, Dojo — это просто мамонт, а ExtJS 6, хоть и привносит новую архитектуру, но на самом деле мало чем отличается от ExtJS 4. Т.е. там появилась поддержка какая-то, более хорошая работа с мобильными устройствами, но концепция не поменялась. Там чуть лучше стала архитектура, но для нас, как мы оценили, примерно одинаковая, что мы на ExtJS 6 будем переписывать честно архитектуру, прямо так, как они предлагают, что мы будем на любом другом фреймворке переделывать — примерно одинаково по затратам. В итоге отказались, потому что все тот же UI слой, все тот же publish/subscribe.

Истинных кандидатов, на самом деле, было только два.



Первый — AngularJS — по понятным причинам, который еще очень активно отстаивали и несколько отделов компании, и некоторые внешние советчики. Но с ним возникла очень интересная дилемма. С одной стороны, это выглядело действительно очень хорошим решением, с другой стороны, я видел очень много статей на Хабре и, вообще, в англоязычном Интернете, в которых обсуждают некие допущенные при его проектировке именно концептуальные ошибки, приводящие к тому, что все, как бы, очень круто, но мы запутались.

Наше собственное зрение на это дело такое, что если брать версию 1, на которой у нас в компании есть два проекта, и посидеть-покурить исходники, то у этого фреймворка реально хорошая модульность разделения на отдельные кусочки, каждый из которых делает свой маленький функционал — вот это очень полезно и хорошо. Но нет единого стиля раскладки по файлам, нет единого стиля именования каких-то переменных и единого стиля форматирования кода, т.е. это та вещь, которую хотелось бы как-то получить до кучи с фреймворком, но ни фига не получится. И со временем этот стиль раскладки меняется. Также от себя добавлю, что зачастую находятся места в коде, которые по-хорошему должны бы быть отдельными классами, но почему-то их в виде объекта с функциями туда пихают. Трудно дебажить, очень много разной хитрой «магии», очень сложно интегрировать с какими-то новыми технологиями, потому что стандарты абсолютно все свои… Как собирать это дело — тоже не очень понятно, однако этот вопрос можно решить. Но самая беда, что начальству я это продать не мог, потому что мы все говорили, что «Ребята, они делают новую версию, и код будет несовместим». Что делать дальше — непонятно.



ОK, полезли смотреть версию 2. Версия 2 прямо вообще отлично выглядит, как то, что нужно, такой бэкендно-ориентированный подход, все разложено по полочкам, хороший очень синтаксис на TypeScript — то, что надо. Но, блин, нет шансов на релиз, вообще, нет. Я, самое главное, не понимаю, эта супер-мега гугл корпорация, она давно работает с python… Пример того, как python переходит с версии 2 на 3 — это просто хрестоматийный пример того, как надо это делать. Надо поддерживать синтаксис старой версии, надо быть backword compatible. А здесь какой-то адский ад просто. Он будет несовместим. «Мы сейчас что-то новое делаем. Вот альфа-версия, для нее ни хрена нет документации. Когда мы запустимся — непонятно и, самое главное, у нас во всех трех языках еще разный синтаксис». Ну, зашибись, блин!

Это что, это решение? Вы извините меня, это локомотив фронтенд-разработки, это, типа, самый крутой фреймворк, который все страшно любят? И что мне делать с админками, которые сейчас пишет четыре человека на AngularJS? Прийти и сказать: «Ребята, вы знаете, мы просто садимся и все переписываем. У нас ничего не станет лучше, мы просто переезжаем на новую версию». — «А зачем переезжаем?» — «Ну, потому что старую забросили». А они меня, конечно же, спросят: «Слушай, а есть такая штука, как в python, типа, «by 2 to 3». Т.е. давай натравим какой-то парсер, и он нам сейчас переформатирует код, и оно хоть как-то начнет собираться». Ты говоришь: «Извините, нет. Причем, мало того, что нет, оно сейчас еще все поменяется. Завтра у нас будет другой синтаксис». И это продать тоже никому невозможно. Совет директоров на меня посмотрит и уволит на завтра и все. Т.е. что делать с AngularJS — непонятно.



Мы дальше стали смотреть, и было второе решение — это React JS, который сделал Facebook. C удивлением оказалось, что это не фреймворк, а всего лишь UI библиотека. У нее очень четкая понятная структурность, четко понятно, что это единый data flow, который только получает данные, только их отрисовывает. Каждый компонент изолирован, у каждого компонента есть декларация, чего он получает на вход, чего он в итоге отрисовывает, чего внутри он хранит в виде промежуточного стейта. Нет, вообще, каких-то магических фильтров и прочей фигни, которую надо откуда-то подключать, учить и знать, как работает… В этом плане все максимально предсказуемо и это очень классно. Мне понравилось, что есть очень простая возможность тюнинга производительности — четко понятно, как она работает, четко понятно, как ее использовать, ничего суперсложного в этом нет. Есть даже серверный рендеринг, который нам не нужен, но круто, что он есть.



До кучи к этому шла архитектура Flux, которую активно двигает Facebook. Мы посмотрели на все это дело, у нас, как бы, был so-so. С одной стороны то, что one-way data flow, и то, что синхронная обработка как у стейт-машины, где четко понятно определенное состояние приложения — это супер. Но как приложение делится на независимые блоки и как разделить его, как в Angular JS, на какие-то отдельные сущности, не очень понятно. Потому что, мне кажется, там явно есть антипаттерны в виде того, что store’ы хранят данные, одновременно реализуют бизнес-логику, реализуют еще логику изменения этих данных. Т.е. это и модель, и контролер одновременно. Идея с единым диспетчером, как единый Event Bus с уникально именованными событиями, где можно быстро найти в коде, где что поменялось, делать быстрый рефакторинг, и компоненты работают изолировано друг от друга — это супер. Но совершенно непонятно, как обеспечивается динамика, как открыть, например, на одном экране два окна, которые бы работали независимо друг от друга, но при этом генерировали бы одинаково, например, события…

По большому счету, Facebook ни фига не зарелизил код, этого нет, это ни фига не фреймворк, это некая архитектурная идея. Причем, изобретенная в 80-х годах, которая называется Event Bus.



ОК. Давайте посмотрим какие-то сторонние фреймворки, которые реализуют эту фигню. Я пересмотрел штук пять, они все как две капли друг на друга похожи, и они все в этом плане намного хуже, чем AngularJS, и намного хуже, чем Ext JS, потому что в них нет почти ничего. Да, там лучше видно, как работает архитектура, но все еще нет речи ни о каком динамическом создании store’ов, их выгрузки и какой-то линковки UI компонентов между store’ами так, чтобы части приложения работали изолировано друг от друга и можно было бы два компонента создать одинаковыми, с одинаковым view, и два контроллера, и они бы не воевали друг с другом этими событиями. Поэтому в этом плане с разработкой веб-приложений все очень странно, т.е. зачастую непонятно, как это делать. Зато в этих фреймворках видно развитие javascript за последние 5 лет, в виде изоморфности, в виде npm-модулей, в виде вынесения функционала библиотеки, в виде поддержки ES6 — это хорошо. Только, блин, ни фига нет, вообще, никакой инфраструктуры тестирования у них, и непонятно как писать тест. Особенно с этой новой суперархитектурой непонятно, как писать тест. И нет интернационализации.

Попутно мы наткнулись на typescript’ы. В этом плане это, вообще, бомба.



Я подумал, что самый супер — убрать излишний креатив разных разработчиков, которые очень любят делать свои «велосипеды» — с помощью этого отлично можно. Typescript — это транс-компилятор, т.е. ты пишешь код, напоминающий javascript, с таким же синтаксисом, только расставляя типы. Т.е. у каждой переменной есть какой-то тип, причем, они могут быть сложными, может быть у переменной одновременно несколько типов, и в итоге он эти типы убирает, создавая тебе javascript-файл с абсолютно таким же синтаксисом, где просто убраны эти типы, и там еще есть несколько полезных syntactic sugarвещей, которые соответствуют стандартам ECMAScript 2006. Т.е. просто компилятор из ECMAScript 6 в 5.



Там, например, есть такие сложные типы данных, когда ты можешь сделать целый контракт, т.е. там объекты с вложенной структурой, и теперь у тебя разные части приложения заранее знают, что из API приходит вот такой вот хитрый вложенный объект, или, например, повторяются в нем поля. Мы используем это как некий клей между отдельными частями приложения, т.е. каждый пишет эту бизнес-логику, ориентируясь на какой-то интерфейс. И компилятор при сборке сразу же проверяет, можно ли скомпилить это, правильно ли ты организуешь доступ к этим полям, правильный ли тип в них подразумеваешь.



Потом, там есть интерфейсы. Забегая вперед — фреймворк, который мы написали, основан сильно на интерфейсах, т.е. мы, ориентируясь на принцип solid, разбиваем на более мелкие зоны ответственности и делаем так, чтобы у нас разные классы зависели от небольших интерфейсов. Получается у нас больший декаплинг приложения.



Точно так же, как в python’е, есть поддержка дженериков. Есть декораторы, как в в python’е, есть дженерики, как это принято в мире С++, и которыми мы активно пользуемся. И есть составные типы. В редких случаях, можно сказать, что в этой переменной может быть или строка, или число, тогда, когда этого не избежать. Он тоже нормально с этим работает.



В итоге после этого исследования вопросов стало только больше. Какую архитектуру выбрать? Какое решение правильное? Как идти в ногу с развитием javascript, в виде ECMAScript 6? Где взять библиотеку UI компонентов?

И в этом плане Ext JS очень активно держит удар, в нем все это есть. В нем есть своя сборка, в нем есть механизм интернационализации, в нем есть понятная архитектура и прочее. Т.е. то, что получилось тогда, получилось странно, но только альтернативы то нет. Ну, как бы, она есть, но ее надо делать самому. В итоге, хотим фреймворк с Typescript, все хотели на этот момент фреймворк с Typescript. Без — уже не хотел никто.



Ну ладно, чего делать? Напишем задачу сами себе. JS-кодеры должны писать код. Верстальщики должны верстать и общаться с дизайнерами. Явно нужно сделать максимально простой UI слой, чтобы в нем разобрался дизайнер, и чтобы это было понятно программисту без жуткого наследования CSS-стилей в три-четыре уровня без жуткого наследования компонентов. Нужно сделать четкую и понятную архитектуру, код, примерно понятный бэкенд-разработчикам, и нужно разделение зон ответственности — отдельно верстка, отдельно код, отдельно контроллеры, отдельно хранение данных, стараться запихать состояние приложения в один какой-то тип классов, назвав его моделью. И, главное, больше границ, правил и стандартов: именования, форматирования кода, раскладки по файлам, всего этого дела. И при этом на Typescript. И при этом еще так, чтобы это все дело не было монолитным фреймворком, потому что все это дело нужно будет еще внедрить в существующий код.



Мы в итоге взяли фреймворк, который называется Este.js. Он ни о чем вам не говорит, он был наиболее революционно-инновационный. Плавно переписывали, пока от него не осталось вообще ничего.

В итоге было несколько проблем.



Первая проблема. Получается так, что store — это некий антипаттерн во flux. На практике у нас ничего хорошего с этим не вышло. Мы в итоге обратно разделили их на классы, которые хранят данные и могут их менять, и отдельно бизнес-логику в контроллере. Это примерно то же самое, куда сейчас идет развитие flux, когда у них есть отдельно вынесенные объекты со стейтом. У нас этот объект со стейтом просто называется store.



Было вот так.

Получилось примерно вот так:



Т.е. изолированные блоки, примерно так же, как в AngularJS, с таким же механизмом, в виде модулей. В каждом модуле там один или несколько своих store’ов, которые общаются с одним из нескольких контроллеров. И в итоге все это дело работает отдельно от view. View только читает данные store’ов и генерирует некие action’ы, которые единый dispatcher раскидывает (на самом деле, не единый, у каждого изолированного блока может быть еще свой) между контроллерами, каждый из которых подписывается на события и решает, реагирует он на это событие или нет. В итоге у нас приложение работает как набор вложенных друг в друга приложений, в каждом из которых внутри flux. Это иерархический MVC, где view просто вложены друг в друга, а контролеры изолированы.

Вторая проблема в том, что шаблоны Facebook предлагает делать вот так:



Мы, конечно, долго мучились, мы поняли, что это вообще не вариант, и мы стреляем себе в ногу. Я абсолютно не понимаю, зачем мне нужно смешивать кучу JS-кода, фигурных скобочек, круглых скобочек, логику и все вместе в UI компоненте, когда, по большому счету, суть UI компонента в том, что он берет какой-то шаблон и рендерит его в браузере. Мы посмотрели на такой проект как wix-react-templates, написали свой, сильно-сильно похожий. Но в нем нет кода. Только есть блоки, которые обеспечивают итерацию, if, then, else и переменные, больше ничего нет. Т.е. задача компонента — в эту переменную запихать заранее то, что в ней будет выведено. И задача компонента — указать сколько раз итерировать какой блок с какими данными. Так выглядит шаблон:



Вот такой мы написали свой собственный парсер этих шаблонов, который делает из него DOM-дерево и генерит такие шаблоны, сильно такие же, как их генерит JSХ:



Вот, это дело уже автоматически генерится, и с этим делом работает React.



И суть UI компонента в том, что он декларирует некие пропсы, декларирует некие стейты и в самом простом способе эти пропсы запихивает в блоки и в переменные. Построили некое дерево, которое потом рендерится.



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



И, соответственно, дальше генерится такой же шаблон, но только в нем эти строки заменены на строки на русском языке и этот span тоже распарсен и подставлен в шаблон.



С динамикой беда в том, что не очень Facebook объясняет, как это делается, как сделать независимой работу двух компонентов. Мы в этом плане нашли несколько вариантов решений и сейчас их прорабатываем.

Что в итоге получилось?



Получился фреймворк с хорошим ООП и с маленьким интерфейсом, с дженериками, близко похожий на то, как это было написано на java. С dependency injection, которая обеспечивает связь классов внутри одного модуля, у которого только две внешние зависимости — это React и lodash. В котором можно сделать любую архитектуру — захотим рефлакс, можно сделать рефлакс, захотим MVC — можно сделать MVC. Потому что там три с половиной файла и плюс React. И с нормальным механизмом сборки через web-pack…



Мы сделали два пилотных проекта — один на Ext JS 6, другой на React. Абсолютно с нуля, без использования существующего кода, оба повторяют один и тот же функционал существующей админки, но только одну единственную страницу на ней, на которой некоторые кнопки не кликаются. Достаточно немного, все это вместе заняло где-то месяц работы в сумме.

Задачи были — сделать анимации, сделать кастомный, нами рисуемый скроллбар, сделать отдельный интерфейс для узких экранов типа а-ля планшетов, сделать отдельно мобильную версию, когда экран совсем узкий, и сделать, чтобы все это авторизировалось и ходило в json rest, грузило реальные данные, которые у нас есть в API и с ними позволяло работать.

В итоге получились такие цифры:



На них можно не смотреть, но суть в том, что оба проекта реализованы с нуля, получились так, что flux + react выигрывал от 2-х до 5-ти раз. Но с большой звездочкой, что когда у нас будет столько же UI компонент, сколько есть в ExtJS, размеры билдов и скорость инициализации, она, конечно, упадет, потому что в этом плане мы тягаемся с монстром индустрии.



Ясно, что просто так на это дело не переехать. Поэтому мы сели, покурили все существующие интерфейсы с дизайнерами, собрали некий единый файл, в котором 60 простых компонентов типа панелей и кнопок, 15 сложных — это типа у нас есть таблица, в которой можно выключить какую-нибудь колонку, отсортировать ряды или, например, есть дроп-даун, в котором можно теги набирать — это прямо конкретно сложные вещи.



Я некоторые из них заверстал. Прямо сделал рабочими компонентами на react’е, это у меня заняло где-то 4 дня.



В итоге получилось так, что мы процентов 10 сделали, оценили, как 2 тыс. строк кода за 4 дня и получили примерную оценку в 2 человеко-месяца для реализации всех UI компонент, из которых состоят наши проекты.



Долго думали, как делать, но пока решили так, что новые проекты сразу делаем на новом фреймворке, попутно создавая эту UI библиотеку в отдельном репозитории. Старый код не трогаем, но встраиваем «независимыми блоками» в него новый функционал в виде как «берем отдельную панель или страницу, ее переписываем на новой». Либо, если это новый функционал, то, вообще, делаем эту страницу сызнова. Соответственно, новый фреймворк прикидывается UI компонентом внутри Ext JS, делая вид, что это какая-то панель, которая как-то отрисовывается и внутри себя чего-то делает, а наружу, максимум, одно-два события отдает. И, конечно же, при модификации старого кода ты либо портируешь существующий функционал, либо правишь, как есть.



Так что суть доклада, как всегда: превозмогайте трудности; велосипеды, баги, костыли — делайте все свое. Делайте свое, потому что ваша команда теперь обладает технологией и экспертными знаниями, как она работает. Т.е. мы читали исходники react’а и, наконец, понимаем, как же он, блин, работает.