Хакатон II
Dec. 13th, 2014 11:19 amЛюбопытно, но я после беглого просмотра работ 242 участников II тура не увидел ни одного, кто бы справился с разбором TOSов в реальном времени о_О
Придумалась тут на днях офигенная концепция как на клиенте, в браузере, разрабатывать и отлаживать серверный js-код, работающий с БД. Из картиночки справа в общем всё понятно.
В нашем типичном стеке серверных технологий – node.js + express + cradle + CouchDB – достаточно заменить только cradle.js на PouchDB.
Обвес, позволяющий проделывать весь этот трюк в браузере, оказался на удивление несложным в целом. Я его как proof of concept написал за вечер, а на следующий вечер у меня уже заработал серверный код, полностью написанный в нашей самопальной IDE.
Как ни странно, всё взлетело сразу почти, без особого бубна с функционалом БД. Споткнулся я сначала на криптографии, но это мы проработали прошлой зимой, оставалось только чуток подкрутить. Гораздо более серьёзным оказался затык на библиотеке, обеспечивающий Promise-функционал нужного синтаксиса.
Промисы – модная и очень удобная штука, мы активно используем. Коллбэки – фу, промисы – кул. Беда в том, что синтаксис промисов иногда существенно отличается от библиотеки к библиотеке, там нет единого стандарта.
Исторически так сложилось, что на клиенте мы используем модель jQuery.Deferred – которая не очень то удачна, по-честному. Ну и оказалось что для node.js нет либы, которая повторяла бы синтаксис $.Deferred – чему я был очень удивлён.
В результате перебора bluebird.js, затем lie.js [ага, var Promise = require("lie")] и затем Q.js оказалось, что проще всего имитировать $.Deferred под нодом с помощью Q. Ну, как известно “то, что вы ищете, вы найдёте в самом последнем месте”, да.
Так вот, в самом простейшем варианте код выделки симулякра $.Deferred из Q.defer умещается в 20 строк:
var Q = require("q"); var Promise = function(){ var q = Q.defer(), qp = q.promise, pi = { then:function(a,b){return qp.then(a,b);}, fail:function(a,b){return qp.fail(a,b);}, done:function(a,b){return qp.done(a,b);}, progress:function(a,b){return qp.progress(a,b);}, promise: function(){return q.promise;}, resolve:function(a,b){q.resolve(a,b); return pi;}, reject:function(a,b){q.reject(a,b); return pi;}, notify:function(a,b){q.notify(a,b); return pi;}, isResolved:function(a,b){return q.isFulfilled(a,b);}, isRejected:function(a,b){return q.isRejected(a,b);}, state: function(){ var state = qp.inspect().state; return state==="fulfilled"?"resolved":state; } }; return pi; }
Если не заигрывать сильно с this, не засовывать синхронный код в промис и использовать только базовый синтаксис, этого достаточно. Вдруг кому пригодится.
Сегодня кста выяснилось, что node.js даже последних сборок использует уже не поддерживаемую Гуглом версию V8. А нод много где в продакшене используется о_О
Сделали первый проект, который, в каком-то смысле, распространяется на “физический” мир. Для меня это был пробный шар в реализации некоторых технологий того, что нынче называется “интернет вещей”.
Проект – диспетчерская для дорожной организации. Основная задача – распределение техники по участкам на даты и ведение отчётности по фактической занятости. Всего получилось три веб-приложения, естессно jQuery.my.
Вот скриншотик фрагмента одного из приложений – непосредственно перемещение техники между участками. Вместе с техникой “тащится” привязанный к ней поп-ап, это новая фича в jQuery.my.
Ещё в рамках проекта мы впервые попробовали сделать удалённый датчик работы тяжёлой техники. Датчик собирает данные и сливает их на сервер, если есть связь, или сохраняет до тех пор, пока связь не появится, и потом сливает.
Интересно, как мы этот датчик делали.
Сначала я подумал, что для этой цели идеально подойдёт Tessel, и даже уже начал делать первый подход к снаряду. Первый подход породил вот такую конструкцию:
Это, конечно, очень красиво эстетически, но в середине сентября, когда это фото было сделано, я понял, что собрал мобильный телефон без тачскрина и аккумулятора. Даже, если быть точнее, браузер мобильного телефона.
Ну то-есть, это javascript-микроконтроллер с модулями GPRS и GPS, с камерой, акселерометром и SD-ридером.
Эта конструкция требует постоянного питания, корпуса и вообще бубна. Первый подход занял один вечер и на выходе дал существенное переосмысление задачи. В результате вся эта конструкция заменилась мобильным телефоном под Андроидом.
На телефоне – PhoneGap-приложение, написанное на javascript. Для накопления и репликации данных оно использует технологии, на которых работает cloudwall.me – они стали приемлемо надёжными. В общем, отладка этого всего хозяйства, конечно, доставила, и пока всё неидеально, но задачу поставленную мы решили.
Ещё я знаю, как с помощью этого всего существенно улучшить отчётность и эффективность продуктового ритейла, но там огромную работу надо проделать, чтобы создать прототип.
А у меня какая-то дикая по силе депрессия, фак.
Открыли бету мобильной версии, в общем-то, первую в нашей истории. По клику на картинку сразу она и откроется, хотя на десктопе довольно страшненькая.
При наличии десктопной версии (наш случай) мобильная версия не требует индексирования – индексируется основная. По этой причине мобильную версию не обязательно делать html-статикой, это может быть веб-приложение.
Так даже лучше, потому что нет оверхеда на передачу HTML-разметки, передаются только данные. Это для мобильного инета имеет значение.
Именно так тут и сделано. Приложение это – один манифест jQuery.my. Единственный браузер, в котором не заработало из тех, что мы дотянулись – первый iPhone 2007 года.
Я в самом деле очень этим горд, хотя оно такое всё довольно простенькое.
Дело в том, что это приложение – milestone ещё и с другой стороны. Оно полностью написано в специализированном IDE для манифестов, который теперь встроен в портальную CMS.
Изнутри редактор выглядит так:
jQuery.my два года всего с небольшим. Оно вполне боевой стало технологией.
Ломаю голову, как мне это всё маркетить.
Сделан целиком в редакторе из предыдущего поста. Редактор этот встроен в корпоративный интранет заказчика как веб-приложение.
В разделе “Прайс-листы” не только таблицы, но и интерактивные калькуляторы “с памятью”. Калькуляторы эти генерятся при выгрузке сайта на S3 – пользователь просто копипастит прайс из экселя, а парсер всё это в калькуляторы превращает.
Вообще, конечно, многообещающая технология. Скорость вёрстки прототипов или статических сайтов какая-то просто нереальная.
Интересно, что при сохранении документа с сайтом в CouchDB, сайт сразу, без выгрузки на S3, доступен в виде превью. Все файлы сайта хранятся как аттачи к документу базы, а они (аттачи) доступны в CouchDB по пермалинкам.
Также замечу, что статического хостинга дешевле чем Amazon S3 просто не существует в природе. Счёт в доллар за месяц при 50К посещений – вполне себе реальность.
UPD. Спасибо service_picky за ценное замечание насчёт названия файла для скачивания. Pricelist.xls – это неудбно, надо писать в названии компанию, чтобы файлы не путались.
Мы его всё же сделали, приложение такое. Хранит целые статические сайты одним документом в CouchDB. Сейчас в бою тестируем, делаем реальный проект в нём.
Инклюд там, обработка исходников кастомизируемыми препроцессорами, хранимыми прямо в документе и куча других вкусностей. Приложение целиком сделано в моём новом IDE, в 4 руки, общие затраты времени – порядка 12 часов.
Объём кода после minify/gzip – 6 Кб. Javascript рулит!
Переделали ещё один сайт СМИ – pravdasevera.ru. Стало так:
А было до этого вот так:
Ну, как водится всё javascript, в облаках и заточено под редакционный цикл новостного СМИ.
Из предыдущей самописной CMS было перезалито 30000+ материалов, сегодня редакция начала работу в новой системе.
Интересно, что платформа с первоначальной заливкой контента со стороны была развёрнута практически в том виде, что сейчас, менее чем за двое суток.
В бете нового Двиналэнда применено довольно много технологических решений, снижающих нагрузку на облака. Одна из стратегий, которая попутно даёт мгновенный отклик некоторых интерфейсов – обработка, рендер и поиск на клиенте.
Называется это у нас “словари” и работает это примерно так.
Существует крупная категория данных, которые обновляются в подборках не по частям (как, например, новости), а разом. Это, скажем, ежемесячные отчёты об исполнении бюджета, какие-то списки организаций или услуг, телефонные справочники.
В силу характера документооборота это практически всегда или экселевские файлы (иногда с имитацией иерархии), или SQL-выгрузки, или веб-сервисы. Так или иначе, это всегда таблицы. Чаще – эксель.
Типичные объёмы – от сотен до единиц тысяч строк в 5-15 колонок. Связность обеспечивается в момент приёма до уровня гиперссылочной целостности – куда надо подставляются пермалинки.
Такие данные неразумно хранить в “разобранном” виде – проще их в момент поступления в систему конвертировать в жестко унифицированный формат и хранить единой записью. В силу того, что у нас вся система – javascript, эта запись, понятно дело, json. Вопрос, какой структуры.
Коль скоро мы собираемся искать на клиенте, нам эти данные надо туда передать. Также очевидно, что перед поиском их можно будет обработать. Стало быть, надо делать представление с минимальной избыточностью, хорошо пакуемое gzip-пером уровня выдачи на скоростных режимах (ритмичное, то-есть).
Данные у нас табличные, пусть и с псевдоиерархией, так что задача это лёгкая. Мы конвертим исходные данные в массивы массивов, запоминая названия колонок.
То-есть не [{name:"John", year:1980}, {name:"Ann", year:1990}],
а примерно {cols:["name","year"], data:[["John",1980],["Ann",1990]]}
Только в силу структуры экономия против по-объектного, и, тем более, против HTML-формата, получается многократная.
Раз оно получается короткое (100Кб словарь пакуется до 10-15Кб), хранится единым куском и не требует сборки, его можно и нужно инлайнить. И мы действительно до определённого порога инлайним эти данные прямо в страницы выдачи.
То-есть, когда страница догрузилась, данные не просто тоже загружены, они уже даже разобраны и проиндексированы. В силу того, что большинство даже мобильных систем нынче двухпроцессорные, рендер и индексирование разносятся браузером по разным потокам и для пользователя это незаметно.
Рендерятся данные после рендера всей содержательной статики. За выдачу данных с вкусным интерактивом отвечают jquerymy-манифесты.
Причём к одним и тем же данным могут быть привязаны разные манифесты, а к одному манифесту – разные данные. Например, в материале о расходах бюджета http://new.dvinaland.ru/budget/-e0ut55ow вверху бюджет диаграммой, а внизу – таблицей. Это одни и те же данные. Сама страница весит 450Кб, и эти данные занимают большую часть её объёма. При передаче это всё сжимается до 65Кб, размер небольшой картинки.
Там чуть менее 3000 строк данных в 5 уровнях иерархии.
С точки зрения редактора это выглядит как “поставить в этом вот место виджет Таблица с поиском и привязать к ней вот эти данные”. Это всё в админке интерактивное, драг-н-дроп, можно выбрать оформление, ширины колонок, фильтры и тп.
В силу того, что чётко разделены и стандартизированы попадание в систему, хранение, выдача и обработка, любое звено можно менять, не трогая остальные. Также любое звено легко форкается в целях тестирования.
С точки зрения юзера это выглядит как мгновенный отклик итерфейсов – все данные уже на клиенте и проиндексированы. Скажем, если на странице http://new.dvinaland.ru/gov внизу в справочнике наколотить gmail, можно увидеть, сколько ещё деятелей юзают вражью почту ггг.
За последние полгода эта цифра уменьшилась кратно, но остались ещё несознательные.
bower install jquerymy
или на jquerymy.com.Такой milestone в некотором смысле – я написал первый в своей жизни IDE, заточенный под разработку и тестирование jQuery.my-форм.
Интересно, что IDE сам по себе тоже приложение jQuery.my – на картинке в редакторе кода открыт сам редактор этого кода, центральный компонент. И кнопкой Play можно запустить в IDE превью самого себя.
Вот например редактор показывает живое превью самого себя во всплывающем окошке:
Из интересных фич:
Хвалите меня, немногочисленные читатели ) Устал чёто как собака.
PS. Мне пришли компоненты робота – микроконтроллеры, камеры, акселерометры, серво и тд. Начал проектировать.
Открыли публичную бета-версию обновлённого портала областного правительства, в продолжение их пресс-центра (ровно год прошёл, да). Сначала скриншотики, кликабельны
Теперь чем оно всё круто.
Вся система целиком, до последней строчки – javascript, и при этом практически любая страница после первого захода видна менее чем через секунду после клика (в России, в 120мс пинга до хостинга). Всё потому, что как и на пресс-центре применено блочное кэширование и в 99% случаев страницы отдаются целиком из кэша в RAM, даже без обращения к БД.
Оно плотно интегрировано с пресс-центром, это не просто одна CMS и стилистика, это единая платформа в облаках. Из соображений усиления периметра безопасности платформа состоит из нескольких компонентов, связанных только по https – скажем, головной сайт не хранит и не обрабатывает данные форм и авторизации, это делает специальный ресурс. Также на фронтэнде невозможно авторизоваться в админку – её там просто нет.
Эта платформа импортирует данные из других систем – телефонные справочники приходят в SQL-формате, ежемесячные обновления бюджета – в CSV, афиши – в JSON и т.д. После импорта данные приводятся в унифицированный внутренний формат, а потом отображаются в виде табличек, диаграмм, списков ссылок и т.д.
Особенно полезны для вдумчивого читателя интерактивные диаграммы бюджета. На секторы можно кликать. Смею предположить, что такое представление бюджета для народа – лучшее по простоте навигации из всех, что я видел. Оно основано на одной заброшенной австралийской инициативе 5-летней давности по раскрытию open data. Мы из этого сделали технологию, в которой данные обновляются в один клик.
Все материалы имеют “срок годности” – дату, после которой система начнёт напоминать о необходимости обновления. Такой фичи я просто вообще нигде в CMS не встречал, а для большого госпортала она абсолютно необходима. На предыдущей версии портала нереальные завалы неактуального старья – и про то, что информация протухла редактор портала мог узнать только случайно.
Мы сделали механику для исключения такого рода бардака.
Когда мы это всё начинали, планировалась авторизация через соцсети. Эта идея быстро отвалилась, потому что в принципе не позволяла сделать хоть сколь-нибудь квалифицированное обращение к власти, а мне хотелось, чтобы эта форма на каждой вообще странице была.
Использовать СНиЛС как на госуслугах – не вариант, это другой класс защиты персональных данных, мы бы не поместились в сроки и бюджет. Да и неудобный он до смерти, “интернет по паспорту”.
Остался мобильник. Вообще нам стоило существенных усилий убедить коллег из правительства, что это приемлемая авторизация. И примерно в тот момент, что мы всё же убедили, что это концептуально верно, Медведев предложил простые госуслуги оказывать через авторизацию по SMS. К июлю. Ну вот мы и сделали к июлю под это целую платформу.
---
Вообще, работа проделана колоссальная – переработано почти 400 страниц информационного контента, урегулированы вопросы поставки обновлений из ведомств, масса данных уточнено. Ну и портал правительства, наконец то, для простого человека стал не бесполезен.
Началось всё вот с такой картинки:
Ну и да, вся эта система управляется приложениями jquerymy. Внутри системы даже IDE есть простенький для горячей замены кода системы из браузера прямо, тоже на $.my.
Такие дела.
Рабочий год закончился в 4 утра на любопытном моменте.
Я летом придумал название для всей облачной кухни, что мы делаем. Домен даже купил. Картинка вот нарисовалась.
Рабочий 2013 у меня закончился на том, что я вынес на CDN первую часть разделяемого системами кода и спланировал реорганизацию системы так, чтобы такого кода было очень много. То-есть все неспециализированные приложения, библиотеки, css и шаблоны системы будут загружаться с CDN во всех инсталляциях.
Идеально, чтобы с конкретного экземпляра системы грузилось только ядро, данные и специфичные только для инсталляции приложения/шаблоны. Всё остальное надо держать на CDN. Так и будет.
Технологически для начала это будет S3. Оказалось, что S3 вполне в состоянии отдавать упакованные файлы – если их туда класть уже за-gzip-ленными с исходным расширением и ставить Content-encoding явно. Как-то мне не приходило это в голову, я смотрел на всякие чуть не Akamai, а решение то под боком.
То, что грузится с CDN, будет кэшироваться в localStorage, а вновь загруженные обновления сначала проверяться и в случае сбоя отбрасываться. То-есть примерно механика Last Known Good Config в винде.
Помимо этого будет полное версионирование, то-есть конкретный апп может попросить не последнюю, а какую-то точную версию подлежащего кода (это значит апп просто будет жить в iframe).
В общем, существенная часть этого всего уже существует и хорошо работает в бойкой альфа-версии (которая в феврале станет публичной бетой), но само название я вынес в интерфейсы внутренних систем только вчера.
У меня пальцы чешутся рассказать что это будет, но не могу. Поэтому всё так расплывчато написал, просто чтобы зафиксировать день рождения CloudWall.
И да, с Новым Годом, с новым счастьем )
Я недавно наткнулся на эмулятор Mac OS 7 в браузере. На javascript. Поигрался с любопытной игрушкой – и как-то не придал особого значения.
Именно с System 7 кста я в своё время пересел на Win95. Правда, это была 7.5, но не так уж они с 7.0 и отличаются.
Вообще, Win95 выиграла у Мака в моей картине мира всего по одной причине. В Вин95 была правая кнопка и всё, что с этим связано. На Маке не было ничего даже похожего тогда, штатная мышь была однокнопочной.
В эмуляторе выложен всякий софт того времени – Microsoft Word 4.0 и Excel 2, Aldus (ещё не Adobe) PageMaker 2 и тп. И этот софт прекрасно работает, примерно с той скоростью, как я помню. Я не сразу осознал значение этого – а оно имхо довольно интересное явление само по себе.
Дело в том, что эмулятор полноценной графической ОС это уже куда менее игрушка, чем всякие там ZX-Spectrum и подобные. Под Макосью 7.6 работали Adobe Photoshop 4, Quark XPress 3.32 и Macromedia Freehand 5.5 – на этих продуктах держалось тогда процентов 90 западной издательской индустрии. Всей вообще. Ну, где-то Illustrator был вместо Freehand.
Интерфейс этих систем по нынешним меркам минималистичен, но вполне понятен. Просто за прошедшие 20 лет немного что придумано нового, находки восьмидесятых-девяностых просто раскрашены и обросли пузырями.
Также замечу, что перечисленные софтинки в тех версиях по функционалу не отстают, а где-то превосходят многие аналогичные решения, сделанные на современных веб-технологиях.
И ещё замечу, что весь комплект из Макоси, Ворда, Экселя и Пижамкера при передаче по сети “весит” 10Мб, передаётся в один javascript-файл и кэшируется на клиенте. По этому параметру современные веб-решения просто вообще далекоооо отстают.
Всё это вместе открывает очень любопытные перспективы поставки старых приложений бандлами. Единственные ограничение – localStorage браузера, но это пройдёт.
В общем, готов поспорить, что в 2014, макс в 2015 мы увидим полный порт Win95 на яваскрипте.
С год примерно назад написал про этот концепт, вот и вот. Год был для nodejs-комьюнити очень бурным, в том числе и в плане взаимопроникновения клиентских и серверных технологий. Что в результате:
Сам я тоже этот концепт юзал везде, где можно и мне кажется, что оно становится трендом. Вот например http://artsy.github.io/blog/2013/11/30/rendering-on-the-server-and-client-in-node-dot-js/
Это очень радует.
MEAN – это Mongo DB + express.js + angular.js + node.js. Это такой новый LAMP – и он сыграет такую же роль в развитии небольших интерактивных многопользовательских проектов и особенно сервисов, как в своё время “сыграл” LAMP при взрывном росте количества небольших сайтов.
С одной стороны, это здорово. Я наблюдаю огромное количество проектов на этой связке. С другой стороны, уже вполне начало проявляться то, чем грешил LAMP – попытка натянуть простую, но неподходящую архитектуру на сложный проект.
Хороший пример LAMP – Битрикс, который умеет всё, но ничего не умеет хорошо и быстро. Когда Битрикс был маленький, он был быстрый (хотя и дырявый). А потом стала ограничивать платформа – потому что иногда нужна быстрая key-value БД, а у тебя под рукой только MySQL. Потому что для организации расширяемой бизнес-логики по-хорошему язык должен поддерживать функции как объекты первого класса – а php это заумел только с 5.3 (медленно и через жопу). Потому что апач – это приемлемо для “классического” около-REST веб-сервера, но совсем плохо для организации IM-обмена. Ну итд.
Ровно то же самое будет происходить с MEAN. Покомпонентно в нём два слабых звена – Angular и Mongo. Разбираю.
Это прекрасная NoSQL БД, когда у проекта нет дизайна. Не от русского слова “дизайн”, а от английского “design”. Ну то-есть нужна какая-то БД. Когда заранее неизвестно, что точно от БД требуется, но хорошо бы, чтобы БД умела всё, мало ли что понадобится. MongoDB (как и MySQL) такая и есть.
Зато Монго очень проста для понимания человеку, пересаживающемуся с SQL. Проще всего Монго воспринимать как такую SQL-таблицу, в которой колонки заранее не приколочены. Всё остальное очень похоже на SQL.
Всё, что нужно знать про Angular – это то, что если вы писали на php например<div>Width = <?php echo (width/2.54); ?>см</div>
, с помощью Angular вы будете писать<div>Width = { {someObj.width/2.54;}}см</div>
.
Оно имеет все те же родовые травмы, что и php – фрагментарность, недекларативность и “размазанность” кода, который затруднительно разделять на независимые компоненты.
Зато оно позволяет очень быстро делать простые какие-то проекты с несложным интерактивом.
UPD. После написания поста в ЖЖ вскрылась уязвимость. Код Angular выше исполнялся и заменялся на null, пришлось вставить пробел между { и {. Таким образом мы имеем явную проблему с Angular – типа XSS. Пусть оно называется XSAS – cross site angular scripting. Чёто не особо улыбается проверять юзеринпуты на то, могут ли они быть Angular-кодом.
В любом случае MEAN – это отличная альтернатива LAMP. Уже вовсю появляются хостинги под него (Nodejitsu, Heroku), codebase под js растёт бешенными темпами, оно всё модульное и легко настраивается.
Но это неуниверсальное решение для небольших проектов.
Сёдня в процессе переписки в твиттере народился прекрасный по сжатости код:
window.addEventListener("keyup",function(e){var o=e.target; if(o.nodeName[7]=="A") with(o.style)height=0,height=o.scrollHeight+"px"})
Этот код, если его разместить при загрузке на страницу, сделает все textarea на странице автомасштабирующимися под набор. Не только те, что уже есть, но и те, что в будущем вставятся в DOM.
132 символа и никаких там библиотек – чистая Vanilla )