Выпуск 68 · подкаст «Тысяча фичей»

#68: Исследуем границы современных моделей вместе Владимиром Ситниковым

2:19:23
↓ скачать mp3

Александр Пахомов и Владимир Ситников — мейнтейнер PostgreSQL JDBC-драйвера (pgjdbc) и Apache JMeter, около двадцати лет в Java и производительности SQL-систем — разбирают агентскую разработку на конкретных артефактах: тридцать тысяч строк подсистемы кодеков, которые невозможно отревьюить глазами, кросс-ревью тремя моделями, скилл технического английского, появившийся после того, как правки в документацию отклонили как AI-слоп. Обсуждают, что идёт в скилл, а что в CLAUDE.md, APM как пакетный менеджер для агентских конфигов, орду ревьюеров-персон, профилировщик и фаззинг как обязательные гейты агентского SDLC, комментарии, которые описывают прошлое, и декомпиляцию вместо чтения исходников. В финале — где проходят границы моделей и человека и на что инженеру сейчас тратить время.

Главное

  • Тридцать тысяч строк кодеков, сгенерированных агентом, человек физически не может отревьюить — выход в том, чтобы ревьюить тем же инструментом: три независимых ревью (Opus, GPT, Fable) плюс кросс-сравнение вердиктов, где каждая модель находит что-то своё.
  • Промпт «сделай ревью» бесполезен, пока не выбран фокус: построчное ревью, архитектурное или план дальнейших действий — сужение фокуса дало заметно лучший результат на всех моделях.
  • Скилл технического английского (компиляция публичных style guides) появился после того, как правки в документацию pgjdbc отклонили как AI-слоп; теперь он стоит глобально и, в частности, формирует описание PR — «почему это делается».
  • Оба сидят на минималистичных сетапах: развесистые чужие скиллы дают контекст-полюшен. Писать стоит только то, на чём модель уже спотыкалась, — к тому же выводу приходит и разбор CLAUDE.md у Тео Брауна.
  • APM (Microsoft Agent Package Manager) — фактически npm для агентских конфигов: версионируемые пакеты скиллов, хуков и промптов, переносимые между Claude Code и Codex; корпоративные конвенции ставятся одной зависимостью.
  • Профилировщик и фаззинг должны стать частью агентского SDLC наравне с юнит- и интеграционными тестами: без жёстких верификаторов агент не понимает, где важна производительность, а где — краевые случаи.
  • Coverage-guided фаззинг (JQF + JetCheck) нашёл в кодеках реальные баги — например, `+Infinity`, подобранный эволюционно, а не «придуманный» моделью. При этом сам код фаззера модель пишет плохо: в обучающих выборках фаззеров почти нет.
  • Модель не умеет оценивать сложность и экспертность: для неё `A + B` и дерево Фенвика примерно одно и то же — поэтому она не понимает, что комментировать, а что нет, и пишет комментарии про то, почему не работал старый код.

В выпуске

  • Владимир СитниковОколо двадцати лет в Java и производительности SQL-систем. Мейнтейнер PostgreSQL JDBC-драйвера (pgjdbc) и Apache JMeter; участник программных комитетов конференций JUG Ru Group (Joker, JPoint, Heisenbug, SmartData, DevOops), помогает спикерам готовить доклады. GitHub ↗
Расшифровка

[00:00] Александр: В гостях Володя Ситников. Володя, привет, расскажи про себя, чем ты занимаешься.

[00:04] Владимир: Да, привет, Саша, спасибо за приглашение. Я занимаюсь в основном программированием, поддержкой Java и SQL-систем — где-то около двадцати лет этим занимаюсь. Очень люблю производительность в её прямом смысле: ну то есть потюнить что-то, соптимизировать или, например, поисследовать, а почему же оно упало, сломалось, выдало out of memory, закрашилось и так далее. То есть начиная с Java и заканчивая каким-нибудь отладчиком: почему у меня Java-машина упала здесь? Забавная ситуация: я, когда второй-третий раз поймал какой-то крэш, пошёл на Medium статью написал — чтобы в следующий раз, когда сам такой же крэш найду, по статье просто точно так же сделать. И потом начал лайки собирать: народ тоже так же приходил, говорит — а у меня точно такая же проблема. Смешная ситуация. По своим находкам я поддерживаю команды pgjdbc — это, собственно, библиотечка, с помощью которой очень многие Java-программы общаются с Postgres. И поддерживаю Apache JMeter, нагрузочный тул. Участвую в программных комитетах конференций Joker, JPoint, Heisenbug, SmartData, DevOops — это конференции, которые организует JUG Ru Group. Я там по большей части в программной части: помогаю спикерам готовиться. Мне это нравится, я сам выступал и люблю другим помогать с подготовкой. Тут по-разному бывает: у кого-то доклады доходят, у кого-то нет, кто-то становится серийным докладчиком или спикером. Но в целом мне нравится продвигать знания в массы, и получается так, что когда ты сам что-то рассказываешь — ты можешь это рассказать, но ты делаешь рассказ вглубь.

[02:29] Александр: То, как я работаю, кстати, можно будет поразгонять — про большие проекты, где много репозиториев: там двадцать репозиториев классических, есть фронтенд, какой-нибудь пеймент-сервис, бэкенд, который ещё ходит в пять других. И вот работать с этим всем вместе я начал из так называемого Project Hub: я создаю отдельный проект на GitHub, линкую туда все эти репозитории, создаю общий контекст, общий CLAUDE.md, общие правила, команду туда с именами, может быть, даже расшифровки созвонов, если есть настроение, — и фигачу там с Клодом. И вот у меня есть под это темплейт на GitHub, ссылочка будет потом, для тех, кому интересно. И вот буквально вчера Fable опять вернули обратно — мы тут в кулуарах уже про него начали говорить, — и я сразу же Fable туда залетаю, в этот проект, говорю: давай смотри, ты всё знаешь, скажи, что можно улучшить, просто посмотри на него. Ну реально, там какой-то максимально тупой промпт был, но смысл такой. И он прошёлся, посмотрел, вывел мне, наверное, штучек шесть вещей, пару багов: он там shell-скрипт на macOS на голом environment у меня завёл, сказал — вот если у тебя не установлено вот это, то будет ошибка, давай мы это поправим. Тесты написал на shell-скрипт. И потом говорит: а чего у тебя ничего в скиллы не обёрнуто? Срочно в скиллы. Всё обернул в скиллы — короче, сделал такой нормальный pull request, я его принял, сегодня буду тестировать. Но что забавно: Opus считал, что всё круто. Точно такой же промпт я ему давал, специально тестировал, — и он такой: о класс, всё замечательно, замечательно.

[03:56] Владимир: Ну ты знаешь, вот это «что лучше, что хуже» — это же дело такое субъективное. Лучше для кого? Для модели, которой ты задал вопрос, — однозначно.

[04:06] Александр: Насчёт баги, которая действительно бага была…

[04:10] Владимир: Не, ну баг — баг, конечно, да. Я пытался, когда подобные штуки делать, сравнивать: ну типа, давай ревью кода сделаем, или архитектурное ревью, или ещё что-то. Я сначала сделал втупую — ну, как втупую, довольно подробно всё-таки написал: вот хочу проревьюить большой шматок кода, написал, накладывал, все дела. И получил какое-то ревью: что-то меня порадовало, что-то нет. Я потом пошёл и говорю: а вот смотри, я хотел ревью сделать, вот такой промпт писал — что ты скажешь вообще? Может, надо ещё что-то доспросить и получше сделать? Он говорит: ты знаешь, дорогой, ты, когда промпт указывал, всё-таки не сказал, что тебе надо. Тебе надо построчное код-ревью, или тебе нужно архитектурное ревью, или тебе нужна масштабируемость и pluggability? Это была подсистема кодеков в PostgreSQL-драйвере — то есть там сейчас вообще никакой подсистемы нет, я как бы написал и хотел её поревьюить. И, соответственно, GPT говорит: ты всё-таки определи, что тебе надо. Ну, я так и определился: наверное, всё-таки архитектуру надо. То есть смотреть код — там сорок тысяч строк кода, бесполезно будет на каждую ругаться. Она говорит: ну тогда надо по-другому. И бахнула совершенно другой — ну, не совершенно другой, но она реструктурировала, спросила. И потом уже, резюмируя, её вариант промпта я загнал в разные модельки — и там прямо намного лучше стало.

[05:33] Александр: Мне вот интересно, а что конкретно ты там написал в этом промпте? То есть чем он поменялся?

[05:39] Владимир: Сузился по фокусу. Потому что у меня действительно, если почитать исходный, — у меня и сами мысли так немножко скакали. Условно: я наколдовал тридцать тысяч строк кода…

[05:51] Александр: Нормально, уважаемо.

[05:52] Владимир: Код с тестами, ну, сколько-то. И там, разумеется, была куча дубликатов, где-то какие-то баги. Но исходная задача такая: вот PostgreSQL-драйвер, у него много методов — то есть ты можешь из JDBC читать getInt, getString, getTimestamp, getObject классом и так далее. Исторически вся эта штука была написана двадцать лет назад, и там, разумеется, в каждом getInt ифы: типа, если из базы пришло число типа int, а пользователь попросил int — мы его вот так декодируем; если из базы пришёл short — мы декодируем в string. Короче, вот это просто тупо ифами было написано, и в одну, и в другую сторону — то есть и set, и get. У меня цель была, во-первых, сделать кодеки, чтобы изолировать в одном месте: вот это работа с int, это со строкой. А во-вторых, чтобы поддержать всякие массивы, структуры, которые до этого в принципе не были поддержаны, — и чтобы для массивов и структур эти локальные getInt не были везде захардкожены. И код, разумеется, где-то не очень, где-то очень — но вот он на эти тридцать тысяч это сделал. Соответственно, ревью такой штуки — понятно, что человеку такое ревьюить невозможно. Ну то есть можно пытаться открыть и там каждый кодек вдумчиво ревьюить, но их… реально тяжело. И мне хотелось понять, в ту ли я степь иду, что нужно архитектурно поправить, где-то там дублирование, не дублирование, чтобы нормально это в целом получилось. И понять, куда дальше двигаться.

[07:26] Александр: Ага, вот это очень интересный момент. Я бы сейчас подсветил, знаешь, реальность, в которой мы сейчас находимся как программисты, как инженеры, — мне кажется, это важно. Мы сейчас достигли такого уровня пользования нейросетями и такого уровня самих нейросетей, их уровня написания кода, что в целом мы способны написать работающий, решающий задачу код — вот эти тридцать тысяч плюс строчек кода — в серьёзный продукт, которым пользуется куча людей, такой как JDBC-драйвер. В целом мы способны это сделать, это можно. Но мы не способны его уместить в голову. Ты сказал: отревьюить его человеку невозможно — и это факт. То есть мы создаём чего-то так много, довольно крутого, нормального — ну, там можно что-то править, но такого классного. Но мы не можем сами сказать, погрузившись туда: а это реально классно, или там всё-таки есть что-то, что надо улучшать, или это вообще не то? Где-то там есть какая-то мелочь, сто строчек кода, которая вообще всю концепцию меняет. Мы как люди не способны — то есть мы упёрлись в наш кожаный мозг. Это очень интересно. И как же теперь решать эту задачу? Вот типа, ты нагенерировал — у меня абсолютно так же. Что делать? Мы используем тот же инструмент, но уже для решения другой задачи: мы говорим инструменту — а давай мы теперь с тобой поревьюим. И вот это круто: то есть ты ревьюишь вместе с Клодом или с GPT-шкой. Это круто. Я просто подсветил этот момент, потому что это важно.

[08:53] Владимир: Да-да-да. Я часто кросс-ревью делаю, но даже в рамках одного инструмента всё равно история, что «давай порецензирую, посмотрю, что у меня с этим кодом». Получилось, что исходный мой вопрос был в духе: я то ли код хочу ревьюить, то ли хочу архитектуру, то ли хочу построить план дальнейших действий. Это немножко разные истории. И, соответственно, мне в данном случае GPT-шка помогла сфокусироваться и понять, что мне всё-таки хочется в первую очередь, чтобы модель не отвлекалась, когда ревью делает. И потом я эту штуку на ревью прогнал через три модели: тогда были Opus, GPT и Fable — он тогда ещё был доступен. Получилось три ревью, они большие. Вопрос: кто из них прав, кто виноват? Но я потом сделал на самом деле кросс-сравнение — то есть отдельный проход, который бы посмотрел, на что обращал внимание каждый, где они накосячили, где нет. То есть кто-то мог подсветить какую-то багу, а по факту баги нет. Или кто-то какую-то багу нашёл, и она правильная. Получилась серия таких кросс-ревью. Ну и в конце концов я их ещё раз сравнил через GPT. В итоге они все сошлись, что ревью от Fable наиболее точное и правильное — хотя каждая из трёх моделей что-то своё уникальное нашла. Забавная ситуация в том, что вот это сравнение, кто был прав, кто нет… Мне, с одной стороны, было банально интересно: есть ли что-то прямо суперкосмическое у Fable на этой задаче — ну типа, кода много, может быть, что-то бы нашла. По ощущениям — нет. Читается действительно лучше, по отзывам моделей действительно лучше, качественнее — но не выглядит, что космос-космос. То есть, похоже, не та задача, что ли, не знаю, ну или просто так. А по факту, конечно, ревьюшка полезная, потому что я потом пошёл все их три и тоже полномерно реализовал. [10:56] Владимир: Эту историю я на гитхабе выложил.

[10:59] Александр: Непонятно, куда сейчас эти промпты… может быть, отдельно обсудим. Коммитишь ли ты планы, промпты, ресёрчи в проекты — или ты где-то отдельно их держишь, удаляешь потом?

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

[11:41] Александр: Да, то есть смотри: я понял. Ты, когда сказал «это ревью уже не актуально», имел в виду не только саму выжимку и информационную ценность ревью и то, что ты сделал, а в целом — во-первых, сам твой промпт для каждой модели, которой ты давал, подход, методологию вообще этой работы; MD-файлы, которые наверняка остались в результате этого; как ты потом из этих MD-файлов получил ещё один MD-файл, дал на вход модели, которая пошла фиксить всё; как ты потом это всё валидировал. То есть у нас появляются такие промежуточные артефакты процесса взаимодействия с нейросетью. И эти артефакты — большинство из них, по ощущениям, действительно актуальны только в моменте работы: то есть ты по ходу просто снапшоты делаешь мыслей, заметок — и выкидываешь потом. Но какие-то действительно могут иметь огромную ценность — и в качестве обучения, и в качестве того, а как другие делают, вот этого кросс-опыления у нас как у программистов. И мне кажется, было бы круто как-то собрать всё это вместе где-то и куда-то выложить. И в целом, например, подход с твоим кросс-ревью я бы себе затащил в Project Hub как скилл. Ну реально, просто скилл: типа, сделай кросс-ревью — погнали.

[13:00] Владимир: Ну, такой скилл-то есть уже, и он даже опубликован — и не только мой: OpenAI сделали такой же скилл, плагин к Claude Code. Идея в том, что Codex можно запускать как инструмент командной строки: codex -p, промпт — и всё. Соответственно, скилл, который говорит: спроси у пользователя, что он хочет ревьюить — коммит, ветку или ещё что-то; запусти Codex с промптом на ревью, чтобы он что-нибудь нашёл; Клоду скажи, что чинить; Клод либо сам починил не глядя, либо у пользователя спросил и запустил вторую итерацию ревью. Такой скилл я написал, когда ещё не было этого официального плагина от OpenAI. Он тоже выложен на GitHub, может, ссылочку тоже приложим. Прямо берёшь, ставишь — не мудрёная, не большая штука, но за счёт другой модели оно немножко другие баги иногда находит. Тут я не усердствую, не говорю «всесторонне следуя архитектуре, security» — то есть если вот это всё надо, я просто отдельно указываю: я чувствую, что здесь безопасностью пахнет, давай перепроверим лишний раз, есть тут security-уязвимости или нет. Ну, в смысле, нехорошие security-паттерны в коде. Но в целом такая generic-история меня много раз выручала. Знаешь, смотришь изменения, код — нормально всё, уже можно коммитить. Я думаю: ладно, вроде кушать не просит — давай ревью бахнем. Раз — оказалась там бага. Это прямо забавно.

[14:34] Александр: Да, я тоже себе взял за привычку: любой pull request — как бы я своей головой ни думал, что тут вообще можно просто мержить, — я всегда запущу максимальную модель с максимальным эффортом и скажу: сделай мне самое брутальное ревью. Просто закидываю, потому что кушать не просит: если у тебя подписка, то навряд ли ты почувствуешь эту нагрузку и выжжешь все лимиты. А там через десять-пятнадцать минут пришёл, быстренько глянул взглядом — такой: о, ну реально же про это не подумали. И, возможно, это будет даже не само ревью по факту, а, например, какой-то follow-up, какое-то странное поведение, которое при этом возникает. В общем-то, это такая инженерная гигиена, как я последнее время это называю. Что-то, что мы как инженеры в целом, как мне кажется, делать хорошо бы. Это признак квалификации, понимания вообще, что от тебя требуется и кто ты такой. Но по поводу твоих скиллов — я тут немножко вернусь назад, — и того, что уже есть от OpenAI: это интересная тема на самом деле. Скиллов дофига. По сути, скилл — это просто лежащий маркдаун-файл в правильном месте, чтобы его моделька подтянула. Но идея в том, что, мне кажется, саму концепцию скиллов… Раньше я воспринимал её как батарейку, как библиотеку — как что-то, что ты импортировал себе в Python-файл и теперь можешь вызывать функцию. Но это немного не то. Когда ты так воспринимаешь — действительно, если библиотека уже написана, на вход параметры получает, на выход всё структурировано, ты вызови, зачем тебе свой велосипед строить. Но вот с маркдаун-файлами как будто бы построить свой велосипед со скиллами — более правильная идея, чем переиспользовать чей-то. Потому что твой велосипед будет адаптирован под твой workflow. И он будет учитывать, может быть, даже какие-то тонкости внутри именно маркдаун-файла — то есть это не настолько детерминированная input-output штука, это всё-таки более такая сущность, она внутри что-то содержит. И я каждый раз сам скиллы под каждый проект прямо пишу с нуля. Их там на самом деле с пяток: делаешь ревью, «двигай тикет», деплой — в общем, их не сильно много, но каждый из них я описываю и создаю в процессе работы. То есть я как бы из пластилина каждый раз вылепляю — но зато потом работает круто. Вот не знаю, что ты думаешь насчёт того, использовать ли чьи-то готовые скиллы или делать свои?

[17:03] Владимир: Я здесь, честно говоря, скорее между двух наковален стою. Потому что есть скиллы — например, ревью: казалось бы, всем нужны ревью-скиллы, но всем нужны немножко разные. И есть какие-то истории, где ревью-скилл на кучу страниц описан, и ты смотришь — там всё правильно, всё надо: и обратную совместимость проверить, и API, и best practices, и ошибки, и коды ошибок, и понятность, и переводимость, локализация. Ну и я смотрю: а действительно ли мне всё это надо в каждом проекте? И поэтому я на такие скиллы пока смотрю так: ну вроде прикольно, но я бы такое не стал использовать — хотя можете попробовать. Примерно так я на это смотрю: может быть, и попробовать, но как-то чрезмерно уже. А есть другого типа скиллы, которые актуальны прямо везде. У меня история началась — я даже не знаю, — наверное, знаешь, с английского языка она началась, когда я внезапно подумал, что LLM хорошо пишет документацию. Я такой: ну на русском-то понятно, что она криво пишет. Иногда даже — знаешь, как за ребёнком записываешь какие-то смешные слова, которые ребёнок двух-пяти лет придумывает, фантазирует, — так и тут: LLM-ка иногда русские слова фантазирует, говорит: вот это у вас линчпин в проекте. Какой линчпин? Расстроился, смотрю: кто такой линчпин? А она прямо такая: это у тебя точно линчпин, ведь да? Ну, я думаю: по-английски-то они уж, наверное, нормально обучены, сколько можно. Выборка хорошо работает. Я пошёл, значит, документацию перелопатил, поправил в Postgres-драйвере — ну, чтобы ошибки поправить, структурировать нормально и так далее. Мне-то это нормально выглядело, я английский так читаю нормально. А мейнтейнеры из Канады — Dave посмотрел, говорит: не, это какая-то ерунда. Но здесь я готов поверить, что там может по-английски быть ерунда: не только то, что тире слишком много, но в целом возможны обороты. И получилась такая забавная ситуация: куча изменений, которые вроде бы очевидно улучшают документацию, но принять их невозможно, потому что якобы слоп. Хотя тот ещё вопрос, что хуже: плохая, с ошибками, но рукотворная документация — или слоп, но хотя бы проверенный, правильный. Но здесь у меня какой момент. Сначала я смотрел только на эти тире: что тире какие-то, не тире. Но потом я пошёл и решил: ну смотрите, есть же всякие стайлгайды — как писать документацию, как писать пользовательские интерфейсы, как называть кнопки, пункты меню, сообщения об ошибках. То есть есть куча компаний, которые их публикуют. И вопрос: а почему бы сетке не сказать, что вот мы сейчас будем писать техническую документацию? Я такую штуку проделал: прошёл, проресёрчил — несколько итераций deep research, что сначала посмотри вообще, какие компании признаны в мире, у которых есть стайлгайды, может быть, есть уже готовые скиллы, как писать англоязычные технические тексты. Она нашла, говорит: есть много компаний, ни у кого скиллов нет, но есть много гайдов. Давай, короче, отберём — отобрали лучшие из лучших, скомпилировали. [20:25] Владимир: …и вот набрали такой набор из этих гайдов, правил, как писать тексты. В частности, там история в духе «не пиши длинных предложений, разбивай на короткие».

[20:39] Александр: Из этого, знаешь, мне вспомнилась книжка «Пиши, сокращай» — я читал, мне кажется, что-то подобное. Ильяхов. Если кто не читал — в целом можно и не читать. Ну, прикольно. Ну что, получилось?

[20:51] Владимир: Получилось, да, получился скилл — написание англоязычных текстов. Там забавно, что английский разный: есть британский, есть американский, поэтому на самом деле два скилла. Но получился скилл, который, во-первых, пишет технические истории — вот как правильно писать, например, сообщения об ошибках; или как именовать issues, как именовать PR, что писать в PR и так далее. Вот скилл, который всё это делает. И он у меня по факту сейчас установлен глобально — во всех проектах, что бы я ни делал: он установлен в домашнюю папку. И когда я говорю Клоду «создавай PR», он создаёт PR согласно этому скиллу. То есть он банально пишет, почему требовалось изменение, что конкретно сделано — но не конкретно, а что примерно сделано, на высоком уровне, — ну и потом какие-то детали: как тестировать, как проверять и так далее. Бесподобные истории: клодовские и кодексовские PR выглядят так себе, я бы сказал, с точки зрения описания. И если для твоего личного проекта это, может, и не так важно — ты и так знаешь, что делаешь, — то когда ты какие-то сторонние проекты заводишь, вполне нормально, когда выглядит по-человечески. И вот такого типа скиллы: как писать английский текст, как писать маркдауны. Потому что у тебя там есть выбор: ты можешь их писать одной строкой до конца и не переводить, а можешь врапить. И смешно, что зависит от того, куда ты этот маркдаун пишешь: если ты его пишешь в файл и коммитишь в git, то лучше врапить — иначе дифы смотреть невозможно, у тебя там километровая строка, одно слово поправилось, и у тебя вся строка в дифе. А если ты пишешь тот же самый маркдаун, но в качестве комментария на гитхабе, то врапить не надо, потому что на гитхабе будет уродски выглядеть: на гитхаб надо писать одной строкой, а гитхаб сам поврапит.

[22:46] Александр: Я понимаю. Но знаешь, у меня на этот счёт есть немного такое мнение, которое я давно сформировал, — мне кажется, это норм. Я понимаю, что подобные приколы, наверное, могут быть у каких-нибудь моделей, GPT а-ля 5.3 — ну, так, с головы беру, — что она тебе маркдаун зафигачила в одну строку, и pull request прислала, и потом дифы странные. Просто у меня с Opus и с Fable тем более никогда такого не было, чтобы какая-то такая фигня была. Ну, в комментариях и в описании pull request — согласен, такое себе выглядит, что от одного, что от другого. Но мысль-то в чём? Вот этот скилл — он же, скорее всего, потеряет актуальность через полгода-год. То есть он просто не нужен будет, потому что все модели по дефолту будут нормально всё делать. У меня вот такое ожидание — типа good enough. Потому что их уже, я думаю, обучают на специфических кейсах: судя по тому, как они вообще задачи решают и оформляют, их подкручивают под это и как бы встраивают вот эти скиллы, которые мы сейчас костылим, уже непосредственно в саму модель. И тогда я думаю: а стоит ли моего внимания и затраченной энергии вот эта организация, всё это продумывание сейчас, на текущем моменте, если это со следующим поколением моделей или даже быстрее потеряет актуальность? Я себе постоянно такой вопрос задаю — просто вербализирую мыслительный процесс. И я чаще всего отвечаю: да ну, нормально. Ну да, pull request выглядит нерасслопно — ну мне всё равно, я прочитать могу. И в этом плане ещё один момент: должны ли мы адаптировать модели под себя или адаптироваться под модели? Вот это интересный вопрос. Я вижу, как пишет код модель, — я знаю, что я бы написал код по-другому. В стилистике даже: я бы не писал так много комментариев, во-первых. Я бы, возможно, чуть больше тестов писал — даже чуть больше, чем нужно, потому что я в TDD всегда разрабатывал. Я бы там что-то ещё… Но потом думаю: не, ну а что решает? Код без багов — а что тебе ещё надо? То, что тебе читать чуть-чуть сложнее, чем свой код или чей-то другой человеческий, — ну, наверное, это твоя проблема, а не модели. И будь добр, адаптируйся, братишка. Я вот себе так говорю — и поэтому у меня как-то быстро, легко получается всё это принимать. Мне интересно, как ты на этот счёт думаешь: то есть чья это задача — модели под нас подкручивать или самим всё-таки поменять майндсет и научиться читать нейрослоп и не испытывать кринж?

[25:22] Владимир: Смотри, тут два вопроса в одном. Во-первых, ты говоришь: стоит ли тратить время на адаптацию, на написание третьих скиллов для того, чтобы модель, типа, всё правильно делала. И я здесь скажу, что время ты не тратишь — потому что вот эти скиллы я поставил себе один раз глобально в пользовательскую директорию, и всё. Я никогда их вручную никуда не ставлю, они просто всегда есть. И я знаю, что текущие модели — и Opus, и GPT — здесь хромают, поэтому эти скиллы… ну, английский там подольше, конечно, маркдаун совсем мелкий, они уж кушать не просят. Но с другой стороны, когда я сказал, что чуть-чуть большие чужие скиллы не особо использую и практикую, — это как раз и сдвигает меня скорее в ту вторую сторону, которую ты назвал: пользуемся чем есть и пытаемся научиться работать с моделью, как она есть, без каких-то дополнительных правок. То есть я не пытаюсь модель тренировать, что «ты, пожалуйста, пиши код без конструкторов, только на фабриках» или ещё как-то. То есть вот такого типа скиллы — «тесты пиши, их там больше, меньше», — здесь как раз скорее, как ты говоришь: что есть, так и адаптируемся. Из локальных проектных историй я скорее пишу про то, как правильно пользоваться местными API. Например: у меня nullability-аннотации. Вот есть какой-то код на Java, и там в проекте nullability-аннотации — и они не для красоты стоят, а они проверяются, и код не компилируется, падает, если nullability-аннотации стоят неправильно. И здесь, с одной стороны, тема несколько популярная, но не суперпопулярная — то есть модель понимает, но она вообще не понимает, как правильно этим пользоваться. И ей прямо надо на текущем уровне развития говорить: вот сюда пиши, туда пиши, вот такие best practices. Ну, примерно как сеньор-разработчик, который в принципе понимает, что такое nullability, но что nullability не надо ставить у локальных переменных или что, например, @NotNull — это зашквар, человек может не всегда понимать. А как раз вот такого типа скилл я пишу. Ну или, например, у меня определённым образом тесты надо писать, чтобы покрывать не один кейс, а сразу параметризованно кучу, — и это я тоже пишу в скилле: смотри, вот у меня есть такой-то фреймворк. Кстати, тоже вопрос: как ты отличаешь — ты вообще отличаешь ли скиллы от CLAUDE.md?

[27:58] Александр: Да, это хороший вопрос. У меня CLAUDE.md последнее время… В общем, я про это думаю так — вроде так это и работает, — что CLAUDE.md идёт на вход каждому запросу, отправляемому в Anthropic условно: он там всегда есть. И вот исходя из этого знания я такой: а что я хочу, чтобы было всегда? Вот я так себе вопрос ставлю — и тогда уже туда информацию кладу. Всё, что можно оттуда выгрузить — выгрузить в линтеры, в статические проверки, в пост-ревью… Вот у меня есть скилл типа self-review: он саб-агента запускает, и у него на вход есть checkstyle, style guide, ну, как угодно — типа, на что обращать внимание. Если я думаю «ничего страшного, если это потом асинхронно догонится, но я лучше сэкономлю место в CLAUDE.md» — то я туда отгружу: одним циклом условной итерации готов пожертвовать. Если можно автоматизировать — условно хоть как-то, хоть каким-то скриптом, — то в ста процентах случаев тоже туда: и pre-commit hook’ом, и post-tool use, куда угодно засунь, чтобы просто себя валидировать самому. Вопрос только — локально или на CI. Ну, наверное, всё, что можно локально, — локально, всё, что можно на CI, — и на CI. Вот так я мыслю, и всё, что остаётся, остаётся в CLAUDE.md. Можно даже посмотреть — у меня сейчас последний проектик тут недалеко, что он там написал в CLAUDE.md. Потому что интересная история: по ощущениям, в последнее время я всё реже смотрю в CLAUDE.md.

[29:23] Владимир: Ну так и есть, да: ты там мало пишешь и мало оставляешь. Я так же себе это понимаю. Просто иногда бывает, что люди словом «скилл» называют любую инструкцию в том или ином виде, которая пойдёт в LLM, — поэтому я тут уточнил. Но смотри, есть, например, штука типа «как запустить сервис в докере для локального тестирования». Моделька может иногда сама найти это грепом по файлам, но иногда она такая: ну, наверное, нету такого скрипта, пойду сам выполню. И вот такого типа инструкции всё равно приходится писать явно. [30:00] Владимир: …которые то ли сработают, то ли не сработают. Как поднять тестовую базу? Ну, пойду в интернет, подниму в докере — и всё, база. О, ещё скрипты надо накатить — а вот, кстати, скрипты тоже накачу. Ну то есть зачем ей всё переизобретать, если можно ей один раз сказать: смотри, у нас уже есть готовый compose-файл или готовый Helm-чарт для проекта. И здесь получается как раз, что такие штуки — какая бы умная модель ни была — всё равно нужно описывать.

[30:28] Александр: Сто процентов. Я, знаешь, в последнее время больше про другое: а кто должен это описывать? Вот давай так — не мы же руками должны описывать CLAUDE.md. То есть эти маркдаун-файлы модель готовит сама под себя, а мы можем это провалидировать: что там нет чего-то, что уж точно не надо, и что она как-то не так нас поняла. Но в целом оно само. У меня чаще всего так. Я вот сейчас зашёл в свой проект посмотреть в CLAUDE.md — и понял, что с моей точки зрения там написана полная фигня. У меня в CLAUDE.md написано: «если тебя спросили setup project — то есть это первый промпт, setup new project from template — то следуй этим инструкциям». И я подумал: как это глупо — иметь это в CLAUDE.md, потому что ты один раз это сделал, а оно потом каждый раз. А потом я подумал: а вдруг она настолько умно сделала, что в setup-инструкциях есть удаление этой строчки из CLAUDE.md потом? И я уже такой: надо будет перепроверить. То есть это же прикольно было бы — оставить это на первый setup, а потом переписать. Интересно, я сейчас посмотрю, кстати.

[31:33] Владимир: Насчёт переиспользования этих скиллов — знаешь, если ещё на шаг назад вернуться: ты говорил, это похоже на библиотечку, давайте использовать библиотечку. Я последнее время плотно подсел на APM, Microsoft APM — не знаю, слышал, не слышал: Agent Package Manager. Это по факту а-ля npm для агентских конфигов: то есть это скиллы, хуки, промпты, вот эти AGENTS.md — всё это. Довольно забавная история: та же самая механика — ты в YAML описываешь ссылкой на версии тех самых компонент, которые тебе нужны, то есть берёшь и подгружаешь себе: мне, пожалуйста, здесь нужен пакетик для работы с Java-кодом, с Go-кодом и прочим. Но по сути это ничем внутри не ограничено — внутри обычные скиллы лежат, и всё как обычно пишется. Но закрывается задача импортирования этих скиллов для разных харнесов. Потому что ты-то, может, в Claude Code сидишь, а кто-то, может, в Codex — или одновременно и так, и так. И тебе по-хорошему скиллы, даже если ты делаешь ревью или ещё что-то, нужны и для того, и для другого харнеса; они немножко в разных папочках сидят, и их нужно как-то так поддерживать. Соответственно, меня здесь радует, что он закрывает эту задачу: а как мне в моём проекте быстренько поднастроить, чтобы было как надо. Например, у нас есть какие-то конвенции, которые конкретно в нашей компании выстраданы: что логирование в Go должно вот так выглядеть, трассировка должна идти через такую библиотеку, к базе подключаемся через такую библиотеку. Соответственно, есть вот этот APM-пакет go-conventions, который ссылается на всё остальное; ты его у себя один раз ставишь — и всё. И потом дальше говоришь Клоду: напиши мне микросервис на Go. И оно выдаёт прямо правильный микросервис согласно тому, что у нас принято, по всем слоям: и Go, и Docker, и Helm, и вот это всё. И вот это прикольная штука с точки зрения библиотек, мне кажется.

[33:41] Александр: Слушай, ну ты здесь тоже две темы затронул. Первая — это в целом менеджмент, дистрибуция вот этих скиллов, по сути маркдаун-файлов, расположенных в нужных директориях. И второе — это харнес: то есть в конкретном проекте конкретные штуки. И вот здесь APM — я же могу его себе условно в закрытый environment куда-то установить, и это будет моим закрытым, условно, Docker Hub, который стоит и распространяется среди моих коллег, то есть решается проблема этой дистрибуции. Я просто всё думал, что, возможно, это всё-таки как-то через git — ну, я делаю через git пока, но вижу, что это какой-то костылик. А package-менеджеры тоже вроде какие-то…

[34:31] Владимир: Поясни, что ты называешь «через git»? Копипастишь, что ли?

[34:35] Александр: Нет, git clone, и там сабмодули — и погнали.

[34:39] Владимир: А, сабмодули. У меня какая-то аллергия образовалась на сабмодули, потому что…

[34:43] Александр: С ними тяжело работать, я согласен. Но Клоду норм — он-то нормально.

[34:49] Владимир: А, вот как. Это, кстати, отдельная тема — что Клоду многое норм, можно тоже проговорить. Меня, значит, не радовало клонировать, да и эти сабмодули тоже не очень выглядели. И APM вроде таким нормальным ответом послужил: потому что ты пишешь как зависимость — типа, вот у меня зависимость на go-rules. И всё, они там импортируются, они работают. Сама тулза прямо хорошо развивается. У них, кстати, интересная сама агентская история построена: если ты им заводишь PR, issue — или кто-то там кнопочку прожимает, — запускается неимоверная орда агентов, которые ревьюят и пишут комментарии. С одной стороны, там прямо очень-очень много всего написано — даже посмотреть, как устроено, уже забавно. Но с другой стороны, они успевают много чего делать: то есть заводишь им баги, и они довольно оперативно их выкатывают и исправляют. Это тоже такая хорошая, позитивная история.

[35:47] Александр: Слушай, вот это интересно разобрать, кстати. Потому что, мне кажется, половина слушателей этого подкаста так или иначе сталкивается сейчас с проблемой: ну окей, как выстроить на проекте процесс, когда мы используем модели, фигачим — и при этом обеспечиваем контроль качества, движение и эволюцию продукта? Потому что, я думаю, каждый проект в своей истории развития и адаптации агентской разработки сталкивался с тем, что у них что-то упало — какой-нибудь прод, — или они не вывезли, что-то дропнули. То есть не смогли, не успели создать процессы под тот быстрый бум кодогенерации, который случился. И я постоянно об этом думаю, потому что это часть моей работы. Мне интересно поподробнее как раз изучить: окей, орда ревьюеров — ок, дальше что? Вот они на ревью тебе накидали на вентилятор говна — что дальше? То есть как процесс сам обеспечивает конечное delivery?

[36:48] Владимир: Я думаю, это всё равно на людей замыкается — конкретно этот вопрос я не исследовал. Там, знаешь, что интересно — для меня это было неожиданно, может быть, для тебя очевидно: допустим, заводишь ты им issue или заводишь какое-то предложение, давайте вот поправим тут багу. Очевидные ревью — это код-ревью: допустим, проект на Python написан, и они говорят — вот у вас там Python не Python, тестов хватает, не хватает. Это прямо вообще. Но дальше у них есть такая штука — user experience review. То есть агент, который смотрит с точки зрения пользователя и говорит: нужна ли вообще такая штука пользователю, полезно, не полезно, удобно, неудобно. Вот прямо с таким фокусом ревьюер. Есть ещё один ревьюер, который говорит про обратную совместимость: насколько вот эту фичу будет тяжело тянуть, не тяжело тянуть, нужна, не нужна. И, соответственно, у них примерно шесть таких персон, и очевидных из них только парочка — все остальные максимально типа странные. А, там есть ещё, знаешь, такой ревьюер-маркетолог: как мы это будем продавать и насколько это поможет продвижению продукта. Я не знаю, конечно, когда это полезно. Ну, в принципе, это то, что ты сказал буквально пару фраз назад: что постоянно думаешь над тем, как это всё продвигать, как наше изменение поможет. У них это прямо есть в штатном паке ревьюеров. Я, конечно, заводил по большей части технические баги — что смотрите, у вас тут CLAUDE.md создаётся или нет, или там какая-то ошибочка, — и поэтому отзывы этого маркетолога были банальные, просто бесполезные. Но в целом само направление выглядит как минимум интересно: что они прямо это автоматизировали, это думают, и наверняка в каких-то UI-историях это прямо поможет. А во-вторых, есть такая тема: это то, что человек потом в конце концов постит. То есть они такие автоматические ревью сделали, а человек, я думаю, всё равно замыкается. То есть я не видел того, чтобы прямо само собой куда-то проталкивалось по пайплайнам и ещё каким-то агентом двигалось. Вот здесь интересно услышать: ты хоть раз такое видел, не видел — чтобы целиком цикл строился? [39:12] Александр: Ну смотри, вот тут как раз у меня есть такое размышление — какие вопросы я себе задаю каждый раз, когда делаю попытку что-то подобное задизайнить. Вот я моделирую процесс у себя. Окей: представляешь, как радовался человек, который придумал user experience reviewer? Он такой: вот это я классный, вот это я сейчас… Я каждый раз такое испытываю. А потом такой: ну вот он сделал ревью — и что? Ну реально, и что дальше? То есть кто его будет читать? Ладно, его прочитают, согласен, один раз прочитают. А не создаю ли я дополнительную нагрузку на человеческие мозги вот этими своими ревьюерами? Я больше пользы приношу и улучшаю продукт — или я больше слопа приношу, и люди от этого быстрее устают и меньше деливерят в итоге? Вот я такой вопрос себе задаю, и каждый раз я прямо думаю: блин, ну мне-то в целом вообще пофигу, я могу работать с любым количеством слопа — потому что я могу взять Клода и сказать: давай, что там важного, неважного, отранжируй, отсортируй, я посмотрю. То есть я уже научился работать с этим объёмом слопа. Но я понимаю, что большинство людей — даже вот коллег продвинутых — негативно реагируют на подобный текст, ну, внутренний. И они не получают удовольствия от работы, когда видят такие портянки: потому что их надо читать.

[40:32] Владимир: А смотри: читать надо, здесь я согласен. У меня есть даже человек, который говорит: я вообще не пользуюсь сетями, потому что слишком много текста выдаётся, не успеваешь всё это читать. Но смотри, здесь портянка — я поясню — она свёрнута. То есть у тебя в комментарии на GitHub возникает summary, executive summary; у них там забавно, что — что ответить человеку. То есть они не вот это проверяют, а там типа рекомендуемый ответ в GitHub, и дальше идёт рекомендация. А потом свёрнуты ответы каждого из агентов: там можно посмотреть — вот это dev, UX, security; агент, который проверяет, будет ли этому проекту лучше расти в опенсорсе или нет; документация, какой-то SEO-агент, — они свёрнуты. То есть ты их не читаешь, если не развернёшь. Это же не проблема: их читает условно твой агент, который получил этот фидбэк и дальше уже применяет. Или твой агент их читает и видит; ну или человек, который развернул и смотрит. Поэтому здесь нельзя сказать, что это прямо куча слопа, который портит картину или мешает читать.

[41:42] Александр: Это хороший мув — разделять ответ для людей и ответ для агентов. И это, мне кажется, тоже важный шаг: что текст бывает разный. Мы сейчас находимся в той реальности, что издалека он выглядит вроде бы как текст — ну, это не программный код, казалось бы. Но текст тексту рознь. И нам, людям, иногда нужно понимать: вот этот текст надо читать, или его надо по диагонали просканировать, или вообще нет — просто модель сама разберётся, условно. Вот ранжировать так текст, классифицировать — у нас должна быть наша внутренняя нейронка натренированная. Мне кажется, это одна из адаптаций под новые реалии, которые мы как инженеры, наверное, обязаны сделать, потому что иначе ты просто сойдёшь с ума. Я наблюдаю за индустрией, за коллегами — особенно в русскоязычном сообществе это сплошь и рядом: люди прямо реально как-то противятся или реагируют токсично, негативно на какие-то вещи, связанные с генерацией. Я не знаю, с чем это связано, я тут не сильно глубоко анализировал, но каждый раз, когда я кого-то прошу поревьюить, а у меня, понятное дело, pull request сгенерирован — я его, естественно, сам просканировал своей уже натренированной нейронной сетью, которая быстро говорит: да, всё нормально, — и отдаю другому человеку, который не так шустро, может быть, сканирует слопный текст. Я чувствую, как он страдает. Я вот через монитор это ощущаю. И я не знаю — ты с таким сталкивался или нет? Или, может быть, как у тебя самого прошёл вот этот рубеж, когда ты такой: да, теперь я код генерирую, и мне от этого кайф?

[43:27] Владимир: Я, ты знаешь, по-разному. Кажется внутренне, что есть проекты чуть более важные, чуть менее важные. И когда, например, я пишу вспомогательную CLI-ку для интеграции с какой-то системой, то я там вообще код не смотрю: я пишу, что мне надо — типа, мне интеграция нужна, — код не смотрю, оно какие-то себе тесты пишет, какие тесты пишет, я тоже не смотрю. Ну, примерно так. И максимум, что я делаю, — Codex’ом делаю ревью, похоже вообще на правду или нет; то есть на уровне того, что я завожу «хочу сделать вот такую фичу, загружать новый тип данных», а он говорит: а ты не указал, какие фильтры тебе нужны, или что делать в таком-то случае, если данных нет. Ну давай укажем — ладно, всё, сошлись, поехали. А есть код, где чуть более важна производительность: профилировку надо написать, отправку данных, чтобы система не захлебнулась, пока показывала их. Здесь — ну что, надо смотреть на код. И тут какой-то шматок слопа был бы прямо болезнен. Поэтому я уж который день сижу, вожусь с дизайн-документами, чтобы дизайн сошёлся, — потом посмотрим, что будет. Как раз хочу уложиться до Fable и посмотреть, что будет: дизайн я уже, наверное, на финальной стадии, надеюсь, успею — и посмотреть, что будет с этим шматком у Fable. Вот тогда я тебе точный ответ дам. Но, ты знаешь, я думаю, что, так сказать, родной нейрослоп намного проще воспринимается, чем чужой. Вот ты себе так задачу не пробовал ставить, не сравнивал? Потому что ты, когда пишешь промпты, ты направляешь нейронку, ты понимаешь, что ты хотел, — то есть ты понимаешь, что хотел сказать автор. Поэтому когда ты ревьюишь этот код, ты, понимая, что хотел сказать автор, уже смотришь, то или не то сделано. А когда ты смотришь на чужой код, ты, во-первых, не понимаешь, почему он написан так или иначе, ты не понимаешь, проверял ли там человек какие-то краевые случаи, — и ты смотришь даже на небольшое изменение: блин, ну как-то вот странно, а что ж такое сделано? И вот эти недосказанности очень сильно затрудняют чтение.

[45:50] Александр: Угу, вот это хорошо ты сказал — слово «недосказанность». Я в последнее время ловлю себя на такой привычке: каждый раз, когда я прошу человека что-то посмотреть, я досказываю что-то недосказанное, что у меня в голове есть. Я такой: так, вот он сейчас будет открывать, вот он это увидит, там есть ссылка на тикет, там всё чётко с моей точки зрения сейчас — но что есть у меня в голове, чего нет у него? И, как правило, это интенция: а с чего всё началось? А зачем я вообще это сделал? Я такой: ну вот тут я производительность улучшил, на бенчмарках померил, работает — кайф; здесь я сделал сборку по-другому; а здесь вот просто верхнеуровнево, буквально одним предложением, но самую суть — чтобы он с этой сути начал и потом уже погружался в pull request. И по опыту скажу: стало лучше. Реально люди прямо такие: а, ну давай-давай-давай, окей, вроде то.

[46:46] Владимир: Ещё разок порекламирую этот скилл написания английских текстов — да, или русских, там тоже есть, — он как раз в pull request первой фразой выводит, почему мы это делаем: как раз что хотел сказать автор.

[47:02] Александр: Да-да-да. Но видишь, этот автор делает это исходя из того, что он видит: у него же контекстное окно такое…

[47:10] Владимир: Ну, человек — да, тут, конечно же, вопрос, что делал человек, как он ставил задачу нейронке, почему он хотел это делать. Я могу тебе показать, но, как правило, нейронка сама неплохо выводит, почему оно сделано, — из того, что ты ей исходно ставил, какие она действия делала и так далее. Она же какую-то задачу решала, и ты с ней пришёл к какой-то задаче — поправь вот здесь, чтобы, не знаю, не потреблялись лишние байты. Ты мог ей просто сказать «замени А на Б» — она такая: ладно, всё, заменил А на Б; я не знаю, что она сделала в таком случае. Но я же обычно прихожу с вопросом: у меня вот здесь хочу, чтобы пооптимальнее что-то работало, — и она тогда конкретно эту часть и выносит в обоснование, почему PR сделан. Но да, конечно, вот эта история — как донести до других, что ты хотел или что ты пробовал. Потому что зачастую, знаешь, это вопрос комментариев: когда нужны комментарии в коде. У меня ответ теперь такой: когда нейронка решила, что они нужны, — пускай они там будут. Вот сейчас у меня так. А раньше — окей, два года назад если бы ты задал этот вопрос…

[48:16] Александр: Я бы такой: если я читаю код и у меня возникает в голове вопрос «что происходит?» — здесь нужен комментарий. Вот я так мыслил.

[48:24] Владимир: Да, ровно так. Я на самом деле здесь прямо очень не рад текущим нейронкам — и Opus, и GPT-шкам. Они склонны, во-первых, слишком много писать, а во-вторых, они склонны писать устаревающие комментарии. То есть в духе: был код написан одним образом, они его поправили, починили багу — и комментарий: смотри, старый подход не работал, потому что была такая… [48:48] Владимир: …короче, полностью багу начинает описывать в комментариях. Ты видел, не видел?

[48:52] Александр: Видел, видел, да.

[48:55] Владимир: И получается, что комментарий описывает не новый код, а описывает, почему старый не работал. А человек, который смотрит, он не видел этого старого кода, ему это вообще не нужно. И вот такие комментарии я прямо вырезаю.

[49:08] Александр: Это интересный момент. Вот я не вырезаю — и вот как я думаю. Во-первых, исходя из просто базовой, простой, очень жизненной философии, которая жизнь упрощает. Знаешь, есть там типа стоицизм условно: если ты его принимаешь и живёшь по нему, то тебе жить легче. Вот у меня такой нейро-стоицизм: если нейронка сгенерировала этот комментарий и он не вводит в заблуждение — явно там нет ошибки, баги и всего такого, — пускай будет. Типа, она обучалась на каких-то выборках, она произвела продолжение своей выборки, значит, ей это нативнее. И всё. И я такой: может, да, я бы не писал, и читать тяжелее — я с ней не согласен, но… стоицизм. Это первое наблюдение. А второе — почему это может быть полезно, почему она это делает? Они же не тупые. Я думаю, что это может помочь в целом ей самой в последующей работе с кодом — чтобы она этот подход просто уже не использовала. Комментарии — кривовато; как будто бы нам нужен инструмент, чтобы следить за изменениями конкретного места. Казалось бы, тут git, возможность через git, — но как будто бы через git тяжелее и не так эффективно всю историю этого куска нейронке разматывать. Поэтому она сейчас в комментариях это пишет — и уже этот подход не будет использовать. То есть она для себя сохраняет знания о коде вот здесь. И да, они уже не имеют значения. А то, что человеку сложнее будет читать, — ну, мне кажется, мы уже почти там, где реально прямо глазами читают единицы. То есть полпроцента всего кода в мире, а то, может быть, даже и 0,01% всего кода в мире стоит внимания людей. Вот реально.

[50:45] Владимир: Всё так. Я единственное здесь не соглашусь с тем, что не мешает: оно эту же нейронку будет отвлекать. То есть лишний код — точно так же, как лишние фразы в CLAUDE.md — будет нейронку отвлекать. Разумеется, достаточно умная нейронка должна понять, что ей сейчас важно, а что нет. Но вот эти замусоривающие комментарии, которые рассказывают про старые истории, банально могут увести её вообще в сторону.

[51:11] Александр: Вот смотри, я прекрасно понимаю ход этой мысли. И здесь у меня есть следующий вопрос, который я каждый раз себе задаю: а немного ли ты на себя берёшь, Саша, думая, что нейронку что-то введёт в заблуждение? Не переоцениваешь ли ты в этот момент свои когнитивные возможности? И не являешься ли ты biased на то, как ты раньше программировал? Да, раньше тебя бы это увело. Ну, в целом я просто понимаю, что можно изи — и думаю, что так оно и есть: ты просто отсекаешь комментарии где-то на входе в нейросети, которые генерируют; ты этот процесс каскадный делаешь, и до конкретной генерации следующего токена доходит уже достаточно умный. Они реально крутые. И вот я каждый раз себя так осекаю: не бери на себя слишком много. Ты уверен? Реально ты уверен, что хуже или нет? Если на сто процентов уверен — газ. Если нет — то у тебя есть более важная работа. Я так себе всегда говорю. Почему у меня эти комментарии и висят в коде. Но я понимаю, что это в целом довольно радикальная позиция принятия всего.

[52:09] Владимир: Ну да, но зачастую, конечно, комментарии прямо нормальные получаются. Здесь у меня скорее пограничная ситуация, где я бы написал скилл, который проходит по коду и пытается удалить то, что не нужно с первого раза, — ну, не нужно читателю. То есть это примерно тот подход пятилетней давности: какие комментарии тебе были бы нужны, когда бы ты этот код первый раз увидел и задался вопросом, а что вообще здесь написано, почему так и не иначе. Но, к сожалению, сколько я наблюдаю сейчас — нейронка не способна оценить качество. Она не способна оценить сложность, она не способна оценить экспертность. Для неё очень многое может оказаться и лёгким, и сложным одновременно. То есть ты её спросишь: вот дерево Фенвика — это типа лёгкая штука или сложная? Ну давай вот напишем дерево Фенвика, мне тут надо, — ну любая нейронка сейчас просто напишет, и всё: там кода три с половиной строки, оно и напишет. Но если среднего программиста спросить, что такое дерево Фенвика, — ну блин, это будет круто, если хоть как-то ответят. И получается, что комментарий «мы тут реализуем такое-то дерево, вот такие свойства нужны» — вроде прикольный, полезный комментарий, который объясняет. Но момент: как понять себе, что уже пора комментировать или нет? То есть ты тут A плюс B пишешь или ты тут пишешь дерево Фенвика? А там буквально одно и то же — практически нет разницы. Но для человека очевидно, что дерево Фенвика надо поставить в комментарии и сослаться, а к A плюс B не надо писать комментарий, что мы складываем A плюс B. И вот нейронка не может оценить, какой степени знания нужны человеку — ну, типа, чего ожидать от среднего инженера, который вдруг этот код увидит, поревьюит или ещё что-то сделает и задастся вопросом, а что вообще здесь происходит. Это мем такой старый, знаешь: чем отличается плохой код от хорошего?

[54:11] Александр: Так, и чем же?

[54:13] Владимир: Количеством «какого чёрта?» в секунду.

[54:19] Александр: Да, нормально.

[54:20] Владимир: И вопрос в том, чтобы они были положительные, позитивные — когда ты смотришь и думаешь: а вот почему? И вот такие комментарии как раз нужны. Хотелось бы, чтобы нейронка такие оставляла, но она, к сожалению, сама плохо может понять, что человеку очевидно, а что нет. Потому что для неё и дерево Фенвика все знают — ну что они, не учились на программистов, что ли, в школе. Поэтому — и это не только с программированием так, это и с оценкой.

[54:49] Александр: Вот можно сейчас, знаешь, как сделать такой эксперимент: эту запись прогнать через транскрипцию и попросить нейронку оценить экспертность кого-нибудь — Володи, например, — в любой области: в Java, в вайбкодинге, ещё в чём-то. И она тебе выдаст какой-то ответ. А потом её может…

[55:07] Владимир: Ну подожди, ты что, по ключевым словам?

[55:09] Александр: Ой, да, по ключевым словам любой может назвать.

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

[55:58] Александр: Да, на комментариях мы хорошо так поразгоняли, мне понравилось. И, знаешь, мне кажется, вот тут я как раз набрёл на такую мысль: что у нас тулинг — и в том числе языки программирования, и тулинг, который отображает для человека суть программы, — несовершенный. Нейронке-то хотелось бы туда побольше нафигачить в какие-то блоки типа historical: справка, вот тут было сделано так-так-так, такие-то комментарии, вот там случилось это событие, поэтому вернулись обратно. Вот это каким-нибудь бранчем куда-нибудь отодвинуть, убрать — а человеку показать уже отдельно сам конечный алгоритм. И тут комментарии — да, они подсвечиваются другим цветом в редакторе, но это не то. Как будто надо что-то другое: нужен какой-то фолд, или вообще отдельная система, или какая-то вьюха на код — сделать code view, где ты прямо как человек читаешь суть и уверен на сто процентов, что это соответствует алгоритму. То есть я хочу понять алгоритм и сказать «то — не то». Я не хочу в детали, я не хочу вот уже всего этого, это не моя задача. И кажется, подобный тул — или язык программирования, или даже не язык программирования, а в целом надстройка над текущими языками — это то, что уже должно как будто появиться и, возможно, то, чем мы будем в скором будущем пользоваться. Потому что сорцы сами по себе уже становятся как будто бы для нейронок, а для людей надо что-то другое.

[57:24] Владимир: Да, вот ты говоришь, сорцы становятся для нейронок, — но ты сам назвал IDE, поэтому, наверное, ещё иногда открываешь. Я вспомнил шутку из обсуждения лет семь назад. Вопрос был такой: почему комментарии отображаются блёклым шрифтом, если это самая важная часть программы?

[57:43] Александр: Угу. Получается такая дилемма, да? Они как бы не исполняются, поэтому исторически все блёкло отображали — что-то как будто неважное. А здесь на самом деле это самое важное. А ещё, знаешь, есть такой подход — связка агентских сессий с кодом: какой-то стандарт на то, чтобы в git или ещё где-то, в дополнительных объектах, в каких-то аннотациях хранить агентские сессии, которые можно было бы потом смотреть. То есть ты сейчас смотришь git blame и видишь: не знаю, Володя накоммитил эту строку десять лет назад. [58:27] Александр: Было бы прикольно ещё видеть, каким промптом Володя это накоммитил, что он ещё писал в этот момент.

[58:35] Владимир: Сейчас это ты пишешь максимум в коммит-месседже — там выше ссылки на issue, и там тоже может что-то быть. Но стандарт на агентские сессии — это примерно та же степь, про которую ты говоришь. Хотя это, конечно, не совсем то.

[58:48] Александр: Да, я бы тут ещё, знаешь, добавил: чем может быть полезна агентская сессия? Если мы говорим прямо про сессию — то есть не про начальный промпт и твои промежуточные промпты, а именно про сессию. Потому что что есть в сессии? В сессии есть процесс исследования нейронкой проекта, его структуры: что она вообще видит, что перед ней есть, куда двигаться, какие у неё есть правила, документация и так далее, чего пользователь хочет. А дальше она начинает грепать проект, смотреть тесты, какие-то темплейты, кукбуки, всё что угодно — и вычленяет какую-то суть: мне нужно сделать вот это, вот это. Потом она запускает, что-то падает, она такая: а-а, тут надо с ключом… а тут вообще только на Java 25 всё собирается. И вот какие-то gotchas — она их так называет, готчи, не знаю, как по-русски.

[59:40] Владимир: По-русски у меня пишет «готча», «у тебя две готчи».

[59:48] Александр: Нормально. Готча — да, есть такой гонщик-дрифтер… Короче, это прикольно. И в чём здесь ценность вот этой сессии? Как раз в этих готчах: что она их нашла — это интеллектуальный труд модели, который стоило бы вычленить и учитывать в последующей работе. Но если ты вот так втупую просто трейсы этих сессий куда-то прикладываешь — ну, модели проще самой заново сделать трейс, чем трейсить по трейсу. Надо это вычленять и куда-то сохранять как базу знаний о проекте, о том, как с ним работать. Причём не человек должен это описывать, что у нас вот так, вот так, а — в ходе работы нейронка сама что-то нашла, что-то такое, что человек даже не подумал бы, что это может быть важно: не знаю, абсолютный путь до какого-то бинаря, который она постоянно запускает, — ну банально, я просто из головы взял какую-то такую неочевидную фигню. И пускай она это себе помнит где-то. И в этом плане у меня есть практика: когда я вижу, что мы прямо много шуршали, была серьёзная сессия и в итоге задачу добили, — я говорю: расскажи мне про свои готчи, что ты там видел, что происходило, что было для тебя тяжело. Он мне так листом выводит: да, вот в этой сессии я много пытался получить доступ к dev-кластеру, а на самом деле у тебя auth протух, и надо было сразу тебя попросить сначала обновить аутентификацию для kubectl. Супер — давай мы это будем каждый раз в начале проверять. Всё, сделали, сохранили в тот самый Project Hub, закоммитили, коллеги себе эти инструкции притянули — потому что у них есть инструкция «git pull перед каждой новой задачей». И всё, теперь у всех Клод стал работать быстрее, потому что мы вот эту выжимку сделали. Это очень крутой подход, который я для себя использую и с коллегами делюсь. Это со стороны как раз вот этих сохранений сессии: то есть сам процесс работы майнит инсайты, которые стоит сохранять. Вот такая мысль. Ты чем-то подобным занимаешься — или у тебя оно просто чаще работает?

[1:01:47] Владимир: Я точно так же здесь действую. То есть если вижу, что модель спотыкается, идёт не туда — ну, пытается запустить не на той Java. Или ещё, знаешь, как забавно: например, в проекте настроены тулчейны — то есть ты через командную строку можешь выбирать «тесты запускай на такой-то Java», вне зависимости от того, какая у тебя дефолтная, чтобы можно было тестировать. Модель не догадается это сделать. И ты видишь, что она сейчас запускает: а, посмотрю — у вас там такой Java нет, надо скачать; скачаю, запущу — не помогло, почему-то в рантайме не та версия. Ну, после такого, конечно, идёшь и объясняешь ей: смотри, у тебя есть такая возможность, это нормально. Нет, SDKMAN есть, оно SDKMAN’ом всё делает. Проблема в том, что проект не использует напрямую ту Java, которую ты используешь в JAVA_HOME. Какой подход, если про Java говорить? В идеале ты компилируешь на последней Java, а тестируешь на всех остальных: то есть не надо компилировать на старой Java, потому что там банально есть баги в компиляторе. Компилировать надо на самой нормальной, получаешь бинарник, который совместим со всеми, и потом уже на всех остальных тестируешь, что сам твой код работает нормально. Поэтому попытка использовать JAVA_HOME для того, чтобы рулить всем, обречена на провал: ты свою систему сборки запускаешь неважно чем — хоть 17-й, вообще неважно чем. У тебя система сборки должна сама выбрать, что для компиляции она берёт 25-ю, а потом для тестов сама где-то там в SDKMAN находит нужную тебе, на какой ты тестируешь: 17, 11, 8 и так далее. А моделька, в том числе Opus, думает, что JAVA_HOME, который ты передаёшь, влияет на всё. Но оно, конечно, не настолько тупое, чтобы этому слепо верить: поэтому оно пишет себе мелкий тест, который проверяет, на какой Java запускается, запускает этот тест — и тест ей показывает, что хоть она JAVA_HOME передала, но в рантайме всё равно не та версия, которую она ожидала. Она такая: блин, какая-то ерунда творится, почему-то JAVA_HOME не действует, давай попробуем и вот так, и вот так, и давай у пользователя спросим, что делать, вообще какая-то ерунда, — там скрипты начинают дебажить. И это всё та же самая история, как у тебя: то есть она куб правильный не может найти. И здесь идёшь и пишешь ей в CLAUDE.md, чтобы она в следующий раз нормально писала. Есть статья, целое видео с исследованием, как надо эти CLAUDE.md писать, — этот самый Тео.

[1:04:18] Александр: А, видел я в твиттере. Я единственный вот твит… Я в твиттере не сижу, но вот он как-то до меня долетел, и это было — у меня, кстати, было такое в момент Клод-FOMO. Он, короче, твитнул, что он бросает пить алкоголь, потому что ему нужно фигачить с кодом и слишком много концентрации надо, — и вообще исключил из своей жизни, типа полный газ. И я себя поймал на абсолютно той же самой мысли в этот же самый момент: я такой — я Тео, да. Но потом я эту затею бросил.

[1:04:46] Владимир: Тео забавный товарищ в плане того, как он подаёт информацию, что он рассказывает. Но у него есть один из видеообзоров на тему того, что в CLAUDE.md вообще ничего не надо писать. Это немножко нас, конечно, возвращает назад, но — продолжая тему. Смотри: ты хорошо сказал, что есть какие-то проблемки, с которыми модель сталкивалась, — вот их-то и надо писать. И там видео, которое разъясняет ровно этот момент: на полчаса, со всякими научными исследованиями и прочим — как модельки решают задачу с рукописными CLAUDE.md, без CLAUDE.md, с файнтюнингами и прочим. Но там ровно та же схема: говорит — пишите только то, что привело к косяку модели. Если модель не накосячила, сама нашла, как ваш проект собирать, — так что это тогда писать? Она и сама всё сделает.

[1:05:34] Александр: Да-да. Это, знаешь, такое… Исследования — это, конечно, интересно, но я последнее время как-то с опаской на них смотрю. Потому что, во-первых, мне кажется, надо прямо вникать: если мы берём исследование, то надо вникать, как оно делалось, кто авторы этого исследования, какая методология, какую вообще задачу они решали, — в первую очередь, прежде чем даже прочитать заголовок исследования. Вот такой у меня подход. Потому что, как правило, ты смотришь и думаешь: блин, ну они фигню делали. Ну вот последнее исследование вообще не то — и думаешь, дальше читать нет смысла. В этом плане я, знаешь, исследователь сам себя — как-то я так себя позиционирую. То есть: а для меня что работает? Я просто дофига всего пробую. Для меня, если задача с двух промптов условно до прода дошла — вот это круто. Что я сделал такого, чтобы это произошло? И дальше я оттуда как-то достаю — именно в моём проекте, именно у меня на опыте. А смотреть опыт других людей в этом очень быстро меняющемся мире — мне как-то жалко времени своего. Ну реально: столько всего вокруг происходит, люди говорят очень много всего, делают много всего. Я такой: а давай просто посмотрю сам.

[1:06:50] Владимир: Мы сейчас с тобой наговорили, знаешь, на что? Мы сколько-то часов наговорили — и ты произнёс фразу: «слушать опыт других людей, кто как делает, — это какая-то шляпа».

[1:07:02] Александр: Ага, да-да.

[1:07:05] Владимир: Мы именно в этой точке и находимся.

[1:07:09] Александр: Да, добро пожаловать в реальность. Ну, в общем-то, да, это я так, просто мысли вслух.

[1:07:14] Владимир: Конечно. Я тут согласен, что надо смотреть на то, кто, зачем и что наисследовал. Но с одной стороны, было исследование — это лучше, чем совсем нет. А с другой стороны, никто не мешает попробовать или не попробовать. То есть я примерно такой же подход по факту и применяю. То есть не то, что ты получаешь после /init: вот ты /init сделаешь — он тебе какую-то шляпу напишет, но там много всего будет бесполезного, что тебе по факту не особо-то и надо, где модель бы и не спотыкалась, сама бы нашла. И я здесь скорее согласен с тем, что берёшь сырую модель с сырым git и правишь по месту только там, где она реально косячит. А может быть, и не придётся править: новая выйдет — и всё будет нормально.

[1:07:57] Александр: Да, вот у меня тоже такая позиция. [1:08:03] Александр: По поводу, кстати говоря, наверное, можно поговорить про IDE и вообще про инструменты, которые нас окружают, — привычные инструменты, которыми мы пользовались как программисты на Java, на всём подряд. Я вот понимаю, что у меня сейчас из реального активного инструментария, который постоянно перед моими глазами: это, естественно, Клод в терминале; tmux, который разделяет кучу сессий Клодов и окон, и организация этого пространства в нём. Дальше это командная строка — как правило, чтобы запустить Vim, прочитать что-то длинное или посмотреть тут на месте, что он там написал; сделать авторизацию в AWS, условно запустить команду — то есть терминал, что-то подсапортить Клоду. Это всё, что в терминале. И дальше это GitHub как место конечного принятия решений: где я смотрю, делаю чаще всего поверхностное ревью, но если это серьёзный код, то, конечно, пока ещё вникаю. И делаю мерж — ну, смотрю, что все CI-чеки прошли, меня устраивает, и делаю мерж. И дальше какие-то деплои: если они автоматизированы, они сами происходят, либо я ещё одну кнопку нажму. Это всё, что передо мной происходит в последнее время, — то есть я больше ничем не пользуюсь для разработки. Вот я бы хотел твой опыт послушать: чем ты пользуешься? А дальше поразгонять эту тему эволюции инструментария — куда мы вообще движемся?

[1:09:26] Владимир: Я начинал пользоваться с консольки — ну, с этой Codex-консольки, — но в какой-то момент перешёл на десктоп-приложение.

[1:09:37] Александр: Интересно. Ты, кстати, первый, по-моему, программист, который десктопом пользуется, — ну, из тех, кого я знаю.

[1:09:43] Владимир: И вот это было интересно, потому что я пробовал два раза переходить на десктоп. Первый раз, когда я переходил, там было явно меньше возможностей — явно меньше возможностей по управлению, по группировке; и, похоже, не знаю, они больше вкладывали, что ли, в CLI. Банально попробовал — не зашло, вернулся назад. А буквально полгода, наверное, назад я перешёл на десктоп и полностью перешёл. Есть единственный случай, когда я CLI запускаю, — можешь попробовать угадать. Но в десктопе, на мой вкус, гораздо проще, во-первых, группировать сессии. То есть у меня по сценарию получается, что есть много изменений, которые не замержены…

[1:10:24] Александр: Давайте посочувствуем друг другу.

[1:10:28] Владимир: Есть много изменений, которые не замержены. В идеале мы, конечно, не должны начинать новую фичу, пока не замержена старая, но…

[1:10:33] Александр: Добро пожаловать.

[1:10:40] Владимир: Правда жизни в том, что когда ты не единственный мейнтейнер проекта, тебе надо дождаться какого-то кивка с той стороны. В итоге у тебя есть куча историй, которые ты одновременно пытаешься подтолкнуть, и они висят открытыми и висят. Как такое вести в терминале, я вообще не понимаю. Потому что либо это папочками надо вести… У меня когда-то была история: tmux, этот самый Ghostty, поделил на панели — вот это всё. Но потом получается, что у тебя условно восемь окон, и этого тоже мало: у меня там порядка, например, пятидесяти, может быть, сотни сейчас сессий висят в разной степени готовности. В десктопе ты это группируешь, скрываешь, архивируешь старое — и прямо наглядно видишь, что у тебя осталось. Второй момент: в десктопе проще смотреть на код. То есть в терминале его как-то выборочно скрывать и раскрывать неудобно, а тут ты прямо скрываешь и раскрываешь, у тебя нормально видна и подсветка, и код, и маркдаун отображается. Если надо, ты их быстренько открываешь в уже нормальном просмотрщике — потому что если у тебя какие-то графики, ну, ты построил какой-то дизайн, или оно тебе предложило, как будет фича выглядеть, и построило диаграммку, этот mermaid в маркдауне, — в терминале ты это так себе увидишь, а тут открываешь, и всё сразу видно. Поэтому я прямо активно подсел, всё прекрасно. Но в терминале у меня есть один случай. Проблема в том, что когда ты какой-то новый проект начинаешь или у тебя какая-то задача, не связанная с проектом, — вот в десктоп-приложении (в Codex это получше, у Клода тяжело) долго выбрать папку, в которой ты работаешь. Там, знаешь, буквально такой один комбобокс: ты открываешь комбобокс, и он говорит «выберите, найдите» — я не знаю, как они отсортированы, даже не смотрел, но как-то они там не отсортированы. Последние сто проектов или сколько, в которых ты тыркался. И у тебя два варианта: либо найти среди этого списка тот, в котором ты хочешь сейчас создать сессию, либо открыть file open и на файловой системе искать. А я в терминале гораздо быстрее туда навигируюсь, там пишу claude — и, может быть, какие-то очень быстрые сессии там делаю. Но прямо полностью переехал в десктоп и рад.

[1:13:00] Александр: Интересно. Слушай, а если тебе, например, нужно что-то сделать — какой-нибудь дашбордик, то есть какую-то лёгкую автоматизацию? Это, кстати, такой новый кейс, про который мы вообще ни слова не сказали: крафтинг тулинга под себя. То есть сейчас получается — ну реально, я просто всегда был такой, что я какой-нибудь скрипт напишу, плагинчик присобачу, CLI-ку, чтобы локально у меня были все мои автоматизации; ну, был такой бзик. А сейчас я такой: так я вообще могу построить всё что угодно для себя, что мне нужно. Вот у меня есть свой процесс работы, не знаю, на проекте X: там есть Jira, созвоны, мессенджер и, допустим, GitHub. Я это всё могу в один дашборд у себя локально объединить и двигать у себя локально — то есть я прямо могу запариться. В этом плане просто безграничный the sky is the limit, что называется. И вопрос мой в том: я, например, делаю иногда CLI-дашборды, использую Go, Bubble Tea — прикольный фреймворк для написания быстрых CLI-тулов и дашбордов, TUI-приложений, точнее, — где можно что-то быстренько посмотреть. Вот есть ли у тебя такой use case — первый вопрос; а второй: если есть, то как ты его реализуешь? В вебе или CLI какую-то пишешь, если ты постоянно сидишь в десктопе?

[1:14:17] Владимир: Ты знаешь, я либо не задумывался — но именно дашбордов не пишу, ни тех, ни других. Если тулинг пишу, то это скорее CLI и TUI, но они, знаешь, у них интерфейс — JSON-выход. То есть это JSON output… Сказал «JSON-выход» и понял, что по-русски это для меня криво звучит.

[1:14:40] Александр: Интересно, как ты… JSON-выход?

[1:14:41] Владимир: Да-да-да. То есть для меня это звучит как перевод с английского — наверное, есть какое-то нормальное слово, не знаю, не будем заморачиваться сейчас. Значит, я скорее затачиваю вывод под модель, чтобы модель потом могла — ну, либо модели, либо jq, либо ещё кто-то — проинтегрироваться с этой CLI и дальше уже что-то делать. Поэтому дашборды, не дашборды — это я скорее пойду и Клода спрошу: скажи мне что.

[1:15:10] Александр: Окей, принимается. Так, из тулинга у тебя, получается, десктоп — и Codex, и Клод.

[1:15:17] Владимир: Да. Вот по поводу «IDE — не IDE»: у меня по факту среда-то открыта. Но, возможно, это моё оправдание, что я ещё до сих пор код хочу посмотреть или верю в то, что важно, что я его буду смотреть. Опять же, зависит от проекта. Если говорить про этот Postgres-драйвер — там всё-таки немножко важно, во-первых, не испортить производительность типичного сценария: когда там getInt и ещё что-то делаешь. Приложениям до сих пор важно, чтобы они не тормозили, не тупили, поэтому тут важно прощёлкать, что у тебя действительно цепочка вызовов нормальная, код выглядит правильно и так далее. IDE открыта.

[1:15:59] Александр: Я очень много последнее время размышляю — потому что я тоже перформанс люблю, оптимизации обожаю в целом, — но реально ли у тебя есть такая внутренняя уверенность, что, просмотрев код, ты можешь хоть с какой-то долей сказать, что он быстрый?

[1:16:16] Владимир: Да нет, конечно. Но я могу проверить свои базовые гипотезы. Смотри, у меня — и возможно, здесь такое оправдание, а возможно, здесь я прав, — у меня не было никакого стороннего наблюдателя, который бы посмотрел и сказал, что я всё неправильно или что я всё правильно делаю. Потому что, знаешь, кто-то говорит: надо делать небольшие изменения, не делайте десять фич в одном PR, катите их отдельно. Ну, я здесь тоже согласен, что не надо десять фич в одном PR катить и что вот это всё не надо делать. Но если посмотреть на вот этот PR про кодеки, то у меня внутреннее оправдание такое. Смотри: у тебя есть кодек для int, например. Ну вот int — это обозримый фрагмент, у него там десять методов, допустим, разные форматы туда-сюда, ты его можешь посмотреть. Но ты хочешь, чтобы у тебя в кодек-движке содержались не только int’ы, но и структуры, которые могут в себе кодировать int’ы; массивы, которые могут в себе содержать int’ы, которые могут в себе содержать структуру, содержащую int’ы. И казалось бы — вот я себе так оправдываю, — что эта вся штука вот так вот связана: если ты сделаешь просто кодек для int, потом тебе всё придётся переделывать, потому что ты мог не предусмотреть, как оно в целом свяжется. [1:17:35] Владимир: Вот я себе такое оправдание держу: PR на тридцать тысяч строк кода, который по факту сразу всё делает — ну, сразу все кодеки, которые имеют смысл.

[1:17:45] Александр: То есть он решает задачу от и до.

[1:17:47] Владимир: Да, он от и до решает задачу — можно сказать, что это одна фича. Кто-то мог сказать: нет-нет, дорогой, давай ты будешь постепенно выкатывать. Ну а я не знаю, как постепенно выкатывать, потому что реально: ты сделаешь, а окажется, что потом всё переделывать — и зачем тогда было? Это первый момент. А второй момент: когда ты делаешь конкретно вот эту большую фичу, в ней я понимаю, что есть сценарии, которые точно были важны в старой версии. Вот конкретно int’ы было важно уметь получать из базы и возвращать в Java без дополнительных боксингов, поисков по кодекам и так далее. То есть хотелось бы, чтобы у тебя, во-первых, сами int’ы работали, во-вторых, массив int’ов — то есть когда int-массив, чтобы он тоже приезжал сразу, без создания промежуточного массива Integer’ов и потом перекодирования каждого туда-сюда. Потому что вот это как раз очень легко получить, если у сетки просто попросить сделать тебе структуру кодеков: она тебе сделает generic-код, который сначала всё забоксит, а потом ещё и раскодирует. В итоге, конечно же, финальное решение только за профилировщиком — то есть ты будешь это всё профилировать и смотреть, где реально проседает. Но на простых и понятных сценариях ты вполне можешь глазами проверить и посмотреть, в правильную ли сторону оно вообще идёт. И вот для таких ситуаций я IDE держу, открываю, смотрю, как чего.

[1:19:14] Александр: Вот ты хорошо сказал, кстати, — первое упоминание профилировщика в этом подкасте. И мне кажется, это для меня с самого начала очевидная идея: что в харнес и в software development lifecycle с агентами нужно включать профилировщик. То есть это должно быть частью цикла: что у тебя как есть юнит-тесты, интеграционные — так и перформанс-тесты должны быть, причём с профайлом. Не знаю, async-profiler запустил, флеймграф посмотрел, трейсы посмотрел, «от» и «до» сравнил, дифф. То есть это часть этого лайфсайкла. И я всегда, когда думаю про перформанс, когда какие-то оптимизации делаю, смотрю: а давай с точки зрения конечного вход-выход — вот тот самый. На входе было медленно, на выходе стало быстро; функциональность не поменялась, стало быстро за счёт, не знаю, оптимизации garbage collector’а — меньше мусора генерим, теперь у нас throughput больше. Круто. Вот что меня как человека в конечном итоге интересует и где моя экспертность принимает решение «надо — не надо». А всё остальное — давай я сделаю так, чтобы агент сделал это близко к идеальному. И в этой картине мира читать код у меня где-то вообще в конце. Если я, знаешь, уснуть не могу и думаю: блин, ну вдруг он там, не знаю, unsafe-вызовы пишет, а я это не покрыл тестами, и у меня там процесс потом будет…

[1:20:38] Владимир: …убиваться, kill -9 где-нибудь.

[1:20:39] Александр: И я такой: ладно, пойду всё-таки прочитаю, нет ли там такого треша. То есть какие-то психологические моменты я для себя решаю чтением кода — а не качество кода увеличиваю. Потому что я уже давно признал, что качество кода… ну, с Opus 4.8 и Fable 5 я лучше, наверное, редко смогу написать — вот именно если алгоритм какой-то. То есть он просто что-то не так понял, скорее, если он написал плохо; если он понял так — то код напишет лучше.

[1:21:07] Владимир: Я как-то так живу: либо я плохо промпты пишу, либо это код особенный. Но я очень долго выравнивал на то, чтобы вот эти кодеки не анбоксили лишний раз, использовали прямые пути для частых случаев и так далее. То есть у меня всё это было и в дизайн-спеках, и ещё в чём-то — было написано много раз. И при реализации, казалось бы, оно это много раз видело, и при ревью это много раз видело, но… ушло немало промптов на то, чтобы написало по-нормальному.

[1:21:41] Александр: Вот попробуй в следующий раз профайлер в SDLC вставить — и просто поставить его на неделю, пусть оно профилирует, пока не допрофилируется. Ну, кстати, насчёт недели не знаю, но нужно сказать, что минимум аллокаций: попробуй сделать десять итераций и минимизировать количество аллокаций. Я думаю, он дойдёт. Ну, вот у меня такое чувство есть.

[1:22:01] Владимир: Ну, может. Но я не знаю. Там, в общем, проблема, которую я видел, — может быть, это проблема из-за того, что API корявая. То есть сама API, которую я пытался реализовать, наверное, нестандартная для какого-то микросервиса: у тебя есть данные в каком-то виде, и ты их можешь запрашивать через десять разных геттеров — ну, там не десять, двадцать шесть на самом деле разных геттеров. Одни и те же данные: какие-то конверсии запрещены, какие-то разрешены, и для каких-то конверсий есть сокращённые быстрые пути. Поэтому, возможно, в данном случае оно и по косу делается. Но у меня, знаешь, были такие истории, что оно какие-то конверсии дублировало: ну я же знаю, как это делать, — я и тут, и там, и сям пропишу, а не в одном хелпере. Потом ты смотришь и говоришь: нет, ну опять ты какое-то дублирование кода сделал. — А, да-да, точно-точно, давай исправим. И вот эти истории, возможно, исправятся профилировкой: то есть она увидит какие-то длинные пути.

[1:22:58] Александр: Но дублирование кода оно не поправит. А дублирование кода — это по факту дублирование багов. То есть эти баги как раз поиском багов находятся и исправляются.

[1:23:11] Владимир: Да, вот я как раз сейчас более-менее код уже написал, перехожу к фаззингу и профилированию, — и фаззинг как раз находит баги, которые оно там насадило как раз дублированием. Но на этом примере я не сказал бы, что модель достаточно умна, чтобы с первого раза всё написать нормально, — типа, код не надо смотреть. Возможно, но какого-то типа код оно прямо пишет — ну ура: условно helper CLI просто работает. Я даже не трачу время на поиск и анализ — понимаешь, вот веб-сайт, с которым я хочу проинтегрироваться: я в DevTools записываю то, что я там нажимаю — типа, нажимаю «добавить комментарий», — записываю этот HAR-файл и говорю: вот, Клод, смотри, HAR, разберись, добавь фичу. Всё, оно пошло, разобрало, посмотрело, какие заголовки, какие пути, — раз, проинтегрировало, написало. Что написало, я даже не знаю. И работает. То есть тут я даже вообще не задаюсь вопросом, насколько оно хорошо или плохо написало код. А вот где-то всё-таки IDE я открываю. Ну, я бы посмотрел на того, кто бы смог такое сделать без анализа кода: то есть там нужны какие-то жёсткие… ну, не guardrails, а верификаторы для этого цикла, чтобы оно там профилировало и так далее.

[1:24:26] Александр: Да-да, именно только так. И это задача сложная — вот эти гейты выстроить так, чтобы оно не работало вечность, чтобы было как-то адекватно. Это прямо челлендж, я согласен.

[1:24:41] Владимир: А знаешь, у меня сейчас есть свежее — это как раз написание фаззера. Я не знаю, ты фаззеры писал, не писал?

[1:24:48] Александр: Я, кстати, хотел спросить у тебя: а что ты для фаззинга использовал, собственно? Что-то готовое или своё написал?

[1:24:52] Владимир: Ну конечно, готовое. Есть два направления фаззинга. Фаззинг — это когда ты генерируешь случайную последовательность байт, подаёшь её в приложение и смотришь, смогло оно декодировать или нет. Это, кстати, очень актуальная задача для JDBC-драйвера — вот прямо для них. Это суперактуально, потому что действительно: база тебе что-то присылает, тебе нужно это раскодировать и банально не упасть, out of memory не вызвать на какой-то случайной последовательности байт. Но на самом деле у тебя может база оказаться злонамеренная — и она тебе прислала что-то и убила твой клиент; ну там, кто-то вместо базы тебе встрял и убил. Кто-то положил туда запись с чем-то, что при десериализации, не знаю, тебе открывает шелл.

[1:25:38] Александр: Всё так, да-да-да.

[1:25:40] Владимир: А возможно, это какие-нибудь солнечные лучи, космические, тебе побили поток байт — и у тебя байтик не тот пришёл, и опять всё навернулось. Из-за того, что драйвер на декоде слепо поверил в длину массива и создал массив такой длины. Но из забавного — знаешь, у меня есть с Kafka такая тема; надо посмотреть, починили или нет. Вот давай запишем — я прямо пойду и, может быть, issue заведу. Короче, с Kafka такая тема: когда ты Kafka-клиентом подключаешься к брокеру, оно при подключении начинает протокол парсить. И если ты plain-клиентом подключаешься к TLS-брокеру — ну, TLS-брокер тебе выдаёт TLS-ответ, SSL, вот это всё, — а plain-клиент пытается распарсить это как plain Kafka-протокол: ну такое, типа первый байт — это длина массива, второй байт — это там, и так далее.

[1:26:28] Александр: Ну как раз та самая случайная условно последовательность, неожидаемая, не по протоколу.

[1:26:32] Владимир: Да-да. Но она, получается, не случайная — всегда одинаковая, потому что люди зачастую просто тупят и на TLS-сервер подключаются plain’ом. И Kafka падает с out of memory: потому что там какие-то hello-TLS байтики говорят клиенту «аллоцируй, пожалуйста, полтора гига массив». А у тебя микросервис. Это забавно выглядит, но, конечно, не должно от out of memory падать: оно должно просто сразу падать и говорить, что у вас там сервер палёный, не будем мы с таким работать. [1:27:04] Владимир: Надо посмотреть, актуальна ли ещё эта проблема или нет. Ну а когда такое падает, конечно, рано или поздно Клод разберётся, но это вызывает довольно много недоумений, как с этим работать. Это в драйвере такая штука. А с другой стороны, есть в драйвере проблема — как я говорил, куча геттеров, куча сеттеров. То есть ты можешь записать одни и те же данные — ну, не знаю, timestamp: ты можешь записать setTime, setCalendar, setObject и в object передать LocalDateTime, Instant… Короче, много всего можно передать в базу, а потом можно прочитать всеми теми же самыми штуками. И вот здесь другой тип фаззинга: когда у тебя есть готовый, условно, Java-объект — нормальный готовый Java-объект: строка какая-нибудь, массивчик, структурка, какой-нибудь определённый timestamp, — и ты его записываешь, допустим, в кодек и проверяешь, что кодек может его декодировать. То есть тут ты фаззишь не рандомную последовательность байт, а рандомишь уже такие структурные объекты. Это немножко другой тип фаззинга, и ты проверяешь, что кодеки могут кодировать и декодировать. Ну, будет странно, если у тебя кодек смог закодировать, а назад потом нет.

[1:28:12] Александр: Да, то есть что-то, наверное, уже сломано.

[1:28:14] Владимир: Вот у меня такие баги и находились.

[1:28:15] Александр: Инвариант, кстати, который надо проверять: на всех инпутах инвариант должен соблюдаться.

[1:28:19] Владимир: Да, инвариант — это вот property-based тестирование. И я нашёл, знаешь, очень смешно. Я всю эту историю с кодеками начинал ещё, когда Клода не было — ну, разумеется, она никуда не пошла. Сейчас, когда кодить гораздо проще стало, я пошёл кодить, дошёл до того, что надо тестировать, нашёл заново библиотеку для этого фаззинга — и нашёл там issue. Свою же, шестилетней давности. Знаешь, эта библиотека была хардкодом написана под JUnit 4, а он уже устарел, — и у меня там было предложение: давайте разделим движок и имплементацию, чтобы можно было запускаться на разных. Ну ладно, я, короче, нашёл ещё раз всё то же самое, накодил, разумеется, сделал поддержку. Это очень забавно сейчас получается: когда ты находишь свои же issues шести-восьмилетней давности, их чинишь — и оно типа работает. Но здесь забавно, потому что эта библиотека Клодом подключилась на раз, всё хорошо, — и она прямо с учётом coverage фаззит. То есть она не просто пытается подавать рандомные строчки, рандомные объекты, а смотрит на code coverage в процессе работы и пытается подавать такие входы, которые затрагивают новые ветки.

[1:29:36] Александр: Да, я такую библиотеку писал — у меня дипломная работа в магистратуре была, вот прямо она.

[1:29:43] Владимир: Это очень круто.

[1:29:43] Александр: Генетический алгоритм. Да, генетический алгоритм — и у них есть ещё более точное название для конкретного подхода, типа property-based что-то тестинг. Когда ты, по сути, можешь генерировать бесконечное количество разных инпутов, — и как определиться, какой инпут оставить в конечном датасете, а какой выкинуть, потому что он идёт по тому же самому пути в коде, по которому прошёл предыдущий? Они разделяют это на классы, классы инпутов — по-моему, так это называется, я уже забыл: то есть каждый класс инпута ведёт в отдельный code path. И ты оставляешь по одному экземпляру инпута из каждого класса, и твоя задача оптимизации — найти все классы и по одному инпуту из каждого класса, всё. И тогда у тебя это решено. И там не только код — там и code coverage разный бывает, как его мерить: можно мерить построчно, по инструкциям, по блокам. То есть это тоже интересно: coverage — if зашёл налево и направо, это if; там есть интересные развёртки этих инструкций. Но вообще говоря, это задача, которая не решается на сто процентов в некоторых случаях — то есть ты иногда можешь просто не подобрать этот инпут. С другой стороны, ты можешь распарсить код и понять, а куда же я всё-таки не зашёл, что там вообще такое, и пытаться эвристиками придумать обратно, какой должен быть под это инпут, — но это очень сложная задача. И мне кажется, как раз с Клодом сейчас, может быть, можно написать какое-то новое поколение фаззеров, которое делает анализ кода и исходя из этого полностью покрывает фаззингом все возможные пути использования, с глубиной, не знаю, максимальной. Ну да, это интересная тема, я прямо вспомнил: у меня была задача — я, по-моему, про это в подкасте говорил, — что нужно было дать класс на входе, на Java или Spring, и написать на него юнит-тест. Вот такую задачу без нейронок я решал с помощью генетических алгоритмов — и, кстати, получалось. Это было круто. Но давай обратно к твоим фаззерам, которые ты пофиксил.

[1:31:49] Владимир: Да, так вот: я его пофиксил, но мейнтейнер, конечно, удивился — к нему пришли с PR через шесть лет. Говорит, он собирался проект архивировать уже в этом году, там действительно активности особо не было, — и тут, знаешь, к нему свалилось. Но забавно получается, что он скрестил вот этот JQF-фаззер и — ещё у JetBrains на GitHub лежит JetCheck, property-based генератор, широко известный в узких кругах. Короче, эти две тулы скрестились, народ более-менее принял PR, JetBrains даже версию JetCheck выпустили. И в итоге какие-то баги нашлись. Ну то есть я начал писать, нашёл баги — например, такую: ты записываешь строкой «плюс бесконечность», а потом пытаешься распарсить getTime. Что должно произойти? Вот такого типа ошибки — что там парсить, не парсить. Вроде нашлось, вроде бы неплохо. Причём я фаззер, знаешь, не учил писать «плюс бесконечность»: я сам по себе фаззер написал — ну, как не я, конечно, Клод, — и не учил его, написал просто «давай рандомную строку», и всё. А он сам догадался, что надо написать «плюс бесконечность». Это очень прикольно.

[1:33:08] Александр: Кстати, это не «догадался» — это эволюционно подобрал набор символов, которые вот это сделали. То есть он вообще не знает значения этого слова, он просто перебором, чистым перебором пришёл.

[1:33:20] Владимир: Да-да. Но довольно быстро он к этому пришёл — то есть это не то, что я там часами запускал; я думаю, если ещё на часы запустить, может быть, можно ещё что-то получше сделать. Но это очень классно, потому что если бы я просто рандомил — давайте введём рандомный вход и посмотрим, что у нас кодек не упал, — скорее всего, оно бы ничего не нашло. А вот с учётом coverage, с учётом этого всего… Может быть, можно Клодом понаписать что-то получше, но в принципе тул готовый был, почему бы не взять — и просто работает. Но там есть и обратная сторона. С одной стороны, я всё это понимаю на уровне идей: вот как мы сейчас обсудили — идея понятная, и это как раз хорошо, что тебе сейчас AI очень много реализует из твоих идей. Я говорю: давай это сделаем, — давай, всё, поехали, понаписали. Но я потом посмотрел код вот этого фаззера, который она понаписала. Он, ты знаешь, вообще не соответствует тому, что я просил. То есть я говорю: давай все геттеры протестируем. Оно написало десять из двадцати шести. Я потом прихожу, говорю: а где остальные? — А, точно, остальных нет, ладно, давай добавим. Или, знаешь, я прямо явно говорил: у меня getObject — когда ты говоришь getObject, ты ещё передаёшь класс: какого типа объект ты хочешь получить? То есть ты хочешь получить OffsetTimestamp или LocalTimestamp, неважно. И ты вот это должен проверять — что ты разные типы вызываешь. Я явно говорил: товарищ дорогой, давай проверять так и так. И всё — а там Object.class, всё. То есть Object.class тебе как бы хватит на все случаи жизни. Ну, то есть понимаешь, задача не самая простая, потому что тебе надо ещё как-то описать, какие допустимые значения: если ты туда записал, не знаю, int, то читать его как дату — это какая-то ерунда, оно должно падать как минимум. По факту, кстати, не падало — оно нашло ещё одну багу. Оно нашло багу, что если записать long и прочитать как дату, оно неявно делало там Date.valueOf и считало как unix-эпоху. В результате ты мог получить какую-то корявую дату, а спека говорит, что просто падать надо в таком случае. Я тоже отдельно завёл реестр того, какие вообще допустимые конверсии туда-сюда. Но ты знаешь, оно очень криво сделало абстракцию: очень много дублирований вот этих словарей — того, что допустимо, недопустимо. Это код, который прямо противно смотреть. Ты смотришь — он одноразовый, короче: он по месту написан, вот этот фаззер, без какой-то вдумчивости, без reusable. И когда ты говоришь «давай напишем ещё один, который немножко другой», она: ладно, ещё один, вообще немножко другой, там похожий. Короче, это беда.

[1:36:04] Александр: Может быть, знаешь, потому что в обучающих выборках реально нет фаззеров? Ну или мало их, очень мало — это редкость.

[1:36:08] Владимир: Тут я согласен: культура написания вообще отсутствует. Поэтому здесь это ещё один случай, где я реально смотрю на код и понимаю, что это очень плохой код. Ну, он какую-то задачу достигает, что-то он фаззит. Но я, во-первых, прямо глядя на код, понимаю, где он не закрывает. А во-вторых, я понимаю, что там надо дедуплицировать. Ну как я понимаю? Я смотрю — у него похожие. Я спрашиваю: вот эти два класса очень похожи, давай объединим. Не-не-не… [1:36:34] Владимир: …нельзя, они разные. Короче, она очень убедительно отвечает, что чинить очень сложно и так далее. Ну а это ещё один из экспериментов, который я в Fable зарядил: говорю — Fable, посмотри, скажи, как по-нормальному написать, чтобы не дублировалось.

[1:36:52] Александр: Каждый нормальный, уважающий себя программист пришёл в Fable и попросил его посмотреть.

[1:36:58] Владимир: Ты знаешь, что он сказал? Оно выкатило такой план: говорит, тебе надо вот так делать. Я смотрю — всё хорошо, выглядит правильно. А потом этот план я даю: вот, моделька, посмотри, мне тут насоветовали. И угадай, что Клод сказал?

[1:37:13] Александр: Клод, который Opus.

[1:37:14] Владимир: Да, Клод, который Opus, — посмотрев на план от Fable. Что он тебе сказал?

[1:37:20] Александр: Слушай, ну либо он сказал, что это всё хрень, либо как-то криво — вообще не понял, что от него хотят. Смотри, вот я слышал такое мнение, что любая модель, довольно актуальная, очень похожа на инженера: если инженеру придут и скажут какую-то задачу, он скажет — а может, я не буду её вообще делать? Чего тут хотите, какая-то непонятная задача.

[1:37:38] Владимир: Значит, Opus сказал: ну смотри, дорогой Володя, тебе шашечки или ехать? То есть если ты хочешь тестовое покрытие наращивать — не парься, пиши ещё, и будет у тебя расти тестовое покрытие. Ну а если тебе очень шашечки нужны — можно, конечно, рефакторинг сделать, там как по плану. План нормальный, всё хорошо.

[1:38:00] Александр: Ну классно, что ответил.

[1:38:01] Владимир: Да, и тут я тоже так смотрю: а ведь правду говорит.

[1:38:08] Александр: Тебе что надо вообще?

[1:38:10] Владимир: Да-да. Но внутренне я, конечно, пойду рефакторить, потому что вот это дублирование прямо супер странное.

[1:38:15] Александр: Слушай, ну у тебя задача, конечно, очень объёмная — во-первых, с точки зрения объёма кода. И код такой интересный, редко встречающийся: подобные вещи вообще на Java — это прямо реально мало кода, то есть это драйверы, какие-нибудь коннекторы, какие-нибудь особые клиенты; в целом не самый распространённый код. И в то же время — вот мне кажется, знаешь, что интересно на этом кейсе: что ты так прощупываешь реальные пределы текущих моделей. Просто есть люди, которые пишут код, которые модели вот так вот щёлкают каждый раз, и у них всё идеально, они такие: всё-всё решим. А когда ты начинаешь двигать и посматривать вот эти границы — а где реально начинают фигню делать? И вот это, мне кажется, ценность текущего выпуска подкаста для тех, кто полчаса назад не дропнулся после моего тейка, что не надо никого слушать и надо на своём опыте изучать. Они могут для себя вынести как раз, что есть такие кейсы, на которых реально ещё сложно: то есть вот он предел — условно, на этом конце континуума мы вот здесь находимся, и дальше пока надо двигаться с экспертизой, с человеком, с ревью кода, с направлением. Само пока ещё не может. Это круто, это такой инсайтик я для себя намайнил. Потому что на моих задачах, даже на самых продвинутых, у меня как-то получается направлять модель так, чтобы она делала то, что мне нужно. И, возможно — я сейчас думаю, — я просто в клиент не лазил; думаю, если залезу, возможно, с такими же проблемами столкнусь, как и ты. Это интересно для меня. Но в целом про пределы текущих моделей, про их границы, про их возможности, мне кажется, неплохо получилось.

[1:40:04] Владимир: Но более ходовые штуки, как профилирование, например, — здесь тоже у меня иногда возникали вопросы. Я говорю: а может, здесь напишем как-то пооптимальнее? Она пошла, написала бенчмарк, сравнила, говорит: нет, написано нормально, сильно быстрее не будет, а код лишний — давай, короче, не будем. Ну давай, ладно.

[1:40:23] Александр: Это классно.

[1:40:23] Владимир: Да, вот это прямо очень классно, что оно не ленится, идёт, пишет и так далее. Доходит, конечно, до абсурда иногда. Знаешь, у меня была история: возник out of memory — ну типа out of memory, хипдамп, всё. Я говорю: ну посмотри, что там вообще не так с этим хипдампом. И Opus пошёл, написал парсер хипдампа — просто взял, написал парсер хипдампа на Java, распарсил, нашёл багу, починил. То есть он просто заваншотил этот самый парсер, там триста строк, и с помощью него нашёл багу.

[1:40:57] Александр: Ну это вообще жесть.

[1:41:01] Владимир: И багу правильно починил, что удивительно. Я ему, знаешь, прямо говорю: ну вот посмотри, там есть MAT, есть CLI, ещё что-то, может, какие-то готовые CLI-ки он возьмёт. А мне говорит: это всё шляпа, долго разбираться, я сейчас быстренько сам сделаю.

[1:41:13] Александр: Красавчик. Просто тулинг, который он под себя иногда пишет, меня тоже поражает. И в этом плане — если перейти к тому, что хорошо получается у текущих моделей, на что можно прямо взять и довериться, — это поиск багов по каким-то артефактам. То есть если у тебя есть хипдамп, логи — даже если их довольно много, он их не все будет в контекст пихать, он их погрепает и аккуратненько найдёт. То есть вот эти артефакты: ну, типа логи, хипдампы, трейсы…

[1:41:47] Владимир: Трассировки, метрики, да.

[1:41:49] Александр: Да. Ну, в основном, конечно, это всё-таки логи, а какие-то трейсы, ошибки. И когда это есть — просто закидываешь, и нормально настроенный проект с работающим харнесом, который он понимает, — и реально это частенько ваншот. Просто задача — тишина. Чуть-чуть там подправишь: давай тут ещё, может, тестик напишем, может быть, ещё что-нибудь такое. Но в целом очень круто.

[1:42:11] Владимир: Вот по поводу таких багов. По поводу логов, кстати, интересный вопрос: я довольно часто делал историю — посмотри, тут упала CI, почини.

[1:42:21] Александр: Вообще изи, да.

[1:42:23] Владимир: Вообще изи. Но, ты знаешь, она начинает грепать туда-сюда. Я в какой-то момент понял, что у меня в проекте CI определённым образом устроена, и говорю: давай напишем скрипт, который сразу загрепает ошибки. И вот это получается: то есть можно, с одной стороны, довериться модели, чтобы она каждый раз грепы заново подбирала, а с другой стороны — ты пишешь скрипт, который заведомо на этом проекте правильные грепы делает. И всё равно такого типа тулинг нужен.

[1:42:53] Александр: Я так и ставлю задачу, когда подобное вижу: говорю — смотри, тебе нужно будет очень часто разгребать подобные проблемы, которые ты сейчас разгрёб. Давай подумаем над тем, как это можно автоматизировать, напишем CLI: сделай мне дизайн, какие ты там команды хочешь, — посмотрю, и полный газ. И, как правило, он всё чётко делает: да-да, нормально, смотри — вот здесь мне нужен аудит, здесь мне нужно уметь перезапустить конкретный тест, а здесь мне нужно получить аутпут этого теста. И я такой: да-да-да, всё, давай. И потом ты добавляешь: а теперь вот этот тул используй для диагностики проблем. И как по маслу потом — просто он фигачит офигительно. Ещё такую же тему, например, я для себя сделал с диагностикой проблем в кубере. На dev-кластере я настроил доступ и говорю: ну вот смотри, у тебя есть n подов, n сервисов, вот здесь у тебя GitOps-репа, вот здесь Argo CD, вот здесь Helm-чарты, вот это — короче, всё это имей в виду. А теперь смотри: мне нужно, чтобы ты мог легко, быстро деплоить, настраивать поды, разворачивать новые, смотреть логи, что всё работает, и репортить мне, когда уже всё готово, — чтобы я просто прошёл и конечный результат просмотрел. Давай напишем тулу. И вот у меня там есть условно своя обёртка над kubectl, в которой у него restart, diagnose, trace, — и вот это всё он себе написал, использует, просто офигенно. То есть какие-то кросс-микросервисные проблемы, которые возникают от череды последовательных действий: условно, сделал какую-то запись, она попала на S3, другой сервис подхватил, записал в базу запись, а тот сервис упал. Вот это всё он может протрейсить и сказать: а, да, тут фигня, тут на самом деле в том сервисе у тебя конфиг не сделан — я уже поправил, передеплоил, проверяй. Ты такой: вау. И вот такие тулы для диагностики, конечно, просто ускоряют. Он так или иначе всё равно дойдёт, но если это задача повторяющаяся, то, конечно, автоматизировать.

[1:44:52] Владимир: Но сам по себе он не дойдёт — это только ты ему должен сказать, что задача повторяющаяся.

[1:44:58] Александр: Да-да, вот именно. Вот до чего он не доходит — что это повторяющаяся задача, что здесь бы хорошо автоматизировать. Потому что он как будто натренирован решить задачу — и он решит её. Но он не сделает так, чтобы в следующий раз решить её можно было быстрее. Вот мы тут тоже ещё одну грань современных моделей нашли — что всё-таки не до конца. Но я думаю, они к этому придут: это довольно очевидное направление оптимизации текущих моделей — что они будут под себя тулинг всё лучше писать.

[1:45:28] Владимир: Они уже неплохо пишут. Ну то есть я просто вспоминаю, что было год назад: модели до Opus что-то там на Python писали, половину времени их дебажили, бедняги, а потом что-то выдавали. То, что сейчас — shell-скрипты, которые он под себя пишет, в temporary-директорию делает анализ, потом это всё удаляет, — это уже next level. И следующий level, возможно, какие-то CLI-тулы, ну, посмотрим.

[1:45:54] Александр: В этом плане я тоже, когда думаю: а чего бы в комьюнити такого классного принести — какую-нибудь автоматизацию, что-нибудь написать, что было бы полезно, — потом всегда обрубаю себя: да блин, ну следующее поколение моделей… [1:46:06] Александр: …это уже сделает. Ну вот они реально это сделают, потому что это очевидно — это очевидное направление улучшения технологии, и оно будет. То что я сейчас это сделаю? Вот я не знаю, есть ли какие-то направления, которые, может быть, не настолько очевидны — или очевидны, но не придут в следующее поколение моделей? Есть ли у тебя такое понимание?

[1:46:26] Владимир: «Очевидно не придут»… Ну, просто говорят: не знаю, надо шарить за архитектуру. Я такой: ну уже шарит нормально. Надо ли — вопрос. По факту этот вопрос эквивалентен тому, что мы обсуждали про ограничения моделей: если ты говоришь, что чего-то не придёт в будущих, это, во-первых, должно уже отсутствовать сейчас — потому что если модель сейчас уже умеет писать на Python, ну значит, и следующая тоже будет. А во-вторых, ты должен как-то понять: ну, наверное, это не починят. Вот интересные моменты — то есть тут надо обсуждать фейлы.

[1:47:04] Александр: Да, как модель фейлится — где она себя ведёт не так.

[1:47:07] Владимир: У меня одно из таких поведений — это когда она начинает дебажить. И сейчас она очень плохо дебажит, в моём понимании. Ну, как очень плохо — она постоянно пытается декомпилировать код. Где-то это её спасает, но где-то прямо выглядит странно: типа, у тебя падает ошибка в Spring, а она такая — а, Spring, пойду найду джарник, декомпилирую класс, вот точно, по байт-коду, тут вот так вот. Я, конечно, понимаю, но, по-моему, лучше было исходник читать. Не знаю, насколько часто ты с таким поведением сталкиваешься, — но у меня модель очень часто уходит в анализ не по исходникам, а непонятно как.

[1:48:09] Александр: Ну да, бывает такое, я это видел, наблюдал. Когда Opus такое вытворил первый раз на моей памяти — что он пошёл, декомпилировал, разобрался и сделал, — я такой… Ну, для меня как для инженера раньше этот процесс — это жесть: то есть всё, назад пути нет, ты всё перепробовал, ничего не помогает — ну пойду, короче, туда. Я думаю: а как ты это так легко делаешь? Я был в шоке, я тогда офигел — я такой: да, вот оно, теперь они могут. У меня такой подход был только тогда, когда, знаешь, исходники посмотрел — такого быть не может; ты проверяешь байт-код, а там реально не так: то есть или у них с ошибкой скомпилировано, или джарник одной версии, а исходники другой, — и ты вот это уже проверяешь.

[1:48:31] Владимир: Да, но здесь тоже вопрос возвращается: является ли это эффективным способом решения проблемы — или можно было бы проще и сэкономить и токены, и время, и мощности; то есть ты мог бы просто банально не греть планету. Я поэтому даже хотел у тебя спросить: как-то ты шаришь сеткам свои знания или конвенции по тому, где искать исходники? Потому что такое ощущение… Ну вот я работаю с определённым набором проектов — не знаю, двадцать-пятьдесят, — рано или поздно я их затрагиваю. На том же самом Spring я активно не пишу, но иногда что-то возникает, и у меня клон Spring есть. Можно было бы логично объяснить сетке: смотри, если ты хочешь найти какой-то проект — посмотри, может быть, есть уже форк готовый, и не надо тебе декомпилировать, а просто бери и изучай, если ещё надо. Ты такую задачу решаешь или просто не глядя?

[1:49:24] Александр: Слушай, смотри: во-первых, это стек-специфичная проблема, актуальная исключительно для Java. Потому что в Go у тебя это лежит рядом; в Rust бинарный код он тоже смотреть не будет — он будет искать исходный, если нужно. То есть так как у нас есть байт-код, вот у него все ручки чешутся, и реально его читать. У меня так получается, что я огромное количество сейчас фигачу на Go и на Rust — просто потому, что это настолько более быстро и эффективно: что-то с нуля сделать на Go — ну просто невероятно. Поэтому на Java я делаю только необходимые задачи — то, что надо на Java, потому что существующая кодовая база. И там я такие проблемы встречал, но они настолько редкие были в моих решениях, что я им не придал значения, — потому что основной мой фокус это Go-стек.

[1:50:15] Владимир: А как она узнает правила пользования сторонними библиотеками? То есть ты считаешь, что модель сама должна знать, как пользоваться, — или она должна ридмишку почитать, или что? Откуда она вообще узнает про то, как этой библиотекой правильно пользоваться, что создавать, что передавать? Про Go, про что угодно.

[1:50:34] Александр: А про Go там, по-моему, у тебя сорцы лежат локально: если ты стандартно используешь Go package manager, то ты прямо из git их себе берёшь, и там есть readme. И мне кажется, возможно, из-за этого оно так лихо всё и делает. Возможно, просто из-за того, что язык сильно проще — тут надо поразбираться. Я не знаю, как должно быть, но мне кажется, что мы как комьюнити всё-таки должны прийти к какому-то артефакту. В том плане, что должна быть какая-то спецификация библиотеки, которая деливерится и поставляется клиентам, чтобы они такие: оп, да, вот так вот смотреть. Но вообще говоря, мне как инженеру — ну есть же интерфейсы.

[1:51:17] Владимир: Ну а она откуда про них узнает, про эти интерфейсы? Ты библиотечку-то подключил — они же где-то должны быть. Она или должна, не знаю, GitHub почитать, что ты подключил, или должна куда-то локально скачать и почитать.

[1:51:28] Александр: Да, я понимаю: мы всё-таки избалованы IDE и тем, что IDE всегда тебе подтягивает эти сорцы, и ты, смотря в библиотеку, видишь сорцы. Это очень такая иллюзия — я понимаю, что я как раз в эту ловушку и попался.

[1:51:44] Владимир: Ты никакие MCP-шки, CLAUDE.md не пишешь для того, чтобы направлять агента, где искать вот это всё?

[1:51:50] Александр: Вообще нет.

[1:51:52] Владимир: Ну, это довольно редкая проблема — но вот если подумать, а как должно быть? Давай подумаем, как можно было бы именно в Java эту проблему решить для Клода.

[1:52:04] Александр: Слушай, а является ли — мне просто интересно — то, что он в байт-коде интерфейс посмотрит, проблемой?

[1:52:11] Владимир: Ну, мне кажется, проблема, потому что там всё-таки слишком низкоуровнево: там много байт-кода для выражения какой-то очень простой мысли. Потому что у тебя в самом байт-коде какие-то ссылки на метод — там не написано «вызываем какой-то метод», там «вызываем инструкцию номер двадцать пять», а двадцать пять — это где-то там наверху. И банально в обучающей выборке этого тоже гораздо меньше: то есть кода такого простого, как пишут, как не пишут, что вообще происходит, — гораздо больше нормального. Поэтому из общих соображений модель должна лучше понимать нормальный код, и он более ёмкий: там есть комментарии, почему что написано, — а у тебя в байт-коде нет комментариев. Поэтому вроде бы в теории это должно улучшать. И, знаешь, как… Когда ты подключаешь какую-то библиотеку, она может часть задач упрощать: то есть как, не знаю, правильно взять трейсинг-заголовки из HTTP-запроса. Ты можешь request header вручную парсить, а можешь библиотечкой — чтобы она правильно, не ошиблась и так далее. И вот здесь есть риск, что у тебя библиотечку подключат, а парсить всё равно будет по-простому: ну а что, не умеешь, что ли, распарсить? Сам не умею. А кажется, что нет, не умею. И здесь хотелось бы, чтобы по факту, когда ты подключаешь библиотечку — не знаю, Java, Go, плюс-минус неважно, — ты каким-то образом подключал и базу знаний, как этой штукой пользоваться: то, что по сути человек неявно имеет в виду, когда он пишет библиотеку.

[1:53:42] Александр: Слушай, а может ли являться такой штукой JavaDoc?

[1:53:48] Владимир: Ну, не совсем может, конечно, — но и не совсем нет. Мне кажется, JavaDoc немножко для другого; вот обычно это статьи на какой-то вики — как какой-то более расширенный комментарий. А JavaDoc — это, знаешь, уже такое: принимает ли этот метод null или нет. Ты смотришь и говоришь: если он там null на входе, то он упадёт — ага, хорошо, не будем null передавать. Это окей для JavaDoc. А когда ты говоришь, что надо вот эти методы в таком порядке вызывать или что вообще надо вызывать именно вот этот класс с этими методами для решения такой задачи, — это непонятно.

[1:54:21] Александр: Ну, package-info, что ли?

[1:54:25] Владимир: Наверное. Потому что я его никогда не писал. Ты писал package-info в Java?

[1:54:30] Александр: Вообще никогда. Слушай, я вот думаю… Я вспомнил, что у себя в Java-проектах я такую практику сделал. Это, правда, не про использование сторонних библиотек, а про использование даже… Мультимодульный Gradle-проект, у тебя там, не знаю, десятки модулей. И в целом ты должен так же — каждый модуль это условно библиотека для внутреннего пользования, — и вот надо как-то описать, как её использовать. И у меня есть такие файлы, которые называются кукбуками: dev-кукбук, agent-dev-кукбук в каждом модуле. И как раз в CLAUDE.md прописан просто один индекс: что когда ты работаешь с модулем — смотри кукбук; в каждом модуле он лежит вот по такому-то пути. То есть такая лёгкая индексация — вроде не ошибается. И в ревьюере, в агенте, который ревьюит, есть всегда «проверь, что по кукбукам…»

[1:55:27] Владимир: …надо обновить, надо обновить.

[1:55:28] Александр: Да, то есть эти правила — и они работают. И в этом плане, может быть, поэтому я не особо… [1:55:39] Александр: А вот если ты подключаешь что-то снаружи — мне кажется, что что-то подобное должно деливериться как часть джарника.

[1:55:47] Владимир: А по-другому как? Вот это да. Как часть джарника — тут разные аспекты есть: есть «как пользоваться», есть «как трублшутить», например.

[1:55:57] Александр: Да-да. Как пользоваться, как трублшутить. То есть что бы я туда включил, вот в такой кукбук, который поставляется с джарником? Я бы включил туда, во-первых, понятное дело, GitHub: то есть сорцы здесь, релизы здесь, мейнтейнеры здесь, заведённые issues здесь. Быстрый такой индекс — чтобы если уже есть issue в GitHub, а ты нашёл багу в библиотеке, то она либо уже есть, либо вот так её заводи. То есть вот этот бэкпортинг агентами проблем в твою библиотеку — прикольная штука: когда ты её автоматизируешь, ты такой — ой, а сколько всего мне начинает бэкпортиться, оказывается, потому что люди часто забивают. Дальше — понятное дело, как эту библиотеку использовать, в каких случаях; do’s и don’ts, наверное, какие-то такие: используйте вот здесь, не используйте вот здесь. Не надо с помощью моей библиотеки для парсинга HTTP-заголовков парсить gRPC с помощью кастомного плагина — не надо, не предусмотрено. Трублшутинг, наверное: какие-то дебаг-истории, логи, как настроить, посмотреть — как активировать логи, какие есть проперти, которые нужны для такой отладки. Потому что откуда ты их — либо по исходникам будешь выискивать, либо напишешь. И причём там было бы то, что я бы сказал агентам своих пользователей: если ты долго ковырялся с моей библиотекой и видишь, что можно улучшить, — gotchas так называемые — репорть вот сюда, вот темплейт. И таким образом комьюнити само бы себя развивало. Я так на внутренних проектах стараюсь делать: вот на одном сделал и смотрю — прикольно, улучшается, эволюционирует вот эта документация не моими руками. Это круто. И что бы ещё там? Ну например, я, кстати, про свои библиотеки вспомнил — в плане модулей: как писать в этом модуле интеграционные тесты? Вот тебе темплейт. То есть прямо темплейт: берёшь, копипастишь и вставляешь в нужные строчки просто вызовы других. Там и жизненные циклы, остановка кластера, запуск — вот это всё уже есть, а ты просто кейсы накидай.

[1:58:02] Владимир: Крутая штука, сильно прямо работает. Так, что ещё такого в голову приходит? Да вроде всё, на первый взгляд. А есть ли у нас… То есть я, получается, могу это просто как часть релиза, как мейнтейнер библиотеки, сделать — как часть релиза, который просто в корневой jar кладёт md-файл, грубо говоря, или набор?

[1:58:24] Александр: Ну например, да. Проблема в том, что нет стандарта — это согласование: агенты не будут оттуда брать. Но с другой стороны — ну фиг, можно посмотреть, что они делают. Если они туда сейчас смотрят, то, может быть, оно и догадается. Может быть, кстати, если оно джарку декомпилирует, то увидит там md-файл — может быть, воспользуется. Но хорошо бы, конечно, чтобы стандарт появился.

[1:58:49] Владимир: Ну вот мы с тобой сейчас обсудили вопрос, научатся ли будущие модели такому сами. Потому что сейчас, по сути, люди — это же самое дело: вот ты нашёл какую-то рандомную джарку, которая называется spring.jar, ты открыл, посмотрел — о, похоже, это всё-таки Spring Framework, а не Spring Boot; пошёл, нашёл GitHub, за-репортил. То есть ты в принципе сам сейчас это делаешь. И моделька тоже на это способна — но её надо пинать, скорее всего, чтобы она пошла и разобралась. Возможно, будущие прямо действительно научатся это делать самостоятельно. Фиг знает, я пока не верю: ну то есть я думал, что мы ещё год-два проживём, и пока всё это нужно будет.

[1:59:30] Александр: Ну, к слову о том, что нужно, что не нужно: я тоже постоянно себе такой вопрос задаю — такое уж время. И я так мыслю: вот мне много чего интересно, но, углубившись и закопавшись, упоровшись по какой-то теме, — я с точки зрения своего продвижения в будущем делаю инвестицию или это потеря времени? У меня каждый раз такая вилочка в голове есть. И в этом плане я, конечно, всегда выбираю инвестицию. И вот как ты считаешь: на что сейчас инженеру с точки зрения инвестиций в будущее стоит тратить время?

[2:00:08] Владимир: Значит, на что стоит тратить время для инвестиций в будущее как инженеру. Наверное, надо прощупывать границы. Повторять уже решённые задачи — это неплохой вариант для обучения, но постоянно делать одно и то же, наверное, стрёмная конструкция.

[2:00:26] Александр: Интересно, да, давай зафиксируем это. То есть рисуем в голове такое облачко — давай сферу. И если вы внутри этой сферы — это то, что современные модели решают: всё, это их зона комфорта, они там как рыба в воде. И вот если вы как инженер вместе с этими моделями решаете эти задачи и плаваете в комфортной зоне, то вы не развиваетесь — это не инвестиция, с моей точки зрения. А инвестиция — когда ты утыкаешься в границу этой сферы и такой: опа, а вот здесь не получилось, и так не получилось, а вот так вроде получше. Вот когда такое наступает — здесь как будто бы имеет смысл находиться. То есть нам, инженерам, надо находиться на границах этой сферы, нежели чем внутри неё. Потому что внутри уже модели — и не надо с моделями конкурировать, они лучше. Это потеря времени, всё, отпусти.

[2:01:22] Владимир: Да-да. Но здесь есть обратная сторона: ситуация в том, что пытаться отгрузить на модель то, что ты не знаешь, как сделать руками, — пока странная конструкция. То есть условно сказать «сделай хорошо» можно, «make no mistakes» тоже можно, «плюс ещё надо обязательно» — но будет ли в этом смысл, непонятно. То есть по-хорошему нужно, с одной стороны, находиться на границах того, что ты примерно понимаешь, как делается, а с другой стороны — ты должен всё-таки понимать, как это делается.

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

[2:03:00] Владимир: «Модель знает, я не знаю» — сложная ситуация, потому что ну а как, я не знаю. Я, наверное, либо не отмечал такие задачи, либо не ловил себя на этой мысли. Но вот смотри, как я… Есть куча тулов, которые люди пишут под себя. Например, недавно я делал очередной транскрибатор, который загружает видео с YouTube и ещё откуда-то, разбивает по спикерам и делает сводку — ну, текстовый анализ, кто какой спикер. Казалось бы, сейчас все это делают, всё отлажено и так далее. То есть это как квадратик «модель знает, я не знаю» — я думаю, да. То есть я понимаю идею, но совершенно не разбираюсь, какие там сейчас модели актуальны, не актуальны, как вообще что делается. На уровне концепции я, наверное, понимаю, что это такое; сам бы я мог написать, но надо было бы довольно много искать — ну, как довольно много: наверное, где-то есть примеры на Python и так далее. Но я вот этой модельке загрузил, говорю: давай, короче, транскрибировать. Она такая: оба-на, у вас тут созвон, ну, пара человек — триста шестьдесят спикеров. Ну, это человек читает очередную версию доклада — там двое на созвоне, а она говорит: триста шестьдесят человек. Это вот то, что выдаёт Opus просто по такой просьбе, хотя я ему ставил задачу, что там в принципе будет, какого типа созвон.

[2:04:25] Александр: А это почему? Неправильно задачу поставил или что? Почему там триста шестьдесят?

[2:04:29] Владимир: Я так, наугад сказал. Ну, наверное, смотри: у тебя есть паузы или какие-то небольшие «да», «мы», «а», «у» — то есть когда человек что-нибудь сказал на полсекунды, а модель уже пытается понять, это какой-то старый человек, это новый человек и так далее. Говорит: давай, короче, для распознавания людей использовать от пяти секунд — вот пять секунд плюс, там будем смотреть, что же это человек. А потом все эти короткие фразы либо сведём к известным, либо скажем, что это просто кто-то неизвестный. А ты такой: а, какая идея! Давай, короче, сделаем. И даже пошла — всё, одним промптом всё сделала, и после этого оказалось два человека, как и надо. Соответственно, что? Я вот не знаю. Идея — ну наверняка все так делают. [2:05:09] Владимир: Вот если бы кто-то… Ну вообще я бы ожидал, что сама модель так и должна была сделать, честно говоря. Я думаю, что многие так делают, кто разбирается в теме, — наверняка какие-то пороги есть. Но что получается? Это граница того, что я знаю, а модель нет? Как-то… Я бы не ставил себя на такую позицию, что я типа сильно умею: мне кажется, конкретно эта ситуация наверняка уже сто пятьсот раз исследована — как правильно транскрибировать и привязывать спикеров к их голосам, уже всё должно быть решено. Но по факту, когда ты такую задачу делаешь, оказывается, что нет.

[2:05:45] Александр: Да, и такие задачи лучше всего, насколько я знаю, всё ещё решаются просто разделением аудиодорожек в сорцах — и лучше не придумаешь. Ну а когда у тебя финальный уже сведённый mp3, тут, конечно, приходится приседать. Но возвращаясь к этой теме — что ты не знаешь, а модель знает, или вы оба не знаете: мне кажется, тут важно понять идею самих границ. И что двигать границы — модели или свои — это то, чем, наверное, стоит заниматься инженеру: чувствовать эти границы, находить, понимать, что это границы, и двигать их. Мне кажется, это неплохой инсайт под конец записи — чем, наверное, стоит заниматься. В то же время есть такие мысли, что ты же перестаёшь писать код, перестаёшь что-то делать, забываешь — у тебя этот навык атрофируется, и ты уже не такой крутой инженер. Вот я не знаю насчёт постоянной практики написания кода — как ты думаешь, она актуальна?

[2:06:51] Владимир: Ну, сейчас, наверное, ещё пока да, я думаю, но как будто бы…

[2:06:57] Александр: Потеря ли это времени — если ты сам код пишешь? С точки зрения профессионала и именно работы, а не хобби.

[2:07:03] Владимир: Я думаю, это скорее потеря времени. Хотя в любом случае код ты чаще читаешь, чем пишешь, — вне зависимости от того, кто его пишет: когда пишут коллеги, пишут сети или ещё что-то, ты всё равно код чаще читаешь. Поэтому важнее уметь его читать. Уметь его писать — может быть, какой-то навык, но вопрос, где он тебе нужен. Например, я условно комфортно пишу код на Java и на Kotlin, а Go читаю со словарём. Значит ли это, что мне сейчас срочно нужно уметь идти и писать код на Go? Вот я, честно говоря, не знаю. То есть у меня сетка пишет CLI-ки на Go, и они работают, выполняют задачу. Я иногда смотрю код — но с точки зрения того, какого типа тесты оно написало, что оно проверяло в целом. И то зачастую спрашиваю: а вот такой вход будет ли работать? Я не пишу код на Go — в смысле, руками, — и думаю, что нормально, до тех пор пока я не буду пытаться стать Go-разработчиком. Но, конечно, можно меня поймать на этом вопросе: а можно ли заговорить на английском языке, только читая по-английски? Скорее всего, нельзя. То есть тебе нужно попасть в ситуацию, которая вынуждает тебя учить язык, чтобы ты изнутри был вынужден на нём заговорить: когда, например, все твои знакомые, друзья что-то обсуждают, а ты не можешь слово вставить, и это печально, — и ты такой: блин, надо тогда подучить, чтобы хоть какие-то темы начать обсуждать. Вот какая должна здесь возникнуть ситуация, которая вынудила бы тебя именно код писать? Я не знаю. Можно рассматривать это, знаешь, с точки зрения ассемблера: надо ли уметь писать на ассемблере и на байт-коде? Или — как недавно была картинка в этом же самом твиттере: ну что вы, фуллстек-инженеры, объясните, что это за микросхемка такая? Насколько вы фуллстек-инженеры? И здесь казалось бы… В принципе, раньше это тоже было — у тебя ревью кода: это всё шутки были, что если у тебя в PR пять строк кода, там будет пять комментариев, а если в PR пять тысяч строк кода — ни одного комментария не будет, ну вроде норм. Но в идеале, конечно, хотелось бы смотреть сначала на архитектуру, на то, что вообще концептуально меняется, — потому что любую строчку потом можно поправить, доработать, если это не будет мешать. Ну, кроме того случая, когда ты в public API что-то выкатываешь и потом это поддерживаешь десять лет — это, конечно, больно. Но если ты говоришь не про такие строчки, которые в public API висят, а про детали реализации — ну что, починишь, и всё, какая разница? Тебе не надо париться над каждой строкой. Но а зачем тогда париться над написанием каждой строки? Тут казалось бы: уметь мыслить архитектурно — более важный навык, чем писать код. А это значит, что писать какие-то архитектурные концепты, объяснять другим, как ты что строишь, почему именно так, — вроде более важный навык, чем умение писать строки кода.

[2:10:10] Александр: Да, я тут полностью согласен — что называется, ни дать ни взять. В этом плане у меня ещё есть такие мысли: а кто такой вообще современный программист тогда? Вот ты нанимаешь себе инженера — какие к нему требования нужно выставить, чтобы сказать, что его квалификация высочайшая? Оно как-то очень сильно трансформировалось. И я смотрю — у меня просто довольно радикальная позиция, я думаю, слушатели знают: если человек пишет код руками, а его можно было бы не писать руками… Давай так: есть всё-таки очень маленькое подмножество кода, который всё ещё где-то руками лучше, проще написать. Но вообще говоря, подавляющее, абсолютное большинство кода надо генерировать. Если человек ко мне приходит с рукописным кодом, я сомневаюсь в его квалификации: а ты за X денег, которые ты потратил, программируя руками, — это эффективно? Ты бы мог решить три задачи, а решил одну. За что я эти деньги плачу? Вот такая мысль. И то же самое про ревью: да, есть небольшое количество кода — довольно значимое всё ещё пока, — в который надо вникать. И вот если человек вникает в код, в который вникать не надо, у меня тоже вопрос: а ты на что время тратишь, зачем? Ты в границах вот этой нейронной сети и себя немножко потерялся.

[2:11:33] Владимир: Да-да. Но это, знаешь, вопрос очень коварный. Потому что умение отфильтровывать важное от неважного, во-первых, действительно приходит с опытом, и это показатель — когда человек понимает, что важно, а что неважно. Но с другой стороны, это очень сложно измеримо. Потому что важное и неважное — оно в ощущениях, для конкретного проекта, конкретной задачи и так далее. То есть здесь мы вроде бы считаем безопасность важной, потому что… Или здесь мы считаем нагрузку важной, потому что… Или: здесь это тестовый код, а какая разница, как его писать? Ну, это, наверное, универсальный ответ — что действительно какая разница, как написан тестовый код: на скорость не влияет, ни на что не влияет, тут все сойдутся. Но вот когда более спорные моменты — то вопросики, что считать важным, а что нет. И есть какое-то внутреннее, условно, твоё-моё чувство, что мы считаем важным, — и мы так и напяливаем его на то, что делает человек: да, он действительно подсвечивает важные штуки; нет, он тратит время на неважные штуки. И вот здесь гораздо проще, наверное, как-то с собой сравнить и сказать: похоже, он тратит время на неважные штуки — и такое: нет, похоже, этот человек не той квалификации, которой мне хотелось бы. Но, к сожалению, я не знаю, как это условно измерить. Это может нас вернуть к вопросу, а что будут уметь сетки: мы говорим, что они умеют, не умеют измерять. И, знаешь, я когда-то делал такие штуки: типа, оцени показатель сложности или ещё чего-то от одного до пяти. И оно какую-то цифру выдаёт. Но, к моему сожалению, цифра получается очень рандомная, прямо суперрандомная. Ну, конечно, для простых случаев она просто оценит, но — мы уже говорили, — что дерево Фенвика, так это же вопрос на «раз», любой дурак напишет.

[2:13:26] Александр: Ну, я в институте писал тоже — очень классная штука. Я ходил на курсы олимпиадного программирования, фанател по этой штуке; там всякие классические алгоритмы. Она забавная, эта самая структура данных, тем, что её изобрели не так давно — ну, сейчас уже, конечно, давно, но, по-моему, даже в двухтысячных. То есть условно фундаментальная структура, но изобрели не в пятидесятые прошлого века, — и это уже само по себе какой-то факт: когда что-то новое, какой-то хитрый простой алгоритм изобретают сейчас — мне лично кайфово слушать про такое, само по себе прикольно. Ну и давай пасхалочку раскроем всё-таки: расскажи, что за дерево Фенвика, — для тех, кто дослушал до конца, чтобы они потом могли попробовать.

[2:14:18] Владимир: Да. Значит, дерево, которое помогает найти сумму элементов от нуля до… То есть когда у тебя есть массив чисел, и там лежат эти самые числа, и тебе нужно понять, чему равна сумма чисел, находящихся от нуля до какого-то — или от одного элемента до другого.

[2:14:40] Александр: Так, а числа рандомные и расположены рандомно?

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

[2:15:21] Александр: Оно хранит, получается, дельты — и ты просто дельту где-то меняешь. Мы говорили про что? Про дерево Фенвика и про то, что это такая структура данных, которая хранит дельты, насколько я понимаю, сумм: то есть сколько надо прибавить, чтобы следующее…

[2:15:37] Владимир: Да, она позволяет считать какую-то функцию поверх — ну, не обязательно сумму: она может считать максимум, минимум, вроде бы, или сумму; может быть, только сумму. Здесь я начинаю плавать. Я, знаешь, нахожусь на уровне того, что знаю: такая прикольная структура есть, она может в подобных ситуациях быть нужна, — но мне надо открыть, посмотреть, что она из себя представляет. Это скорее такой пример условно уникально простой штуки: ну типа, она супертопорно простая, но очень классная.

[2:16:06] Александр: Да-да, я понимаю. Ну, в общем-то, я думаю, что мы довольно неплохо поговорили. Мне понравился сам диалог, и в целом произошла такая, я думаю, инженерная синхронизация понимания того, что происходит вокруг и что мы как будто бы двигаемся. Ну вот я, например, для себя думаю: не, норм, всё — моё понимание индустрии ок; люди, которых я как профессионалов уважаю, примерно так же думают. И это круто, потому что времена такие, скажем так, когда много полярных мнений возникает и надо как-то сориентироваться — а ты вообще ещё нюха не потерял? За что тебе большое спасибо. Думаю, слушатели тоже что-то подобное для себя в этом выпуске откопали. Я бы в конце хотел дать тебе слово — свободный микрофон, что хочешь, то и говори. Давай, микрофон твой.

[2:17:02] Владимир: Да, спасибо, Саш, за приглашение — было приятно поговорить, обсудили много интересного. Есть то, что хотелось бы, конечно, проверить: выровняться — интересно, как другие сейчас себя ощущают и что они наавтоматизировали. Потому что иногда складывается ощущение, что народ бежит уже гораздо-гораздо более быстрыми шагами. Но здесь есть, конечно, и вопрос, а как синхронизироваться. Потому что раньше такой точкой были, например, конференции или митапы, где люди собирались и рассказывали свои находки или практики. Я долгое время участвую в конференциях, я в программных комитетах — Java-конференции, тестирования, SmartData, DevOops — до сих пор. И возникает очень сильный вопрос: актуальна ли ещё в принципе конференция? Если ты можешь AI-шкой всё это сделать и можешь в ChatGPT точно такой же ответ, казалось бы, получить, — зачем мне вообще смотреть какие-то видео, не просто ходить, а зачем мне даже видео смотреть, зачем мне читать статьи, если всё и так Клод прочитает? Тот ещё вопрос, на который я себе частично отвечаю так. Во-первых, вот мы с тобой поговорили, обсудили — и это в Клоде тяжело найти. Ты не узнаешь в Клоде, чего Клод не может: он тебе, честно, не признается, пока ты его явно к стенке не прижмёшь. Так и с какими-то обсуждениями фейл-сценариев или опыта на практике — оно, конечно, по-прежнему работает. Но вопрос, куда идёт индустрия, прямо гораздо, гораздо острее, чем раньше. Социума нет в Клоде, вот что.

[2:18:51] Александр: Я думаю, что на этой фразе — что в Клоде нет социума — мы можем и закончить и оставить с этой фразой наших слушателей. И до следующего выпуска. Всем пока. Володя, спасибо за то, что пришёл.

[2:19:03] Владимир: Спасибо за приглашение.