Эргономичный код
831 subscribers
96 photos
3 videos
24 files
442 links
Канал о разработке поддерживаемых бакэндов - про классическую школу TDD, прагматичное функциональное программирование и архитектуру и немного DDD.

Группа: https://t.me/+hrqD87p0Oa

Канал в Max: https://max.ru/id544512614458_biz

https://azhidkov.pro
Download Telegram
Привет!

Мы тут в группе три дня делились опытом внедрения ИИ в практику - присоединяйтесь, если ещё нет:)

Ну и походу дела возникла идея одного опроса и я пока писал пост захотел провести второй (открытый) опрос - сейчас их заведу

#ai@ergonomic_code
Открытый опрос - пишите в комменты.

Чем вы занимаетесь пока ИИ агент работает?
Привет!

Сыновей я делаю в три раза лучше, чем пишу книги и блоги - в канале снова будет (ещё большее) затишье на пару месяцев, пока жизнь переустоканится:)
1❤43🎉9👍2🏆2🔥1
Привет!

Потока создания пост.

Мысль первая

Пока мне было не до интернета, практически одновременно Саша Гранин написал, что разработка с ИИ у него не работает, а Макс Морев, что у него работает.

Я сейчас нахожусь в первом лагере - меня ИИ скорее замедляет, чем ускоряет.
И я пока не могу понять где правда. Но упустить паровоз ИИ страшно, поэтому продолжаю жрать кактус.

По этим двум причинам (текущий подход меня тормозит, а не научиться в ИИ страшно) я сейчас мигрирую от хайпового SDD к максимально ленивой спецификации - на входе брифы задачи и решения на 1-2 странички максимум, а дальше весь дизайн just in time™️ в цикле ТДД.
И всё это на ручной тяге - брифы я пишу сам руками, потом агент их ревьювит на предмет дыр/недоспецификации, а потом цикл ТДД я веду руками же с ручным ревью каждого шага.

В общем, у меня как всегда - выходит какой-то свой алтернативно одарённый мейнстриму велосипед. Но раз вы здесь - видимо вам тоже быть серой массой мейнстрима стрёмно 😂 Так что может вам мой велосипед больше понравится или он натолкнёт вас на свой велосипед:) Когда будет готов.

Хотя... Мой велосипед в части спеки/дизайна - это как раз то, как весь мейнстрим работал ещё пару лет назад. Так что может я просто быстрее остальных вернулся к адекватности:)

Да и SDD - выглядит как тот самый пресловутый водопад, от которого отказались 30 лет назад.

Мысль вторая

Судя по всему, для того чтобы получить кратный рост скорости разработки от применения ИИ - надо параллелить работу. При том на 3-4+ потока.

И тут я вижу две проблемы:

1. не все люди (я - точно) готовы работать в параллельном режиме. Я ещё готов вести одновременно с основной задачей разработки 1-2 мелких утилитарных задачки или баг фикса. Но вести одновременно две (или 6 🤯) полноценных задачи - нет, не мой путь.
2. не все организации (моя - точно) готовы обеспечить команду 3-4 x <размер команды> независимыми потоками работы.

—

Вобщем продолжаем наблюдать за ситуацией. Я всё ещё не берусь предсказать куда эта вся эпопея вырулит.

#ai@ergonomic_code #dot_agents@ergonomic_code
👍3
Привет!

У меня периодически спрашивают как обстоят дела с перформансом у ЭП в целом и функционального стиля + Spring Data JDBC в частности.

Я всегда говорил "У меня не хайлоад и мне всегда хватало - никогда не приходилось ничего целенаправленно оптимизировать".

И вот у нас Проекте Э планируется переход от ~0.5 (3 в утренний пик) RPS к штатным 17 RPS 24/7. Тоже, конечно, не супер хайлоад, но уже существенная нагрузка, которая откровенных косяков не простит.

Я соответственно пошёл мерить и к моему небольшому удивлению, бэк сходу вывез эти 17 rps в течение 10 минут. При том по прочим метрикам вывез без проблем и мог бы больше, но я пока не стал искать предел - есть более приоритетные задачи.

Единственное что, это был только первый этап и БД была практически пустая - 100К записей в целевой таблице, а с такой нагрузкой рабочий объём будет 500-600М записей.

Тестируемая операция:
0. авторизация по JWT-токену с парсингом и верификацией и с SELECT-ом его активности в БД
1. нетривиальный парсинг json-а с поддержкой 8 минорных версий схемы, валидация и дедупликация данных
2. один SELECT с локом по юзеру
3. пара простых SELECT-ов в целевую таблицу
4. маппинги DTO -> Domain -> Persistence
5. один INSERT в целевую Postgres inherited table
6. один простой INSERT в таблицу transactional outbox-а
7. асинхронно - публикация события в rabbit mq и удаление по id из outbox-а

Чутка цифр по запросам:
0. всего запросов - 14199
1. ошибок - 0
2. avg - 115.5ms
3. p90 - 151.8ms
4. p95 - 296.5ms
5. p99 - 511.9ms
6. max - 1968.9ms.

И по железу:
1. бэк - 1 pod в k8s с лимитами 400m CPU/750Mi RAM, JVM heap 550Mi. Вот тут я прям удивился, что spring-то оказывается мохёт на 500мб РАМ О_О. А в проде уменя зачем-то 2гб стоит.
2. Postgres - cloud.ru-шный менеджед на rds.pg.x1.large.2 | 2 vCPUs | 4 GB

17 RPS - тоже нифига не хайлоад, конечно, но уже и не стыдно людям рассказать.

#ergo_approach@ergonomic_code #spring_data_jdbc@ergonomic_code #project_e@ergonomic_code
❤2👍2😁1
Привет!

Я решил провести аттракцион невиданной щедрости!
Да, с появлением третьего ребёнка у меня резко появилось свободное время 😂

Одному счастливчику сделаю бесплатно* полезный микро-продукт** под рабочую или личную задачу.

Напишите в личку - @d_r_q - я расскажу в чём подвох и вы решите подходит ли вам это или нет😄

Большинство из вас, конечно, само может провести свой аттракцион, но может вам лень, а кому-то из ваших знакомых надо:)

* не публичная оферта, подробности в личке :)

** приложение / сайт / бот / ИИ-агент / сервис
🔥3🤯2
Привет!

Не устали ещё от "(ещё большего) затишья на пару месяцев"? 😂
Самому страшно представить, что через два месяца начнётся 🤯

В общем я тут ещё немного поупражнялся с нагрузкой Проекта Э:

1. 2 ноды в cloud.ru по 4К в месяц
2. 1 менеджед постгрес по 4К в месяц
3. 2 пода с лимитами в ~25-50% от ресурсов ноды (1 из 4 гб РАМ на всё, 1 из 2 CPU)
4. при 70 rps в течении 10 минут - медианное время ответа 175мс, 99 персентиль - 616мс, максимум - 1470мс.
5. на 100 RPS под упёрся в CPU - скорее всего за недорого можно и на 100 RPS выйти, но для меня это уже явный оверкилл.

Попутно отловил прикольный косяк в реализации, которым на мой взгляд многие могут грешить.

У меня хэширование паролей при логине (тяжёлая операция на сотни миллисекунд) делалось внутри транзакции. Соответственно запросы логина во время ожидания хэширования выжирали весь пул подключений и тормозили целевые запросы.

Вобщем проверьте у себя - не делаете ли вы хэширование паролей (или другие чистые, но алгоритмически тяжёлые операции) внутри транзакций:)

#project_e@ergonomic_code
👍6
Привет!

Не спрашивайте как я нашёл на это время, но я тут посмотрел новую документалку про Рича Хикки и создание Clojure.

Если вы уже фанат Рича - посмотрите обязательно.

Если вы ещё не фанат Рича - надо им срочно становиться. На мой вкус это самый крутой визионер и инженер современности.

Для этого сначала посмотрите Simple Made Easy
Потом - Are We There Yet
Потом - Database as a Value
Потом все остальные его видосы в хронологическом порядке от корки до корки.

Ну и в конце - документалку из начала поста:)

#talks@ergonomic_code
❤5👍1
Привет!

Я тут подбил немного пугающей статистики:
1. во второй половине 25-ого года, когда я ещё львную долю кода писал сам, у меня было ~1 баг на 175 строк кода.
2. а в 26-году, когда я перешёл на ИИ-разработку - уже примерно по багу на 80 строк кода 😱

Помним, конечно, что есть ложь, наглая ложь и статистика, но... Двукратный рост... Двухкратный, Карл.

И это при том, что у меня ещё достаточно хорошая страховочная сетка на регрессии - без неё у агентов поди было бы ещё хуже.

#ai@ergonomic_code
😭5
Привет!

Ну, моя эпопея с нагрузкой продолжается (часть 1, часть 2) и продолжает генерять материал для канала.

Я перешёл к этапу проверки работы с БД целевого размера (600М строк).
Идти решил постепенно: для начала залил 50М строк в целевую таблицу, запустил нагрузку и... Опять упрёся в ЦПУ на хэшировании паролей в транзакции при логине -> забитый пул подключений -> тормоза аутентификации целевого запроса на получении подключения для проверки активности токена.

Решил, что хватит извращений и надо залечить проблему с хэшированием в транзакции.

Залечил, запустил нагрузку, иии... Бэк начал 500-ить на логине. То есть стало хуже чем до фикса.

Полез копаться. Выяснилось:
1. я из транзакции вытащил чтение SDJ-агрегата, у которого было две связанных коллекции
2. т.е. это был не 1 запрос, а 1 + 2 (чтение корня + чтение коллекций).
3. при том второй запрос выполняется до завершения первого
4. и так как транзакции не было, SDJ для второго запроса захватывал новое подключение
5. в итоге 10 потоков логина на чтении корня агрегата выбирали все подключения из пулла, потом пытались сделать второй запрос и блокировались навечно, потому как все подключения уже были заняты предыдущим запросом корня, который ждал результатов запроса коллекций, который ждал... ну вы поняли:)

Завернул чтение агрегата обратно в транзакцию, запустил нагрузку (на 50М строк) и...

70 rps в течении 10 минут - медианное время ответа 137мс, 99 персентиль - 314мс, максимум - 1644мс.
т.е. в итоге корректный фикс срезал мидиану на 15%, а 99персентиль - на 30.

Мораль басни:
1. Не держите тяжёлые вычисления внутри транзакций
2. Но держите все обращения к SDJ внутри транзакций:) Вообще это прямым текстом написано в оф. доках - осталось только не забывать, не тупить и не лениться.
3. SDJ безусловно на порядок-два проще Hibernate, но всё равно слишком сложен для кожанного мешка

#spring_data_jdbc@ergonomic_code #project_e@ergonomic_code #ergo_approach@ergonomic_code
❤3
Отдельно стоит рассказать про "Полез копаться".

Сначала я методом пристального вглядывания начал втыкать в свой первый фикс, пытаясь понять что за фигня. Повтыкал минут 5 иии... пошёл к Codex-у с гопатычем 5.5 medium-xhigh.

Гопатыч долго (часа 3 в разных сессиях) и упорно втирал мне про, то что проблема в количестве запросов подключений и длине очереди, рисовал мне всякие формулы в духе "время обработки запроса = размер очереди * время обработки одного запроса" и т.п. И в целом был довольно убедителен.

Но у меня в голове картинка не сходилась - я не мог понять как эта очередь выстраивается так, что какой-то из запросов не получал подключение в течение 30 секунд.

Я уже было отчаялся и решил забить - проблема-то решена, по факту, пока можно жить дальше.
Но решил попробовать в вебе GPT-5.6 Sol/Xhigh и он сразу ткнул меня носом в то, что подключения тупо заканчиваются и загрузка агрегатов уходит в дедлок.

Тут у меня картинка в голове сошлась, я быстро пробежался дебаггером, увидел, что действительно всё так и происходит и успокоился.

Мораль этой басни:
1. Все врут. В том числе и топовые ЛЛМки.
2. Если в чате с ЛЛМкой вы чувствуете себя дебилом - скорее всего дебилом является ЛЛМка.

#ai@ergonomic_code
👍3💯2
Я никогда на самом деле не работал с историями, но общий посыл на сто процентов плюсую - задачи надо ставить в терминах и интересах пользователей.
❤3👍2
Про те самые Story

Термин "история", как синоним фичи, думаю, известен всем. Спасибо джире. Но вот что за этим словом кроется, как я вижу, понимают далеко не все.

Я очень люблю рассказывать вот такое. В 90-е наш любимый Кент Бек садился с заказчиком и просил рассказать свою историю. Что не так, что нужно починить. И вот это и есть та самая история, unit of work.

Я часто вижу, что работа бьётся так: таска на подключение к базе, таска на то, чтобы приделать Кафку, сделать "движок", "ядро", "фабрику", "стейт-машину", "скелет" или что там ещё любят делать. Оно понятно, как так получается: все сели, подумали, как решать проблему, нарезали на более-менее независимые куски, создали под них задачи и раздали программистам.

Это, конечно, никакие не пользовательские истории. Трудно представить, что ты приходишь к таксисту, оператору или, не знаю, врачу, спрашиваешь, что у него болит, а он в ответ: "ну, в базе данных нет того-то, Кафка не подключена, ядра нет".

Вроде бы и пофиг, да? В целом, да, отчасти. Это работает, но кое-что ломается. Сделав так, вы потеряли интент, намерение, заменив его инструментом. Мой последний пост был как раз про это: вы заменили цель средством. Если со средством все ок, то и цель будет достигнута. Поэтому обычно и работает.

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

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

В общем, технические детали - это первое, что выдаёт "неправильную историю" или, если корректнее, проблемную постановку задачи.

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

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

И вот эти детали реализации, как раз, опять приводят разработчика к вопросу, как победить авторизацию и загрузку, а не к вопросу, нужны ли они вообще. Где-то нужны, где-то, а где-то, весьма вероятно, нет.

Так что правильнее всего так: обычно история - это какая-то боль.

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

Это явно не боль пользователя. Но ответ элементарный: истории бывают не только у пользователей, но и у маркетологов, аналитиков, админов, начальников. И даже у разработчиков.
❤5
Привет!

Внимание, реклама!

Одним из потенциальных микропродуктов моего аттракциона невидной щедрости стал сервис управления закладками с оплатой российской картой (аля Firefox-овский Pocket).

С этим микропродуктом связана небольшая история.

Участник аттракциона написал, что ему нужен сервис управления закладками.
В ответ на это у меня, естественно, первый порыв был разработать сервис с нуля - как собственно я и обещал в посте про аттракцион.
Но в рамках проработки идеи я пошёл смотреть аналоги и... нашёл готовое рабочее опенсорсное self-hosted решение - https://linkding.link/.

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

И я решил проверить идею рублём - я запущу этот сервис, если до 29 июля соберу 10 возвратных депозитов по 350 рублей.

Сервис я запущу в течении 14 дней после собора нужного количества депозитов, либо верну деньги 29 июля.

Linkding позволяет вам:

1. Собрать все свои закладки в одном месте;
2. Быстро добавлять закладки с помощью расширений Firefox и Chrome;
3. Тэгировать и отмечать прочитанными закладки;
4. Сохранять копии страниц на случай удаления источника;
5. И ещё несколько минорных фич.

В дальнейшем стоимость сервиса будет 350 рублей в месяц навсегда.

Если вам нужен такой сервис - напишите мне в личку (@d_r_q).
🔥5❤2
Привет!

Историческая минутка.

Если вы интересуетесь функциональным стилем, то возможно слышали про статью "Can Programming Be Liberated from the von Neumann Style?"

Это опубликованная версия лекции Бэкуса - автора Fortran-а и соавтора Backus-Naur Form - прочитанной при вручении ему премии Тюринга (нобелевки в мире информатики), в которой он критикует императивное программирование с операторами присваивания и в качестве альтернативы предлагает функциональный (хотя и довольно своеобразный) стиль программирования.

И если вы интересуетесь ФП, но не слышали про статью - это уже первая полезняшка:)
Но не последняя - я тут недавно около этой статьи накопал ещё пару интересных ссылок.

Во-первых, Бэкус занимался этой темой до своего выхода на пенсию в 91-ом году и было несколько попыток реализовать систему из статьи, чему в интернете посвящена целая страница :)

На этой же странице есть ссылка на сайт некоего Paul McJones, который кажется, может быть интересен любителям ИТ-археологии, но я в него не закапывался - меня таки накрыл дефицит времени, после рождения третьего ребёнка.

Во-вторых, Дейкстра (тоже лауреат премии Тюринга и мужик, который решил, что Go To плохо, придумал стурктурное программирование, семафоры, "separation of concerns", слоёную архитектуру и много ещё чего) для своих "подписчиков" сделал разгромное ревью доклада Бэйкуса, которое дошло до самого Бэйкуса через третьи руки, после чего у них случился научный махач.

Много лет спустя, разбирая свои бумаги для Библиотеки Конгресса, Бэкус каталогизировал эту переписку с комментарием:
This guy’s arrogance takes your breath away
--
От высокомерия этого парня захватывает дух


А Дейкста и правда был тем ещё токсиком:

Object-oriented programming is an exceptionally bad idea which could only have originated in California.
—
Объектно-ориентированное программирование — исключительно плохая идея, которая могла зародиться только в Калифорнии


The use of COBOL cripples the mind; its teaching should, therefore, be regarded as a criminal offence.
—
Использование COBOL калечит разум; поэтому его преподавание следует считать уголовным преступлением


Fascination with the equipment is the hallmark of the amateur
—
Очарованность оборудованием — отличительный признак дилетанта


—

В общем если у вас есть время - покопайтесь в этих ссылках от души за меня:)

#fp@ergonomic_code #papers@ergonomic_code
❤5👌3
Привет!

Простые CRUD-приложения - это сложно

Если помните, я уже писал, что с момента перехода GPT-4 -> GPT-5 я качественных скачков в росте пользы от агентов больше не видел.
И вот, вышел GPT-5.6-sol - а я снова не чувствую никакой разницы с GPT-5.*

Недавно я в Проекте Э сделал с ним не совсем тривиальную задачку: обеспечить синхронизацию обработки аутбокса на нескольких репликах, которая требует обращения во внешнюю систему.

И это был ужас.
В процессе он мне в несколько заходов генерял код, который напомнил мне тот ужас, с которым я работал в "лихих нулевых и десятых" и почему я вообще начал делать Эргономичный подход.
Но мне в итоге удалось свести этот ад к простому и изящному коду.
Ну точнее - мне удалось заставить гопатыча сделать это.

И при этом грешил гопатыч ровно тем, чем грешили мои коллеги из "лихих годов":

1. локальные хаки и костыли, вместо пересмотра модели
2. привнесение надуманной сложности, которая не имела практической пользы
3. бездумный перенос кусков кода из одного контекста в другой, где они теряли смысл и вообще ломали смысл окружающего кода
4. хрестоматийные ошибки дизайна - дублирование смысла кода, с немного разным выражением (DRY); нарушение CQS; нарушения баланса захвата/освобождения ресурсов; неуместные граничные/специальные случаи; нарушение зон ответственности (do one thing)

И вся эта история с чудесным преображением кода, решающего одну и ту же по сути задачу, навела меня на другую мысль.

В прошлом году я скрипя сердцем признал, что всю жизнь занимаюсь всего лишь "простыми CRUD-приложениями", которым не нужны ни ЧА, ни DDD, ни ФА, ни любая-другая-крутая-аббревиатура. И чтобы как-то повысить ценность и значимость своей работы, а так же обосновать необходимость ЭП, я даже придумал термин "сложные CRUD-приложения".

Так вот глядя на то, как гопатыч делал какую-то невероятно ацкую реализацию для простого CRUD-приложения, я понял, что простота моего кода - это не данность, не повсеместное состояние дел и не то, что доступно любой макаке - это достижение которым можно и нужно гордится и которое основывается на моих 20+ годах практической работы и поиска способов писать простой код.

И всё это сподвигло меня начать писать новый большой пост с разбором этих сессий кодирования с вариантами названия "Шок! GPT-5.6 не может написать простую крудилку!" и "Простые CRUD-приложения - это сложно".

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

Полезняшка №1: роллауты сессий

Если вы не знали, кодекс (думаю, другие агенты делают так же) хранит все чаты у себя в папочке в открытом виде.
И по этой папочке вполне можно делать поиск - у меня на это есть специальный скилл.

А у этого скилла куча применений:
1. основное у меня - я большинство правок своего фреймворка (он, кстати, жив и развивается) идёт через скилл fix-framework-context куда я пишу ид сессии, что агент сделал не так и как надо было. И гопатыч по роллауту разбирает почему агент в сессии сделал не то что надо и как это поправить.
2. я сейчас отчёты о работе за месяц для заказчика формирую гопатычем и на вход среди прочего подаю эти сессии
3. ну и в контексте этого поста - по этим сессиям гопатыч восстановил мне хронологию наших с ним метаний во время решения задачи с привязками ко времени, промптам и бэкапам - без чего я бы вряд ли смог так подробно разобрать что происходило, как это делаю сейчас

Полезняшка №2: Бэкапы

Начну пожалуй с бородатого анекдота: люди делятся на тех, кто ещё не делает бэкапы, и кто уже делает бэкапы.
Но у меня не просто бэкапы - у меня развесистая супер надёжная система, про которую при желании можно написать отдельный пост.

И одна из особенностей этой системы заключается в том, что для моих рабочих директорий у меня снимаются снапшоты каждые 5 минут и для 8 последних дней хранятся все эти снапшоты.

Благодаря этому для каждого своего промпта за последние 8 дней я могу откопать точный код на котором его писал и понять почему я его написал.
Что оказалось так же супер ценным, для написания поста, о котором я говорил выше.

Для бэкапов системы (на Linux) я использую Timeshift, для бэкапов рабочих файлов, архивов и конфигов - backintime, а для синка файлов между устройствами - syncthing с нодой с шифрованием на VDS-е за 900р/мес.

—

Вобщем - пишите простой код, учитесь делегировать тупую работу агентам, следите за агентами и делайты бекапы:)

#ai@ergonomic_code #tips@ergonomic_code
👍10❤4
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍3🔥3
Саша пишет про процессы, как всегда очень круто, имхо
👍3❤2