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

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

Обновление IntelliJ

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

А потом попробовал — а новый интерфейс, оказывается, … удобный! Сам с себя удивляюсь, что такое возможно.

Киллер-фичей для меня стала возможность засунуть кнопки для действий на верхнюю панель — более чем уверен, что и раньше можно было что-то подобное делать, но сейчас явно стало проще. Туда сразу попали и Diff, New Scratch File и Zoom, которые раньше через Shift+Shift находил. Плагин для запоминания горячих клавиш идет прямиком в помойку. Без багов, правда, не обошлось, что делать.

Ну а еще приятно, что в этом релизе есть маленький PR от меня.

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

Вайб-режиссер для GPT

В дикой природе миллион советов про то, как правильно спрашивать “ИИ”, чтобы получать правильные результаты. Если кто вдруг забыл, то GPT — это чат-бот на стероидах для генерации правдоподобного текста, а не интерфейс к энциклопедическим знаниям. Очень частый рецепт: определите роль, задайте цель, укажите ограничения и желаемый формат вывода. Иногда к этому добавляют “расскажите об аудитории”.

Честно говоря, запоминать правила для промтов — уныло. Да еще и меняются они периодически. “Ты ж AGI”, давай уже мне ответ без вот этих всех реверансов, железяка! И вообще, я аж две кнопки нажал — погугли и подумай!

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

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

Методика голосования Apache

Занятный документ, который описывает способ голосования в Apache Software Foundation. Выглядит местами переусложненно, но, возможно это следствие процесса его эволюции (похожим образом эволюционируют описания командных процессов в документации, если они есть конечно). Да и вроде как красивые модели человеческих процессов редко применимы в реальности.

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

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

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

Кастомные комбинации для Compose Key

Понадобилось мне упростить себе ввод, да еще и экзотическим способом — хочу быть владычицей морскою, которая может на русской раскладке писать ј, ћ, џ, ђ и прочие славянизмы.

Разумеется, вспомнил про Compose Key — не зря блог веду, получается! :). Сначала попробовал найти готовые комбинации — все стандартные комбинации можно посмотреть в файлах локали(ей):

cat /usr/share/X11/locale/en_US.UTF-8/Compose | grep č

И если для латиницы все в порядке, то ћ не будет ни в латинской раскладке, ни в русской. Придется делать самостоятельно.

Для этого нужно создать ~/.XCompose и добавить туда сначала include "%L", чтобы работало все стандартное, а потом свои правила, например

<Multi_key> <Cyrillic_CHE> : "Ћ" U040B

Тут <Multi_key> — это собственно Compose Key, <Cyrillic_CHE> — заглавная Ч, а U040B — код для Ћ. Чтобы узнать обозначение для Ч, можно использовать xev | grep keycode. А чтобы узнать код для символа (и заодно найти его) — есть встроенное приложение Character Map, можно воспользоваться онлайн-таблицами вроде этой или чуть более прикольными штуками, которые распознают рукописные символы.

Увы, чтобы протестировать все это безобразие, придется разлогиниться и залогиниться снова, какого-то более простого способа я не нашел.

Но в итоге все получилось, я доволен.

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

Функциональный DDD

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

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

Жизненный цикл аннотаций Java

Как известно, в Java есть три варианта аннотаций по RetentionPolicy:

  • Compile — видны только компилятору, полезны для преобразования кода.
  • Runtime — видны и при исполнении, можно сделать что-то рефлексией, например, создать класс из JSON.
  • Class — записаны в байткоде, но не видны через рефлексию, могут из пользоваться инструментацией или в плагинах (чтобы делать что-то при их загрузке).

А теперь минутка извращений! Несмотря на то, что через рефлексию не видны аннотации с уровнем Class, если очень-очень надо, то можно… перепрочитать класс через что-то вроде

clazz.getResourceAsStream(clazz.simpleName + ".class")

и запихать это в ClassReader из ASM с переопределенным visitAnnotation. К счастью, в прод этот код не попал, но пики надо держать острыми.

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

Коаны Elixir

Поразвлекался с еще одним языком — Elixir. Ничего серьезного не написал, прочел LearnXinYMinutes и cheatsheet и сразу начал делать коаны.

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

Сам язык мне показался странным: вроде типизация есть, но она не очень строгая. Список — контейнер для каши из объектов разных типов, 1 > "33" — это норма, миллион привкусов структуры/ассоциативного массива и т.п. Есть интересные идеи, но в целом впечатления смешанные.

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

Подробнее описывать пока не буду — планирую еще что-нибудь написать на Elixir попозже, чтобы полноценно акторную систему использовать.

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

Степень влияния задержки на пользовательский опыт

Неплохая статья (хоть и с всратыми картинками) про то, как воспринимается время с точки зрения типичных пользователей:

TLDR:

  • 0.1 с — “мгновенный ответ”, “это сделал я” (печатаю символ)
  • 1 с — максимальное время без потери фокуса (предпочтительное время загрузки веб-страницы), “это сделал комп”
  • 10 с — нет сил ждать, время смотреть тик-токи и подумать о чем-нибудь другом
  • 1 м — если неинтересно, то пока
  • 1 д — оптимальное время ответа от техподдержки, ежедневная рутина
  • 1 неделя — если пользователь посещает сайт раз в неделю, то это можно назвать привычкой
  • 1 месяц — время решения в B2B процессах
  • 1 год — время, за которое можно стать “продвинутым пользователем”
  • 10 лет — время изменения орг структуры/процессов большой компании
  • 100 лет — время для перемен в обществе (эээ, сомнительно, но ладно)
СсылкаКомментировать

Впечатления от Cursor

На прошлой неделе потыкали с коллегами палкой в Cursor, который AI агент и кодит за вас. Мы попытались пофиксить относительно мелкий баг (отсутствие валидации пользовательского ввода у одного из эндпоинтов) в реальном приложении, которое уже несколько лет в проде. Написано оно на Scala + Play (что может дать представление как и о его почтенном возрасте, так и о степени легаси).

Мы открыли проект, дали агенту лог с ошибкой от невалидного ввода и попросили Cursor sanitize input. Он изменил глобальный обработчик ошибок контроллеров, по сути добавив try-catch. Попросили исправить ошибку собственно в контроллере, но не сказали, в каком. ИИ нашел похожую ошибку в другом эндпоинте, но мы решили в рамках эксперимента закрыть на это глаза и продолжить.

Что хуже, обработка была заточена под конкретный пример неправильного ввода. Промт важен: мы уточнили, что надо именно validate. ИИ использовал херовую регулярку (даже если проигнорировать контекст/инварианты). После пары итераций с доведением ее до уровня “и так сойдет”, попросили добавить валидацию для всех эндпоинтов с таким же параметром. Cursor сделал отдельный статический класс валидатора и добавил его вызов в паре контроллеров (но точно не везде, где было нужно). Решение в итоге получилось хреновым, код тоже был не супер, но по виду это должно было худо-бедно работать.

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

Наконец, запустили тесты и получили ошибки. И после этого агент резко сдулся. В тестах были проблемами с ассертами и моками, и Cursor не смог их сам исправить даже после 30 итераций “запусти тесты и поправь ошибки”. Мы даже пробили максимальный лимит на количество запущенных команд от одного промпта (25). Мы давали небольшие подсказки, предлагали решать проблемы по порядку и т.п., но ИИ не смог побороть тесты. В то время как продакшн-код был написан за полчаса, с тестами провозились больше часа и в итоге бросили.

Посмотрев на изменения, обнаружили, что ИИ в процессе добавил новый эндпоинт, хотя его никто не просил. Попросили по приколу Copilot отревьюить PR — но он не смог, потому что не знает скалу:) Мержить PR не стали — проще с нуля сделать, чем править.

В итоге впечатления похожи на те, что я писал ранее (1, 2, 3): можно использовать как помощь для рутины и грязной работы, но если ИИ застрял, то проще сделать самому. Одно из полезных открытий — если давать ИИ наводки типа “залогируй параметры, чтобы лучше понять ошибку”, то он чуть лучше работает. Не исключено, что ИИ испытывал трудности из-за стека технологий, но сомнительно, что для какого-нибудь JS были бы кардинально другие впечатления.

С точки зрения самого Cursor: есть прикольная фича, что можно заставить ИИ править код, пока не пройдут тесты, но разумеется, это не поможет, если ИИ тупит или ходит по кругу. Был еще один мелкий баг: если использовать режим “ask”, итеративно дорабатывать решение и затем применить его, код может оказаться в неконсистентном состоянии – например, в какой-то момент ИИ добавил приватный метод, который нигде не вызывался, хотя в его первом ответе вызов был.

В общем процесс ощущался как общение с гиперактивным, быстрым, не очень опытным, а иногда и очень тупым джуном.

P.S. На следующий день на HN в топе попался сборник проблем кодинга с AI и коллеги вбросили эту статью — там все в целом по делу.

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