?

Log in

No account? Create an account

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

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

Категория: наука

ICFPC 2019
tonsky

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

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

Очень любопытно посмотреть, чего ты стоишь. В голове-то ты мог много себе про себя нафантазировать, а тут вот объективная реальность, ладдер, и ты либо можешь компьютер заставить делать что ты хочешь, либо не можешь. Никаких «если бы», никаких «возможно, наверное, мне кажется». Мы довольно посредственно выступили (на момент закрытия 29 место из 142 участвовавших, в лучший свой момент были на пятом).

Исторический скриншот. Дальше мы сильно сдали
Исторический скриншот. Дальше мы сильно сдали

Участвовали втроем, я в первый раз. Как я понял, средний размер команды ~5 человек, не редкость и восемь встретить. Втроем у нас довольно хорошо делились области ответственности, было бы больше появился бы организационный оверхед (как мне кажется). Восемь человек я бы вообще офигел менеджить и вообще ничего бы не написал, наверное. С другой стороны, больше рук – можно попробовать больше подходов. Можно вложиться в инфрастуктуру. Наверное.

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

Собери бонусы, закрась лабиринт
Собери бонусы, закрась лабиринт

Clojure, несмотря на все плюсы языка высокого уровня и быстрого iteration time, по ощущениям подошла довольно плохо. Потому что все упирается в перформанс. Можно сколько угодно рассуждать про «глобальные оптимизации против локальных», ненавидеть байтоебство, мыслить как стратег с высоты птичьего полета и гордиться тем, что не знаешь, как устроен компьютер, но это все и в императивных языках можно делать. Они же не отнимают способности мыслить и планировать. Да, механика записи мысли чуть более многословна, ну зато оно того стоит. Плюс за три дня вы разницы может и не заметите даже. А вот по перформансу заметите, еще как. Как ни крути, а команда, которая обсчитает за условное время X в два раза больше вариантов, чем ее конкурент, будет в топе выше. КАК НИ КРУТИ. Больше здесь строго лучше. Либо больше итераций, больше вариантов попробовать, либо решения будут более глубокими, а значит и очков принесут больше.

ICFPC это как раз такой случай, когда лучше чуть больше устать но получить программу которая будет нагружать процессор по делу, а не только мусор за юзером подбирать. К тому же, как ни странно, старые императивные языки может и не очень легко позволяют до энтерпрайзных масштабов раздувать программы, но что-что а бегать по массивам и мутировать структуры они похлеще функциональных могут. Ирония – соревнование приурочено к конференции по функциональному программированию, а побеждают в нем все стабильнее C++ и императивщина.

Выглядит красиво, жаль вся эта мощь обслуживает всякое говно вроде lazy sequences, primitive boxing, high-order functions вместо того, чтобы решать задачу
Выглядит красиво, жаль вся эта мощь обслуживает всякое говно вроде lazy sequences, primitive boxing, high-order functions вместо того, чтобы решать задачу

Сейчас я думаю, что даже если бы мы выбрали просто Java с unboxed примитивами и примитивными массивами, было бы качественно лучше. C++/OCaml/Rust может быть дали бы еще 1,5-2 раза прирост, но это уже не изменило бы ситуацию качественно. Но может и нет, цифры так, с потолка.

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

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

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

не с этого хакатона, но смысл такой же
не с этого хакатона, но смысл такой же

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

лабиринты, генерируемые нашим алгоритмом, имели хорошо узнаваемый вид
лабиринты, генерируемые нашим алгоритмом, имели хорошо узнаваемый вид

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

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

Визуализатор организаторов
Визуализатор организаторов
ух как же меня бесило выбирать эти файлы каждый раз!
ух как же меня бесило выбирать эти файлы каждый раз!

Самое большое, чего там не хватало — пошагового реплея, перемотки назад и вперед, ну и доп информацию тоже иногда хочется какую-то вывести. Как разбился лабиринт, что думает бот, такое. Я написал в какой-то момент простой визуализатор через println и clear screen, он даже мультики показывал типа, но хотелось бы чего-то более удобного и универсального.

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

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

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

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

Как правильно распределять силы я пока не понял. Я выложился по максимуму в первый день (до 6 утра, на следующий встал в 11) чтобы как можно больше впихнуть в Lightning Round (первые 24 часа). В результате весь второй день был как в тумане и работалось как на автопилоте. В третий зашли нормально, я переписал алгоритм даже, но тоже было очень тяжело. Возможно, здоровый сон каждый день (ну ок, кроме последнего) суммарно дал бы больше эффективности за три дня, чем такое.

Перерыв на обед
Перерыв на обед

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


Отступаем, нас окружили!
tonsky

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

Короче, прикидывая разные способы расстановки юнитов на доске, я понял, почему в героях 1-2-3 сетка была шестигранная. Дело к количестве спрайтов. Смотрите, если сетка вот такая:

...и мы атакуем гоблина с позиций 1, 2 или 3, мы можем в принципе ничего не менять и использовать один и тот же спрайт, бьющий вправо от себя. Такой же, как все ребята, что стоят слева. Форма шестиугольника гарантирует, что враг всегда будет немного правее, так что терпимо.

Для позиций 4, 5 и 6 мы зеркалим спрайт. Вуаля! Нужно рисовать каждый спрайт только в одном (!!!) варианте. А юнитов в героях ого-го сколько!

Кстати, обратите внимание, что если сетку повернуть на 90°, то это свойство пропадет. То есть даже угол поворота неслучаен!

Если взять параллельную квадратную сетку, как тут (wargroove):

то напасть можно слева, сверху и снизу, а это уже три варианта каждой анимации (лево-право зеркалятся, верх-низ не). Три варианта это прям тяжеловато.

Дальше идет сорокапятиградусная изометрия. Как в Into The Breach:

Тут положения всего два — мордой вниз и мордой вверх, вариации лево-право идеально зеркалятся. Уже лучше.

В Into the Breach, кстати, решили даже этим не заморачиваться и вообще не крутят юнитов. То есть если надо напасть назад, то бьют жопой. Тоже вариант, решает кстати проблему из предыдущего поста, что не очень хочется разглядывать юнитов со спины. И не такой уж плохой, как кажется — я наиграл 26 часов и понятия не имел, что у них атаки так топорно сделаны, пока не загрузил и не начал изучать специально.

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

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

Ну а в пятый уже было настоящее 3Д, и там можно крутить модели уже как хочешь. И к шестигранной сетке никто возвращаться не стал. Почему? Моя гипотеза — квадратная дает больше тактических возможностей: меньше места, сильнее толпятся юниты, проще закрыться. Правда, это если не разрешать диагональные атаки, а они в пятых были.

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


Не Vim-ом единым
усы2
tonsky

Появился повод высказаться по поводу Vim, а я давно собирался. Мнение такое, что он, крутой для своего времени, сегодня просто морально устарел.

Disclaimer: я просидел исключительно на Vim около года, активно программировал, так что это не рассуждения в вакууме. Я был в этой шкуре, знаю о чем речь на собственном опыте. Тем не менее, я без особых сожалений (и потерь, как я считаю) сменил Vim на более современные редакторы.

Итак.

Для начала давайте оспорим тезис, что набор текста — редкая операция. По моим оценкам, набор и трансформации делятся скорее как 50%/50%, т.е. набор далеко не редкая операция. Грубо, каждому переносу соответствует редактирование (т.к. код редко когда переносим без изменений), а каждому удалению — вставка (статистически, по GitHub, обычно графики вставок/удалений очень симметричные). Т.е. бегать между режимами приходится достаточно часто, чтобы записать необходимость их переключения в некую дополнительную ненулевую «нагрузку».

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

Так вот, не хочу никого расстраивать, но система команд получилась такой не из-за какого-то великого инсайта, а просто потому, что у автора был тормозной модем и он «хотел печатать быстрее, чем обновлялся экран». Ну, представили ситуацию, да? Набрал «выделить текст, от кавычки до кавычки, заменить, ввести „абырвалг“, выйти», послал голубиной почтой и пошел пить кофе. Более того, даже в момент создания подход Vim не имел смысла для локального редактирования, где задержки нет. 

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

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

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

It was really hard to do because you've got to remember that I was trying to make it usable over a 300 baud modem. That's also the reason you have all these funny commands. It just barely worked to use a screen editor over a modem. It was just barely fast enough. A 1200 baud modem was an upgrade. 1200 baud now is pretty slow.

9600 baud is faster than you can read. 1200 baud is way slower. So the editor was optimized so that you could edit and feel productive when it was painting slower than you could think. Now that computers are so much faster than you can think, nobody understands this anymore.

The people doing Emacs were sitting in labs at MIT with what were essentially fibre-channel links to the host, in contemporary terms. They were working on a PDP-10, which was a huge machine by comparison, with infinitely fast screens.

So they could have funny commands with the screen shimmering and all that, and meanwhile, I'm sitting at home in sort of World War II surplus housing at Berkeley with a modem and a terminal that can just barely get the cursor off the bottom line.

It was a world that is now extinct. People don't know that vi was written for a world that doesn't exist anymore.

Но зато в Vim удобные «шорткаты» (команды, окей) и их много! Да, но в современных редакторах их не то чтобы сильно меньше. Даже стандартные системные (!) справляются с перемещением текста весьма неплохо (Cmd+←→ == начало/конец строки, Alt+←→ == прыгать по слову, Cmd+↑↓ начало/конец документа, Alt+↑↓ вверх/вниз на страницу). Окей, на Винде чуть похуже.

Плюс команды в Vim всё-таки немного более избыточны, чем хотелось бы. Проще жить, когда один инструмент решает две-три задачи (даже так: работает в двух-трех разных ситуациях), чем когда у тебя на каждый специальный случай отдельная кнопка. Вот например специальная команда для вставки в конец строки («a»), это что вообще? В обычных редакторах туда можно просто поставить курсор, а тут отдельная «команда». Или «r» (заменить одну букву и выйти), тогда как в обычном мире просто Backspace (кнопка «забой» :), которая и удаляет, и заменяет, если на месте удаленного набрать новую букву.

Ну и самая большая цена, которую вы платите сегодня, пожалуй, это то что подход Vim не совместим ни с чем вообще. Vim работает только в Vim, поэтому во всех остальных местах вы будете постоянно чертыхаться, пытаясь нажать «i», «Esc» и ходить по тексту через «hjkl». Везде: в браузере, в календаре, документах, эверноте, чатах, спотлайте, везде ваши так долго тренировавшиеся привычки идут лесом.

Здесь еще я мог бы пожаловаться на архаичность и несовместимость Vim с современным миром. У него, например, два буфера обмена ¯\_(ツ)_/¯ и оба внутренние. Ни один из них не попадет в ваш системный, т.е. скопировать текст внутри Vim и вставить его еще куда-то не получится. Он не умеет различать вставку текста и набор, поэтому если вы скопировали какой-то кусок кода (скажем, со StackOverflow) и вставляете, он его будет набирать посимвольно, что медленно, смешно и хреначит все отступы к чертям. Да, только из-за этого есть специальный режим «paste mode» и да, его-то как раз легко забыть включить/выключить. Часть этих «особенностей» пофикшена в графических клонах, скорее всего, но все равно, знакомство с ними было забавным и это тот случай, когда «через свежую покраску все равно проглядывали признаки старого, очень старого материала».

Ну и немного про достижения Vim. Хочу еще раз заметить, что Vim такой, какой есть, потому что так получилось. За ним не стояло какого-то гранд дизайна или проверенных научных моделей, система команд не то чтобы какая-то особенно логичная или удобная. Он ни подо что не оптимизировался, кроме модема и клавиатуры автора, у которой Esc был на месте Tab, а физических стрелок не было, зато уже были картинки стрелок на «hjkl»). Да-да, именно поэтому всем поголовно вимерам приходится маппить Esc на Caps Lock.

Зацените кнопку «рубля», кстати

Так вот. Первое великое (и случайное) достижение: стрелки на home row. Действительно, тянуть руку в правый нижний угол очень далеко, а перемещение по тексту очень частая операция. Процентов 50% успеха Vim я отдаю тому, что люди просто осознают всю идиотскость расположения стрелок в правом нижнем углу на клавиатурах, а Vim — наиболее доступный способ эту проблему хотя бы частично решить.

Но это откровение никак особо Vim не принадлежит и в идеале неплохо бы сделать его отчуждаемым. Стрелки не становятся вдруг удобнее, когда ты выходишь из Vim и переходишь, скажем, в браузер. Я решаю это маппингом Caps Lock + IJKL (да, не HJKL) на стрелки. Очень удобно и главное: работает везде.

Вторые 50% успеха я отдаю высокому порогу входа. Тут надо объяснить. В устройстве человека есть такой баг (ну или фича): люди не начинают лучше владеть инструментами/навыками/привычками со временем просто так, сами по себе. После того, как они научились делать задачу как-то (неважно, как, лишь бы получался результат), они будут продолжать делать её именно так. Если не прикладывать осознанных усилий, через год пользования Idea, например, ты будешь пользоваться ей так же, как через первую неделю. Горячие кнопки сами себя не разучат, удобные фичи не найдутся. Нужно тренировать себя, читать обучающие материалы, смотреть, как пользуются другие.

В примере с Idea ты вроде как более-менее понимаешь, как редактировать текст (так же, как и везде), поэтому естественного толчка к самосовершенствованию не происходит. Ты продолжаешь редактировать, как умел.

С Vim же ты вообще не понимаешь, что происходит. НИ ОДИН твой навык не работает. Тебе приходится разбираться. Ну и пока ты разбираешься, читаешь, ты успеваешь захватить значительно больший кусок области «редактирование текста», просто потому что никогда до этого специально её не изучал. Плюс постоянный цикл «блин, новая ситуация, в которой ни один разученный мной навык пока не работает» заставляет какое-то время гуглить, читать и смотреть, как другие люди просто редактируют текст

Спорим, для условного «Ворда» вы никогда бы даже не подумали гуглить такую табличку?

Опять же, это совершенно случайный фактор (высокий порог входа) и даже почти что контринтуитивный, но я считаю, что он как раз и сыграл значительную роль в успехе Vim. Ну а дальше, когда все частые ситуации разучены, начинается такое же плато, плюс включается Стокгольмский синдром :)

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


Панель Шрёдингера
усы2
tonsky

Классическое нытье: куча мобильных приложений и сайтов делает заголовки, которые прячутся по скроллу. Идея, как и все современные тренды, максимально дебильная: типа, пока скроллишь вниз, весь экран занят контентом: текстом там, картинками, не знаю. Но стоит руке дрогнуть и скрольнуть на один-единственный пиксель вверх, как тут же со всех сторон вылетают панели, кнопки, статусы и прибамбасы. Вот они вылезают, скажите мне, что бы что? Просто пораздражать своей анимацией? Или люди что, вверх не листают? Все с первого раза понимают? Штука еще и в том, что если (если!) эти гребаные панели действительно нужны и на них хочется посмотреть, ничто не подскажет, как их достать. Худший вариант интерфейса: вызывается случайно all the time, а когда нужно, то фиг поймешь как достать.

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

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

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

А как делать-то тогда?

Первое: не надо этих ваших анимаций. Хотите чё-то на экране показать — показывайте всегда, не надо случайно вызываемых жестов к нему приделывать. Чего нам точно всем не хватало [сарказм] — еще одного аспекта управления и так уже перегруженными многофасеточными контрольными центрами (мобильниками то есть). Если вы хотите чтобы гребаный хэдер с вашим гребаным лого мазолил мне глаза, ну будьте мужиками, примите решение, показывайте его всегда. Только не надо уменьшать его по скроллу, это их двух зол обе: вы и глаза мозолите, и анимациями заколебете.

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


Десктопные UI
усы2
tonsky

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

Кажется, что идея провальна с самого начала. Но в мире есть успешный пример кросс-платформенных UI которые прилично выглядят на любой платформе. Это веб. Да, веб-сайты не собраны из системных компонентов, каждый вебмастер рисует свои кнопки и панели с нуля. Но все привыкли и не возражают. Браузер аккуратно доделывает системно-специфичные детали: нативный скролл (с инерцией или без), рендеринг и выделение текста, системные контекстные меню, системное поведение внутри даже полностью перерисованных инпутов. Системные нюансы, даже в комбинации с полностью уникальным скином и лайаутом, создают вполне приятный пользовательский опыт. Решение оказалось в том, чтобы не притворяться нативным системным приложением, иначе попадешь в uncanny valley, область фальшивых елочных игрушек.


на фото: Transmission Remote GUI (Free Pascal) притворяется нативчиком

На основе браузера сделали Электрон — бандл из хрома, node.js и ваших html/css/js, упакованных в обертку как-бы-приложения. С точки зрения пользователя — всё классно. VS Code, Atom, LightTable, Figma, Zeplin, Slack, VK Messenger, Rocket.Chat, Github Desktop, GitKraken, Basecamp, Ghost, Brave browser, Hyper, SimpleNote — прекрасные, вылизанные приложения, очевидно, что как платформа Электрон уже состоялся.


на фото: системное контекстное меню в Visual Studio Code (Electron)

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

Претензия к Электрону, собственно, одна — это такой Докер для десктопа. То есть он пакует огромную тучу всякой фигни ради несоизмеримо маленького функционала. То, что нужно Хрому для веба, например совместимость с IE 5.5, всякие quirks mode, не знаю, видеокодеки, non-strict JS, устаревшие CSS свойства и режимы и совместимость их с новым и современным — это раз в 100 больше того, что вы когда-либо сможете и захотите использовать. И это никак не отковыряешь. Меня даже не размер бандла беспокоит, а то что весь этот легаси серьезно мешает приложению достичь своего потенциала скорости, простоты, надежности. Тот же JS — явно не лучший язык, с кучей совершенно левых/произвольных проблем-ограничений, медленный просто потому, что он настолько плох что уже не ускоряется, явно не готовый к тому, что под ним будет файловая система, что бывают потоки — да, мы не можем выкинуть его в вебе — но на десктопе-то ради чего страдать?

К сожалению, с браузером только всё-или-ничего. Как и докер, это явно неверный вектор развития — бандлить кучу говна просто потому, что так получилось и проще. И все равно web это лучшая на сегодня UI платформа, с лучшим integrated developer experience.

Вопрос, собственно, про альтернативы. На случай, если я проглядел что-то.

На QT бывают хорошие, красивые приложения. QT бывает кросс-платформенный, но это C++. Он, конечно, обходит JS по категории sanity, потому что он не сильно умный и в любой ситуации ты просто делаешь то что тебе нужно, а не пытаешься бороться с тормозами вмененного тебе динамизма. Figma, например, компиляют C++ в JS, чтобы работать в вебе, но лишь бы не писать на JS. Но все равно C++ ужасный язык, низкоуровневый, долгая компиляция, без REPL-а — а UI работу я себе не представляю без REPL-а.


на фото: Telegram Desktop (QT5) с кастомным контекстным меню. Не видно, но скролл тоже фальшивит

Java-решения (Swing/JavaFX) страшны как черт. Я тут скачал демку JavaFX, которая прям с дистрибутивом идет, так у них даже ховер на кнопках тормозит. Плюс естественно всё не нативное — ни скролл, ни выделения, ни контекстные меню, а нарисованное как будто программистами. Окей чтобы накидать что-то по-быстрому для нетребовательной аудитории клерков, но вылизать, кажется, невозможно.


на фото: Modena demo app (JavaFX). Пойдет, но тормозит и всё ненастоящее

Я не уверен, насколько хорош в этом плане SWT — смогу ли я выкинуть весь look-and-feel и нарисовать что-то стильно-современно-плоское, например? Не хотелось бы, чтобы получилось что-то уродливое вроде Eclipse. Он вообще живой еще?


на фото: страница проекта SWT

Что еще бывает? Или выхода нет?

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


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

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

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

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

Итак, что же я думаю по поводу Clojure?
tonsky
Расширяемый чат-бот [1] оказался куда более толковым для освоения языка материалом, чем Проект Эйлер. Я потрогал практически всё, что было в Кложе, и почти не повторялся.

Страх перед скобочками сильно преувеличен. Их перестаешь замечать в первый день, куча гораздо более важного происходит внутри них. Пишешь себе код как везде, выравниваешь, копи-пастишь, читаешь, никаких проблем. Ставить их вокруг функции намного логичнее, чем часть выражения оставлять снаружи, часть внутри, и не дай бог можно опускать. Мне когда-то это казалось отличной идеей, а-ля ML, Coffee Script, Perl — мусора меньше, но потом я как-то увидел чужой исходник на Ocaml-е — пространство, равномерно заполненное двух- и трех-буквенными аббревиатурами, и понял, что скобки, они к лучшему, не мешают, а помогают читать.

Синтаксис в Кложе самый крутой, конструкции навернуты невероятные [2], но если поначалу тупишь [2], то потом все отлично, привыкаешь. Причем чтобы с этим всем разобраться, надо ковырять стандартную библиотеку, а не книгу по языку, что тоже довольно скоро начинает казаться естественным и логичным. И даже, разделение элементов списка пробелами, без запятых — как-то вдруг свежо, стройно и красиво решает проблему их назойливого болтания в начале и конце.

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

Динамичность тоже отличная штука. Пишу я своего бота, он у меня в фоновом потоке законнекчен, и не разрывая никаких соединений я его спокойно обновляю и тестирую. Говорят, если соединить repl с Емаксом, будет еще круче и код вообще из редактора будет обновляться, но я его пока боюсь, хотя надо уже браться. Главное, всё это построено на тех же самых примитивах, что доступны пользователю языка, то есть можно писать скрипты, работающие с неймспейсами, грузить туда-сюда, сканировать, менять, всё что угодно. Всё, чего вдруг не окажется, собери себе сам, как и в случае с синтаксисом.

Про собственно код. Намерения маппятся на текст программы точнее и плотнее, чем, опять же, везде, где я видел. На глазок получается, что одна функция на Кложе ≈ один файл на Джаве (при компиляции примерно то же соотношение).

Если об ощущениях, то это выглядит так: сидишь, думаешь, здесь так должно работать, а в этих случаях так, и если это, то то, и еще в этом случае надо вот это учесть, потом думаешь: ну всё, надо уже писать. Пишешь, пишешь. Проверяешь, пробегаешься по всем случаям, что продумал. Да, вроде всё учтено. Оглядываешься — написал четыре строчки.

Если еще об ощущениях, то чем больше я погружаюсь, тем больше паззл сходится. Последний раз такое было с Эрленгом, в котором все части очень грамотно и красиво дополняли друг друга, но там это укладывалось в одну нетолстую книжку. Здесь все началось с Рича Хики, который сначала рекомендовал всем не быть хипстерами, а выявлять настоящие проблемы и решать их [3]; продолжилось им же в толке про деконструкцию устоявшихся программистских конструкций на элементарные ортогональные части [4], и блестящим воплощением этих идей по всей Кложе.

Ну и в конце концов, из Кложи, возможно ввиду ее молодости, еще не высосали весь фан. Я, например, оторвался с антропоморфными названиями частей чатбота и лог-функциями типа (omg! …). Если попытаться представить что-то подобное в другом языке, вдруг понимаешь, что в Джаве запрещены имена классов из менее чем трех слов, в Скале названия берут из математических теорем, на Хаскелле пришлось бы называть их по-гречески (что круто, но крутизну оценили бы те восемь человек, которые его используют)1. На Питоне пришлось бы соревноваться в остроумии с Гвидо, чтобы писать на С, нужна борода, а на Ноде-ЖС, если давать осмысленные имена, велик риск обнаружить, что задница управляет мозгом через коллбеки. Получается, что единственное место, где можно ловить кайф по части названий — это Кложа.

Когда я узнал, что они всю эту красоту еще и в браузер перенесли (в очередной раз сделав это очень умно и по делу — [5]), стало понятно, что деваться некуда, скоро все будут писать на Кложе, поэтому надо работать на опережение. Я, в общем-то, даже с JVM уже примирился, хотя нечаянно закрыть repl пока ощутимо больно. Oracle, давайте уже допиливайте свою модульность и быстрый старт, будет с вас хоть шерсти клок.

Резюме: всем брать пример с Рича Хики. Кложа опционально, но горячо рекомендую.

Ссылки:
  1. Разбор кода чат-бота, in english.
  2. Пример одной из сложнейших конструкций condp.
  3. Мини-конспект первой презентации Рича Хики про решение проблем.
  4. Конспект второй презентации Рича Хики про элементарные ортогональные части.
  5. Introduction Стюарта Сиерры и видео Рича Хики про ClojureScript, in english.


1 На самом деле, если мне когда-либо доведется что-либо писать на Хаскелле, абсолютно точно первый свой тип я назову Пиписька. Просто чтобы сбить пафос.

Простота против универсальности
tonsky
Почтовые папки — это понятный интерфейсный объект, да еще и подкрепленный физической метафорой. Как люди используют папки? Наверное, они заводят папку под какое-то условие — адресат, ключевое слово в теме письма и т.д. Пользователь видит папки каждый день при работе с почтой, заходит в них, ищет в них. (В тексте под папками понимаются как ярлыки гмейла, так и классические imap folders, изложенные мысли верны для обоих.)

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

Вот, например, настройка фильтров ГМейла:





А так выглядят правила Яндекс-Почты:




По сути примерно одно и то же. У Яндекса можно одновременно указать От кого ИЛИ Кому, но почему-то можно выполнить только одно действие.

Самая человечная, наверное, Зимбра:



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

Понятно, почему так получилось: программистам не привыкать работать с абстрактными сущностями, и им же не привыкать к действию-объекту (rm file вместо file rm). Эта гипотеза объясняет возникновение фильтров. (А по интерфейсу гмейла видно, что фильтров с первой технодемонстрационной реализации до сих пор не коснулась рука не то что проектировщика, но даже дизайнера).

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

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

P.S. Кстати, если посмотреть внимательно, один фильтр может складывать письма только в одну папку. То есть даже сейчас перевернуть отношение фильтр-папка ничто не мешает.

UPD: В Опере сделано страшненько, но правильно (спасибо legolegs за подсказку):