Category: литература

С высоты-3

Пост вызвал некоторую дискуссию, в связи с чем я не перестаю удивляться, насколько людям кажется что мир устроен так как им хочется а не так как он устроен на самом деле. Многие живут мыслью что то что они (ну или я) пишу это не настоящая Кложа, а где-то там далеко есть настоящая, и если сильно припрет то взял type hints и поправил и так-то и пишут настоящие джедаи. У них все всегда сразу достигает JVM-уровня скорости потому что они сразу везде указывают примитивные лонги и вообще все специфицируют и раскладывают сразу оптимально. Ну или разложат если будет нужно.

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

Так вот. Я сам не то чтобы чужд оптимизациям и натягиванию ужа на ежа. Я потратил достаточно много времени, пытаясь делать разные вещи быстрее, чем они есть. Придумывал какие-то оптимизированные defrecords в DataScript. Менял функции на макросы для инлайнинга. Городил макро-DSL для работы с массивами. Писал макросы, которые эмитят сразу оптимальный JS. AOT-прекомпилял Кложу в классы для быстрого стартапа. Видел тоже разного: всякие библиотеки для быстрой математики, патченные исходники с отложенной инициализацией var-ов, фоновые «прогретые» JVM для быстрого старта. Даже мантра «держи репл всегда запущенным» в общем-то про то, как бороться со тормозами на старте Кложи. Про все это можно сказать одно: это очень изнурительно, и удовольствия в этом никакого нет, только сложность и постоянное разочарование.

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

Но если уж ввязался, то просто делай как все — будет проще, приятнее и честнее. Если язык предлагает records, бери и используй records, а не городи свой хитрый макрос на deftypes. Если нужно позвать функцию — значит, нужно позвать функцию. Если компилятор при этом продалбывает arity в метаданных, чтож — значит, продалбывает, такова цена. Так устроен язык. Хорошо, если это просто по недосмотру и можно отправить патч в компилятор. Если нет, что ж. Все равно нормальный, обычный код, собранный из того, что дают, в конечном счете, на длинной дистанции, выигрывает именно своей простотой и нормальностью. Потому что локальные оптимизации всегда останутся локальными и будут только мешаться под ногами непредвиденным образом; чем дальше, тем больше.

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

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

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

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

[...] при разработке на Кложе удобно думать в математических понятиях (а хешмэп это пожалуй самая близкая к функции структура данных). При разработке на Расте это кажется прямо-таки немного противоестственным, и хочется уже взять плоский кусок памяти, и как-то там его расчерчивать.

Язык определяет мышление, best tool for the job, вот это все. Банально, но на конкретном примере оно всегда как-то доходчивее.

усы2

Переосмысляем профессию

Ну что же. Сразу после знаменитого поста я поехал на корпоратив/конференцию Таргетпроцесса. Идеальный способ распрощаться с работой: предполагалось три дня на природе, вдали от техники и интернета, так что я прямо у них в офисе захватил книгу «Дзен и искусство ухода за мотоциклом» (сорри, как-нибудь верну). И что же там пишут?

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

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

Я пошел учиться на программиста в 2001, начал возиться с компьютерами году чуть ли не в 1995-м, наверное. Работал программистом ever since. Это где-то 13-14 лет non-stop. Казалось бы, какие уж тут вопросы. Однако! Где-то в районе 2007-2008 я четко помню, как потерял интерес и увлекся юзабилити (то, что сейчас UI/UX). Разобрался (сам), прочитал все главные книжки, даже поработал немножко за деньги юзабилистом. Подсел на регулярные советы Горбунова. Потом вроде как интерес к программированию вернулся, особенно когда начало что-то получаться, но юзабилити и дизайн так и шли фоном.

И идут до сих пор. Например, я рисую логотипы всем своим проектам.

один из любимых

Я сделал собственный дизайн своему ЖЖ, потом tonsky.me. Все слайды для презентация я делаю сам. У меня куплены Sketch, Pixelmator, iPad Pro с пенсилом + ProCreate специально для рисунков. В свое время я довольно много времени провел в Final Cut. Это ли стек программиста? В нескольких докладах я рисовал миллион ручных иллюстраций.

уже классика

Я делал собственные цветовые схемы для LightTable, а потом для VS Code.

Про любую диаграмму, даже самую служебную, чтобы что-то объяснить, меня обязательно спрашивают: какой тулзой я её нарисовал? Никакой. Все ручная работа.

да, даже про эту

Добавилась типографика. Я шрифт сделал, блин! У меня есть посты про «читабельную Clojure», где я рекомендую, как сортировать импорты и сколько пробелов ставить после функции. Еще один пост про мою личную систему выравнивания кода пока в заметках.

любой нормальный программист, если он вообще заметит в чем тут разница, покрутит пальцем у виска

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

Кроме «как», меня волнуют еще и вопросы «кому» и «зачем». Весь мой ЖЖ, в активную профессиональную фазу, он весь про «программисты! Остановитесь и посмотрите, что ж вы делаете-то!»

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

В общем-то к остальным вещам из жизни у меня отношение тоже сугубо романтическое: машина/телефоны/кинотеатр/приставки/сантехника/мебель. Я люблю хорошие, продуманные вещи, но внутрь лазить не хочется, хочется, чтобы кто-то пришел и сделал. А если что-то не работает, я бешусь и фрустрирую — ровно как барабанщик Джон в книжке. Главное, я даже книжу-то совершенно случайно захватил. Я и понятия не имел, что найду внутри. Что внутри мне всё объяснят про меня же. Совпадение так совпадение.

Что же получается? Мама, я занимаюсь не тем? Может я дизайнер, мама?

усы2

Танцуй, завещай

Мне тут письмо пришло, про мой журнал и, кхм, информационный стиль. Слышали? Вот тут можно почитать. Не бойтесь, там коротко и по делу все. Но я еще короче: это про то, как написать объявление так, чтобы читатель не умер, пока дочитает его до конца (в инфостиле: «читатели читают объявления до конца и не умирают»). Все классно, полезный навык, но есть проблема. Максим Ильяхов — человек-главред — увлеченный и шумный, и среди дизайнерской тусовки чуть ли не единственный, кто пишет про тексты и язык. Пишет много. Если вы думаете начать писать, то вам нужен рецепт, образец, и с большой вероятностью, если такой рецепт поискать в интернете (а где еще искать?), вы наткнетесь на инфостиль. Упрётесь даже, просто в силу скудности альтернатив (будущие Салтыковы-Щедрины ищут и упираются…).

И вот просыпаюсь я однажды, а инфостиль везде: в объявлениях, на сайтах, лендингах, в пабликах и блогах, лонгридах, есть даже книга, написанная в инфостиле (про инфостиль, разумеется). Вы скажете: сколько же нужно знать, чтобы нормально написать объявление? Как минимум 440 страниц, с картинками, правда. Принцип: адепты инфостиля пихают его куда не надо.

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

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

усы2

Сказка о потерянном времени

Потерял вчера полдня, пытаясь понять, почему input рисуется без значения в нашем React/ClojureScript/Rum приложении (и сейчас уже плюс день, чтобы это починить, and counting). Разговорился с интерном, рассказал ему что там за история — и тут он заметил, как его восхищают такие вещи, как интригует ковыряться в таких сложных материях и как он тоже так хотел бы.

Тут, конечно, меня накрыло. Накрыло, потому что я всё это делаю через огромное страдание и жалею о каждой минуте, потраченой на эту возню. Конечно, если смотреть на мир софта как на данность, то у нас есть впечатляющей сложности артефакты, с которыми нам дано повозиться, и, в общем, крутизна программиста в том, насколько ловко он с этим управляется. Но если посмотреть, например, со стороны затраты/результат, то возня это как раз холостой ход и гордиться тут нечем.

У нас уже есть JS, CSS и HTML, в которых одни и те же вещи называются и работают тремя разными способами. Теперь умные люди придумывают React (и носятся с ним, как будто он дан нам свыше) и вводят четвертый способ. Реакт работает через JS, поэтому ему надо уметь конвертироваться в DOM-атрибуты (и назад!). Он также хочет рендериться на сервере, поэтому ему приходится уметь и в HTML-атрибуты. Потом появляется ClojureScript со своим kebab-case и естественно вводит пятый способ и библиотеку Sablono. Во всей этой вакханалии невозможно не потерять информацию, и она теряется, возникает куча смешных случаев типа: одно из самых популярных свойств class конфликтует с желанием использовать объекты как хэши в JS, и в итоге там оно называется className, а в ClojureScript этой проблемы нет и оно снова называется class и цепочка получается class (CLJS) → className (React) → className (JS) → class (HTML/CSS). И это я еще про консистентность в SVG атрибутах не начинал. Ну и в итоге все закономерно заканчивается тем, что и React, и мой Rum (у которого свой server-side render) вынуждены хранить полную таблицу соответствия всех возможных атрибутов со всеми. Звучит продуктивно, да?

Окей, но Реакт зато нормализует. Опять же, don’t get me started, как он нормализует, но допустим, что в этом-то плохого? Опять же, это было бы хорошо, если бы он смог если бы он был дан свыше и кроме него ничего бы не существовало. Но если смотреть на React как на просто один небольшой кусочек паззла в grand scheme of things, то он скорее мешает, чем помогает, потому что это еще одна дополнительная сторона, требующая себе внимания. Т.е. я уже не просто пишу HTML-сериализатор, я пишу сериализатор с оглядкой на то, что где-то рядом будет Реакт и их, возможно, будут использовать вместе. А у него, конечно, свой взгляд на вещи, и нужно отдельно, когда работа сделана, тратить чуть ли не еще больше времени, чтобы его уговорить. Плюс в Реакт доложено всякого, и я бы знать про это не знал и был бы счастлив, а теперь вот приходится учитывать.

Если смотреть на это как на артефакты цивилизации атлантов, конечно, масштаб впечатляет, а те, кто способен с ним совладать — полубоги. Но как результат человеческого труда, если объективно на него посмотреть, с оговоркой что это всё хорошие люди делают и они наверняка выкладываюстся на 120% и лучше так чем никак, то это артефакты, которые рождают проблемы, а не решают их. Список атрибутов устареет, события будут приходить невовремя, эмуляция placeholder в ИЕ сломается (честно, лучше бы они настоящий использовали), установка onClick на root будет мешаться на iPhone и т.д. А, и два вида инпутов на каждый, переключаться между которыми, типа, не рекомендуется! Я прям вижу, как люди, когда это писали, сидели и думали: а вот тут ты, мой дорогой, да-да, лично ты, будешь страдать, потому что мы такую вот штуку придумали и тебе с ней жить. То есть, конечно, они так не думали, но я бы хотел, чтобы как раз думали, чувствовали это постоянно (я, например, чувствую), а потом взглянули на себя в зеркало, ужаснулись и спросили «что я за человек такой? Кто дал мне право обрекать на муки других людей?»

Все привыкли ругать браузер и DOM, мол, legacy и источник проблем (а все фронтендеры, подразумевается, хорошие и всё всегда делают правильно, ха-ха). Но штука же не в этом, штука в том, что мы не можем взять DOM как данность и пойти делать более сложные вещи. Вся эта возня с JS-миром не ощущается как прогресс. Скорее как толчение воды в ступе. Или нет — как воду решетом носить. Когда вместо того, чтобы заклеить дно скотчем и работать дальше, вместо этого к нему приделывают ручку, дают более быстрому носильщику и начинают придумывать, как сделать, чтобы вода меньше расплескивалась во время бега. Это не решение проблемы и не прогресс. Хочется артефактов, которые закрывают какую-то область, пусть маленькую, но без дыр. Чтобы если ты ее взял, то ты беспокоишься о меньшем количестве вещей, а не о большем.

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

усы2

Проблема с ярлыками

Чем отличаются эти две иконки?

Если у вас есть какой-никакой опыт с компьютерами, вопрос покажется вам слишком простым. Однако, есть проблема.

Ярлык — абстрактное понятие. Его можно понять, но для этого требуется усилие и определенный склад ума. Ярлык противоречит бытовому опыту. В жизни, если у вас есть книга, то она либо стоит на полке («все книги»), либо лежит на столе («десктоп»), либо мы ее сейчас читаем («открыта сейчас»). Можно сказать, что у книги есть состояние, ее можно переводить из одного в другое, но — на что можно всегда положиться — книга одна и она всегда в каком-то одном месте.

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

Положение усугубляется тем, что ярлык нарочно выглядит так же, как и исходный объект, но работает по-другому.

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

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

Что делать? Делать интерфейс надежным (вещи всегда ведут себя одинаково и предсказуемо). Качество интерфейса, в котором хотя бы часть элементов работает всегда одинаково (всегда-всегда, без контекстов, условий, попапов и прочих «но») вырастает на порядки (см. мой пост Единственная надежная кнопка).

Дальше: не вводить абстарктных концепций. Ориентироваться на бытовой опыт. Проще всего с иконками: если у тебя приложение есть, есть и его иконка. Ярлыков нет, иконка одна и где-то в одном месте лежит: в панели быстрого запуска, на десктопе, в папке Хлам. Это очень простая и прямолинейная концепция: иконка=приложение, папки/панели/экраны=место.

Так работает, например, iOS, который перепридумывали с нуля, выбросив наследие десктопных компьютеров:

У каждой иконки может быть только одно место. «Вид» удаления только один, и он совсем удаляет:

А вот Android сохранил ярлыки и создал путаницу:

Даже в свежайшей 6-й версии они путают пользователя тем же вопросом, что и Windows 95: удалять ярлык или приложение? Такие вопросы можно задавать только бородатым 40-летним сисадминам.

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

Формально, как программист, я понимаю ход мысли, но это очень, очень сложно и нелогично на бытовом уровне. У меня на столе лежит книга и я хочу убрать ее на полку. Зачем перетаскивать ее в мусорное ведро, да еще и в другом конце комнаты?

Но прогресс не стоял бы на месте, если бы в Гугле не придумали как сделать хуже чем было в Windows в 95-м году. Ярлык сейчас от приложения визуально не отличается совершенно:

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

Полноты ради, у Windows Phone та же проблема, но с десктопа нельзя приложение совсем удалить, только ярлык. Плюс в том, что хотя бы не нужно принимать решение (Удалить или Удалить?). Это значит, что человек сможет пользоваться своим телефоном без услуги «звонок другу», но все-таки приложения будут копиться. Это все-таки лучше, т.к. прямо сейчас жить можно, а проблему можно решить позже — очень правильное качество «скромных» интерфейсов.

В обсуждении просьба помнить, что это пост о конкретном интерфейсном аспекте, а не о том, что «Андроид говно» (конечно говно, даже windows phone лучше). Просто единственный нормальный пример, где нет этой проблемы — iOS, в остальных местах она везде есть (особенно на десктопах). Также, не надо мне пожалуйста рассказывать что я тупой и не разобрался. Или что вы лично разобрались и не видите проблемы. Это искаженное восприятие и отсутствие эмпатии. Некоторые вещи должны (и могут) быть сделаны так, чтобы не надо было разбираться.
усы2

Ну, за независимость!

Управлять зависимостями трудно. Сам факт того, что такое понятие существует, уже намекает, что там есть с чем повозиться (простите мне чересчур мягкую формулировку, я сдерживаюсь изо всех сил). Поэтому один из важных принципов разработки — не тащить зависимости. В институте учат, что переиспользование кода — главная благодетель (и эта мантра наделала ужас сколько вреда). Так вот, переиспользование кода из сторонней библиотеки — тот случай, когда копипаста лучше переиспользования. Бывают библиотеки, большие и сложные, дающие бонус только целиком. Зато он существенный, и без него никак. Тяжелая алгоритмика. Новые качества. Тогда — конечно. А всякие утилитки, функции на десять строчек, удобные оберточки над платформой — задумайтесь, выдохните, и не тащите. Скопируйте одну функцию, если правда удобно. Я уж не говорю про случаи, когда быстрее сделать, чем искать, какая библиотека это уже делает (может это форма социализации такая, использовать чужой код, даже тривиальный? Или неуверенность в себе?). Особо остро выделяются свалки, где много разного, а раз много, значит каждый релиз что-то да сломают. Вообще, жалко, что так мало у нас ценят законченные вещи. Доделанные до конца, с фиксированым скоупом, а значит стабильные, не меняющиеся.

Есть еще конфликты версий, но с этим проще. Следуйте принципу: в своем приложении творите что душе угодно, тащите сколько угодно хлама, если времени не жалко потом его обновлять. Но если делаете библиотеку — у нее не должно быть зависимостей. От слова совсем. Полностью самодостаточный код, зависит только от платформы. Да, несправедливо по отношению к авторам библиотек — не вкусить им плодов прогресса и удобства опенсорсных АПИ (гг). Но эта жертва сэкономит непропорционально много времени всем остальным. Если подумать не о себе, а о потенциальных заинтересованных в библиотеке коллегах, понятно, что у них в приложении организационные вопросы уже как-то решены — логирование, коммуникация, хранение стейта, управление подсистемами, event loop. Если автор библиотеки пытается что-то из этого заиспользовать в библиотеке (упростить жизнь себе? помочь пользователям?), очевидно, он будет только мешать. Крепитесь, это не так уж страшно.
усы2

(no subject)

Вслед http://ermouth.livejournal.com/641180.html

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



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

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

Расширяемость

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

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

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

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

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

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

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

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

Не надо так.

усы2

Om, React и все-все-все

React.js — это библиотека, недавно перевернувшая JavaScript-мир с ног на голову одной простой идеей: давайте оперировать не настоящими DOM-елементами, а JavaScript-классами, их изображающими. Синхронизацию этого симулякра с настоящим браузером отдадим библиотеке.

Оказалось, что если не трогать DOM, работать с объектами настолько дешево, что можно их даже не хранить, а всегда дергать функцию state → pseudo-dom, генерирующую каждый раз новый псевдо-дом. Это первое достижение React-а, сделать двухстороннюю синхронизацию данные-интерфейс односторонней. Мы всегда пишем, как из данных получить UI, и никогда не пишем, как один UI перевести в другой UI. На всякий случай еще раз: подход «а вот по этой кнопке скроем панельку» был хорош до определенного предела, пока сайт был в основном статический, с немного меняющимися частями. Сейчас же то, что рисуется в браузере при загрузке, и то, что там будет через 2 минуты, может не иметь ничего общего вообще. Поэтому подход «дайвайте опишем, как эволюционирует наш DOM» работает не очень из-за комбинаторного взрыва — слишком много способов, как он может эволюционировать.

Второе достижение React-а в том, что они реализовали концепцию «всё свое ношу с собой», придав компонентам адекватную стандартизованную структуру. Грубо говоря, в момент создания компонент сам себе нужные ресурсы выделяет и сохраняет в собственный стейт (таймеры, сокеты, листенеры), а в момент удаления — прибирает. Звучит банально, но здесь важен факт, что это есть. Ситуация аналогична проблеме неймспейсов — яйца выеденного не стоит, но в JS их забыли и каждый разработчик вынужден пускаться в собственную езду на лыжах по кирпичам. DOM-листенеры тоже, кстати, крепятся к компоненту, но уже самим react-ом. Это опять же важно для highly dynamic интерфейсов — руками за всеми ресурсами следить и замаешься, и не уследишь.

Получаем, что react-овские компоненты это такие маленькие самостоятельные кирпичики, которые действительно можно складывать в стену и они сами будут работать, не захламляя приложение в неожиданных местах типа регистрации в top-level listener или создаваемых, но никем не удаляемых setInterval.

В общем, я примерно всю революцию уже описал. Можно делать самодостаточные, переиспользуемые компоненты (у них честное воткнул-и-готово), очень простой и мощный data binding (произвольная js-функция state→dom, и не надо выкручиваться в ограничениях template bindinds, и вообще html с шаблоном не нужен), быстрая синхронизация с DOM. React.js маленький-легковесный и это, в целом, opinionless библиотека, которую можно совмещать с чем угодно. Используется Фейсбуком и Инстаграмом, куча баек про то, как интерфейс, переписанный на React, избавляется от проблем со скоростью отрисовки. Но главное, что с ростом количества динамических частей на странице код не начинает катиться в говно экспоненциально. В целом, прорыв уровня jQuery.

Теперь Om. Om — это ClojureScript-биндинг к React-у от David Nolen, главного коммитера ClojureScript, и первая вещь, которую надо про него понять — это не биндинг. Да, он использует React, оборачивает его в cljs интерфейсы, но на самом деле под этой (достаточно выгодной) этикеткой продает свои, совсем другие идеи.

Первая, и очень хорошая — зачем нам рендериться на любое изменение стейта, давайте рендериться один раз на requestAnimationFrame. Мы получим те же 60 fps и еще меньшую площадь соприкосновения с DOM, чем в React. За счет этого, например, он обогнал голый React в ToDoMVC перфтесте.

Вторая — это управление состоянием всего приложения. Если React в этом смысле был достаточно нейтрален (ну, ты, это, давай там сам как-нибудь сам), то у Om насчет состояния вполне четкие планы. Дэвид постаралася сохранить переиспользуемость компонентов и добавить несколько бонусов сверху. Если коротко, то состояние всех компонентов в Om — один большой atom, персистентная структура, а все компоненты получают view в эту структуру на то место, которое относится непосредственно к ним. Т.е. они получают такой handle (в терминах om — cursor), через который они могут читать кусочек этого большого дерева и писать в него. Если компоненту нужны подкомпоненты, можно создать под-курсор из своего курсора, например.

Эта простая идея дает два бенефита:

Возможность показывать в разных местах страницы одно и то же значение буквально. То есть, например, слева у нас таблица сотрудников (компонент table), и в колонке «пол» у них или Man, или Woman. А справа у нас text input для редактирования списка полов, и мы в нем меням Man на Male и в таблице все автоматом синхронизируется. Потому что оба компонента работают с курсором на одно и то же место в атоме. Из-за особенностей реализации text inputs в React можно даже сделать так, чтобы значение в таблице менялось по мере набора букв в text input.

Второй бенефит — это возможность работать с состоянием всего приложения как с чем-то цельным. Это персистентная структура, значит можно хранить историю состояний всего на 100 (например) версий назад, каждое состояние иммутабельное и все они разделяют кусочки, которые не изменялись. Элементарно прикручивается undo, причем на любую версию: ты просто говоришь om-у (а он react-у): давай сейчас вот это состояние рисуй, и react сам вычисляет оптимальный способ его нарисовать из текущего dom: где что удалить/добавить/подвинуть, чтобы получить целевое. Палитру History в фотошопе видели? Короче, бонус в том, что управление состоянием вынесено за скобки. Можно прикрутить логику синхронизации с сервером, undo, сохранение в localStorage — и всё это будет снаружи и отдельно, а не размазано по GUI-компонентам.

Там не всё идеально — документация мутная, курсоры излишне хитрожопо сделаны и не описаны (точнее, сейчас описаны, но это я доку написал), и вообще оно alpha. Но это уже, наверное, самый востребованный GUI-фреймворк на cljs — я думаю, из-за hype вокруг React + имени создателя. Я не то чтобы рекомендую, я скорее популяризирую хорошие идеи, плюс это еще такой спасательный круг тем, кто полезет в Om разбираться.

Вот здесь можно посмотреть на мои эксперименты: игра «41 носок» вживую, исходники.