?

Log in

No account? Create an account

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

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

Категория: it

pub mod fiasco
tonsky

Лучший язык, в котором правильно сделаны модули (ну или неймспейсы) — Кложа. Один файл === один неймспейс. Неймспейс может называться только так, как называется файл, и никак иначе. И лежать он должен тоже ровно по пути пакета. То есть (ns me.tonsky.hello) может и должен лежать в me/tonsky/hello.clj и нигде иначе. Сначала меня это почему-то напрягло — эй! свободу ограничивают! а как же самовыражение??? Это при том что в остальном Кложа — довольно либеральный язык и позволяет любую другую дичь творить спокойно и вообще говоря это чуть ли не единственное место, где абстракция «как организовать свой проект на файловой системе» протекла в язык, который, вообще говоря, весь такой интерпретируемый, динамичный, код может есть с руки и про файлы ничего не знает.

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

Тут-то судьба забросила меня в Балтийское море, на остров Котлин. У Котлина какой основополагающий принцип? Если где-то что-то запрещают, у нас разрешают! Все обиженные, обездоленные приходите к нам и творите что хотите. Этот же принцип применен и к файловой системе. В Джаве ведь как? Один файл == один класс. Какое расточительство! В Котлине один файл == сколько угодно классов, объектов, функций, констант и чего угодно еще. Более того, файл может объявлять объекты в пакете, в котором он даже не находится. То есть какой-нибудь src/main/kotlin/me/tonsky/hello.kt может спокойно объявлять package go.fuck.yourself; и никому за это ничего не будет!

Что же тут не так? Помимо самоочевидного бардака, становится довольно сложно понять, где что находится. Скажем, ищу я класс me.tonsky.Draggable. Смотрю в me/tonsky/ папку а там layout.kt, main.kt и scene.kt. Ну офигеть! Класс может быть в любом. То есть на самом деле это не один файл содержит множество объектов. Это один модуль размазан на несколько файлов с ничего не говорящими названиями. Разница тонкая, но существенная.

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

Все это, конечно стимулирует продажу IDE от одноименной компании, но почувствуйте разницу! Язык, разработанный на деньги IDE вендора, и язык, который при разработке не предполагал, что у вас вообще будет какой-то редактор (а судя по форматированию классов в clojure.lang писал его Рич в блокноте и пропорциональным шрифтом).

А потом вскрывается еще одна беда — разные файлы-то, получается, срут в общее пространство имен! То есть если ты в oops.kt написал val default = 1, то у тебя вдруг перестал работать wtf.kt про который ты даже не слышал, просто потому что он тоже определил val default = 0 когда-то а в алфавите W идет после O. Никакой изоляции. Не будешь же, в самом деле, по папке с одним файлом заводить на каждый класс. Сомнительное, короче, удобство.

А потом я пришел в Раст. Его систему с модулями я настолько не понял, что специально сейчас сидел перечитывал. Итак:

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

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

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

Раст позволяет импортить как модули, так и отдельные типы. Причем синтаксис общий. Что создает еще больше путаницы. Модуль — это неймспейс, средство изоляции имен, не больше. Тип — это уже что-то полезное. Давайте уже как-то разделять.

Видимо, по старой доброй C-традиции, в Расте сделали include вместо import. То есть когда ты говоришь use module, ты не просто создаешь некий синтаксический псевдоним, действующий исключительно до конца файла для разрешения имен. Нет, ты буквально добавляешь все что было в module в текущий файл. Не сослался, а скопировал и вставил себе. Это плохо, потому что вместо понятной модели «есть штука, она одна и существует там, где написана, плюс есть способы сослаться на штуку, псевдонимы, они могут быть любыми» мы получаем «одна и та же штука, размноженная N раз в N местах». А я еще удивлялся, почему одни и те же функции и из std::, и из core:: торчат. Вот почему!

Ну и на вишенку, модуль определяется не в том файле, где он написан, а в его родителе! Скажем, если вы сделали govno.rs, и написали в нем код, вы потом идете в lib.rs и в нем уже пишете mod govno;. Или, если хотите, определить его публично, pub mod govno;. То есть понимаете, да? Если вам интересно, торчит ли govno.rs наружу, вы не можете зайти в него и посмотреть. Вам нужно сообразить, кто его родитель, найти в этом родителе (в произвольном достаточно месте) надпись mod govno; и там узнать, есть ли префикс pub у него. Если вы хотите создать какой-то достаточно глубокий модуль, скажем, kak::zhe::vse::zaebalo, вам нужно пойти и создать всех промежуточных родителей и в каждом написать ровно по одной строчке:

lib.rs:
pub mod kak;

kak.rs:
pub mod zhe;

kak/zhe.rs:
pub mod vse;

kak/zhe/vse.rs:
pub mod zaebalo;

kak/zhe/vse/zaebalo.rs:
<your code here> 

В каком-то смысле это все следствие относительности имен и «удобства» их использования. В каком-то — следствие концепции вложенности. Этот пример прекрасно ее иллюстрирует: слишком много возни, слишком много вопросов, а в чем профит не ясно. Скажем, если модуль kak будет публичным, zhe — нет, vse — тоже нет, и наконец zaebalo — публичным. Смогу я его в конце концов заимпортить? Если нет, то в чем смысл pub в pub mod zaebalo;? Если да, то в чем смысл того, что промежуточные модули — приватные? И сколько файлов мне придется посетить, чтобы вычислить, доступен ли zaebalo для импорта?

Короче. Я не очень понимаю, как тут можно запутаться, но опыт показывает что путаются все и постоянно. Модули — плоские. Пути — абсолютные. Один файл === один модуль. Все, что надо знать про модуль, написано в нем самом. Будете делать свой язык — смотрите не объебитесь.



С высоты-3
tonsky

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

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

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

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

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

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

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

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

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

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

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


С высоты-2
tonsky

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

Ну и что я сделал. Я пошел учить Rust. Не, ну интересно же, как компьютеры сегодня могут, если их правильно попросить.

Чтобы потренироваться я портировал на Раст наше решение из ICFPC. Причем портировал точь-в-точь: все те же структуры данных, те же алгоритмы, те же константы. Ну разве что не персистентные: там, где в Clojure update, в Rust у меня clone() и только потом push/insert, потому что в комплекте персистентные структуры не идут, да и так идиоматичнее. Важно: я не пытался что-то улучшить, срезать углы, реализовать покрасивее, нет: я написал ровно то, что мы и на Clojure написали. Ну, чтобы сравнение было честным.

Как только мой решатель начал что-то решать, я сразу же побежал сравнивать производительность. Rust ожидаемо вырывался вперед, но не на безумные цифры. Типа, вместо 4-5 секунд на задачу решал за три. Я даже собрался уже разоблачающий пост писать, что мол язык не важен, важны структуры данных и алгоритмы, в них весь перформанс, а не в том, на каком языке вы их записали. Потом, правда, коллеги подсказали, что я забыл снять с ручника, то есть запускал Rust в debug-билде. Ну и конечно, стоило поставить --release, как скорость выросла раз в двадцать. Впечатляет, да?

Самое печальное тут в том, что это все время на одну и ту же работу. Чистый оверхед. Программа на Clojure не выдает какой-то более умный или точный или качественный ответ. Она приходит к тому же финишу, только к ногам привязаны огромные 20-кратные гири. Раст на одном ядре обгоняет Кложу на двенадцати ядрах в 3,5 раза!

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

Зато 17 раз!!!

Исходник и голые цифры. Выводы делайте сами.



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

Про Clojure и что я все сильнее про него ощущаю.

В каком-то смысле это продолжение моих размышлений, куда податься после Software Disenchantment, когда я понял, что надо что-то менять, но не понял, на что именно.

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

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

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

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

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

Никого не волнует, насколько инженеру хотелось бы и было бы удобнее печатать, скажет, фару на тридэ принтере из резины. Важен только результат. Большинство программистов вокруг нас пишут на прикладных языках высокого уровня – они просто ездят на машинах, они потребители. Но для того, чтобы они могли это делать, сами машины должны быть сделаны максимально хорошо.

И вот меня тянет как будто все больше в эту область. Инструментов, основ каких-то, значит. А трагедия в том, что моя любимая Clojure ну никак для этого не подходит, как бы мне этого ни хотелось. Чем дальше, тем больше понимаешь, что эта чудесная простота дается не бесплатно. Просто задачи были такие, что небесплатность была незаметна. Приглядишься бывает, с одной стороны hot loop из семи залуп, а с другой внутри вдруг вылазят какие-то промежуточные сиквенсы, какой-то там pointer chasing, primitive unboxing, вспыхивают на доли секунды замыкания просто чтобы что-то найти в трехэлементном массиве с помощью функции второго порядка, для того чтобы вернуть 2д точку выделяется на всякий случай целый Персистентный Вектор, для того что бы обновить пять полей в структуре у тебя создастся и тут же выбросится четыре промежуточных версии этой самой структуры, а вместо того чтобы посчитать что-то в цикле создастся целая ленивая последовательность, которая, фиг бы с ней, посчитается позже, просто сколько же оверхеда уйдет на то, что по сути могло быть простой итерацией с одной short переменной и оперировать вообще по константной памяти, еще и последовательно уложенной.

Вот кусок, написанный на идиоматичной Clojure:

(concat
 (mapv
    (fn [y] [from-x y])
    (range from-y (quot to-y 2)))
  (mapv
    (fn [y] [to-x y])
    (range (quot to-y 2) to-y)))

Тут тебе все: и ленивость (concat), и ФВП (mapv), и лямбды с замыканиями, и бесконечные ленивые последовательности (range). Вопросов нет, это действительно нормальные, часто используемые Clojure примитивы. Я даже не могу этот код назвать не-идиоматичным. Но. Просто представьте, сколько механизмов там крутится под капотом, чтобы вся эта красивая запись отработала. А ведь все что там по сути происходит это один очень простой цикл:

Point[] res = new Point[to_y - from_y];
for (int y = from_y; y < to_y; ++y)
  res[y - from_y] = Point(y < to-y / 2 ? from_x : to_x, y); 

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

Когда мы говорим о разнице между условными C++/OCaml/Rust, Java и скажем Clojure (особенно средне-идеоматичной Clojure, с коллекциями там всякими), то эта разница может быть 1 к 2-3 к 100 например очень легко. Я помню, когда решал Project Euler и учил Clojure и OCaml, то Кложе-решения мне приходилось ждать какое-то ненулевое время (ну там задачи не шибко сложные, но все же). А OCaml успевал перекомпилять (!) программу, запустить, все обсчитать и выдать ответ за время, пока Java-машина с Clojure только стартовали.

Да, язык формирует образ мысли. Так или иначе, когда язык уже выбран, поиск решения – это вертеть в уме разные варианты имеющихся в нем кубиков, комбинировать, собирать решение из того, что язык предлагает. Можно мыслить на языке. Писать идиоматичный код. Но неплохо бы еще мыслить «на языке компьютера», т.е. представлять себе цену всех этих удобств. Выбирать неуклюжий reduce комбинации из ФВП и трединга. Вынести в record то, что лежало в мапе. Сделать loop, наконец. Иногда цикл это всего лишь цикл. И никак по-другому ты его не запишешь. И это нормально. Компьютер скажет спасибо.

Но это полдела. Если уж быть до конца честным, Clojure для perf-critical подходит из рук вон плохо. Даже Java подходит с очень большой натяжкой. То есть ее конечно можно разогнать, но зачем? Зачем героически бороться, чтобы в конечном итоге все равно, пусть немножко, но проиграть, потерять что-то? В итоге все упирается в то, что лучшее что я могу сейчас делать – учить Rust. А дальше-то что? Что на нем писать-то? Непонятно опять. Проблема.


Справа налево
tonsky

Не хочу специально набрасывать, но вот вчера попалось на глаза и я прям прослезился.

Смотрю, что если в столбце справа путь «abc+что-то», то все нормально. Как только что-то пропадает, «abc+» превращается в «+abc». При том что в DOM мы отдаем совершенно точно «abc+». Одним текстовым блоком. Никаких там вам флексов, это уж точно. Как так? Что-то с глазами? Как такое вообще возможно? Кто вообще посмел раздербанить мою строку, да еще по каким-то дебильным правилам, и если подобное возможно, на какие гарантии в принципе можно рассчитывать? Начитавшись Лю Цысиня, я решил, что инопланетяне нарочно играются с моим мозгом с целью свести меня с ума.

В итоге расследование привело меня типовое решение со StackOverflow. Оказывается (!) веб-разработчикам в целом как-то лень бывает городить лишний вложенный div, и они придумали: а чего бы не заабюзить свойство direction для арабских языков? Только писать в него все равно латиницей. Гениально!

Ну да, текст начинает как бы выравниваться по правому краю. Есть правда нюансы. Цифры, разделенные пробелами, переворачиваются. Знаки препинания переезжают налево. Диапазоны показываются задом наперед, от большего к меньшему.

Проблема? Проблема. Блин че делать? Читаем: you need to wrap the contained elements in another element with direction: ltr rule to reverse the effect. Классическое «придумал себе проблему и героически ее решил». Ооок.

Да, это самый популярный ответ на то, как обрезать текст слева. Да, авторы с удовольствием принимают такой ответ.

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


Что случилось с GUI-фреймворками?
tonsky

Это третий пост в моем квесте по поиску GUI-фреймворка для десктопных приложений. Первый, второй.

Давайте немного сориентирую, что я ищу. Для многих «GUI-фреймворк» почти равно библиотека виджетов, чем больше тем лучше. Чтобы GUI собрать из кубиков лего минимальными силами. Меня это не очень возбуждает, потому что универсальных виджетов мало, а что-то более интересное надо делать под себя все равно. Поэтому для фреймворка важнее «уметь доделать свое», чем «побольше готового».

Также популярно мнение что GUI-фреймворк это look and feel, платформенно-зависимый или же просто не вырвиглазный. Типа это сложная часть, повторить лук платформы. Мне тоже пофиг. Дело в том, что сейчас самое идеальное время для GUI-фреймворка: все наигрались в игру «сделай look and feel как настоящий» и привыкли к веб-приложениям, где вообще каждый первый сайт разный. Плюс в моду вошел flat и минимализм, то есть виджеты рисовать дешево и просто, как никогда. А платформенный look and feel это иллюзия, все равно в каждом реальном приложении миллион случаев, которые не укладываются в стандартные checkbox/input/dropdown. И чем больше приложение, тем больше надо тюнить и дорисовывать самому. UI это не лего, его надо дизайнить и рисовать как целое, тогда будет гармонично.

Таким образом, от GUI фреймворка мне бы хотелось иметь базовые сложные вещи покрытыми (платформенно-зависимая обработка ввода, скроллинг, быстрый рендеринг, вывод шрифтов, dpi handling), какие-то базовые графические примитивы (прямоугольник там, линия, градиент, тенюшечки, svg) и возможность залезть под капот и все застайлить и запрогать как хочется.

Я НЕ ищу сокращения затрат на дизайнера за счет использования готовых компонент/дефолтного look and feel. Меня интересует возможность потратить много и долго, но сделать самому и хорошо, чем кое-как и из готового. Pixel-перфект и именно так, как мне нужно, а не так, как автор фреймворка сделал и сейчас уже хрен отковыряешь. Качественное вылизанное end-user приложение, а не дешево выглядящий массово производимый enterprise.

UPD: Ну и не надо учить меня программировать. Наверное навязывать там свой MVC или VDOM или что сейчас модное и свежее сильно не стоит. А то мода меняется, а фреймворк должен выжить.

То есть нужны идеально композируемые низкоуровневые примитивы без look and feel.

Чтобы не повторять ошибок истории, надо их знать. Я не знаю. Поэтому мне нужна ваша помощь: расскажите, что да как, коротко, доходчиво, грубо. Вопросы конечно кажутся философскими, но нужны именно конкретные инсайты. Ответ «WPF гААААвно» не нужен, он не конкретный и непонятно, в чем конкретно затык, а вот «в WPF нельзя было делать мультидокументные приложения, поэтому он сошел на нет» (например) очень хороший ответ.

Вопросы примерно такие:

— Почему у Java не получилось AWT?

— Зачем понадобился Swing? Что принципиально изменилось по сравнению с AWT? Я так понимаю AWT пилился на C++, а Swing на Java? И стало лень писать по версии под платформу?

— Почему Swing плохо работает? Это косяк реализации или какая-то принципиальная проблема? И в чем именно заключается это «плохо работает»? Тормозит? Разъезжается? Что?

— Что за история с JavaFX, зачем он был нужен, зачем начинать опять новый фреймворк, какую принципиальную инновацию по сравнению со Swing хотели привнести (неужели CSS?) и что не задалось? Почему ноль интереса? Все разочаровались?

— Есть ли какой-то принципиальный затык в реализации кросс-платформенных GUI? У веба вроде бы получается, почему больше ни у кого нет?

— Почему Windows переизобретает свой тулкит в каждой версии, а macOS живет на Cocoa десятилетиями?

— Какое положение занимает QT? Я так понимаю что он C++ и bloated, то есть нацелен больше на энтерпрайз?

— Flutter подход выглядит а) разумно и б) достаточно правдоподобно в) не как говно. То есть поднять свой GUI тулкит с нуля вполне можно и можно даже достаточно убедительно сэмулировать нативный look-and-feel. Почему ни у кого больше такое не получалось?

— Если брать не только кросс-платформенные GUI, то какие есть киллер-фичи, которых больше нигде нет? Что незаменимо и неповторимо?

— UPD 2: Я читаю, что в JavaFX вводится Scene Graph, а в Swing все на JPanel. При этом разница ускользает от меня. Чем принципиально отличаются подходы? (кроме названий классов)

— UPD 3: Я ничего не знаю про tcl/tk, но многие вспоминают его с теплом. Почему?

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

Если вы работали с GUI кроме веба, расскажите, что там у вас была за история?


Пациент умер, выносите
tonsky
Opera Paper Products как-бы-шутка-но-не-такая уж и шутка
Opera Paper Products как-бы-шутка-но-не-такая уж и шутка

Я занимаюсь веб программированием 15 лет. Когда я начинал работать за деньги (компьютер у меня был и раньше, конечно), IE 6 был самым передовым и инновационным браузером, Firefox должен был вот-вот появиться, разработчики верили, что будущее за XHTML, до первого драфта HTML 5 и запуска StackOverflow оставалось 4 года, а до первого Chrome – пять лет. 

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

Получается вот как. Веб хорош для быстрого прототипирования, простого delivery, но масштаб его роста сильно ограничен. Грубо говоря, он подходит только для прототипов и игрушечных задач. Что-то вроде языка Basic, вроде и программы писать на нем можно, но всерьез его никто не берет. Веб, конечно, не пропадет, но в конечном счете займет место какого-нибудь там питона, на котором будут детей в MIT учить и ученые не слишком требовательные графики рисовать.

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

Ладно, простые статические страницы с текстом — ок, может быть. С адблоком и reader mode жить можно. Хотя и тут есть умельцы, которые умудряются сто слов отрендерить в страницу в 20 мегабайт, потому что технологии, инновации и disruption.

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

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

Но если взять платформу в целом, без сверхподвигов и свехржертв, иллюзия пропадает. Если дать на нее посмотреть человеку, не укушенному веб-пропагандой, иллюзия пропадает. Как только приложение открывает кто-то, отличный от его собственного разработчика на гигабитном интернете и двенадцатиядерном аймаке про, иллюзия пропадает. Начинается бесконечный поток убогостей, шероховатостей, заусенцев, тормозов, проблем, ошибок, которые в принципе не устранить никаким образом. Даже если у разработчика есть внимание и желание возиться с такими глупостями, даже если приложить бесконенчые усилия — нет, оно не исправляется в принципе. Я знаю, я сам такой разработчик, и я пробовал много раз, и много раз обжигался. Хотя когда смотришь издалека, на бумаге, вроде все хорошо. Что может пойти не так? Да все что угодно. И не только может, но и пойдет, причем в самом неожиданном месте. Веб это такой аналог российского автопрома — издалека вроде тоже машина, вроде тоже ездит, че еще надо-то? Но, как мы все прекрасно знаем, есть нюанс.

Существует ли версия этой реальности, где веб вырастает во что-то более значимое? А как же WebAssembly?

А что WebAssebly? Эта чехарда имеет смысл только только для людей, которые думают, что компьютеров нигде кроме браузера не существует. Очнитесь, ребята, это еще один никому ненужный слой абстракции. Мы с радостью себя отбросили на N лет назад и теперь с радостью это преодолеваем. WebAssembly — это попытка запихнуть в веб то, что без веба прекрасно работало уже несколько десятков лет как — С++ приложения. Чтобы что? Я не знаю чтобы что. Чтобы условный Вася все равно качал себе Слак, завернутый в Электрон, зато теперь написаный на WebAssembly. Смотри, мам, он почти как нативный, даже иконочка есть! И почти не тормозит. Почти-почти. Еще раз — попробуйте выкинуть говно веб-пропаганды из головы и взглянуть на это трезво. В чем тут достижение-то?

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


Универсальная раскладка (скачать)
усы2
tonsky

Выложил раскладку из предыдущего поста для Мака https://github.com/tonsky/Universal-Layout

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

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

Также здесь включена «машинопись», т.е. цифры набираются с шифтом, а символы на цифрах — без шифта. Это жутко удобно, т.к., как показывает статистика, цифры набираются сильно реже. Тут пруфы. Я, собственно, с 2015 года так и сижу.

По Option (Alt) включается Типографская раскладка Бирмана, не пугайтесь. Это тоже очень хорошо зарекомендовавшая себя на практике штука, если привыкнуть — длинные тире, правильные «кавычки» и другая всячина набирается так же беспроблемно, как и обычный текст. Я разбавил её буквами Ё и Ъ, которые теперь тоже живут на Альте.

Картинка:

Будем считать это версией 1.0, жду звездочек на гитхабе, отзывов и советов.


Инженеры, хватит бегать от ответственности
усы2
tonsky

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

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

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

На круглом столе предлагалось ввести ответственность за баги. Государственное регулирование качества. Комиссии (и комиссаров?) по говнокоду. Сажать даже. Но это смешно, это перекладывание ответственности опять же. Никто внешний не придет и не скажет «всё, делаем хорошо». А даже если и придет, все вокруг не кинутся по щелчку вдруг делать хорошо. Нет государственного регулирования, запрещающего уродливые торговые центры. Единственный путь к хорошей жизни — чтобы у архитектора, который его рисует, было внутренне чувство, внутренняя ответственность, внутренний стандарт качества. Чтобы его волновало.

Come on, разве у вас не скрипят зубы, когда ваше приложение тормозит? Разве у вас не загорается внутри жгучее желание закатать рукава, разобраться и починить в тот момент, когда кто-то находит багу? Те инженеры из Слака, которые слышат постоянно, что сообщения иногда в принципе не доходят, как они спят по ночам? Как они не бегут первым же делом организовывать расследование, комиссию, группу по исправлению? Это ведь не десятое по важности окошко на двадцать пятом экране, это основная функция и она в принципе не работает же.

Разве не хочется вам понять, разобраться, докопаться до правды, когда численные характеристики какие-то не сходятся с вашими прикидками на салфетке? Когда вы слышите, что Android система занимает 6 Гб и что там может быть такого? Как нагрузится канал, если в один Google Doc придет 100 пользователей? Вы вообще прикидываете, считаете вещи на салфетках? Мы перестали считать на салфетках... В 3Д играх, кстати, считают. 

Разве вас не коробит от несоразмерности проблем и решений? Когда для Todo-листа на 200 строк берут Electron на 100MB? Разве не хочется узнать, что мог бы делать ваш комп на пределе? Сколько нормально сделанных чатов он мог бы крутить одновременно в 8Гб оперативки? Мог бы он ресайзить текстовое окно на 60 Hz? 144? 240? Где вообще предел и во что всё в конце концов упрётся?

Разве у вас не растет тревога от непроверенного кода? От решенной частично проблемы? От проблемы, решенной в обход, приблизительно, а не точно? Не вгоняет ли вас техдолг в депрессию? Не выгораете ли вы от того, что все время бежите к новому вместо того, чтобы чинить старое? Добавляете и множите там, где нужно исправлять и делить?

Разве не хочется вам, в конце концов, доделать проект хорошо, до конца, так, чтобы полностью им удовлетвориться, сложить, запустить и уволиться? Откуда у вас силы держать всё это на искусственном дыхании вместо того, чтобы закончить, но так, чтобы оно жило, и отпустить?

Короче, я надеюсь, что вы этого всего не чувствуете на самом деле. Иначе добро пожаловать ко мне в депрессию.


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

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

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

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

Я пошел учиться на программиста в 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
tonsky

Я тут выбрался на природу, а интернет тут только мобильный и только на букву Х (H, в смысле, ну прям не очень). И вот приспичило мне Ютуб-видосик посмотреть, где-то час в 720p.

Вы думаете что это было тяжело и больно? Как раз нет, средствами en.savefrom.net сам видеофайл, 600Mb в итоге скачался за интервал в пару-тройку часов. Мне норм, потому что я получил результат, примерно соответствующий физическим ограничениям и ситуации.

А вот что я не смог, так это открыть youtube.com на ноутбуке (через тот же мобильный интернет). То есть оно пыжилось очень сильно и долго, но максимум, что удалось увидеть — skeleton screen один раз (видимо, был закеширован где-то) и частичный лого в левом верхнем углу в другой раз с буквами «o» и «e» (серьезно, не знаю, как так, но вот так — реально только две буквы загрузились, и именно эти). При этом в network tab девтулов конечно много всякого происходило, что-то передавалось, запрашивалось, тянулось, ломалось, сервисворкеры че-то там шуршали, но результат — пустой экран, сколько не жди.

Ну как бы — а чего ты ожидал, без интернета-то? — но на самом деле чего я ожидал это веб-страницы с несколькими картинками. Просто подумайте — ну насколько сложно это должно быть, и насколько сложно это на самом деле сейчас? В вебе сегодня вообще общее место, каждый первый сайт жирный переросток, собранный из миллиона технологий, работающий только в предположении, что у тебя всё хорошо, тратящий на это в миллионы (106) больше ресурсов, и серверных, и сетевых, и клиентских, чем того требует задача, чем того требует получаемый результат вообще, и все делают вид, что это окей, потому что это поддерживает экономику видимо? Есть повод улучшать сети, покупать разработчикам новые мощные ноутбуки (в mbp mid 2018 можно воткнуть 32Гб RAM и запустить Atom и Slack одновременно!), переобучать их?

Я не разбираюсь, да мне и не очень интересны причины, но это всё чудовищное, просто ненормально гигантское несоответствие между задачами, средствами и результатом, делает меня грустным. Конечный пользователь, я, ничего не получает от того факта, что YouTube сделан на чем он там сделан — Polymer? Angular? — я получаю ту же самую простую веб-страничку с сеткой картинок и подписями-гиперлинками к ним. Еще раз: насколько это сложно? 1 HTML, 1 CSS? Я готов согласиться, что плеер, да, ему там требуется некое количество JS, все-таки нетривиальная задача, и какое-никакое кастомное взаимодействие, но всё остальное-то, боже мой? Зачем? Куда уходят эти тысячи человеко-лет, потраченные на достижение тривиального в общем-то результата непропорционально сложным и обходным путем? Ведь это всё зря, зря, мимо и низачем. Адское трение и чудовищный уход энергии в тепло вместо полезной работы. И тренд на то, чтобы делать хуже. Никто не заинтересован делать лучше. Когда это прекратится? (Никогда, я знаю, но отказываюсь в это верить)

https://twitter.com/cmuratori/status/1018985856843968512

Me: Everyone's web site is way slower than it should be.
Web: That's because they have to scale!
Me: But it seems like things still go down under load.
Web: ...
Me: Amazon runs AWS, and _their_ site didn't even stay up!
Web: Oooh look! Someone released a new JavaScript framework!



REPL
усы2
tonsky

Сегодня я буду проповедовать. Вы все живете неправильно. Вы живете без REPL-а, а надо с REPL-ом.

Как выглядит рабочий цикл программиста С++? Написал 2 строчки, отправил на компиляцию, поставил чайник, поговорил с коллегами, попил чай, и вот уже почти и скомпилялось. Поэтому программисты С++ очень общительные и у них много хобби (нет).

Дальше идут языки с номинальным REPL-ом. Таких много. Python, Ruby, даже Scala и Haskell даже вроде что-то “предлагают”. Ну это такой программный интерпретатор, где можно что-то потыкать палочкой, примеры какие-то позапускать. Продукт, идентичный натуральному — на бумаге есть, поиграться можно, но для работы всерьез никто не пользуется. Это важно — я сегодня НЕ о таких REPL-ах.

Ну и на вершине возвышаются ЛИСП-ы. Что такого особенного в ЛИСП REPL-е?

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

Во-вторых интеграция и inline eval. Вы в REPL-е сидите в терминале, а надо редактор к нему подключать. Исчезает переключение контекста. Исходник это одновременно такой блокнотик-черновик, в которым ты что-то пробуешь, смотришь результат, правишь по ситуации. Написал, проверил, уточнил какие-то моменты, посмотрел как работает, запросик в БД сделал, АПИ подергал-посмотрел, гипотезу проверил, скорость прикинул, контракт набросал. Цикл обратной связи нулевой практически. Потому что это не написал — отправил — дождался, это всё прямо в редакторе происходит, это часть редактирования текста. Только кроме текста у тебя есть доступ прям к рантайму проекта, прям там же.

inline eval выглядит как-то так

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

Цитата:

Live programming. The instant gratification of seeing your program run as you code it, with the tight REPL integration and everything being reified and having the ability to be redefined live. I find it more like jamming to an instrument, while Haskell gives me the feeling I’m composing on music sheets.

В-третьих, бесконечная динамичность. Особенно хорошо для интерактивных приложений, UI и так далее. Важно, что стейт не разрушается, а код обновляется. Можно открыть любую страницу, залогиниться, дойти до куда нужно, все правильно выставить и потом точечно править код, который именно нужную форму рендерит, доводить до совершенства. Грубо говоря, двигать кнопку в коде и сразу видеть результат, без необходимости как-то перезапускать и воспроизводить нужный стейт, чтобы подвинуть кнопку _ещё на два пикселя_.

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

Теперь про подвох. Вы мне не поверите. И это нормально. Это ожидаемо. Вот почему:

Most programmers do not have an experience of what inline-eval is. They have nothing to compare it to. They have not used LISPs and SEXPs. You can describe inline eval and demonstrate it to them until you're blue in the face and they won't get it. It is not until a programmer actually experiences inline-eval as a programming tool that the light goes on.

Но это нормально, надо просто про это помнить. Т.е. моя задача максимум — не убедить вас, что REPL это круто, а убедить вас, что пока не попробуете, решить круто или нет нет способа. Когда подвернется возможность попробовать REPL, вспомните про bias и подойдите к этому хотя бы непредвзято, всё о чем я прошу. Ценность REPL трудно представить, не попробовав. Ну и если вы поигрались с номинальным REPL в какой-нибудь Scala или даже Ruby и не поняли, зачем это нужно, всё равно подождите, когда получится попробовать настоящую REPL-разработку. Я тоже не понимаю, зачем в Scala REPL.

Но всё-таки уточню: возможность REPL-разработки это не еще одна галочка в фич-листе. Это не nice to have. Не надо думать, что у Scala 38 таких фич, а у Clojure 27 таких, у всех примерно равный вес и REPL просто одна из них, но по совокупности мне нравятся те что у Scala. Баланс немножко не такой, скорее такой:

Причины, по которым я люблю язык Clojure:

1. REPL
2. REPL
3. REPL
4-99. REPL
100+. Все остальные причины (иммутабельность, ФП, структуры данных, etc)

REPL — это основной режим работы. Это способ писать программы качественно лучший, чем как вы пишете их сейчас. Быстрее, проще, приятнее, удобнее, лучшего качества. С REPL я бы и на Rust писал бы с удовольствием. И на С++ даже. Пофиг, что там за язык, любые языковые фичи меркнут с возможностью _так_ взаимодействовать с кодом и рантаймом.

Короче, REPL.



Монады против исключений
усы2
tonsky

Я конечно не настоящий сварщик и про ФП мне Рабинович напел. Но я поработал в трех Clojure-командах и одной Erlang и видел, как люди пытаются для обработки ошибок слезть с исключений и перейти на Error монады (например, failjure, бывают и самописные, но принцип понятен). Считается, что исключения это такие грязь и пот для люмпенов, а монады из области чистых идей и разносят их на золотых подносах во дворцах.

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

А в производстве у нас что? Все спешат, тесты покрывают 25% случаев от силы, хорошо если хоть на какие-то failure cases тесты вообще есть, задачи и курс партии меняется еженедельно, коммуникация средняя, такая штука как коллективное внимание вообще можно сказать не существует (ну нельзя на каждый чих оповещать всех, ну нереалистично это). Задача производства ведь какая? Строить новое со скоростью большей, чем разваливается старое, чтобы выйти в конце в net positive. Подход быть внимательным, хоть я сам его и очень люблю и использую в домашних опен-сорс проектах, где всё разложено по полочкам и муха рядом чихнуть не может; такой подход ну не работает, нельзя на него полагаться от слова совсем.

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

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


Фронтендеры не на маках
усы2
tonsky

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

miketansky: Фронтендеры не на маках с чувствами вкуса и хорошего дизайна — это редчайшее исключение. Хотите резко повысить вероятность найма хорошего фронтендера? Жестко и безжалостно дискриминируйте по этому признаку.

А вот реплаи:

flashader: Ни одна статусная (а тем более — зашкварная) вещь не заменит исполнителю мозг и умение думать.

Как будто кто-то с этим спорил. Утверждение было в обратную сторону — если умение уже есть, есть тенденция к переходу на маки.

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

Опять развернули утверждение. Речь же не о том, что дебилы (что бы это ни значило) тоже могут купить мак. Речь о том, что Хорошие Фронтендеры (что бы это ни значило) переползают рано или поздно на мак.

orsinium: Я воспринял этот твит как «Для того, чтобы делать хороший UI, нужно пользоваться хорошим UI». И отметил, что UI в маке хорош, а UX — нет. А навыки в UX я считаю не менее важными для фронтендера и дизайнера.

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

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

На эту тему у меня есть шикарный же пример. Сидел я как-то на докладе про какой-то кросс-мобильный фреймворк, из серии write once — run anywhere, и на одном из слайдов, продающих его, был график выручки компаний от приложения по количеству платформ. Грубо, компании, выпускающие приложение только на одной платформе, там, айос или андроид, зарабатывают условно $1000 в мес на нем. Компании, выпускающие на двух, зарабатывают допустим $2000. На три платформы (+windows phone) уже $5000. Ну и самый пик там что-то типа те, кто выпустили приложение аж на 11 платформ (хз, что это за платформы), гребут уже там, например, $500 000 — непропорционально больше, короче. Ну и показывалось это под таким соусом, типа, за этим вам и нужен наш фреймворк — выпустите под больше платформ, заработаете больше денег. Для презентации кросс-платформенного фреймворка очень удобный аргумент. На самом деле всё объясняется гораздо проще, конечно — если у вас есть приложение, зарабатывающее $500 000, у вас найдутся деньги, чтобы портировать его на 11 платформ. А если приложение херовое, то запускай хоть на 11 платформах, денег не соберешь. Вроде бы банальная мысль. График можно было прочитать и так, и так, а понять его правильно можно только через понимание механики, которая его формирует.


Повышенное чувство собственности
усы2
tonsky

Бывает, что в интернете кто-то слегка неправ, в какой-то детали, и тогда поправить их будет обычным занудством (90% моих постов, ха-ха), а бывает, чтоб вот совсем прям мимо и непонятно даже, о ком речь.

Возможно, вы видели уже эту мысль в каком-нибудь статусе вконтакте или еще в каком солидном источнике:

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

Ну вот прямо сейчас я смотрю на шкаф из икеи. Собранный моими руками. Никаких особенных чувств не испытываю. Шкаф как шкаф. Внутри вещи. Блин, кем надо быть вообще, чтобы испытывать чувства, даже пусть чувство повышенной собственности, к шкафу? Гордость владение икеевским шкафом? Серьезно? Совершенно утилитарная штука.

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

Ну ладно, шкаф действительно смешно. Но вот «домашний кинотеатр». Тоже собирал сам, выбирал проектор, колонку, искал, покупал, соединял, прокладывал. Казалось бы, опять должен испытать гордость владения. Однако всё, что я испытываю, это «клевый фильм, ладно, пора спать» (ну или, что чаще бывает, «блин, что за говно мы посмотрели, как теперь это забыть?»). Как-то не думается о «блин, на каком классном экране мы это смотрим, как я горд, что всё сам собрал». Ты ж покупаешь всё это, чтобы потом забыть и не думать. Если я обо всей этой затее и вспоминаю, это скорее «так, чё всё так хреново стыкуется, куда колонку поставить, тут шнур торчит, ладно, стулом прижмем, че так хреново слышно, почему блютус не работает, неужели что-то еще надо докупать, блин вообще не то купил, почему два пульта теперь, зачем мне два пульта» и как я мучался всё это выбирая и «never again». Гордость владения? Работало бы.

Окей, там еще и программное обеспечение упомянули. Ха-ха, яжпрограммист. Вот есть у меня программа, написанная лично мной для моих нужд, AnyBar называется. Пользуюсь, полезно, удобно. Какие я по этому поводу чувства испытываю? «Ох, че ж сил нету никак это барахло доделать, ладно, потерплю, перебьюсь» и так все 3 года. Короче, опять не про меня, хотя вот какие-то люди думают, что если они сообразили, как запустить готовый билд-скрипт на готовых исходниках, то это чуть ли равно тому что они сами всё с нуля написали. Крафтовый софт получается, ручной выделки. Целый линукс дистрибутив придумали, чтобы таких людей в одном месте собрать.

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

Тот самый шкаф

Сколько пользы от программиста?
усы2
tonsky

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

Меня такой взгляд на вещи всегда шокировал своей недальновидностью. Ну то есть есть миллион вещей, которые:

  1. нужно просто сделать, без них проект можно помножить на 0 (особенно это заметно на старте проекта),
  2. которые не приносят прибыль прямо сейчас, но если их не делать, угробят её когда-нибудь позже (ну тесты там, автоматизация, контроль качества),
  3. всякие репутационные штуки, которые копятся медленно и не трансформируются в конверсию прямо щас (пресловутое качество, надежность, эмоции, поддержка),
  4. синергия, когда суммарно N фич больше чем каждая по-отдельности,
  5. эксперименты, которые вообще говоря в среднем скорее ухудшают прибыль и отнимают ресурсы.

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

Сколько денег принес компании Google сотрудник, реализовавший функцию Crop в приложении Photos? Или вот у Apple вышел iPhone X. Сколько денег принес программист, запрогавший свойство safe-area-inset-top? Давайте предположим, что у вас есть на руках все данные, к которым есть доступ у самой верхушки Apple. Как бы вы это посчитали? То-то и оно.

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

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


Ворчание ягнят
усы2
tonsky

Завел блог на стороне, хе-хе http://grumpy.website. Там — про интерфейсы, тут  — про программирование (если полностью на английский http://tonsky.me не перейду, конечно).

Движок — кастомный на Clojure, написан в прямом эфире часов за 15.

Привет.


В некоторые головы лучше не заглядывать
усы2
tonsky

Бурная история про Xored (it-компания из Академгородка, Платов — её президент):

Многие кинулись обсуждать конкретную ситуацию — был ли мальчик, где деньги, лебовски, можно ли всё исправить, етц. Мне кажется, это не самое тут удивительное (и поучительное).

Безотносительно того, что там произошло и кто с какой стороны сколько наплел, всё рухнуло, когда Платов добрался до микрофона. Даже если он на 100% прав и невинен в данной конкретной ситуации с Алексеем, никуда уже не деться от комментариев (ищите по нику platoff), из которых получается, что более-менее всех, кому с ним не по пути, он даже за людей не считает. Все программисты и комментаторы у него — долбоебы, лузеры, нищеброды, лохи, пидарасы (в терминологии автора — заднеприводные) по умолчанию. И остаются такими, пока не доказали обратное. Я не придумываю, так и написано. Судя по чуть более раннему твиту («Ксоред сбрасывает жыр. Жыр бежит в Yandex, JetBrains и Tinkoff Bank»), уход с должности это тоже предательство и потеря статуса «обычного» человека и «нормального» программиста.

Там еще феерический катарсис, из которого вообще получается, что человек у Платова остается человеком и имеет право на человеческое отношение только до того момента, пока он выгоден замыслу (компании, проекту, лично). Вне этого интервала о нем не думают, договоренностей не соблюдают, кидают («...за последние годы [через Xored] прошло человек 300, из которых кинули трёх-четырёх»), объяснений не объясняют, оскорбляют, высмеивают, травят и это типа нормально.

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


Десктопные 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

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

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