• Видео с митапа о Postgres

    Появилась запись митапа:

    Примерно час я рассказываю про всякие технические кишки, потом дискуссия с Николаем (CTO Самураев) и Владимиром (разработчиком JDBC-драйвера для Postgres).

    Не обещаю, что будет интересно, скорее сильно на любителя.

  • Copilot и документация

    Вчера провел с коллегой эксперимент.

    Коллега подключил в редакторе Copilot и говорит — смотри, как круто он генерит комментарии к функции! Скажем, для функции generate-time-buckets(account, time-frames) пишет что-то вроде “generate time buckets for given account and time frames”.

    Мда, содержательно: для generate-time-buckets получить “generate time buckets”… Мне такой подход кажется малоинформативным: очевидно, Copilot берет сигнатуру и аргументы, конкатит их, разбивает на лексемы и причесывает, чтобы смотрелось по-человечески.

    Предложил эксперимент: пишем фукнцию, которая тупо складывает два числа: return a + b. Называем функцию delete-file и просим Copilot написать докстринг. Что он пишет? Правильно, “Delete а file”. Есть и второй вариант — “Delete a file from S3”, видимо, для корпоративных клиентов в облаке.

    Словом, теперь у нас ИИ-комментарии, а чего мы добились и какую проблему решили — не понятно.

  • Зачем спринты?

    За все время работы в айти я не понял, зачем нужны спринты.

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

    Все это кажется мне бредом. Зачем делить время на равные участки? Зачем считать стори-поинты? Какое знание дает цифра 18 стори-поинтов? Чем это хуже, чем 20 поинтов?

    В чем проблема, если задача из одного спринта переносится в другой? Кто от этого пострадал? Если задача не умещается в спринт, то может просто не впихивать невпихуемое?

    Нужно обсудить процесс? Так проведи серию звонков 1 на 1 с разработчиками. Не обязательно ждать ретро.

    В моем понимании процесс управляется релизами. Скажем, поставили мы задачу выкатить новый релиз через два месяца. Договорились, что в релиз войдет то, се, пятое-десятое. Не успеваем? Что-то упрощаем, что-то откладываем в следующий релиз.

    Зачем нам спринты? Почему все следуют карго-культу гуглов-амазонов? Нужно думать своей головой, а не как менеджер Гугла.

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

  • Шкала ООП

    Когда говорят про ООП, упоминают всякие солиды, наследование и прочее. И не говорят вот про что (а надо бы).

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

    Скажем, у нас есть классы Dog и Cat, унаследованные от Animal. Пока мы передаем собак и котов явно, все хорошо. Но когда мы передаем их как животных (Animal), там может быть что угодно. В итоге на одни и те же данные смотришь по-разному.

    Если предположить, что Animal наследуется еще от чего-то, то получится шкала от Object к Dog/Cat, и как смотреть на объект — зависит от контекста. В некоторых случаях делают даун-каст и ап-каст: передают кота в виде объекта, а потом проверяют: если это кот, то одно, если собака, то другое, иначе эксепшен.

    Эту шкалу (ObjectAnimalMammalDog) важно держать в голове и знать, где находишься сейчас. Лично мне она доставляет много хлопот, когда я пишу на ООП-языках, например Джаве. Шкала — это не вкл/выкл, а некая доля, позиция в в дереве, следить за которой сложнее.

    Может быть, кто-то лучше выразил эту мысль, но либо я не слышал, либо забыл.

  • Не люблю регулярки

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

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

    Другой момент — с регуляркой часто оказывается, что ты не все учел. Предположим, нужно искать в тексте числа с плавающей запятой. Вы написали регулярку, которая ищет числа вроде -12.0042. А потом оказалось, что у чисел может не быть целой части, например -.0042. А еще оказались числа в научной нотации: -1.2E9. И регулярку нужно допиливать, допиливать и накидывать тесты.

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

    В одном из проектов у нас была библиотека для генерации регулярок. Это когда декларативно указываешь: либо это слово, либо это, либо то, но не это и не то, и библиотека строит одну регулярку. В ней учитываются общие начала слов, например для fuck и fuckoff получим fuck(?=off). Выбрал такой пример, потому что фильтровали сообщения в чате. Было много других слов, значения которых я не знал и смотрел в словаре.

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

    Вместо регулярок мне больше нравится парсинг грамматикой. Пару лет назад я прочитал пару статей про комбинаторные парсеры и решил сделать свой. В результате я написал огрызок, который назвал Ostap (потому что великий комбинатор). В библиотеке были простые парсеры и те, что составляются из других (and, or). Можно задать грамматику словарем и получить из нее парсер.

    В результате у меня получилось составить грамматику JSON, и парсер разбирал произвольный JSON-документ. Правда, это было медленней джавного Jackson раз в десять, но за скоростью я не гнался. Почему-то зачесались руки сесть и переписать его на Джаве и собрать парсеры для JSON, INI, Tolm и других форматов.

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

  • Jira

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

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

    Из сегодняшнего: заполняю тикет, прикладываю кусочек кода. Пишу:

    {code:clоjure}
    (dеfn do-some-shit [a b]
      (do-this {:a b}))
    {code}
    

    Сохраняюсь и вижу:

    Unable to find source-code formatter for language: clоjure.
    Available languages are: actionscript, ada, applescript, bash,
    c, c#, c++, cpp, css, relange, go, groovy, haskell, html,
    java, javascript, js, json, lua, none, nyan, objc, perl,
    php, python, r, rainbow, ruby, scala, sh, swift, visualbasic,
    xml, yaml(dеfn do-some-shit [a b]
      (do-this {:a b}))
    

    Иными словами: сообщение о том, что подсветка Clоjure не поддерживается, внедрилось прямо в код! Причем даже без переноса строки: код следует сразу за ...yaml.

    Сначала я проклял всеми словами фронтендеров, но посмотрел в Network и убедился: это серверный рендер. Клиент посылает фрагмент, а сервер возвращает HTML. Поскольку это не JSON, некуда положить нотис о том, что язык не поддерживается, и ребята такие — давайте просто засунем его в код.

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

  • Сишные строки

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

    Беда в том, что, читая эту строку, никогда не знаешь, где конец. Сколько байтов резервировать — 32 или килобайт? Немало ошибок в сишных программах связано с тем, что неверно определяется конец строки.

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

    u s e r n a m e 0 d a t a b a s e 0
    

    А в расширениях, которые появились позже, строки передаются нормально: сначала длина в int32, потом байты без нуля:

    0 0 0 5 h e l l o
    

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

    Чтение строки известной длины — это две строчки кода. Чтение неизвестной строки — это цикл, выделения буферов, конкатенация и прочий бред.

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

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

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

  • Бусти и почта

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

    Дело было так: захожу через Гугло-учетку, все нормально, пришло письмо “здравствуй, дорогой Ivan”. А как начал читать, появилась плашка: чел, ivan@grishaev.me — это твой емейл?

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

    Хоть я и не видел кода Бусти, легко понять, почему так происходит. Когда создается учетка, у нее стоит флаг “почта не подтверждена” — нормальное поведение для регистрации по email. Но разработчики не учли, что в случае с Гуглом почта подтверждается автоматом и выносят мозг подтверждением.

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

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

  • Приглашаю на митап

    В следующий четверг (28 ноября) Health Samurai проводят очередной кложурный митап. Я буду рассказывать про свою библиотеку PG2 — это которая клиент к Постгресу. Начало в 19:00, нужна регистрация. Ссылка на страницу организаторов.

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

    • как устроен Postgres Wire Protocol
    • зачем браться за свое решение, когда есть другие, проверенные годами
    • сопоставление типов Postgresql и Java/Clоjure
    • заморочки с парсингом
    • мысли об API и дизайне

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

  • Можешь поправить

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

    Текст ошибки совершенно нечитаем? Можешь поправить. Сервис делает тысячу запросов вместо одного? Можешь поправить. Хрупкие билды? Можешь поправить. Не собирается под твоей операционкой? Можешь поправить. Не работает в Фаерфоксе? Можешь поправить.

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

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

Страница 9 из 95