Сила сообщества и Sailsjs

Роль сообщества в удобстве использования того или иного инструмента для разработки может быть сильно недооценена. Особенно у нас в СНГ, после эпохи форумных советчиков, которые, прежде чем ответить на вопрос, успеют обвинить, переспросить, предложить десяток вариантов не о том и поспорить друг с другом. Могилы этих топиков всё ещё гуглятся, но отпугивают современного обитателя Toster & Stackoverflow, как и положено могилам.

Боязнь советов и стремление сделать всё одному (этому миру не нужен ещё один велосипед) может нас сподвигать на немыслимые поступки. Например, брать инструмент, о котором никто не слышал.
Точнее, слышали: основной репозиторий собирает на гитхабе 11к звезд. Но это ничего не значит, потому что все остальные репозитории с разработками нужных сервисов для этого инструмента никому неизвестны и last update: two years ago.

Займитесь детальным изучением инструмента, который вы выбираете, перед тем как его использовать!

Речь пойдёт о небезызвестном Nodejs и таком вот замечательном его фреймворке — Sails. О нём я узнал по рекомендации одного из авторитетных (для меня) нодеров, и как только выпал проект на Nodejs, я не стал воротить нос аки заядлый php-шник. Тут же указал Sails вместо привычного всем Express в графе «используемые технологии».

Не скажу, что задумка Sails плохая. Там много простых и понятных вещей, если нужно просто сделать простое API. Даже с авторизацией, даже с валидацией, с вменяемыми сообщениями и Twilio-верификацией телефонного номера. Мне нравилось как легко и просто всё это подключать и использовать, хотя осадок от нодовского «сделай ещё одно замыкание и выпей чаю» даёт о себе знать кошмарами по ночам.

Но спринты двигались, а задачи стояли на месте. «Сделай нормальные сообщения при валидации!», — орал QA. «Где мой swagger?!». «Что за Waterline?!». «Стой, что? Миграций нет?..».
Рабочие дни уходили, начинались выходные, а я пилил и пилил им Swagger вручную, гуглил и гуглил о внешних ключах в Waterline, и…

Первое: все найденные ответы либо были единственными во всём Stackoverflow с двумя-тремя плюсами (я на это ориентируюсь, да).

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

Третье: очень скудные best practice. «Тонкие контроллеры», говорит документация Sails. Но вы не узнаете, как это должно выглядеть. И знаете что? В условиях асинхронности, когда try-catch работает не так просто, как в привычном php, утоньшение контроллера становится искусством. Которым никто не хочет заниматься. И любой сервис, предлагающий что-то для sails, тут же предлагает examples с толстенными контроллерами. А мы и учимся. И страдаем. И используем пачки довольно нестабильного кода…

Ах да! Sails сам по себе 0.12.13 версии. Как бы бета. И недавно выпустили 1.0, но я его не рискнул использовать, потому что на него ещё меньше нужного сопровождающего кода от сообщества и ещё больше вопросов.

Сообщество это сила. Энтузиасты, которые пишут хороший код, тестируют его, развивают фреймворк, расширяют его (я говорю в частности об yii2), делают жизнь невероятно лёгкой и приятной. Это позволяет заняться проектированием и не пригорать по поводу отваливающегося bcrypt (в чём вообще была сложность сделать нормальный bcrypt?) и прочего такого, служебного и нужного только в двух местах во всем приложении.

Используйте популярные фреймворки. Держитесь мейнстрима, не бойтесь быть как все, потому что в программировании это скорее благо для вас. Это тысячи человекочасов, работавших бесплатно (вы же ничего не платили?) для вашего удобства.

Держитесь подальше от Waterline. Сомневайтесь перед тем как брать Sails в работу. У него мертвое сообщество.

Yii2 и виджеты: немного полемики

Насколько прекрасен и прост Yii2 в работе с backend (хотя, так с любым фреймворком: сколько бы ни ругался на Symfony, но 90% работы происходит с PHP, а не с ним), настолько отвратителен в виджетах и рендеринге. Не знаю, есть ли где-нибудь подобный треш, как в Yii2. Сравнивая с тем же Symfony: там разработчики решили остановиться на дефолтном шаблонизаторе twig и не внедрять в стартовые шаблоны никаких примеров чудо-виджетов. Спасибо, ребят!

Виджеты — ужасная штука. «Это самодостаточный блок», говорили они. «MVC», говорили они. Неужели попытки скрыть передачу данных под видом DataProvider во вьюху действительно не дают повода задуматься?

Как только приходится что-то поменять в виджете, начинается боль. Если вы хотите поменять расположение кнопок — должны потратить два часа на поиски и применение информации. Вы достаточно постигли стандартные виджеты типа GridView? Не волнуйтесь! Любой другой виджет, который вы установите, например, FileInput от Kartik — и вуаля, гуглите снова. Гуглите много.

Окей, я не буду голословным, вот вам код:

Серьёзно, он такой и есть. Выглядит интуитивно понятно и очень гибко. Можно поменять язык, можно настроить множественную загрузку файлов, главное что смотрится красиво! Гляньте:

46078f35a64995249bae95a2076351e7

Да, мне тоже нравится. Работа над плагином проделана большая. Но оставьте это плагином. Зачем делать из него такое, от чего мои глаза ( речь идёт про мои впечатления после использования виджета, и они нисколько не объективны, да ) кровоточили разочарованием в принятых решениях. Побуду циником: взамен предложить нечего. Возможно, потому что Yii2 не стоит лезть во frontend. Возможно потому что отделение backend от frontend есть самое логичное, что произошло с вебом. С тем же вебом, где ECMAScript5 до сих пор не определился, как регламентировать асинхронные процессы, и весь Ajax реализован как бы интуитивно, а не по стандарту ECMA (ну и здорово!).

Давайте вернёмся к коду. Вы заметили ‘pluginEvents’? Это элемент массива, значением которого является… JavaScript! Даже jQuery. Впрочем, на использование jQuery нас обрёк сам фреймворк, но ладно. Дело в том, что приходится писать текст JavaScript прямо в строках PHP. То есть, когда в html встречался коннект к БД, бывалые программисты пускают скупую слезу отчаяния, но сами пишут JavaScript в PHP. Почему? Потому что «виджет есть независимый самодостаточный блок». Тогда что можно назвать виджетом? Календарь? Зачем нам календарик, если мы с ним не можем взаимодействовать? Только в том случае, когда нужно выбрать конкретную дату (и только), он нам пригодится из коробки, как есть. Но если при перелистывании месяцев должно что-то меняться во фронте — о-о, да, запасайтесь кофе и зефирками, впереди долгие бессонные ночи.

JavaScript должен уметь общаться с другим JavaScript. Если нет — в дело пойдут глобальные переменные и window.variable = ‘1’. Как только мы захотим привинтить к календарику что-то красивое, то 1) видим что он виджет и плачем 2) не можем спихнуть эту работу на фронтенда, кроме как заставить всё переписать.

Все видели HTML-разметку? Её обычно много, и в глазах рябит. Но вызывает ли сложности изменить разметку? Хм, обычно нет. Это работа лёгкая и скучная.

Но подождите, сейчас вы увидите на редкость грустную разметку.

Часть шаблона, по которому генерится виджет (точнее, сам плагин). Да, здесь yii2 уже ни при чём, но давайте представим, что нам нужно что-то поменять из этого, а оно оформлено и зашито в виде виджета? А если верстальщик сверстает прекрасное новое оформление для FileInput, отдаст вам, чтобы вы внедрили это, что будет? Снова будет грустно. HTML, от которого просто не может быть весело.

И вы попытаетесь использовать библиотеки виджета, чтобы поменять что-то в нём на js, но не получится! Это ведь самодостаточный независимый блок.

Как вывод, я хочу сказать, что современный веб всегда подразумевает интерактивность компонентов интерфейса. Сейчас такие увесистые компоненты, что перезагружать каждый раз страницу ради серверного рендеринга есть непозволительная роскошь. И если вы загрузили файл, а в списке файлов он отобразится только после ф5, это уже плохо!

Интерактивность требует доступности всех компонентов. В виджетах эта доступность страдает. Может, я не умею их готовить (скорее всего, так и есть) — но зачем учиться готовить то, в чём другим людям придётся ещё долго после меня разбираться? Это одинаково непонятная магия для любого новичка, и одинаково муторная проблема для мидла — виджеты, которые нужно менять, с которыми нужно взаимодействовать, и уж тем более с которыми нужно уживаться, когда пишешь SPA.

Трио методов для асинхронных процессов

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

Хороший пример: запуск поиска со множеством параметров по множеству API c последующим разбором результатов через адаптеры. Сам процесс нас не волнует, лишь рычаги управления: допустим, метод run или search (что-то вроде ‘http://site.com/api/v1/run’ ) принимает через POST множество параметров для запуска, а возвращает id.

051091cbc58b2d3c549adbd0168cb3db

Окей, что нам делать с этим id? Нам его нужно отдавать тому же серверу, чтобы 1) смотреть, что он сделал по нашему запросу 2) брать информацию, когда он всё сделал.

Хорошая идея (и, возможно, первая, которая приходит в голову) — сделать ещё два метода, например, check (или status, я просто привык именовать методы глаголами, для REST это неприемлемо) — ‘http://site.com/api/v1/check/id‘. И get-results — ‘http://site.com/api/v1/get-results/id‘.

Зачем нам нужен check? Чтобы проверять, в каком состоянии находится запущенный процесс с полученным из метода run id. А get-results чтобы получать результаты.

Можно решить эту задачу двумя методами: и правда, зачем вообще нужен check, если у нас есть метод get-results, который просто не вернёт информацию, если её нет. Его можно нагрузить дополнительной логикой и возвращать status как один из ключей ответа. Преимущество такого метода интуитивно понятно:

bef78d760a87e6aab392cff755a8ff0d

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

Но это не панацея для всех проблем такого вида: если процесс поиска составной, и в фоне запускается несколько потоков для выгрузки разнородной информации, то метод get-results может вернуть лишь часть результатов. К примеру, поиск по транспортным средствам, где самолёты и автомобили доступны с разных API — тогда самолёты могут найтись, а автомобили нет. Получится такая ситуация, что мы лишний раз нагружаем сервер, вытаскиваем полученные результаты, а они оказываются слишком громоздкими или неполными, и нам придётся делать ещё один запрос, чтобы получить более полную информацию. Само собой, можно спроектировать метод get-results так, чтобы он сводил потери такого вида к минимуму, но гораздо проще в сопровождении будет отделение статистики и статуса процесса поиска в отдельный метод: check. Он может возвращать статистику: сколько уже найдено, минимальная и максимальная цена \ вес \ что-либо ещё из нужных параметров, при этом не станет затрагивать сами данные.

append vs appendChild. Cлетает обработчик события

Попался такой момент интересный — работая с js, создавал элемент такой инструкцией:

Потом навешивал обработчик событий, сначала так:

и пробовал добавить к некоторому объекту через jq:

Тогда беру addeventlistener:

В итоге сделал так:

Да, вне зависимости от способа навешивания обработчика, он не слетает, если добавлять элемент, к которому он приделан, при помощи инструкции JS — appendChild(); DOM-элемент же вытаскивается из JQ при помощи такой инструкции, как указана выше — $obj[0];

append — зло.

Передача массива элементов под одинаковым именем