усы2

Стой под стрелой

Поступки и мысли, о которых могу вспомнить не краснея

Новый доклад «ФП в браузере: Redux»
усы2
tonsky
Текст и слайды: http://tonsky.me/talks/2015-frontendconf/


без темы
усы2
tonsky
Вслед http://ermouth.livejournal.com/641180.html

На меня вот эта книга очень сильно повлияла в детстве:



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

После этого читать «конструктор это метод который...» понятно что нужно, но скууууучно. Короче, такая книжка у каждого программиста должна быть в детстве, чтобы не вырасти неадекватным гиком. Да и вообще, разве может быть плохой книжка, в которой авторы то и дело дают взаимоисключающие советы, а оглавление напечатали на корешке только ради того, чтобы получилось 256 страниц?

ФП в Киеве есть
усы2
tonsky
Был две недели назад в Киеве, прочитал на митапе в Grammarly доклад, продолжение «ФП в браузере». Доклад про то, как сделать векторный редактор на React.js и Immutable.js.

Коротко:

На JS жить можно, с правильной архитектурой писать вполне терпимо. Я ожидал больше страданий. Запилил мультиметоды и атомы, впрочем.

Immutable.js нормальная штука, не хватает только сериализации/десериализации структур в строку, очень странно что они это упустили. Пришлось писать самому.

Еще смешно: Immutable.js портировали реализацию персистентных структур из ClojureScript, при этом писали на чистом JS и умудрились сделать ее в 2-3 раза медленнее, чем на ClojureScript. Вот вам и про преимущества ручного кода перед компилируемым.

Код: https://github.com/tonsky/vec (650 loc)

Живая версия:



Видеозапись:
http://www.youtube.com/watch?v=lDkrXTDwbJQ (разбор кода)
http://www.youtube.com/watch?v=tUtLe1VlkYc (ответы на вопросы)

В Киеве классно:


Не моноспейсом единым
усы2
tonsky
Как вы знаете, я сторонник точки зрения, что код — это еще и красиво (раз, два, три). А что может быть красивее, чем листинги в пейперах по Хаскелю? Встречайте:



Собственно, что я сделал? Взял шрифт из LaTeX (Latin Modern Roman), выкинул всю подсветку (курсив только натыкал кое-где, случайно почти, каюсь). Стрелочки — это не лигатуры, это настоящие юникодные стрелки из UnicodeSyntax. Единственная свинья — в Хаскеле народу чуждо чувство прекрасного и они отказались заменять (\...) на (λ...).

Это вполне рабочая тема для Atom. Код пишется. Форматируется, естественно, табами. Пока это самая слабая часть, хочется семантического выравнивания.

Круто? Распробую — напишу, в чем подвох.

О пользе чистых начал
усы2
tonsky

Тут в Гугл Плюсе Евгений Охотников сетует, что наработки 80–90-х годов нельзя переиспользовать в вебе:

Ну вот, допустим, кто-то 20-ть лет назад сделал движок текстового или графического редактора. Не суть важно, на C++, Eiffel, Java или Delphi. Для десктопа, понятное дело, т.к. Web тогда только зарождался. Какое-то время этот движок был актуальным и мог быть портирован под разные платформы путем адаптации GUI-библиотеки (или же путем написания слоя между движком и конкретной GUI-библиотекой).

Но с окончательной победой Web-приложений над здравым смыслом (т.е. где-то лет 10 назад по моим субъективным наблюдениям), у разработчиков такого движка встал бы серьезный вопрос: а как все имеющиеся наработки портировать под Web? В котором на клиенте нормально живет только JS, а технологии обмена информацией между клиентом и сервером где-то на уровне каменного века? :)

Кроме как путем серьезнейшей переделки потрохов не получится, имхо. Что, как мне представляется, хорошо видно на примере MS Office, который вышел в Web относительно недавно. И где потребовалось много времени и сил на то, чтобы переиспользовать старый код в Office 365, дописав к нему новых клиентов (своих для каждой платформы).

Все так, но это скорее хорошо, чем плохо.

Любая система рано или поздно упирается в локальный максимум, из которого уже не может выбраться эволюционным путем. Интерфейсы в 80-х мало кто понимал. Отчаянное время. Но и сейчас мы далеки от конечного равновесия: никто не обещает, что через пять лет все опять кардинально не поменяется. Мы пока просто не знаем, как должны выглядеть интерфейсы, программы, да и вообще компьютеры. Делать ставку на долгую поддержку в такой период глупо — наследственность тянет через себя не только хорошие вещи, но и давно неактуальные, а также откровенно плохие. Если вы знакомы с современным Фотошопом, в этом видео видно, откуда растут уши у его многочисленных странностей: Undo по Cmd+Shift+Z, кнопки Preview в эффектах, дурацкие модальные окошки с No pixels selected. Все они прожили по 25 лет.

Чем дольше существует система, тем сильнее обостряется конфликт между новыми потребностями и грузом прошлого. Кода много, его невыгодно переадаптировать, репутация питается только былыми заслугами, программа переходит в режим доживания. Становится выгодно начать с чистого листа. Так за последние 5 лет появились легкие и современные альтернативы Адоби: Скетч, Пиксельматор. Из ниоткуда. Но их экономика понятна: полное переписывание это всегда улучшение минимум на порядок. Новые программы удобнее и актуальнее.

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

Возникает чисто практический вопрос: разве это не безумная прорва работы, сделать что-то хотя бы минимально ценное для пользователя, тот же графический пакет или текстовый редактор? Да, но это и есть проблема: так не должно быть. Нет никаких предпосылок к тому, чтобы разработка Иллюстратора была десятилетней эпопеей на миллионы человеко-часов. Просто наши инструменты несовершенны: разработчики на C++ борются с проблемами, которые присущи не предметной области, а самому инструменту. Включая размер кода, который очень быстро сам по себе становится проблемой. Фокус не в том, где взять столько усилий, сколько вбухивает Адоби. Фокус в том, чтобы делать то же самое быстрее и проще. Этому не научишься, если постоянно доделывать один монолит, поэтому даже хорошо, что GTK не натягивается на HTML. Каждый следующий виток снимает еще одну головную боль, и постепенно, раз за разом, мы придем к нужному состоянию, когда студент сможет написать базовую версию Фотошопа за летние каникулы.


Критерий разумности
усы2
tonsky
Меня в комментариях к предыдущему посту спрашивают, как определить, когда программа что-то по делу спрашивает, а когда нет. Как не проявить излишнюю инициативу и не вступить в конфликт с интересами пользователя? Не истратим ли мы ему интернет, если будем все время что-то обновлять, подкачивать, держать в курсе. Хорошо ли, что Windows сам устанавливает апдейты и перезагружается?

Сейчас научу. Определить, что хорошо, а что плохо — просто. Представьте, что есть вот я, человек, а компьютера нет, и программистов нет, и интернета нет. И вот я хочу что-то сделать. Пока я это делаю, мне хорошо, потому что я делаю то, что я сам хочу. Я хочу писать рассказ, и пока я его пишу, я счастлив, я занимаюсь собственным делом. Как только я начинаю делать что-то, что мне не нужно — скачиваю браузер, закрываю попап, лажу в настройки ворда, подключаюсь к вайфаю, борюсь со стилями, сохраняю, закрываю и открываю файл — даже когда это файл с моим рассказом — я грущу, потому что мне это не нужно. Это нужно технологии, но это не имеет ничего общего со мной и моим рассказом. Вот и все, весь критерий.

Любое движение в направлении моих желаний, моих потребностей — хорошо, это очередной маленький шажок в мир будущего, все, что нет — плохо. Перезагрузка — плохо, потому что мне не нужно перезагружать компьютер. Перезагрузка во время, когда я не сижу за компьютером — хорошо, потому что это технология обеспечивает свои потребности и не маячит у меня перед глазами. Однако нюансы: Windows, во-первых, не может нормально определить, пользуюсь я сейчас компьютером или нет, то есть может прервать мою работу, и во-вторых, она не может все вернуть ровно в том виде, в каком оно было. Она даже ворд назад с тем же файлом открыть не сможет. Хуже всего, она может _потерять_ то, что я написал, а это самый страшный грех для программ на свете. Когда перезагрузка от этих недостатков избавится, станет хорошо.

В этом смысле очень легко понять, что не так с cabal update: я не хочу ведь обновлять <что она там обновляет>, верно? Я пишу код, мне хочется писать код, а эта штука встает на пути, мешает. У меня ведь нет цели в жизни «запускать cabal update», это каприз технологии, ничего со мной общего не имеющий. Если так-то, по чесноку, даже система сборки мне не очень нужна — мне нужен код, но у меня нет задачи его собирать. Вернее даже, мне нужна работающая программа. Системы программирования будущего уберут всю эту ересь, программа будет запускаться, работать и разрабатываться в одном непрерывном процессе, как скульптор лепит скульптуру.

Конечно, мы, программисты, так привыкли, что вот оно все так работает: обо всем нужно просить, явно вызывать, дергать, соединять, настраивать и устанавливать. Руками надежнее, потому что инструменты все ненадежные и тупые — могут съесть платный трафик, забыть обновиться, стереть что-то. Нам кажется, это так и должно быть — но это все временное. Морской капитан 18 века тоже бы не согласился, что паруса и мачты не нужны. Знание Linux, владение командной строкой, API — это местечковые артефакты, всего этого не будет в светлом будущем. Компьютеры будущего будут несравнимо прямее и проще устроены, даже для программистов, с гораздо меньшим количеством ручного управления — и гораздо надежнее, потому что минус человеческий фактор. И это не в ущерб низкоуровневости, скорее она тоже упростится.

Люди не придут к компьютерам, как нам когда-то казалось. То, как мы стали «компьютерно грамотными» — ни одно поколение такого больше не повторит. Не будет дома по-особому пахнущего уголка с жужжащей черной коробкой, никто не будет обучаться Ворду и Экселю, по крайней мене не в большей степени, чем пишущей машинке. В Фейсбуке отказались от термина «пользователи», теперь это просто люди — действительно, странно называть особым словом человека, пользующегося компьютером. Мы же не называем особым словом смотрящих телевизор, или разговаривающих по смартфону. Компьютеры растворятся и придут со стороны бытовых предметов — в одном ряду с миксером, журнальным столиком и ковриком для ванной. В конечном итоге, смысл существования Windows не в том, чтобы существовал Windows. Сам по себе он никому не нужен. Так получилось, что в переходный период без него было нельзя, но не ошибайтесь, что это что-то значимое происходит.

без темы
усы2
tonsky
[~/work/getting-started/haskell] cabal install
Warning: The package list for 'hackage.haskell.org' does not exist. Run 'cabal update' to download it.
Resolving dependencies...
cabal: Could not resolve dependencies:
trying: aicontest-0.1.0.0 (user goal)
next goal: vector (dependency of aicontest-0.1.0.0)
Dependency tree exhaustively searched.


Я не хочу наехать конкретно на Хаскель, просто пример показательный. Много какой софт так написан: он умеет сам определить, в чем проблема и как ее починить, но заставляет пользователя это делать.

Я даже представляю примерно ход мысли, что ли: у разработчика есть модель, как софтом должны пользоваться, и он учит пользователя такими вот ударами хлыста. Затачивает голову под нужный порядок мышления. Это и к GUI-шным вещам часто относится, и к консольным.

Идея о том, что работу, там где это возможно, нужно с пользователя молча снимать, она достаточно недавно пришла в широкие массы (скажем, приложения без файлов и ручного сохранения iOS 2007, автообновление Chrome 2008, автосохранение OS X Lion 2011, background app update в iOS 7/Mavericks: 2013). И это часто все еще некое дополнительное усилие, «фича», особенно для десктопного софта, нежели режим по-умолчанию.

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

Кодефест-2015
усы2
tonsky
Лучшие слайды в моей жизни. Так меня еще никогда не перло. В соответствии с традицией, слайды сразу с полным текстом доклада. Будет ли видео — 50/50, от организаторов зависит.

Щелкайте:


без темы
усы2
tonsky
Один мальчик выложил на GitHub в open source облачный распределенный BigData IoT SaaS мэшап с TDD, BDD, DDD, ATDD, STDD, DRY, CQRS, SPoF, EAFP, IoC, DI, DVCS, YAGNI, TMTOWTDI, convention over configuration, zero configuration, SEO, Scrum, microservices, Docker, Cassandra, Hadoop, Cucumber, responsive isomorphic Angular, machine learning, data mining, loose coupling, event sourcing, FRP и Kanban. Но без MongoDB. Потом его все равно в ад забрали, конечно.

https://twitter.com/nikitonsky/status/578457029876047872

Будьте здоровы!
усы2
tonsky
Согласно вот этой статье из википедии, примерно 18–35% людей чихают при взгляде на солнце. Безусловный рефлекс, генетическая черта.

Я провел опрос в твиттере, действительно, многие признались, что феномен имеет место быть (~25 человек!)

Самые интересные ответы это: «я думал у всех так» (еще один: был уверен, что у всех так) и «постоянно советуют -- не получается чихнуть, посмотри на слонце. Постоянно смотрю как дурак и не чихаю»

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

AnyBar: OS X menubar status indicator
усы2
tonsky


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



Использую лично я для индикации состояния билда (вот плагин для boot-clj). Билд крутится в терминале, а так как экранчик у ноутбука маленький, то терминал на заднем плане где-то. Если сломалось — сразу видно по статус-бару. Вот видик, показывающий, как это работает, на старой версии.

Исходники и ссылка на скачивание на гитхабе:

https://github.com/tonsky/AnyBar

Вступайте в фан-клуб, в общем.

Ну и похвастаться:


Изоморфные веб-приложения: скорее нет, чем да
усы2
tonsky

С тотальной победой React-а и функционального подхода на клиенте может показаться, что будущее одностраничных веб-приложений светло и безоблачно. Однако, даже если предположить, что у нас есть хорошая клиентская база данных навроде DataScript, и мы грамотно организовали потоки данных в приложении, остается вопрос сервера.

Как бы нам этого ни хотелось, данные лежат не в браузере (иногда они, конечно, лежат, но это скорее исключение, да и там уже все не так просто стало). На горизонте появляются тучи, простая и стройная архитектура обрастает некрасивыми хаками. Разные компоненты хотят разные куски данных, иногда куски повторяются, надо решать проблему N+1 select, обратная синхронизация, разделение на начальный префетчинг и доставку дельт. REST это новый ORM (пока, правда, не дотягивающий даже до JDBC), а ORM это путь в никуда. Короче, обычный конфликт: наивную версию сделать просто, но работать она будет неприемлимо, а оптимизации вступают в конфликт с базовыми принципами хорошей архитектуры. Facebook предложил Relay + GraphQL, но ощущения пока такие, что хорошо работать это будет в основном на фейсбуке или чем-то очень похожем: рамки сильнее бенефитов.

Что нужно: язык описания зависимостей по данным и протокол синхронизации на его основе, оптимизируемый, в меру универсальный, компонуемый. В идеале один и тот же язык описывает поток браузер-сервер и потоки внутри браузера: от компонентов к родителям, от родителей в центральный sync hub. Потоки двухсторонние: компоненты отправляют запросы по данным в sync hub, там запрос группируется (компонуемость), отсылается на сервер, и наоборот: сервер пушит данные в браузер, sync hub раскидывает по компонентам, кто на что подписался. Возможно, аналогичную схему «одуванчик» можно повторить и внутри сервера.

Вторая область, где не все гладко и сладко — рендеринг страниц на сервере. Если посмотреть с очень высокой башни, можно увидеть основание из слоновой кости и то, что рендеринг на сервере это бред. У нас есть какое-то хранилище, база, это нормально. Есть приложение, оно в браузере и на js. А вот зачем между базой и клиентом нужна какая-то тонкая прослойка в виде рендеринга каких-то странных кусочков html-шаблонов, которые потом надо как-то частично подставлять в уже работающую страницу? Типичное размазывание отвественности: если мы хотим веб-интерфейс, пусть он будет в одном месте (браузер), и пусть у него там будет под рукой все что нужно. Если согласиться, что естественно не держать никакой view логики на сервере (включая тупые параметры REST-концов типа sort=name&order=asc, которые относятся только к вьюхам, вьюхам, вьюхам), роль сервера становится сильно непонятной.

В идеальной архитектуре сервер — точно такой же равноправный луч звезды, присосавшийся к центральной базе/логу событий, как и клиент в бразуере. Просто у него задачи другие — batch-работу какую-то считать, за метриками следить, почту рассылать по расписанию. Это ни в коем случае не паразитирующий посредник на соединении клиент-база. У клиента уже есть всё, чтобы себя обеспечить, сервер как помощник скорее мешает, чем помогает. К тому же все, вплоть до умеренно-больших проектов, всегда делают один и тот же бэкенд: код генерируется и обслуживается фреймворком и на 90% состоит из тавтологии: возьми table user и переложи ее в user.json. Смысл придумывать, писать и поддежривать прослойку, занимающуюся перекладыванием из формы в базу, если и формы, и базы в принципе уже сами это могут? Дайте им поговорить напрямую. В качестве иллюстрации посмотрите Hoodie и noBackend. Хипстерятина, конечно, но хипстеры же неспроста не хотят писать бэкенд — в нем действительно нет большого смысла.

Но я отвлекся. Если строить свое приложение без сервера, всё как раз получается стройно и логично. Но некоторые противные Гуглы хотят, чтобы по GET /index.html HTTP/1.1 отдавался контент, а не какое-то там веб-приложение. И если мы захотим сделать веб-магазин, то какими бы передовыми мы ни были, и как бы сильно нам ни хотелось сократить траты на разработку и душевное здоровье, под Гугл придется прогнуться.

И тут мы обнаруживаем себя у разбитого корыта. Сколько бы нам уши не жужжали про объединение браузера и клиента, примеры там обычно на уровне «реализовать факториал один раз». А тут настоящий, честный тест: языка, инфраструктуры вокруг него, абстракций, всего. Даже если ClojureScript и кроссплатформенный (через cljx несложно, даже почти удобно писать код, запускающийся и на сервере, и в браузере), то передовой React уже не так охотно готов запускаться на JVM. Надо сразу придумывать какой-то JS-рантайм (очень сподручно, я вам скажу) — но это ладно, его можно и придумать, и даже условно-эффективно (правда, не на JVM, а скорее на node.js). Гораздо интереснее принципиальные вопросы: как выковырять весь свой динамизм из веб-приложения, всякие onClick и onChange (можете себе представить), как эмулировать подгрузку данных, куда девать пуш-механизм (можно ли без него? а если по нему приходит важная часть контента?) и завязки на DOM (React, кстати, пример очень хорошей абстракции-затычки конкретно в этом месте). Ну и немножко поиграть в искусственный интеллект: представьте, что у вас живое приложение, которое рисуется в несколько проходов: сначала костяк, потом идет запрос на сервер (асинхронный, конечно), потом приходят данные (или обрабатывается ошибка), на основании этих данных делается еще N запросов, и так далее. Плюс стоят всякие фишечки, чтобы улучшить User Experience — прогресс-бар там, фоллбеки какие-то, анимации — исключительно для человека, не для Гуглового бота же. В какой-то момент вам нужно решить, что только что приложение было не готово, а вот сейчас уже в таком состоянии, что его можно отдавать Гуглу, надо делать снэпшот и высылать html. Решаемо, конечно, но опять — чувствуете? — очень сложно и местечково вместо красоты и фиалок.

И это хорошо еще если мы сможем хорошо подгрузку данных замокать (скажем, если у нас есть тот самый воображаемый язык из начала статьи). Но если для полной универсальности сервер-сайд приложение будет само на себя ходить по REST-концам, ну, там, с декодированием JSON-а, аутентификацией, эмуляцией cookie storage — я, пожалуй, в этом месте сразу на пенсию и мемуары переключусь. Программисты всю жизнь делали нестыкуемые между собой платформы (сколько сил вгрохано в проекты из серии «А это тот же X, только для Питона»). Сейчас жизнь прижала, деваться некуда, и мне, если честно, страшно смотреть, что из этого выйдет. Пока выходят ужасы из серии «перепишем git на js» и «запустим js внутри JVM/Монги/nginx».

Короче, различий между живым браузером и статичной версией для Гугла столько, что впору призадуматься: а нужна она вообще, эта изоморфность (не смейтесь, это термин из JS)? То есть нужна, конечно, но похоже что наскоком ее не сделать. Даже, скорее, если ее и делать, то с самого начала, честно, основательно, и придется многим поступиться. Причем границы этого пока туманно очерчены, но может оказаться, что с такими требованиями мы обратно придем к статичным веб-страницам и тонкому клиенту. Потому что сама постановка вопроса, она такая, несовместимая со здравым смыслом.

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


Неглубокое погружение
усы2
tonsky
Написал про то, как внутри работает DataScript:

http://tonsky.me/blog/datascript-internals/

Навык привычки
усы2
tonsky

Около месяца назад я решил оптимизировать клавиатурную раскладку. Прикинув, сколько и чего я пишу в последнее время (Clojure, CSS, русский/латинский текст), я сделал следующие оптимизации:

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

Общее направление — минимизировать количество нажатий шифта, что должно уменьшить нагрузку на пальцы. Это не универсальный рецепт, многое зависит от того, чем вы занимаетесь — скажем, в CSS и в JS имеет смысл вынести на безшифтовой режим фигурные скобки.

Я даже написал тулзу, чтобы научно обосновать свои действия, вот примерный выхлоп:

    cljs (97) —————————————

    backslash            \      503           81   |
     brackets           []    25786         3142   {}
        colon            ;     5079  <<     7769   :
         dash            -    23239         1606   _
      numbers   1234567890     9598  <<    85609   !@#$%^&*()
         plus            =     1866          490   +
        punct           ,.     8730         1651   <>
       quotes            ‘      827  <<     8544   “
        slash            /     4575         4226   ?
        tilda            `      142           10   ~

    css (7) —————————————

     brackets           []       26  <<      600   {}
        colon            ;      818          866   :
         dash            -      564          184   _
      numbers   1234567890     1757          458   !@#$%^&*()
         plus            =       11            1   +
        punct           ,.      560           51   <>
       quotes            ‘       60           24   “
        slash            /       56            0   ?

    js (2) —————————————

    backslash            \       71  <<     1094   |
     brackets           []     2564  <<     9168   {}
        colon            ;     4736         5409   :
         dash            -     1516  <<     2917   _
      numbers   1234567890     5437  <<    25052   !@#$%^&*()
         plus            =     6720          970   +
        punct           ,.    20530          549   <>
       quotes            ‘     2794  <<     6924   “
        slash            /     5279          517   ?
        tilda            `     1492            2   ~

Две цифровые колонки посередине — это частотность символов из группы. Знак << означает что имеет нехилый смысл поменять кнопку и ее шифтовый эквивалент.

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

(let [[x & xs] @atom]
  (swap! *context* #(assoc % :key "abc")))

Самое интересное здесь — это процесс адаптации. Для меня это не новый опыт — у меня уже есть клавиатура с нестандартной раскладкой, вот такая:

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

И они оказались правы. Примерно так процесс адаптации и происходит. Я прошел его один раз с клавиатурой, и вот недавно второй раз с новой раскладкой.

Забавнее всего, что в процессе обучения подобным механическим навыкам не участвует личность. Мы привыкли говорить — я знаю, я умею, мне нужно научиться. Здесь личность только мешает — учиться неохота, эмоции переполняют, ничего не получается, выигрыш далеко за горизонтом и вообще сомнительный. Проще всего к тренировке подойти отстраннено: как будто ты не себя тренируешь, а собаку. Чужую какую-то собаку. На входе энное количество механических повторений, некая регулярность. На выходе собака умеет печатать. Хочет она, не хочет, даже если она принципиально против — обучение встроено в организм и мозгом не управляется. Если есть тренировка — собака научится. То, что личность собаки в данном случае совпадает с инициатором тренировки — необязательная деталь.

То же самое и со многими другими видами обучения — новый редактор, новый язык программирования, новый курс на Курсере. Полезно смотреть за собой, улавливать структуру поведения, четко разделять цель (научиться чему-то), процесс обучения и собственную эмоциональную реакцию на него. Последнее надо научиться изолировать — эмоции идут и развиваются сами по себе, влиять на процесс они не должны.


Расширяемость
усы2
tonsky

Ковырялся я тут на досуге во внутренностях react.js, и вот что я хочу сказать вам о JavaScript вообще.

Я познакомился с JS когда это был вполне себе простой и понятный язык. Раз: любому объекту в любой момент можно добавить любое свойство, и два: один объект может иметь прототипом второй, тогда свойства ищутся по цепочке. Всё. Конечно, эта кажущаяся простота нелегко давалась разработчикам компилятора, но нам-то, пользователям, было хорошо. Просто и гениально. Я как-то недостаточно наблюдал восторгов по поводу красоты концепции.

Реализация кое-где хромала, конечно. Свойство prototype, к примеру — не путать с идеей прототипов — настоящий бред. Если бы его быстренько — ну, в ES3 там, или раньше — зафиксили, народ бы не ныл и не просил классов. Ну или использование объектов как структуры данных-словаря, до сих пор эпичнейшие баги всплывают, типа того что на npm нельзя создать библиотеку с именем constructor. Мне кажется, именно из-за этого JS-программистов и следом вообще всю frontend-разработку не считают за «настоящее» программирование.

Но реализация — дело наживное. Главное, что языку больше ничего и не надо. Можно стандартную библиотеку доделать, добавить массивы и словари настоящие, и можно вполне писать. Питон как-то так и работает, и много что на нем можно сделать.

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

Ведь почему мы так любим Кложу? Потому что в ней принято делать открытые системы (с подачи Рича, конечно). Первое — библиотеки гоняют данные, и на вход, и на выход, и внутри. Данные, понятно, открыты, это не классы, их легко распечатать, легко поменять, сгенерировать в нужном виде — короче, библиотека никак не диктует, что и как вам делать с данными. Второе — протоколы, протоколом прикинуться легко. Третье — открытые неймспейсы, куда можно при необходимости залезть, посмотреть, поменять что-то. Позволяет, например, тестировать даже то, что для тестирования не предназначалось.

Это приводит к тому, что почти всегда библиотеку на Кложе можно понять и можно заставить делать то, что нужно. Очень трудно загнать пользователя в угол, если только специально не прилагать усилий. Это важно, и я рад, что Кложе-сообщество подхватило этот тренд.

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

Не надо так.


Windows Phone
усы2
tonsky

Тут пошла волна обсуждений Windows-телефонов, ну и я выскажусь, чего уж. В целом мне телефон нравится (Lumia 1520, Windows Phone 8.1), менять его не собираюсь.

Основные страдания, с ним связанные — конечно, отсутствие приложений. Кроме MS, Nokia, Gameloft и безработных студентов почти никто под него не пишет (YouTube и Facebook приложения, например, выложены в магазин Microsoft Corporation), создается ощущение страны третьего мира.

Мне много не нужно, я почти ничем не пользуюсь на телефоне, но базовые вещи хотелось бы. Инстапейпера нет, Дропбокс, Покет, Коуб только неофициальные, соответствующего качества (ок, Дропбокс сегодня вышел — через 5 лет после iPhone). Даже если приложения все-таки выпускают серьезные фирмы, чувствуется недостаток внимания. 2ГИС только онлайн. PDF-ридеры, неожиданно, все или идиотские, или мылят текст (фиг знает, может у меня телефон большой, но на 6” и 370 ppi я хочу читать пейперы как со страницы журнала). Киндл официальный глючит эпически: прям до вылетов на определенном моменте книжки или до пропуска одной-двух строк между страницами. Хрома нет, браузер только ИE, который в принципе вполне сносный и современный (видео-аудио, веб-сокеты, передний край) кроме одной детали: почему-то он какой-то из пунктов CSS стандарта интерпретирует не так как все, в результате размеры слов в абзаце иногда эпично скачут.

Поиграть тоже мало во что есть. Редкая игра из AppStore долетает. В основном все игры или Gameloft, или MS сама портирует. Candy Crush — топовой игре в AppStore — понадобилось два года чтобы до WP дойти. Ну разве что Angry Birds есть, но они и на утюгах есть.

Но это о грустном было, а о веселом вот что: социальные сеточки почти все (фб, вк, тви, инстаграм, вайн, форсквер, даже Path, вотсапп, вайбер) и неплохого качества. Яндекс почти весь под WP портирован. Встроенные приложения или отличные, или огонь: почта, календарики, погода, переводчик (со встроенным микрософтовским аналогом word lens), скайп. Понятно, что идеальный скайп-аппарат это как раз Виндоус Фон — я один раз взял трубку, поговорил и даже не понял, что мне по скайпу звонили. Есть офис, если нужно.

Камерой я продвинуто не пользуюсь, но там вроде как куча наворотов, всяких приложений, возможностей. Я просто на кнопку жму и снимаю. Кстати, физическая кнопка для камеры — тоже огонь.

Еще из выдающегося: дизайн. Микрософт вполне заслуженно родоначальник плоского стиля, и тут он во всей красе (и даже лучше) — лаконичный, стильный, мощный, современный. Эстетически каждый день пир для глаз. Не надо путать с примитивизмом — он достаточно сложно сделан, но обманывает кажущейся легкостью и простотой. И очень удобный — все прекрасно видно и читается сразу, классная типографика, всё хорошо масштабируется — я, например, нигде не страдаю, что на 6” экране ОС или приложения выглядят по-идиотски, в отличие от iPhone 6+, у которого чувствуется натянутость. Material design это вообще смех. Вообще, все основные сентименты у меня связаны с Metro UI, который на самом деле выдающаяся дизайн-система, причем совершенно неожиданно от Микрософт — у которых, как мы помним, «нет вкуса». И вот они на коне и всех обскакали, конкурентов пока не видно.

И последнее, что сильно удивляет после iPhone — количество свобод. Очень многое можно менять и настраивать под себя, в отличие от «вам это не нужно» Эппл. Каждое в отдельности — не конец света, но в совокупности уже существенный аргумент.

Например, micro-usb зарядка — супер удобно, я внезапно понял, сколько у меня этих шнуров дома оказыавется. Оффлайн карты Nokia Maps сразу из коробки — меня в поездках по миру много раз выручали. Можно SD-карту воткнуть, никто слова не скажет, места, соответственно, валом. Тайлы настраиваются под себя — частые и информативные по-крупнее и повыше, редкие вниз или рассованы маленькими, в четверть тайла, по углам. Это и удобно, и живо, в отличие от скучного порядка iOS. Плюс тайлы еще и живые, все нотификации сразу видно с главного экрана, заходить в приложение не надо. Особенно актуально для погоды и календаря. Даже на экран блокировки можно вывести картинку приложения (например, сегодняшнюю погоду или Bing картинку дня).

Еще из убойных функций — тайлом можно добавить на экран объекты изнутри приложений: конкретную книгу, альбом, подкаст, место на карте, настройку из панели управления, человека. Удобно читать несколько книг сразу, не нужно внутри приложения между ними переключаться.

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

Плюс всякие экспериментальные фишки периодически появляются. Например, недавно вышла настройка gestures для управления звонками — чтобы ответить, никуда не надо нажимать, достаточно приложить трубку к уху. Чтобы отклонить, переворачиваешь телефон, и т.п. Есть приложение, которое на любой браузер может вывести изображение с телефона. Есть режим улучшения читабельности на ярком солнце.

В целом, телефон гораздо интереснее Эппла в части базовых сервисов, функциональности самой ОС, свобод, экспериментальных фич. Но скучноват в плане сторонних приложений.


Офигевая от простоты
усы2
tonsky

Олег тут почитал вот это про Максима и их наработки в synrc и прифигел, а я хочу заметить, что это очень показательный пример:

Чтобы сделать что-то существенное, не обязательно нужно много кода.

Если взять язык, в котором почти ничего нет (Эрленг), то кода автоматически будет получаться мало — логично. Неочевидно, что это не обязательно идет в ущерб функциональности. Код может делать все, что нужно, только малыми средствами.

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

Выбор примитивов критически важен. Базовые примитивы Эрленга качественно меняют пространство возможных решений. То, что на других языках невозможно или делается ценой сотни человеко-лет, сотен тысяч строк кода (например, распределенная БД) и с врожденными пороками качества (сегфолты, уязвимости переполнения буфера), при правильном выборе инструмента можно уместить в 2000 строк кода и осилить руками одного-двух программистов. Это не отменяет того, что они должны понимать, что делают, но если понимают, то процесс самого кодирования, вся эта борьба с ветряными мельницами, ручная разгрузка щебня, все это превращается в отдых на пляже. Вообще, забавно, как суперсовременными считаются возможности, заложенные в язык 29 лет назад.

Как-то так и должно программирование в моем понимании выглядеть: сам процесс кодирования должен быть простейшим, даже тривиальнейшим шагом. Тогда можно куда-то двигаться. Грубо говоря, если тебе нужен час, чтобы объяснить все идеи своей программы на доске, почему ты не можешь их воплотить в коде за тот же час? Это не значит, что процесс создания программы займет час — нет, гораздо дольше, нужно собрать входные данные, сделать предварительные тесты, провести исследования, придумать, решить, перебрать варианты, прототипов пару сделать. Но когда уже все решено и понятно, кодирование не должно занимать так долго, как сегодня. Почему считается нормальным, что любое написание программы — это перемещение горы? Вот хороший манифест на эту тему.

Все это немножко другой, нетрадиционный вид программирования. Тот, где существенные вещи создаются на коленке. Где весь веб-стек можно создать мимоходом в процессе создания карточной онлайн-игры, просто потому что ну вот понадобилось. В котором правильные вещи — не те, на которые сотня программистов положила свои жизни, чтобы добиться в борьбе со сложностью собственного процесса хоть какого-то уровня качества и хотя бы немного, инкрементально возвыситься над статусом кво. Правильные вещи идут в обход, копают вглубь, а не вширь. Можно потратить месяц, и на выходе получить 1000 строк, но на этих 1000 строках потом «за час долететь».

Когда кода мало, начинают качественные вещи лезть. Один человек его может серьезно поменять в течение часов, а не отдел в течение трех спринтов. Можно занять или переписать кусок реализации под свои нужды. Если кода мало, его не жалко выкинуть, это тоже важно. Хорошая разработка, достойная, по крайней мере, та, что грузит мозг — это копание вглубь, это переписывание, доведение до совершенства. Часто чтобы исправить код надо его выкинуть, а не прикрутить свеху шаблон «фабрика».

Простые, минимальные вещи, как правило, гораздо лучше соединяются. Самым бесполезный труд — библиотеки по интеграции. Когда меня просят — сделайте, чтобы X работал с Y, очень обидно — ты сделал прекрасный X, и прекрасный Y, и они каждый могут использоваться в миллионе собственных контекстов, X+Y только один из частных случаев, ну напиши ты у себя в приложении две строчки, которые перекладывают из одного в другое. В конце концов, в этом ведь и смысл — вот примитивы, используй их как тебе нужно. Сама просьба об интеграции — сигнал, что X и Y неправильно сделаны. Конечно, нужно очень много мастерства, чтобы сделать правильно, чтобы примитивы были достаточно примитивными, чтобы интеграция стала тривиальной. Но это хотя бы достойная цель, ради нее можно ночами не спать. А вот строчить библиотеки X for Y — это в никуда путь, только если руки нечем занять.

Самое важное, что я хочу о всем этом сказать: так действительно можно жить, это не утопия, не сказки из параллельной реальности. Я наблюдаю подобное и в Erlang мире, и в Clojure. Весь CouchDB — это 20K строк на Эрленге, у них в репозитории bash-скриптов вокруг этого больше, чем собственно приложения. В репозитории Kotlin 300 000 (триста тыщ) строк Java, В Scala тоже триста (из них 270 000 на самой Scala — какой-то не очень компактный язык, да?). А в Clojure всего 60 000. Datomic написали 2 человека, все ключевые подсистемы не больше 1000 строк кода. Я сам, когда понял, что нам не хватает возможностей Twitter Storm, за месяц по вечерам написал распределенный job manager на Clojure. И так далее. Именно подобные вещи должы считаться нормой, а не самодеятельностью. Да, для этого нужно долгий путь пройти, нужны те самые примитивы, на которых серьезные вещи можно было бы строить играючи, их нужно накопить, нужно чтобы их кто-то сделал. Кое-что уже есть, но в целом многого не хватает, и часто слишком большое трение при склеивании всего вместе, есть куда улучшать. Но путь, конечная цель — если вам интересно — какая-то такая.


Программируем мультики
усы2
tonsky

Я тут шутил в твиттере, но на самом деле и не шутил:

How’s “Director of Animation in UI” for a job title?

Разговор вот о чем. Если вы видели Мак и помните первые впечатления от Мак ОС, особенно после Виндоуса или Линукса, скорее всего вас впечатлило огромное количество анимаций. Табы не просто сменяют друг друга, они перетекают. Окошки сворачиваются в док по довольно сложной кривой. Иконки в доке прыгают, а при удалении испаряются в облачке дыма.

Это вовсе не блажь, анимации критически важны. При всей их субтильности и скоротечности они помогают понимать, что происходит. Основные вопросы любого интерфейса — где я нахожусь, как я сюда попал, что есть вокруг — на них сложно ответить в цифровом мире, когда одно окно мгновенно сменяется другим, совершенно на него не похожим. Теряется причинность, связь. Анимации — изящное средство, не отнимающее пространство, задействующее встроенные в человека механизмы восприятия, понятное интуитивно и приближающее светящиеся точки экрана к объектам физического мира.

Анимации точно не даются даром: в том же Маке анимации вылизаны только в флагманских приложениях и в общесистемных штуках типа NSTabView. Сложность тут, скорее всего, чисто техническая.

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

W3C, как всегда, прилагает все усилия, чтобы никому качественно легче жить не стало. CSS-анимации — нововведение уровня border-radius — совсем простые случаи, иногда, как-то, но хоть закрывает. Хорошо что есть, но хотелось бы чего-то посерьезней. Можно упороться и добиться неплохих результатов:

но посмотрите на код. Это совершенно неизменяемо и неподдерживаемо.

Всегда есть JavaScript, конечно, но сам по себе он проблему не решает. Судя по тому, что у Гугла веб-версия Inbox значительно хуже анимирована, чем мобильная, вопрос даже не в количестве усилий.

Не хватает подходящего инструмента, модели. Причем есть ощущение, что чтобы запустить прогресс, придется много чего существующего разломать. HTML, CSS и DOM, например, умеренно удобны для верстки текста, но не выглядят удобным средством разметки UI. Вся история развития веба, начиная с момента, когда в нем захотели делать что-то похожее на приложения, на интерфейс, и до современности, включая flexbox — это страдания по поводу вот этой вот шизофрении, попытки засунуть квадратный кубик в круглое отверстие. Ну нету в CSS инструмента, чтобы поставить логотип в верхний левый угол. Обтекание картинки текстом — есть, а левого верхнего угла нет, и не планируется. Представьте, сколько раз прозвучит слово f**k, если вы начнете верстать что-то подобное на div-ах.

Лучшее, что я пока видел, это Grid Style Sheets, портированный в веб Cocoa Auto Layout. В принципе, он как-то работает, но в большие проекты его брать страшно: новостей давно нет, как падает производительность с ростом числа ограничений (тысячи, десятки тысяч), непонятно. Хочется чего-то подобного нативно в браузер. И это мы только про статику говорим.

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

Но одновременно мы хотим и адаптивности — в отличие от кино/мультфильма, анимация приложений должна быть интерактивной и работать на неизвестном в момент производства содержании. Вот тут, например, понятно как это будет выглядеть на четырех квадратах, и можно даже представить себе, как будет выглядеть инструмент, который позволит подобное нарисовать. Но в приложении у конкретного пользователя квадратов может оказаться и 1, и 10.

Скриншот выше сделаны в Adobe Edge. Обратите внимание, сколько анимаций для этого сайта нарисовали дизайнеры, а потом интереса ради сходите на живую версию и посмотрите, как он на самом деле работает. Лучшее, что есть в живой версии, это спиннеры.

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


SSE vs. WS
усы2
tonsky
Периодически встречаю упоминания, чуть ли не с гордостью, что вот мол мы для синхронизации веб-приложения гоняем server-sent events. Подразумевается, что это осознанный выбор, между WebSocket и SSE выбрали SSE. Я пытаюсь составить для себя карту факторов, которые к такому решению приводят. Сам я вижу вот что:

− SSE односторонний, WS двухсторонний
− SSE не поддерживается IE и мобильным IE, даже самыми последними. WS есть уже везде
− WS умеет binary payload, SSE не умеет (в худших традициях — newline-delimeted протокол). Серьезно, вот как JSON выглядит on the wire:
data: {\n
data: "msg": "hello world",\n
data: "id": 12345\n
data: }\n\n

+ SSE умеет сжатие через gzip, WS сжатие в процессе стандартизации
+ В js API у SSE идут встроенными такие вещи, как event id (дедупликация при реконнекте) и event type (subscribe topic). С другой стороны, это делается тривиально

Все упоминания о выборе между WS и SSE, которые я встречал, были примерно такого толка: «да оно нам как-то и не надо, нам SSE достаточно». Это больше не на осознанный выбор похоже, а на какую-то подсознательную боязнь WS — учитывая минусы SSE. Или я проглядел какие-то потенциальные плюсы?

DataScript for Web Development
усы2
tonsky
Доклад с Clojure eXchange 2014:

Видео (надо залогиниться)

Слайды

Cheers!