• Гарри Поттер и деньги

    Читаю дочке на ночь Гарри Поттера. Она уже читала, но со мной переспрашивает многие моменты. Я в свое время пропустил Поттера, и теперь догоняю.

    Среди прочего заметил вот что: в волшебной стране интересная мера денег. Процитирую Огрида:

    — Золотые — это галлеоны, — пояснил он. — Один галлеон — это семнадцать серебряных сиклей, а один сикль — двадцать девять кнатов, это просто, да?

    Интересно, что оба числа — 17 и 29 — простые. Это значит, ни сикль, ни кнат нельзя разделить поровну между участниками. Скажем, если в группе три-четыре человека, делить 5 сиклей 11 кнатов будет, мягко говоря, трудновато.

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

    Система денег с простыми числами максимально неудобна для расчетов. А потому вопрос: Джоан Роулинг выбрала их с умыслом или случайно? Понимает ли она особенность простых чисел? Выдумала сама или кто-то подсказал?

  • Авито 2025

    Заметка из серии “Иван зашел на Авито”. Приходится делать это раз в год, что поделать.

    Ничего особо не изменилось: всюду спиннеры, спиннеры, спиннеры. По-прежнему огромные баннеры, которые занимают до половины экрана на ноутбуке.

    Страница Messages заработала с третьего раза, до этого что-то шло не так. Выделяю все сообщения, жму “отметить прочитанными” — они не отмечаются. В заголовке по-прежнему мигает колокольчик.

    Публикую объявление, оплачиваю в Сбере. Авито не реагирует на платеж, страница не обновляется. Перехожу в объявление, жму “Опубликовать”. Написано, что уже опубликовано, но пока на модерации. Зачем тогда показывать кнопку “Опубликовать”?

    Смотрю консоль — все залито кровью. Десятки обращений к Sentry и внутреннему трекеру. Ставлю фильтр на JS, вижу запросы к файлам:

    runtime.17ee57e8c945aab7.js
    babel.56c763c5da678bfa.js
    react.dfd1d111f8ede875.js
    core-js.afc06ee845ff2534.js
    sentry.92aa5077131b46e2.js
    react-dom.b2b03dba79dd7e0e.js
    react-router.70c77e8819d4a40e.js
    react-router-dom.952fcbce71c8c0eb.js
    main.085d7b253d7b4fc3.js
    classnames.8bdb4ca7d18147c3.js
    axios.531715197964b964.js
    react-helmet-async.08c35d15407bd540.js
    clickstream.9d25519cca31a2b9.js
    desktop-header.08bc7205e5d97c1c.js
    desktop-error-boundary.60b97a6749bfdf5d.js
    bootstrap.a567aae79d5d83f3.js
    popperjs.23534e9c89ee28ca.js
    redux.812bd211f67f512a.js
    desktop-navigation.e3664b256e3d71c5.js
    navigation.054020057401a579.js
    PhoneActualizationPopup.0710bcce593318a7.js
    AuthProfileConfirmForm.61b7e0d361eaeba6.js
    react-redux.8146e991e20c5797.js
    profile-messenger.3520407fc648a850.js
    fingerprint.ce96eef5e5724e1b.js
    remoteEntry.faea46d9e2064abc.js
    Auth.d430faf2d81cfc87.js
    remoteEntry.6825f5efeccb47cc.js
    WwwProfileMessenger.dda85a70f5fec4e4.js
    

    …и другие.

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

    Повторюсь, современных фронтендеров нужно не учить, а лечить. Это какой-то особый сорт нелюдей. Я искренне не понимаю, как можно выкладывать такое в прод. Не понимаю, как людей не тошнит от настолько плохой работы и собственной неэффективности. Но похоже, им это ок. Человек ко всему привыкает.

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

  • Часы

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

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

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

    Хожу как дурак с часами в рюкзаке, ищу кому подарить. Пока безуспешно.

  • Файл с процентом

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

    С одной стороны, это бред. Когда файлы хранят в облаке, никто в здравом уме не назначает им исходное имя. Файлы лежат как бинарные блобы с машинными уидами, а имя хранится в базе в текстовой колонке. Будь там процент, решетка, эмодзи или DROP TABLE STUDENTS — нормальной системе это без разницы.

    С другой стороны, “не все так однозначно” (с). Я уже рассказывал, как потерпел неудачу из-за пробела в папке S3. Половина клиентов ищут папку Daily Reports, другая половина — Daily%20Reports. Класс java.util.URI просто валится, если дать ему адрес с пробелом.

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

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

  • Кложурная Слака

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

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

    В кложурной слаке зарегана 21 тысяча человек, из них 2.600 активны. За каждого активного пользователя Слак просит почти пять долларов в месяц, в результате месячная плата составляет 19 косарей. До того, как узнать эту сумму, я думал выступить спонсором: перечислять долларов 500 в месяц в общий фонд. Но собрать 19 тысяч будет тяжеловато, да и не ясно, за что столько платить.

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

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

    Просто чтобы посмотреть на реакцию, я предложил Телеграм. А что такого? Есть же русское сообщество в Телеге, и хорошо себе живет. Есть и англоговорящая группа человек на 250.

    Как и ожидалось, нашлись те, кого беспокоит, что Телеграм — это Russian thing. Ничего, что основатель уехал в Дубай двенадцать лет назад? Кроме того, я могу понять, когда россиянин не ставит американский софт, опасаясь санкций. Но почему американец опасается софта, который написан русскими? Уверен, что все сливается в КГБ? Кто-то много смотрел телевизор.

    Другая вещь, которая бросилась в глаза — в этом вашем Телеграме нет модерации. Западный человек настолько привык, что каждая платформа модерируется, что без нее чувствует себя голым. Это что, каждый может написать то, что думает? Людям даже не приходит в голову, что модерацией должно заниматься сообщество: ставить своих анти-спам ботов, дать админские права людям в разных часовых поясах. Модерировать должны вы, а не индусы на аутсорсе, которые грепают текст по ключевым словам, и которым завернуть контент проще, чем оставить.

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

  • Боязнь исключений

    Многие программисты боятся исключений. Как я об этом узнал? Примерно раз в месяц в кложурной Слаке и Телеграме задают вопрос: что мне использовать вместо исключений? Им советуют возвращать мапы с полем error, разные типы-обертки, макросы. Есть несколько библиотек, имитирующих монады. Это когда поделил на ноль, и вместо исключения приходит объект Failure.

    Что тут сказать… можно прятаться от проблемы разными способами. Не смотреть на нее, не называть вслух или креститься. Можно писать программу так, что даже в худшем случае она не упадет. Только вопрос — зачем?

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

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

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

    Терпимость к отклонениям должна быть нулевая. Зарывание ошибок в мапу — путь в никуда.

  • Уведомления о куках

    В позднем СССР сложилась интересная ситуация. Воевать в Афганистане можно было с 18 лет, а пить спиртное — только с 21. Другими словами, не возбранялось легально убивать людей, а вот пить водку — подожди еще три года.

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

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

    • сайт может вывалить 50 мегабайтов скриптов, сделать 250 запросов;

    • сайт может ходить на другие сайты, подтягивать виджеты, которые тянут другие скрипты, и так рекурсивно;

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

    • на сайте контекстная реклама;

    • сайт трекает движение мыши, шлет события на каждый клик

    • в сайт встроены анти-блокировщики, которые замедляют загрузку;

    • сайт может быть частью ботнета (координатором или жертвой);

    • сайт может трекать пользователя через данные в LocalStore и кастомные заголовки. Кук нет, отслеживание есть;

    • функции трекинга уже зашиты в апишку браузера и Джаваскрипта (Beacon API, Geolocation API, etc)

    • и еще штук двадцать пунктов.

    Повторюсь, со всем этим у еврочиновников проблем нет, предупреждать не нужно. А вот куки им не понравились.

    На этот счет у меня есть еще одна мысль, но о ней — в следующий раз.

  • Приши, улучшай

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

    То же самое с кодом: недостаточно его написать и проверить. Когда тесты написаны и код рабочий, нужно пройтись по нему и причесать. Дать нормальные имена, вынести анонимные функции на верхний уровень. Одни участки кода разнести на промежуточные шаги, чтобы не было слишком плотно. Другие, наоборот, сократить.

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

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

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

    Читаю чужой код: коллекцию пропускают через пачку map и partition-by. В каждой из них — анонимная функция со вложенными reduce и другими анонимными функциями. Партицирование замкнуто на другой коллекции, которая что-то достает из первой. Неделимый блок кода размером с экран. Функция в функции внутри функции.

    Нечитаемый ад. Писал его не молодой программист, надо полагать, с опытом. И то же самое: как только он дошел до стадии “работает”, то оформил PR — и получил апрув коллег.

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

  • Две системы клавиш

    Это короткая заметка, которую хотелось бы развить в будущем.

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

    Возьмем современный редактор и посмотрим на хоткеи. Нажатие на кнопку приводит к печати символа, и это логично. Чтобы вместо печати было действие, кнопку нажимают со служебной клавишей, скажем Ctrl, Alt, Command. Все это тоже логично.

    Но вот беда — многие комбинации заняты дефолтами! Ctrl-Q, T, N, O, P — все это системные действия. Еще десяток клавиш уходит на навигацию каретки, еще десяток — на удаление строк, слов и символов, и привет — Ctrl уже исчерпан. Попутно нужно учесть, что на Маке роль Ctrl играет Command, поэтому удвоения емкости это не дает.

    Остается Alt, но на него могут быть повешены хоткеи терминала и операционки, и в итоге какой-нибудь Alt-N просто не дойдет до редактора. Ну и часто на Альт тоже много чего навешено.

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

    В Емаксе хоткеи сделали последовательностями, или цепочками. Например, C-x f открывает файл, C-x o открывает новое окно, C-x C-c —закрывает Емакс. Подход с цепочками позволяет делать домены хоткеев, когда на C-x вешаются базовые функции, на C-h — все, что имеет отношение к справке, на C-x r — операции с прямоугольниками и так далее. Все это легко наращивается вглубь, не мешая остальным.

    Недавно загуглил, как вызвать в Идее выпадашку с методами. Знаете как? Command + F12! Если учесть, что F-клавиши на маке работают с зажатым Ctrl, получается три кнопки одновременно! Пользователь Идеи должен быть осьминогом, чтобы с этим совладать. А в Xcode на полном серьезе одна из функций навешена на Shift+Alt+Command+V. Я уже не помню какая, но точно помню подсказку в меню.

    Не то чтобы это большая проблема; можно продуктивно работать в любом редакторе. Но повторюсь, системно к проблеме хоткеев подошли только в двух редакторах: Виме и Емаксе. Все остальное — ситуативно и нерасширяемо.

  • Выпрямить данные

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

    (var DATA
      {:kek {:foo {:type :LOL}
             :bar {:type :KEK}}
       :owo {:pip {:type :AGA}}})
    

    Ожидание:

    {:LOL {:foo :kek}
     :KEK {:bar :kek}
     :AGA {:pip :owo}}
    

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

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

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

    Итак, если посмотреть на исходную мапу, станет ясно, что когда-то она была плоской таблицей:

    kek foo LOL
    kek bar KEK
    owo pip AGA
    

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

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

    (for [[k1 submap1]
          DATA
    
          [k2 submap2]
          submap1
    
          [_ item]
          submap2]
    
      [k1 k2 item])
    
    ([:kek :foo :LOL]
     [:kek :bar :KEK]
     [:owo :pip :AGA])
    

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

    Я как-то рассказывал о нелепой ситуации со вложенностью. На одной стороне человек потеет, чтобы построить из списка вложенную мапу вида:

    {:node shit
     :children
     [{:node crap
       :children
       [{:node fuck
         :children
         [...]}]}]}
    

    А на второй стороне другой человек потеет, чтобы обойти ее как список. Оба пишут быдлокод и матерятся, а ради чего — не ясно. Такую структуру даже не каждый кложурист обойдет, потому что не все знают про tree-seq и зипперы.

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

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

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

Страница 6 из 93