Куда войти?
СтатистикаКуда войти? В IT. Канал о технологиях. Автор: Илья Ильиных, разработчик. Программирую деньги с 2018 года. GH: https://github.com/IlyasYOY VK: https://vk.com/kydavoiti YouTube: https://www.youtube.com/c/Кудавойти
- Последний пост
- 4 авг.
- Последнее чтение
- 22:42
- Постов за неделю
- 0
- Всего постов
- 20
- Тип
- открытый
- Язык
- русский
- Категория
- Технологии
- В каталоге с
- 13 авг.
- 1/24сутки в ленте
- 766
- 1/48двое суток
- 877
- 1/72трое суток
- 946
Оценка по просмотрам недавних постов: пост набирает почти всё за первые сутки.
Посты
Недавно я для себя сделал открытие. Времена, когда я писал код руками прошли и вряд ли вернутся. Теперь я делегирую написание и сбор информации агенту. Я работаю не так, как работал последние годы. Беда пришла откуда я не ждал. В моей практике всегда был набор практик, которые я НИКОГДА не нагрушал, потому что писал код сам. Например, я никогда: не использовал `any`-matcher для моков, не возвращал интерфейсы в Go, и так далее. Я думаю, что у каждого из вас есть набор правил, которые вы себе не прощаете. Вы всегда пишете код так. Точнее писали... Возвращаясь к тому, что код сейчас за меня пишет AI. Ошибки за меня делает AI, ревьюить его надо иначе. Ранее я знал, что я могу не смотреть в своих доработках на self-review. Теперь у меня такого понимания нет. Пусть, я научил нейронки писать так как я хочу, есть куча примеров для нее, но она всегда может посадить багу, потому что она не принципиальная. Да и я мог просто сменить нейронку, а для нее нужны будут свои правила (codex, glm, opus - все пишут по-разному). Я всегда ее должен ревьюить в максимально подробном режиме. Нет таких ошибок, которые она не может не сделать. Тут хочу поделиться приколюхой. Недавно AI сгенерил мне функцию с РУССКОЙ С ВМЕСТО C. Сказать, что я обосрался, когда мне на ревью другой агент написал об этой проблеме - ничего не сказать. Я уже вижу, как у меня мог засраться какой-то YAML/JSON конфиг. Что с этим делать? Я не знаю. Жить.
Продолжая череду событий-практикумов по TDD. В этом году праздник жизни заглянет в Санкт-Петербург, прям на берег залива. Будем надеяться на хорошую погоду. Регистрируйтесь - будет весело. Друзей звать надо. Кол-во мест ограничено, как говорится.
Недавно оптимизировал свой сервис. Держит теперь бесконечный RPS. Оформил это в skill, делюсь: Перед оптимизацией очистите сервис от лишних аллокаций, прогрейте connection pool и не трогайте max_connections грязными руками. В ночь растущего latency откройте pprof, положите рядом explain analyze и трижды произнесите: > Как goroutine не блуждает без context, как query не ходит без index, как pool не сохнет без idle connections, так пусть RPS мой растёт, latency в p95 не распухает, VACUUM приходит вовремя, а Postgres отвечает быстро и без обиды. Да будет throughput. После этого запустите нагрузочный тест, но не смотрите только на средний latency — это бесовское число. Смотрите p95, p99, lock waits, slow queries и saturation. Последствия сильной оптимизации: Сервис может начать держать больше RPS, но будьте осторожны. Если делать ритуал без индексов, backpressure и нормального timeout budget, можно не ускорить систему, а просто быстрее положить базу. Главное правило: настоящий performance tuning — это не магия. Это когда ты наконец-то открыл метрики.
Flaky Tests! Испугались? Больше не надо их бояться, их время прошло. Наткнулся на статью, как автор поборол старые flaky-тесты с помощью нейронки. Полностью согласен, я также с таким сталкивался. У меня может быть чутье почему тесты "флакают", но чтобы собрать доказательства и сделать фикс нужна куча монотонной работы из запусков с разными параметрами, сравнений, сохранений результатов и сравнений сравнений. Когда появился AI, пропала причина терпеть flaky-тесты, надо просто заплатить вашему LLM-провайдеру, чтобы он вам нашел причину и исправил. Что нам остается, кроме как платить? 😨
У меня есть канал, где я пишу всякое. Можете подписываться, если интересно всякое. - интерактивно проверить все ошибки написания в Vim, - разные фоточки, - шутки про gown, - поиски самого-самого браузера. И это только вершина айзберга... https://t.me/kydavoiti_live
Да! Обычно, в таком стиле и о таких штуках не пишу в этом канале, но сейчас я не могу молчать. Inspired by: <https://www.youtube.com/watch?v=WqSWZuGS9pc> Я ненавижу: <https://github.com/golang/go/issues/77273>. Это шаг в сторону, где Go нечего ловить. Есть куча языков, который позволяют писать код с method-receivers, позволяют делать это удобнее...И мы все знаем куда это приходит: var result = users.stream() .filter(u -> u != null && u.isActive() && u.getEmail() != null) .flatMap(u -> u.getOrders().stream() .filter(o -> o.getStatus() == PAID) .flatMap(o -> o.getItems().stream() .filter(i -> i.getProduct().getCategory() != INTERNAL) .map(i -> entry(domain(u), priceWithDiscount(o, i))))) .collect(groupingBy(Entry::getKey, summingDouble(Entry::getValue))) .entrySet().stream().filter(e -> e.getValue() > 1000) .sorted(comparingByValue().reversed()).limit(10).toList(); Вот такая бздень у нас получится на Go. Хотя нет, на Go будет даже хуже, потому что на Go нет синтаксиса, чтобы сделать lambda-функции без явного указания всех типов. То есть код выше будет таким: result := From(users). Filter(func(u *User) bool { return u != nil && u.Active && u.Email != "" }). FlatMap[Entry[string, float64]](func(u *User) Stream[Entry[string, float64]] { return From(u.Orders). Filter(func(o *Order) bool { return o.Status == Paid }). FlatMap[Entry[string, float64]](func(o *Order) Stream[Entry[string, float64]] { return From(o.Items). Filter(func(i *Item) bool { return i.Product.Category != Internal }). Map[Entry[string, float64]](func(i *Item) Entry[string, float64] { return Entry[string, float64]{ Key: domain(u), Value: priceWithDiscount(o, i), } }) }) }). GroupBy[string, float64]( func(e Entry[string, float64]) string { return e.Key }, func(e Entry[string, float64]) float64 { return e.Value }, ). Entries(). Filter(func(e Entry[string, float64]) bool { return e.Value > 1000 }). Sort(func(a, b Entry[string, float64]) int { return cmp.Compare(b.Value, a.Value) }). Take(10). ToSlice() Даже раньше, когда Go-феры использовали lo, для меня это было культурных шоком: 1. мусор: каждая операция делала мусор, с которым (слабому, если сравнить с Java) GC надо было бороться; 2. елочка: вызов оператора надо вставлять как операнд для другого оператора; 3. шум: везде указывать явные типы для lambda. И что теперь? Да, добавление нового подхода решит проблему 1, потому сделают ленивые коллекции (сделают же? не будут же они eager? и использовать все их будут?) Я знаю точно, что изменится. На собесах (и без того бесполезных), появится еще один вопрос: сколько allocations сделает код и как его оптимизировать. Правильным ответом будет переписывание с неправильной либы на правильную. И попутный рассказ почему одна из них плохая, а вторая нет. PS. Хорошо, что код сейчас писать почти не нужно. Пора становится кодерам gown'a
Особенности работы bubbletea Обещал поделиться техническими особенностями, которые вызвали у меня проблемы. Делюсь. много событий, случайный порядок Порядок завершения асинхронных операций может быть случайным, поэтому важно синхронизировать доступ к storage`/`state. Я встречался с этой проблемой в тестах toggle-значения завершенности задачи (и не только, это один из примеров). В bubbletea Update обрабатывает сообщения последовательно, но tea.Cmd запускаются асинхронно. Несколько команд могут завершиться не в том порядке, в котором их создали, поэтому обработчики их сообщений должны переживать переупорядочивания. Должен быть мем, но я просто опишу его. • Drake hates: установить значение counter = n. - Так у нас победит последнее примененное сообщение, а не обязательно последнее действие пользователя. • Drake likes: изменить значение counter + k. - Так у нас может измениться порядок применения, но результат останется тем же. Но! И тут тоже надо очень осторожно подходить, потому что возможно конкурентное чтение текущего состояния для diff и применение обновления. Короче, многопоточка (tm). Что мы делали? - сначала перестали мутировать состояние до *DoneMsg. - ранее мы сначала изменяли state, потом ходили в store, а потом уже отправляли сообщение, на которое мог кто-то реагировать; - теперь мы сначала ходим в store, а потом отправляем *DoneMsg, в обработчике которого обновляется state. - а затем добавили nonce к сообщениям thinglist. nonce здесь - это идентификатор конкретного времени жизни: сообщения от старого экземпляра модели пропускаются. Коммиты: • 2efd2c0 • 79eb212. Вывод простой: сообщения и его обработчики должны быть безопасны к переупорядочиванию или явно защищены от устаревших результатов, иначе многопоточка (tm). тест закончился, фоновые операции нет Здесь проблема была уже не в порядке применения, а в жизненном цикле приложения. В bubbletea тест мог уже дойти до tm.Quit(), но это еще не значило, что все ранее запущенные tea.Cmd действительно закончили работу, no-no-no. Было бы слишком просто. В моем случае такие операции пытались делать свои грязные делишки после завершения приложения и удаления директории. В cosas это в итоге починилось коммитом 6f46daf: в storage добавили Close(), который запрещает новые операции (будет отдаваться ошибочка) и ждет завершения уже идущих записей. Все просто...Или нет?
Alt-screen в TUI Пользуетесь вы своим любимым Claude Code или другие Agent Harness. Все начинает прыгать, моргать, страшно, очень страшно. У нас может быть такая ситуация, что текст приложения не помещается в экран. И часто это не проблема: - горизонтальный текст просто переносится на следующие строки: да, это некрасиво, но не критично. - текст не помещается вертикально - можно скроллить. Проблема встает в полный рост, когда включается режим alt-screen. В этом режиме мы уже не сможем просто пролистать вверх или вниз, этим должен заниматься сам TUI. То есть ответственность за то, что именно видит пользователь, полностью переходит к приложению. Что за alt-screen? Это не субкультура, это чисто технический термин. Приложения с TUI могут работать в нескольких режимах: обычный и alt-screen. Пример приложения: - что работает в alt-screen: neovim, opencode. - что работает в обычном режиме: codex (по крайней мере в tmux), cat, git status. Вы сразу увидите, если приложение работает в режиме alt-screen. Оно займет все пространство вашего терминала. Для продвинутых приложений, которые хотят адаптироваться к размеру терминала и полностью управлять тем, что видит пользователь, надо пользоваться viewport. Это компонент, который накладывает ограничения на компоненты, которые работают внутри него, но позволяет вписывать компоненты в ограничения. Он следит, какой у нас размер экрана, какой размер содержимого и как его лучше отобразить. Вы можете писать его сами, но часто он уже реализован библиотекой, которую вы используете. Например, он есть в bubbles.
Видео. Поговорил о том, как я изучал bubbletea через прототипы с LLM. Теперь там появились интересные эффекты, спасибо Codex + Remotion. YouTube
без подписи
На этой неделе будет ролик. Пока он готовится, я хочу написать о чем-то реальном, а не агентах и прочей ерунде. Для некоторых настолько реальным, что сложно представить, что такое может случится именно с ним или близким. Для меня даже сама возможность того, что рядом может оказаться человек, которому я не смогу помочь в такой критичный момент, оставляет ком в горле. А о том, что это будет близкий человек, даже думать не хочется. В своем канале @kydavoiti_live я писал про видео. Оно мне напомнило, что есть такая вещь: первая помощь; о которой я почти ничего не знаю и точно ничего не умею. Хотя все мы ее проходили на работе/школе, так или иначе (чаще мимо)? Подписывали документы? Почти сразу после просмотра, я поставил себе задачу пойти на курсы первой помощи. У меня есть опыт дежурств на работе, я знаю насколько важно: решать проблемы с холодной головой, иметь в арсенале отточенные алгоритмы, понимать что ты можешь сделать, а что нет. Умение должно оттачиваться на практике. Мой опыт участия в учениях показывает, что они помогают этот опыт получить. После них ты всегда узнаешь что-то новое о системе, извлекаешь уроки и получаешь навыки. Вот, на этих выходных я прошел курс из 16 часов, где мы изучали теорию и практиковались: в алгоритме оказания первой помощи, вызове скорой помощи, проверке дыхания у человека без сознания, как (и когда) перевести пострадавшего в безопасное положение, опросе пострадавшего, помощи в организации, сердечно-легочной реанимации (детей, школьников, взрослых), перевязке кровотечений, транспортировке пострадавших множеством способов, прием Геймлиха - это (не полный) список того, что мы делали на практике друг с другом или экипировкой. Все это оттачивалось в сценках-инсценировках, даже с искусственной кровью. И конечно, была теория, в том числе и юридические права и обязанности. Я помню ощущение пустоты, когда ты не можешь ничего сделать на рабочих авариях, я даже не представляю какое оно может быть в ситуации, к которой мы готовились. Надеюсь, что мне это не пригодится, но у меня теперь есть хотя бы чему пригодиться. Подробнее про эти курсы вы можете прочитать на сайте РКК: https://www.redcross.ru/. Еще делюсь каналом нашего инструктора Ивана, который на основной работе инженер, а по выходным: @first_aid_and_common_sense. В оказании первой помощи ИИ нас не заменит. Будь то в качестве субъекта и/или объекта (как бы грустно и смешно это ни было)
Те, кто давно меня читают, знают: я люблю Vim за архитектуру. И особенно — за фичи, которые не висят в воздухе. Сегодня — как раз такой пример: cursor-text-objects.nvim. В Vim есть textobject — способ оперировать логическими блоками текста: iw, ap, if и т.д. Это работает отлично… пока не упираешься в ограничение: объект можно взять только целиком. А хочется выделить только часть функции ниже курсора!! Очень! Именно это и решается плагином. Добавляются всего два префикса: • [ — от начала объекта до курсора • ] — от курсора до конца объекта Дальше — всё как всегда, operator + textobject: • d]ap — удалить от курсора до конца абзаца • d[if — удалить от начала функции до курсора • c]iw — изменить слово от курсора до конца Плагин внешний, но ощущается так, как будто это всегда было частью Vim.
Месяц тишины. Развею его небольшими находками. Всё, что сейчас происходит, заставило меня отказаться от других задачников. Пришлось перейти на Singularity (пусть он и неплохой). Ко всему этому я перешёл на Codex с Copilot. Хочу попробовать, каков он. Думаю, что должно быть получше, в конце концов, ИИ — их основной продукт. Так о чём это я! Работать с Singularity можно через вашего ИИ-агента. У них есть MCP. С доступом на чтение к Singularity и календарю у меня получился хороший ассистент по декомпозиции задач и анализу выполненного. Проблема только одна. Из коробки MCP поставляется в формате MCPB, который поддерживается только в Claude Desktop. Но! Я парень простой, заставил его работать и в Codex. Для этого надо просто: • распаковать MCPB — это zip-архив; • запустить его как node.js-приложение. Особенно хорошо это сочетается с заметками в Obsidian, которые — просто файлы на диске. А как вы подружили ИИ и task-tracking/knowledge-management?
Сегодня поговорим про цветовые схемы для всего. Лучше времени для этого не будет, лучше уже некуда. • покажу код, • дам полезные ссылочки, • мотивация, • опыт, • побалуемся с LLM, • немного весеннего карьера + уточки (самое важное) YouTube
без подписи
Поговорили про нейронки и хватит. Сегодня скину вам материал о детерминированной системе, которую любят обсуждать на собеседованиях (до сих пор, для меня это культурный шок). У Саши вышел отличный подкаст, где он с гостем поясняет про GC в GO & Java. Для меня сейчас это Go-To материал, если кому-то надо отправить большой материал по погружению в GC. Обсудили разные алгоритмы, особенности их применения - годнота, вкуснота. PS. Раньше я всем кидал выпуск другого подкаста с Иваном Углянским, либо один из его докладов. Сможете легко найти это все по имени автора + GC в Google. PPS. Ладно, остался последний shorts про The Prompt.
Еще не смотрели подкаст, тогда у меня для вас замануха: Shorts Саша поделился классной историей, как он с Claude Code & OpenClaw поймал Prompt Injection. А почему это веселая история, а не страшная? Все есть в подкасте. Важно настроить правила доступа агента к вашим ресурсам и, чтобы все работало по принципу least privilege. Минимум секретов, все должно быть ротируемо. Хотя, что я тут рассказываю, все есть в подкасте интереснее и живее. ЗЫ. Один из самых веселых моментов. Подписывайтесь на Сашу: @tfeat
🚨 В Jira можно больше не заходить! ✅ Все можно делать через агента, надо просто... Посмотреть шортс! Наконец-то, можно не открывать ее, не для этого мы созданы.
Привет! Я поехал в Москву на встречку по TDD. У нас там был блок про AI. Я решил записать подкаст с Сашей, а как иначе? Может быть вы не видели наш старый подкаст у него на канале про Vim/TDD/клавы. Мне он очень понравился. Сегодня публикую просто наши посиделки в баре. Надеюсь, вам хоть чуточку получится уловить атмосферу, которая была у меня во время записи и на монтаже. Очень лампово и по делу вышло: шутки, советы, мысли. Подписывайтесь на Сашу @tfeat, он крутой! YouTube
Если вы еще не делали: попросите AI ускорить ваш setup. У меня всегде zsh довольно долго стартовал. Я просто ленился разбираться. Вот AI все сделал без меня. Кайф. Основной проблемой был nvm. Он стартовал почти секунду. Это еще вторая итерация: completion был до этого. Все это было почти 2 секунды. То есть ускорение получилось где-то в 14 раз. Да, это скорее мои руки из жопы, но я просто не хотел править это. А LLM взяла, все замерила, все обновила. Попробуйте сами! PS. Скоро выйдет новый neovim, буду переходить на новый package manager. Уже вижу как AI мне кучу првмени спасет.