• 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 и дизайне

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

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

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

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

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

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

  • Пробел в урлах

    Хотя интернету 55 лет, мы до сих пор не починили пробел в урлах.

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

    Смотрю — кто-то поменял название папки в S3. Раньше было Daily_Reports, а теперь Daily Reports (с пробелом). Половина клиентов пишет файлы нормально. Но есть другие клиенты на питоне и баше, которые кодируют урлы дважды. В результате Daily Reports становится новой папкой Daily%20Reports в S3. Один клиент пишет в Daily Reports и ему ок. Второй клиент ищет файлы в Daily%20Reports, не находит и падает.

    Увы, мой быдлокод тоже упал. У меня такая задача: прилетает S3-урл вида

    s3://some.bucket.com/path/to/file.txt
    

    и мне нужно вытащить из него бакет, в данном случае хост. Делаю так:

    (-> s3-url java.net.URI. .getHost)
    

    Но когда в урле оказался пробел, класс URI валится — вай, не по стандарту, не знаю-не могу. Поменял на класс URL — он парсит урлы с пробелами нормально, но теперь ему не нравится схема s3:// — опять не по стандарту. Сделал так: беру урл, меняю схему автозаменой на http://, оборачиваю в URL и достаю хост. Обмазал тестами.

    “Какая шаткая система, если её может разрушить пригоршня ягод!” (с)

  • О переменных среды

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

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

    System.getenv("DB_PASSWORD") =>
    RuntimeException "env variable DB_PASSWORD is not set"
    

    Если вместо исключения будет null, то он провалится в дальнейшие вычисления, например, в формирование урла или бакета. Постоянно вижу такое в коде:

    host = "api." + getenv("ENV_PREFIX") + ".acme.com"
    

    Если ENV_PREFIX не задан, то получится api.null.acme.com. Из-за этого HTTP-клиент пойдет на левый хост и кинет непонятное исключение. То же самое с бакетом в S3: Амазон скажет, мол, нет такого бакета, а вы будете рвать волосы.

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

    (dеfn env!
      ([varname]
       (or (System/getenv varname)
           (throw (new RuntimeError ...))))
      ([varname dеfault]
       (or (System/getenv varname)
           dеfault)))
    

    Исключение не кидается, если передан дефолт.

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

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

    Приходилось работать в проекте, который писали одни чудики. Они прочитали The Twelve-Factor App и особенно прониклись пунктом насчет переменных среды. Результат можно описать одним словом: пи…ц. Представьте проект на 600 файлов, где на каждый чих читается переменная среды, да к тому же приводится к нужному типу. На старте ничего не проверяется: запустил код без переменной — узнал об этом в продакшене. Какой-то чел добавил глобальный кэш переменных и целый ворох связанных с ним проблем.

    Чудики вынесли настройки в переменные среды, чтобы быть свободными от конфигурации. Так им сказали в The Twelve-Factor App. А потом написали ENV-файлы на три экрана. Было несколько ENV-файлов, которые загружались в особом порядке, переопределяя значения друг друга. Например, сначала базовый энв, потом энв текущего окружения (тест, прод, стейджинг), потому энв текущей машины. Удачной отладки.

    Из этого вывод: много чего можно прочитать в интернете, но если нет своей головы, оно не поможет. Нужно делать так, чтобы было удобно, а не как написано в The Twelve-Factor App или на Хакер-Ньюз.

  • Лучший язык

    По мотивам обсуждений во внутреннем чатике, вот вам мысль.

    Лучший язык для решения задачи — тот, который знаешь лучше всего. Если это Питон — пиши на Питоне. Если лучше всего знаешь Джаву — пиши на Джаве. Если это JS или PHP, то что ж… пиши на них.

    Когда вам говорят, что C++ лучше подходит для игр, а R для статистики, не нужно вестись на эту удочку. Язык-то задаче подходит, а вы подходите языку?

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

    Простыми словами, если с Питоном вы 10 лет, а на плюсах писали дай бог в универе, то умножение матриц на Питоне будет медленней, но понятней и проще в поддержке.

    Игры, кстати, хорошо пишутся на C-шарпе в том же Юнити. Полно печатных плат, которые выполняют быдлокод на Питоне и JS. Если вы знаете Лисп как бог, то не составит труда написать мини-язык, который собирается в машкоды — так писали серию игр Crash Bandicoot. В случае с Питоном почти все либы написаны на Си, а Питон — это клей, чтобы их вызвать.

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

  • AI и новички

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

    Library suggestions seems to be one of the areas they’re very weak: they hallucinate a lot about namespaces and functions so the suggested code looks feasible but won’t run, and it actually leads to beginners then raising issues against the suggested library that “gpt suggested this code but it doesn’t work as expected”

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

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

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

  • Всюду AI

    Наиболее раздражающий тренд сегодня — это когда каждая программа подсовывает AI. Открываешь гугло-док, а сверху плашка: попробуй Gemini at no cost. Открываешь Feedly — а там AI-анализатор твоих фидов. Открываешь Хром — а там AI-алгоритм для группировки вкладок.

    Все это в выпадашках, выпадашках, выпадашках. Даже если закрыл, покажут через два дня опять.

    Когда-нибудь AI-истерия, конечно, пройдет. Просто иной раз думаешь — почему я опять должен пережидать очередной вирусняк? Ждать, пока программы отпустит от блокчейна, BLM, прайда и прочего? Я ведь не просил, оно само пришло.

Страница 3 из 88