• Ковид

    Вопрос между делом: как дела с ковидом? Он уже прошел? Все выздоровели? Повальная вакцинация сделала свое дело? Все приобрели иммунитет?

    Где мы находимся: уже перешагнули катастрофу? Ковида больше не будет?

    Может быть теперь, когда ковидная истерия сходит на нет, не мешало бы провести ретро, а именно:

    • надо ли было запирать людей в четырех стенах на год?
    • надо было ставить прививки всем поголовно, в том числе беременным и детям?
    • нормально ли было пускать в магазин за едой по QR-коду?
    • хорошо ли было отказывать в помощи тем, у кого не ковид, а сердце, например?

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

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

  • Краткие ответы на большие вопросы

    Закончил читать “Краткие ответы на большие вопросы” Стивена Хокинга. Того самого ученого в инвалидном кресле, который недавно умер.

    Это второй раз, когда я читаю его книгу. В первый раз это была “Краткая история времени”. Скажу честно, не пошло — она слишком научна. Можно сделать вид, что разбираешься в материале, но не вижу причины себя обманывать, поэтому дочитывать не стал. Напротив, “Краткие ответы…” менее научная, поэтому решил попробовать еще раз.

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

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

    В книге десять глав с рассуждениями на “большие” вопросы — есть ли бог, откуда мы взялись, можно ли путешествовать во времени, как быть с искусственным интеллектом и другие. По мере того как я читал, впечатления от книги менялись интересным образом.

    Первые несколько глав посвящены науке и черным дырам — области, в которой Хокинг был топ один. Читать про Вселенную и дыры интересно, особенно в изложении Хокинга. Постепенно научные темы сменяются социальными, и наступает некий интеллектуальный уклон. Суждения Хокинга становятся откровенно плоскими. Начинаются пугалки про глобальное потепление, Трампа, Брексит, мировой голод и прочие штучки. Ощущение, будто открыл Твиттер демократической партии США.

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

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

    Возможно, часть книги с социальными темами Хокинг не успел написать, и ее высосали из пальца его коллеги на базе его случайных цитат.

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

    Вот такая противоречивая книжка. Горячо советую ее первую половину, остальное — по настроению.

  • PG2 release 0.1.12

    PG2 version 0.1.12 is out. Aside from internal refactoring, there are several features I’d like to highlight.

    First, the library is still getting faster. The latest benchmarks prove 15-30% performance gain when consuming SELECT results. Actual numbers depend on the nature of a query. Simple queries with 1-2 columns work faster than before:

    Metrics:

    Platform JDBC.Next PG2 0.1.1 PG2 0.1.2 PG2 0.1.12
    core i5 2 GHz Quad-Core 16G 127.677926 43.026307 44.36297 21.941113
    core i9 2,4 GHz 8-Core 32G 83.932103 39.551719 27.672117 20.957904
    arm m1 10 cores 32G 49.340986 18.517718 14.670815 9.468902

    Although queries with many columns are less sensitive to the new parsing algorithm, they’re still fast. Here is a chart for a complex query:

    Metrics:

    Platform JDBC.Next PG2 0.1.1 PG2 0.1.2 PG2 0.1.12
    core i5 2 GHz Quad-Core 16G 579.59995 273.866142 80.352246 55.835803
    core i9 2,4 GHz 8-Core 32G 447.326861 270.262248 54.34384 42.815123
    arm m1 10 cores 32G 206.371502 117.241426 30.444798 29.92079

    PG2 has become a bit faster with HTTP. The chart below measures a number of RPS of a Jetty server that fetches random data from a database and responds with JSON:

    The tests were made using ab as follows:

    ab -n 1000 -c 16 -l http://127.0.0.1:18080/
    

    Timings:

    Platform JDBC.Next PG2 0.1.1 PG2 0.1.2 PG2 0.1.12
    core i5 2 GHz Quad-Core 16G 555.55 968.51 915.93 890.62
    core i9 2,4 GHz 8-Core 32G 1304 1909.19 1688.72 1794.75
    arm m1 10 cores 32G 1902.31 2999.06 3026 3363.36

    The second feature is the :read-only? connection flag. When it’s set to true, the connection is run in READ ONLY mode, and every transaction opens being READ ONLY as well. This is useful for reading from replicas. A small example where an attempt to delete something leads to a negative response:

    (pg/with-connection [conn {... :read-only? true}]
      (pg/query conn "delete from students"))
    
    ;; PGErrorResponse: cannot execute DROP TABLE in a read-only transaction
    

    When set globally for connection, the flag overrides the same flag passed into the with-tx macro. Below, the transaction is READ ONLY anyway because the config flag is prioritized.

    (pg/with-connection [conn {... :read-only? true}]
      (pg/with-tx [conn {:read-only? false}] ;; override won't do
        (pg/query conn "create table foo(id serial)")))
    
    ;; PGErrorResponse: cannot execute CREATE TABLE in a read-only transaction
    

    Finally, there is a new reducer called “column” which fetches a single column as a vector. We often select IDs only, but the result is a vector of maps with a single :id field:

    [{:id 100} {:id 101}, ...]
    

    To get the ids, either you pass the result into (map :id ...) or, which is better, specify the :column key as follows:

    (pg/with-connection [conn {...}]
      (pg/query conn
                "select id from users"
                {:column :id}))
    
    ;; [100, 101, 102, ...]
    

    Internally, the reducer fetches the field from each row on the fly as they come from the network. It’s more effective than passing the result into map as it takes only one passage.

    For more details, you’re welcome to the readme file of the repo.

  • Табы

    Иногда нам все-таки везет с дизайнерами.

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

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

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

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

  • Soft delete

    Многие знают о технике мягкого удаления. Это когда записи не удаляются физически из базы, а помечаются флажком is_deleted или выставляется время deleted_at. Удобно, что ничего не удаляется, не нужно воевать с внешними ключами и ограничением целостности. Самое главное — если что-то пошло не так, то снял флажок, и данные на месте.

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

    Начнем с того, что удаленные записи отнимают место на диске. За несколько лет их набегает порядочное количество. Удаленные записи по-прежнему участвуют в индексах, и они тоже занимают место, замедляют обход. В Постгресе есть функциональные индексы когда запись попадает только при условии NOT is_deleted или deleted_at IS NULL. Но чаще всего этим не заморачиваются, и в индекс валится все.

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

        email        | is_deleted
    -----------------|-------
    ivan@grishaev.me | false
    ivan@grishaev.me | true
    

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

    Что касается запросов, то разработчики часто забывают условие WHERE NOT is_deleted, и в выборке оказываются удаленные данные.

    А в другом проекте было по-другому: проблему удаления решали переносом в другие таблицы. Например, для таблицы messages создается ее аналог messages_deleted. Запись переносится атомарно таким запросом:

    with deleted as (delete from messages where id = 42 returning *)
    insert into messages_deleted select * from deleted
    

    Перенос обратно:

    with deleted as (delete from messages_deleted where id = 42 returning *)
    insert into messages select * from deleted
    

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

    На первый взгляд это неудобно, потому что нужны лишние таблицы. Но как замечательно это оказалось на практике! В основной таблице только актуальные данные, никаких флажков и предикатов. Выбирая что-то из messages, ты на 100% уверен, что нет риска выбрать что-то не то. Данные всегда в чистоте. Если однажды мы решим, что удаленные сообщения не нужны, мы грохнем таблицу messages_deleted без риска задеть живые данные.

    С тех пор я придерживаюсь переноса, если это возможно.

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

  • Чтение

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

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

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

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

    Я спокойно читаю технические книги на русском, если, конечно, перевод не совсем уж плохой. Все больше книг пишутся русскими авторами. Книги “Postgres изнутри” Егора Рогова и “Postgres: основы SQL” Моргунова — просто отпад. Они написаны на русском, а первую уже перевели на английский. Попадались хорошие книги русских авторов и по другим технологиям.

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

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

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

    При этом я не считаю себя Д’Артаньяном: я читаю мало, и лишь недавно очнулся после года тупняка. Это заметка — скорее напоминалка себе: меньше тупить в экран и больше читать.

  • Наедине

    Разговаривая с кем-то, помните: разговор один на один и при свидетелях — это разные вещи.

    Беседа с ребенком наедине — совершенно не то, что получится, если рядом брат или сестра, не говоря уж о приятеле.

    Разговор с близким человеком, когда рядом другие родственники, становится сценой из “Уральских пельменей”.

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

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

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

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

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

    Так и живут большие фирмы: постоянное двоемыслие. Будь менеджер умнее, он бы назначил регулярный разговор с глазу на глаз с каждым членом команды минут на 15. Но нет, у него дейли по два часа, планнинг, пост-мортем и другие коллективные штучки.

    Не совершайте эту ошибку: говорите с людьми только наедине.

  • Эмодзи

    Чего я не могу понять, так это эмодзи.

    Скажем, человек пишет в объявлении, что продает щенка. И ставит морду щенка. Зачем? Речь о щенке, и после него морда щенка. Масло масляное. То же самое с автомобилем, ноутбуком и прочим: за словом следует иконка того, о чем написано. Зачем? Я уже понял, что речь о щенке или ноутбуке, зачем ставить то же самое?

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

    Или молнии: каждый клоун ставит молнию к новому сообщению в телеграме.

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

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

    Иные люди тратят дни и месяцы, чтобы затащить эмодзи туда, где их раньше не было. Даже не знаю, что им сказать. К счастью, эмодзи до сих пор плохо дружат с печатью. В мире InDesign и LaTeX их либо избегают, либо вставляют вручную. Это один их тех бастионов, что еще держатся.

    С тем же непонимание я отношусь к лигатурам: какой смысл в завитушках в коде? У меня есть роскошное издание Дон Кихота, и там лигатуры очень кстати. И то не везде, а только в иллюстрациях и подписях к ним. Почему-то сорок лет назад понимали, что лигатуры отвлекают от чтения. А сегодня это знание утеряно.

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

    Напоминает проблему современных мессаджеров. Хочешь отправить текстовый смайлик — и он становится желтым колобком. Я не хочу колобок, я хочу текст. Раньше я добавлял ему нос из тире :—) и алгоритм пропускал его. Но технологии не стоят на месте: теперь и этот паттерн превращается в колобка.

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

    Желаю вам больше эмодзи, пальчиков, смайликов, щеночков и лигатур.

  • AWS, история четвертая. Когда null не совсем null

    Все статьи из цикла AWS

    Еще одна история о том, как Амазон может попить крови.

    Напомню особенности нашей архитектуры. Сервисы записывают в S3 сущности разных типов. Их может быть много, например, полтора миллиона такого-то типа. Чтобы выгрести сущности разом, мы используем чудо-оружие Амазона — сервис Athena. Он собирает файлы из бакета и склеивает в один CSV.

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

    (->> csv
         (get-lazy-seq ...)
         (filter
          (fn [entity]
            (-> entity :attrs nil?))))
    

    На проде, по различным логам и эксепшенам, вижу, что битые сущности просочились в обработку. Как так?

    А вот как: в оригинальном JSON поле attrs было null, все верно. Но при агрегации в CSV Амазон экранирует null кавычками и получается \"null\". При этом его не волнует, что null находится в середине JSON-строки, которая уже экранирована. Какой-то парсер доходит до null и пишет его с кавычками.

    В результате при чтении JSON получается {"attrs": "null"}, то есть строка с буквами n, u, l, l. Чтобы выкинуть эту запись, я переписал фильтр так:

    (or (-> aggregate :attrs nil?)
        (-> aggregate :attrs (= "null")))
    

    Спрашивается, зачем я оставил первый вариант с чистым nil? Потому что, если однажды мы перейдем на другое хранилище, поле опять станет null вместо "null", и фикс придется откатывать. А так оба случая покрыты: и нормальный, и кривой.

    Разумеется, прикол с null нигде не описан, в Гугле ничего нет. Счастливой отладки, уважаемые коллеги!

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

  • Весенняя чистка

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

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

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

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

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

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

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

Страница 5 из 79