Минутка просвещения

Читать в телеге. Когда-то там были посты не только от меня.

Фингерпринтинг TLS

Давным-давно, когда писал краулеры, было достаточно менять User-agent и IP-адреса, чтобы сайт принимал запрос за браузерный. Но это уже прошлый век.

Сейчас можно получить “отпечаток” уже при установлении TLS-соединения: какой протокол используется, какие алгоритмы шифрования поддерживаются и т.п. — это все задается TLS-библиотекой и ее настройками. Записывается в виде “хэша” JA4. Посмотреть свой можно тут.

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

Ссылка • Комментировать

Переключение контекста — дорогая операция

Причем как для процессора, так и для мясного мозга.

Уже неоднократно упоминал это на канале в рамках других обсуждений (например, про количество мониторов) — ну, очевидно же! Но, увы, реальность полна разочарований :(

Исторически я стараюсь на работе делать одну задачу за раз, и фоново получаются всякие чтения чатов и мелочевка. Если цикл обратной связи большой (например, куча тестов вертится на CI) — можно взять параллельно другую задачку, пока первая простаивает. С агентами можно еще какую-то мелочевку взять третьей, но тут мой лимит кончается. Было пару раз, когда я постоянно переключался между 3-4 задачами, и каждой уделял крошечный квант внимания — во-первых, на выходе получалась шляпа, во-вторых, под вечер голова была как вареная. Стараюсь больше так не делать.

Так вот, при этом я слышу как некоторые коллеги хвастаются, насколько они AI-native и рассказывают о 20-30 агентах, работающих одновременно… Выдают ли они результаты хотя бы в 10 раз лучше? Скорее нет. Может, они стали больше делать? Может, но я уже вторую неделю слышу как высокоприоритетная задача все еще в процессе и почти готова (хотя там для MVP дня на два фокусированной работы) — ее делает рой агентов, и задача инженера, как у Микеланджело, выкинуть ненужное (ага, удачи это сделать с тысячами строк баша и сотней коммитов). Про качество даже упоминать не буду.

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

Ссылка • Комментировать

Доверие к коду

Лекция Кена Томпсона из 1984, после которой популяризовался термин “троян” (хотя он использовался и раньше). Интересен пример, на котором Томпсон его разобрал.

Пусть есть какая-то программа с вредоносным кодом. Получили ее исходники — там все чисто. Где искать проблему? В компиляторе/системе сборки. Получаем их исходники — тоже ничего. Где же проблема? В сборке самого компилятора. Но сборку сборки тоже надо собрать… Но неизбежно в конце будет что-то, чему нужно будет довериться.

Но хотя бы начало цепочки можно сделать очень маленьким, которое можно проверить “вручную”, и постепенно наращивать функциональность до нужной. Сам процесс построения такой цепочки называется bootstrapping (раскруткой).

У меня были смутные знания, что чем-то подобным занимается Debian, но нет, у него пока в целях только более слабое свойство — воспроизводимые сборки. А ближе всего именно к реализации изначальной идеи — экзотический менеджер пакетов Guix, у которого начало цепочки — hex0 (357 байт).

Однако, we need to go deeper — а стоит ли доверять операционной системе, где происходит сборка? А железу и его драйверам?…

Ссылка • Комментировать

"Я не знаю язык X"

Два раза за прошедшую неделю услышал подобное заявление в качестве оправдания от разных коллег и что-то пригорело.

И я допускаю, что могут быть обстоятельства, когда подобное высказывание допустимо, но:

  • это не было сократовское “я знаю, что ничего не знаю”, а прям искренний комментарий касательно кода.
  • это сказали не джуны, а два сеньора-помидора с миллионами лет опыта.
  • языки были не какие-нибудь Haskell или Lean, а мейнстримовые Си-подобные.
  • один написал код нейронкой, другой ревьюил нейронкой — господи, ну так попросите ее же вам объяснить если чего не поняли, у вас обоих доступ к Fable есть.
  • если в коде лапша if-ов вместо паттерн-матчинга или switch, или массив сортируется только ради того, чтобы взять первый элемент как максимальный — это, очевидно, не в языке проблема.
  • в конце концов, можно посмотреть на код вокруг и вычленить основные паттерны.

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

Я еще в школе перепрыгнул с Basic на Pascal (какой я старый), а потом на Си, а в универе вообще стало практически без разницы, на чем писать. Были и остались предпочтения (на чем писать “приятнее”), но если надо, то можно написать на чем угодно. Язык — это все-таки инструмент для решения задачи. В мейнстримовых Си-подобных языках настолько все похоже, что “я не знаю язык X” звучит как “я умею пользоваться только крестиковой отверткой, а плоской — не знаю как”.

Ссылка • Комментировать

ИИ-перевод

Попробовал перевести статью про техдолг клодом, в основном ради любопытства, насколько хорошо это делают нейронки. Сохранится ли стиль? Будут ли добавлены load-bearing словечки и прочие LLM-измы? Сможет ли нейронка использовать оригинальные термины (потому что я их перевел с английского изначально)?

Я запустил 2 сессии параллельно: в первой промпт был буквально “Translate this for an international audience”, во второй это был уже абзац с несколькими подсказками, на что стоит обратить внимание. Обе сессии были с Opus 5 High.

Первый перевод был в целом норм с точки зрения сохранения смысла, но выбор слов был местами довольно странный (например, “logical” вместо “makes sense” или “take seriously” вместо “take into consideration”), и порядок слов иногда тоже был непривычным. Разумеется, картинки остались без перевода, и было предоставлено ровно ноль контекста для локальных мемов. Цинизм и мат были смягчены. Больше всего досталось определению техдолга — оно стало более многословным и менее точным. Стиль оригинала местами сохранился, но в основном был потерян, а перевод воспринимался как машинный. Короче, мне не понравилось.

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

Далее, я сбросил сессиям варианты друг друга и спросил что они думают (“меняемся листочками”). Первый чат ответил прямо: бери второй, с минорными правками. А второй похвалил первый за “better English rhythm”, посетовал на отсутствие перевода картинок и сносок и нашел нестыковки. Наконец, я попросил “лУчШуЮ” модель Fable 5.1 Max выдать лучший результат, даже немного помог ей, и все равно на выходе получилось не то, как будто ИИ-рулетку в третий раз покрутил.

В общем, для передачи смысла сойдет, а так средне. Сейчас модно говорить, что “ИИ заменит Х-чиков” — штош, если вы хотите качественный перевод, то ИИ еще не способен заменить переводчиков.

UPD: попробовал по совету экспертов — чистый контекст, второй промпт + нэтив спикер + косяки которые нашлись в переводах:

  1. Определение техдолга — все еще говно, и совпадает с определением из “грязного” контекста буква в букву.
  2. Опять рулетка с выбором слов/синонимов/порядка/временами/числами и т.п. Но, справедливости ради, реже спотыкаешься об такое.
  3. Перевод картинок хуже: например, “Можно, а зачем” в этом варианте переведен как “You could. But why?”, а Opus из второго варианта перевел как “Sure, but why?”, и в “грязном” контексте то же самое.
  4. У Opus “костыль” остался костылем с контекстом про слэнг, а у чистого Fable — тупо “hack”.
  5. Да в и целом опус интереснее/лучше объяснил мемы (чемодан, “если бы мы знали”, ТЗ и т.п.)

Короче, я не увидел качественного улучшения по сравнению с Opus — все равно надо доделывать.

Ссылка • Комментировать

Хорошая спецификация — долго, дорого и не всегда возможно

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

Еще одна проблема заключается в том, что строго следовать спецификации тупо невыгодно. Это разобрано на примере PDF читалок: лучше как-то криво отобразить сломанный документ, чем сказать “ой, не по спецификации” и ничего не делать (закон Постела).

В общем, хотя формальная верификация и стала более доступной, она все еще слабо применима на практике.

Ссылка • Комментировать

Игры OverTheWire

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

Минимальную базу по Linux можно получить, пройдя Bandit. Даже с учетом того, что я все там знаю, все равно было занятно.

Азы по web-безопасности покроет Natas, а по шифрованию — Krypton. Остальные — про реверс-инженеринг.

Ссылка • Комментировать

Культуры зависимостей

Неплохой доклад с тезисом, что различные подходы к управлению зависимостями в индустрии — это культурный вопрос, а не технический. Начинается, разумеется, с веба, а другим примером служат игры. Жирные зависимости — плохо (потому что большая часть вам не нужна), мелкие — тоже (left-pad). Не забыт и вопрос обновления — и часто плохо, и редко плохо (но это решаемо). Короче, перед добавлением зависимости надо думать, шансы прикидывать.

Ссылка • Комментировать

Сравнение Proguard и R8

ProGuard — это обфускатор и минификатор для java, а R8 — тоже минификатор для java и де-факто стандарт для Android. У последнего сложилась репутация как более мощной замены для ProGuard, некоторые не-Android проекты даже рассматривают замену ProGuard на R8 (например, Kotlin), благо формат настроек у них почти совпадает. У меня раньше в голове был образ, что R8 — это то же самое, что и ProGuard, только новее и лучше. Реальность полна разочарований, как говорится:)

Я буду рассматривать только вопрос минификации (обфусцировать java — очень странная идея), и стоит обговориться, что область ее применения очень ограничена — на серверах места полно, а на пользовательские системы java сейчас редко доставляют (Gradle тут скорее исключение).

Вот что я обнаружил, когда попробовал заменить кастомную минификацию в Gradle сначала на R8, а потом на ProGuard:

  1. Вывод R8 зависит от версии JVM, а ProGuard для работы нужна JVM с jmods, которые могут быть не включены в JDK.
  2. R8 не позволяет ничего настроить относительно ресурсов и, как следствие, мультирелизных jar, манифестов, неактуальных контрольных сумм и т.п.
  3. R8 нельзя заставить удалить класс или метод, если на него есть ссылки (даже если знаете, что это логически мертвый код).
  4. R8 переписывает метаданные Kotlin и ломается, если ваш Kotlin новее.
  5. R8 переписывает методы, и, с одной стороны, код получается меньше, но может из-за этого сломаться на новейших JVM/Kotlin с чем-то вроде java.lang.VerifyError: Bad invokespecial instruction: interface method reference is in an indirect superinterface.

При этом R8:

  1. Сжимает лучше, потому что работает на уровне методов, а ProGuard — на уровне классов. Т.е. ProGuard может оставить класс с 1 живым методом и сотней неиспользуемых.
  2. Требует меньше настроек “корневых” классов.
  3. Не такой строгий — если не видны какие-нибудь родительские классы, то предполагает, что они есть.
  4. Поддерживает Kotlin.
  5. Не имеет зависимостей — это один jar.

Мой сценарий довольно особенный и ProGuard оказался лучше, но для Android описанные минусы R8 слабо релевантны, так что для него он будет лучше.

Ссылка • Комментировать

ИИ-переписывание Bun

Многие наверняка слышали историю про то, что bun переписали с Zig на Rust с помощью тучи ИИ-агентов: впечатляющие графики, “новый уровень ИИ-инженеринга”, blazing fast™, убедительные результаты и т.п. Спонсирует все это Антропик, который купил bun в декабре. Эксперимент успешный, переписанный bun уже внутри Claude Code, аж с июня. А еще автор Bun на досуге запромптил Claude, чтобы сделать прорыв по гипотезе Римана. Короче, гений, миллионер, еще и плейбой наверняка.

Мало кто видел ответ создателя Zig на эту статью: “вы не разобрались”, проблема не в Zig и не в языках, потому что вопросики к автору bun были и до этой эпопеи.

А тем временем с момента статьи прошло больше месяца. Автор в режиме “ща, ща” все никак не зарелизит лучшую версию 1.4.0. На гитхабе при этом почти 5 тысяч открытых PR, большинство от агентов.

Выводы делайте сами, как говорится.

UPD: таки зарелизили.

Ссылка • Комментировать