Эргономичный код
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
Привет!

Выпилил в #project_e поддержку АПИ в1 двухлетней давности.
Это примерно 7% всей кодовой базы проекта

Лучшее начало года, пожалуй, сложно представить:)

Ставьте лайк, если тоже больше любите коммиты, в которых удаляете код, а не добавляете новый:)
👍30😁5🔥3
Привет!

Итоги 2025 года - лучше поздно, чем никогда, правда же?:)

Итог №1 - Больше реального кода

Больше всего сил в 2025 году (192 коммита, против 43 и 36 в вики и блог) я вложил в Trainer Advisor - публичный пример проекта, написанного по ЭП.
За 2025 год я в нём сделал 34 различных фичи и фикса, самые крупные и трудозатратные из которых были:
1. Интеграция с Гугл Календарями (PR, пост)
2. Пуш-уведомления (PR, пост)

В результате, TA дорос до 20К строк исходников и 20 таблиц.

Помимо этого в #project_e мы за прошлый год сделали пару новых сервисов и допилили новых фич в ядро на 2.2, 4.1 и 6К строк соответственно.

В итоге суммарное количество промышленного кода, написанного по ЭП, перевалило уже за 121 тысячу строк Kotlin и Java-кода.

Итог №2 - Эргономичная архитектура

Также значительным на мой взгляд итогом 2025 года стало появление Эргономичной архитектуры и её представление с помощью трёх проекций. Описание Эргономичной архитектуры всё ещё в статусе черновика и публичных обновлений не было давно, но за кулисами я весь четвёртый квартал 25-ого года работал над проекцией модели данных. С четвёртой попытки у меня вышел текст, который мне нравится, но ещё надо убрать исторические наслоения из ТА, чтобы он стал хорошей иллюстрацией и собственно добавить эту иллюстрацию.

Итог №3 - Исследование характеристик поддерживаемых кодовых баз

Затем, довольно много времени и сил я потратил на проведение исследования характеристик поддерживаемых кодовых баз backend-приложений. К сожалению, собрать достаточное количество анкет не вышло (хотя анкета всё ещё открыта и вы всё ещё можете её заполнить:) ), поэтому все эти усилия по большому счёту пошли прахом. Тем не менее, у меня появилось слабое, но подтверждение, что ЭП как минимум не вредит поддерживаемости:)

Итог №4 - Большие посты

На поприще блоггинга я смог написать два больших поста:

1. Вам не нужна Чистая архитектура. Скорее всего
2. Учимся читать SQL SELECT

А всего в блог и вики я добавил (немного пугающие) 6660 строк. Это не считая незакоммитанных черновиков:)

Итог №5 - Новые паттерны

Ещё в 2025 году у меня оформилось несколько паттернов, немного сокращающих трудозатраты на разработку (за счёт того, что не надо велосипед придумывать):

1. Переход на UUID v7 в качестве идов сущностей
2. Пресеты сложных фикстур
3. [Wire]MockServers
4. и ещё пачка более мелких см. историю коммитов

Итог №6 - +1см в направлении книги

Прошлый год начался с того, что мне написал проектный менеджер ИД Питер с предложением издать книгу. На этой волне я немного полежал в направлении книги, но переключился на исследование. Знаете как расшифровывается СДВГ? "Синдром дефицита Вау! Голубь!".
И вот в конце прошлого года ко мне пришёл представитель уже второго крупного издательства с тем же предложением. Мы с ним довольно серьёзно продвинулись в планировании книги и ред. коллегия была готова заключить договор на издание книги, но с условием, что авторский текст я сдам до конца 26 года. А я по ряду причин не готов на это подписываться, поэтому и в этот раз не срослось.
Но, держим пальчики, процесс потихоньку сходится, когда-нибудь книга обязательно будет:)

#ergo_approach@ergonomic_code #traineradvisor@ergonomic_code #ergo_book@ergonomic_code
❤8👍7🔥3
Чего ждать в 2026 году

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

Поэтому список далее - это то, что у меня сейчас есть в голове и чего хотя бы теоретически можно от меня ожидать. А что будет на самом деле - только время покажет. Вы же уже знаете, как расшифровывается СДВГ:)

Итак, чего от меня можно ожидать в 2026 году:

1. Актуализация Project Mariotte - это то, чем я занимался до итогов. Обновляю платформу и зависимости и перевожу реализацию на актуальные паттерны ЭП.
2. Пост с опытом миграции на Spring Boot 4. Я уже смигрировал Project Mariotte и два небольших сервиса в Project E. И уже словил и решил гору проблем (с Jackson 3 в основном). На горизонте пары месяцев, я надеюсь мигрировать TA и основной сервис Project E и по результатам написать большой пост с граблями (и решениями), которые я словил в процессе.
3. Рефакторинг TA на актульный гайдлайн ЭП. ТА у меня будет иллюстрацией и для ЭА и для книги, поэтому надо убрать оттуда исторические наслоения и компромиссные решения
4. Описание проекции модели данных ЭА с примером из ТА.
5. Проекция поведения ЭА - там, похоже, тоже придётся ещё повозиться
6. Описание процесса транзакционного анализа и процессов проектирования модели данных и компонентов на его основе.
7. В целом пп 3-6 - это всё работа в направлении книги. Но помимо этого, возможно удастся начать описывать кейсы.
8. Наверняка я придумаю что-то ещё, столь же неожиданное, как и исследование:)

На что я готов подписаться, так это на то, что в 2026 году я продолжу работу над ЭП и продолжу писать о своих приключениях на этом пути в канале:)

В общем как всегда: стей тюнед, будет интересно:)

#ergo_approach@ergonomic_code #traineradvisor@ergonomic_code #ergo_book@ergonomic_code
👍10❤6🔥4
Привет!

У нас в группе вчера зашла речь про использование ИИ в кодировании.

А я как раз последний месяц сам код практически не пишу и активно занимаюсь отстройкой процесса разработки на базе ИИ:)
Поэтому я и в группе подробно ответил и сюда решил репостнуть:)

Общий сетап:
1. Платная подписка на OpenAI за 23 евро
2. Идея для работы с кодом самому
3. VS Code + Codex для работы с агентом

Сейчас у меня процесс устроен так:
1. Я: завожу рабочую директорию задачи
2. Я: в режиме потока сознания сливаю постановку задачи в файл
3. Я: пуляю exec-spec-space-prompt.md (см. аттачи) в модель
4. Gpt-5.2 medium reasoning (в сложных на мой взгляд случаях - high/extra high): задаёт вопросы
5. Я: отвечаю
6. Модель: генерит 4 варианта реализации
7. Я: вот тут идёт самая вариативная часть
7.1. выбираю вариант
7.2. задаю доп вопросы и выбираю вариант
7.3. вижу что какой-то рефакторинг упростит решение -> обсуждаю его с моделью -> прошу сгенрять краткую постановку задачу на рефакторинг -> "делаю" рефакторинг -> на п. 6 с новыми вводными
7.4. даю уточнения к одному из вариантов модели и выбираю его
7.5 вкидываю свой вариант -> на п. 6
8. Модель: генерит 02-solution-options.md, 03-solution-hld.md и пишет транскрипт чата
9. Я: полуяю exec-spec-prompt.md в новый чат
10. Модель: генерит ТЗ
11. Я: тщательно ревьювлю ТЗ.
11.1 Если есть замечания: мелкие правлю сам, больше отдаю модели
12. Я пуляю промпт "реализуй ТЗ" в новый чат с GPT-5.2-Codex low
13. Модель реализует ТЗ
14. Я: смотрю результаты запуска тестов в чате и если их нет, или запущен не полный набор - запускаю сам. Если не прошли - скидываю логи модели и говорю починить.
15. Я: ревьювлю код и
15.1 мелочь правлю сам
15.2 большие куски прошу поправить модель
16. Я: прошу модель записать транскрипт чата реализации
17. Профит

Если модель лажает в кодировании - я пока просто в режиме свалки скидываю указания в AGENTS.md.

Касательно эффективности этого процесса у меня объективных данных нет.
Субъективно:
1. Этап проектирования и написания ТЗ - эффективнее, так как я люблю затупить при генерации или выборе вариантов, а потом не люблю аккуратно их расписывать, поэтому делаю это со множеством перекуров, перекусов, переписов и перекаков.
2. Этап реализации - пожалуй, не быстрее чем делать самому, если в потоке. А если делать на морально-волевых - модель, пожалуй, быстрее справляется. Плюс тут пока модель работает, можно самому заняться чем-то другим
3. Как альтернатива работе со стажёрами/джунами - намного эффективнее. На самом деле, раньше я и с юниорами примерно в таком же режиме работал и это было очень долго. Плюс у модели лучше получается мимикрировать под окружающий код (читай: под ЭП).

Я несколько раз слышал, что соннет лучше код пишет, но не осилил подтвердить у них телефон:)

#ai@ergonomic_code #tips@ergonomic_code
🔥10❤6👍2
Привет!

У меня недавно в Проекте Э случилась поучительная и многогранная история. Эта история одновременно:

1. Иллюстрирует как именно глобальное изменяемое состояние усложняет поддержку кода. И соответственно, почему его стоит избегать.
2. Показывает, что зелёные тесты на внешнее API не гарантируют отсутствие тупых багов внутри.

#why_fp@ergonomic_code #ergo_testing@ergonomic_code #project_e@ergonomic_code
Привет!

Новости с ИИ-полей.

Этот "compelling launch hero" сначала фризит мне ФФ на Андроиде, а потом крэшит его.

Так и живём:)
😢4
Привет!

Саша меня опередил - я сейчас примерно такую же штуку под ЭП делаю.

Но у меня там есть отдельный слой концептов ЭП, на которых я в скиллах ссылаюсь - типа "Диаграмма эффектов", "Эргономичная модель данных", "IRW-анализ" (бывшй транзакционный анализ).
🔥4
Продолжаем про вайбкод

0. Подарочек

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

1. Про мотивацию

Короче, уже видно, что AI-assisted software engineering - это 100% состоявшаяся практика. Ждать ничего уже не надо, это работает уже сейчас - надо брать и переезжать.

Поясняю:
- Обычный поток разработки (по ощущениям, конечно) раза в 3-4 быстрее, но это вилами по воде, потому что никто нормально не мерил и, вероятно, не измерит;
- Отдельные задачи (фронт, доки, инфра и т.д.) идут в десятки раз быстрее и делаются автономно;
- Инструмент совершенствуется в процессе работы, развивают его и вендоры, поэтому скорость растет постоянно.

В итоге, получается несколько даже перекошенный (хоть и в правильную сторону) результат. Если базовый функционал все так же едет вперед с неплохой стабильной скоростью, то вот обвязка, которую часто раньше делали по остаточному принципу (документация, UI/UX, тесты, инфраструктура и многие другие "фишечки") ИИ делает теперь автономно и очень быстро. Поэтому, когда функционал готов, он готов уже сразу весьма хорошо, на уровне лучших домов.

2. Про инженерный подход

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

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

Поэтому в нашей команде очень серьезно относятся к идеям Executable Specification, когда реальное поведение смотрят по тестам, а документация нужна лишь для заметок аналитиков и коммуникации между аналитками и разработкой.

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

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

3. Про ментальную модель

А вот с чем я не согласен, так это с аналогией, что LLM - это компилятор нового поколения. В книге у Vibe Coding Джина Кима и Стива Йегге указывается, что более корректная ментальная модель - не инструмент, а тиммейт. И наш опыт взаимодействия тоже показывает, что одна лишь фраза "What do you think?" в конце каждого промпта полностью меняет процесс взаимодействия.

Оказывается, что директивный способ взаимодействия работает не очень хорошо. Ты сказал - нейросеть нагенерила, как поняла. И частенько нагенерила какую-то фигню.

А вот что работает круто:
- объяснить, что не нравится
- спросить мотивацию такого решения (если оно было принято только что)
- предложить свой вариант решения
- спросить мнение нейросети и попросить её предложить свои варианты

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

4. К скиллам

У меня получился целый фреймворк, который мы зовём "заводиком", заточенный чисто под мою разработку. Я не планировал им делиться, но раз уж спросили, то вот. Из подготовки к публикации - только сожженые 50% макс-сессии токенов на замену любых упоминаний моего проекта на таск-менеджер. Поэтому не серчайте сильно, что не очень user-friendly.
👍8❤4
Привет!

У меня в Эргономичной архитектуре есть ограничение на количество атрибутов сущностей и зависимостей операций (сервисов) с рекомендуемым значением "до 7 +/- 2".

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

Я тут в рамках разработки Ergo AI Agent Framework пошёл снова ботанить понятия cohesion и coupling, и, в частности, пошёл читать Code Complete (aka Совершенный код).

И там на странице 143 английским по белому написано:

Be critical of classes that contain more than about seven data members
The number “7±2” has been found to be a number of discrete items a person can remember while performing other tasks (Miller 1956). If a class contains more than about seven data members, consider whether the class should be decomposed into multiple smaller classes (Riel 1996). You might err more toward the high end of 7±2 if the data members are primitive data types like integers and strings, more toward the lower end of 7±2 if the data members are complex objects.

—

Критически относитесь к классам, содержащим более чем примерно семь полей данных.
Число «7±2» было выявлено как количество отдельных элементов, которое человек способен удерживать в памяти, выполняя при этом другие задачи (Miller, 1956). Если класс содержит более примерно семи полей данных, сто́ит задуматься о том, не следует ли разложить его на несколько более мелких классов (Riel, 1996).

Можно смещаться ближе к верхней границе диапазона 7±2, если поля представлены примитивными типами данных, такими как целые числа и строки; и ближе к нижней границе, если поля являются сложными объектами.


Возможно, вы, глядя на свою MyCoreEntity с 100+ полей и MyCoreEntityService с 80+ зависимостей, думаете, что мы с Макконнеллом теоретики, которые реального кода в глаза не видели.
Но это не так:)

Может быть, и не до 7 полей, но существенно упросить MyCoreEntity можно с помощью:
1. активного выделения Value Object-ов — например, завести класс PersonName(first, middle, last) и заменить три поля на одно;
2. активного выделения аспектов сущности в отдельные сущности — например, убрать из коренной сущности пользователя поле с его подписками, на веб-пуши.

А справиться с MyCoreEntityService поможет:
1. переход от сервисов к классам-операциям (ака юз-кейсам, интеракторам) — выделение каждого метода класса сервиса в отдельный класс с одним публичным методом. С непривычки это кажется дичью — по себе знаю, мне самому так казалось 2.5 года назад — но к этому быстро привыкаешь и назад уже не хочется;
2. повышение уровня абстракции ресурсов/гейтвеев/портов — например, если у вас агрегат включает в себя блоб (картинку), то можно заменить зависимость от UsersRepo и FilesStorage на сложный/составной ресурс/порт/гейтвей, которые внутри себя держит UsersDao для работы с РСУБД и FilesStorage для работы с хранилищем блобов.

#ergo_arch@ergonomic_code #books@ergonomic_code
❤9👍5👀2
Привет!

Реклама

Всем привет!
Давно состою в сообществе ЭП, и, мне кажется, тут должны быть одни из лучших специалистов.
У меня сейчас интересный этап жизни, участвую в удивительно амбициозном проекте, у которого есть много причин прийти у успеху.
Есть вакансия Lead backend Kotlin developer https://hh.ru/vacancy/130258007
Стадия ранняя, так что можно поучаствовать в мотивационных механизмах, в принятии ключевых технических решений и поработать с максимально (возможно даже слишком)) прогрессивным Kotlin стеком.
Все соглашения в правовом поле РФ.
Если будут вопросы, можете обращаться в том числе в личку в телегу. Рад, что могу осветить такую интересную возможность.
Алексей Горбунов @at3r7
❤7
Привет!

На всякий случай завёл резервный канал в Max - подписывайтесь и туда.

А подписаться есть за чем.

Во-первых, я уже перевёл на Spring Boot 4 два небольших сервиса в Project E, Project Mariotte и Trainer Advisor. В процессе я собрал и решил кучу проблем (см. картинки ниже). И из этого опыта я собрал скилл для ИИ-агентов, с помощью которого сегодня планирую перевести на Spring Boot 4 основной сервис Project E.
После этого у меня будет опыт миграции примерно 90 К строк кода и 10-15 различных технологий.
И это всё я соберу в пост-мануал по миграции.

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

В-третьих, под давлением суровой реальности, у меня грядёт существенное изменение в проекции структуры компонентов Эргономичной архитектуры. Описана она пока только в сообщении к коммиту 0691a65.

В-четвёртых, в процессе разработки ИИ фреймворка, я активно дополняю, актуализирую и формализую шаблоны Эргономичного подхода, которые потом активно поедут на вики.

В-пятых, я думаю, что после того, как я закончу ИИ-фреймворк - я смогу поставить на поток превращение интересных мест коммерческих проектов в обобщённые кейсы по типу Project Mariotte - а значит примеров кода по ЭП станет существенно больше.

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

PS>

Этот канал будет оставаться основных столько, сколько это будет возможно
😢8🔥4👎3
Эргономичный код
Кажется, общий ход алгоритма получилось описать достаточно чётко:) А если учесть то, что сейчас могут нейронные сети, то, кажется, они вполне могут справиться с реализацией функций isPrimaryResource и findBestMatch не как боженька, конечно, но не хуже джуна уж точно.

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

А с учётом того, что нейронные сети уже умеют писать код и моих склонностей к мании величия и нарциссизму, у меня в мечтах диаграмма эффектов уже стала самым распространённым языком программирования 5-ого поколения:) М? Мощно задвинул?:)

Осталась только самая мелочь - забутстрапить систему и нарисовать диаграмму эффектов, по которой GitHub copilot сможет сгенерировать
Смотрите, кстати, что вспомнил и откапал. Практически в трёхлетний юбилей поста.

Кто бы мне тогда сказал, что через три года я буду говорить гопатычу "Реверс-инжерни-ка диаграмму эффектов этой операции. Потом спроектируй и покажи мне диаграмму компонентов для реализации этой операции, а потом реализуй" - не поверил бы.
🔥3
Привет!

Знаете старую преподскую шутку - "Я им 5 раз объяснил, сам уже начал понимать, а они - не в какую!"?

Так вот я тут в попытках объяснить ИИ как писать хороший код, сам сделал хороший шаг в понимании этого:)

Жемчужину откопал там где не ждал - в "Чистом коде" анкл Боба в разделе про единственный уровень абстракции. Который, кстати, перечитывал недавно, но в тот раз пропустил.

Так вот жемчужина - техника объяснения кода в терминах "Чтобы ...".

To say this differently, we want to be able to read the program as though it were a set of TO paragraphs, each of which is describing the current level of abstraction and referencing subsequent TO paragraphs at the next level down.

To include the setups and teardowns, we include setups, then we include the test page content, and then we include the teardowns.
To include the setups, we include the suite setup if this is a suite, then we include the regular setup.
To include the suite setup, we search the parent hierarchy for the “SuiteSetUp” page and add an include statement with the path of that page.
To search the parent. . .


—

Иными словами, мы хотим иметь возможность читать программу так, как если бы она представляла собой набор абзацев "ЧТОБЫ...", каждый из которых описывает текущий уровень абстракции и ссылается на последующие абзацы "ЧТОБЫ" следующего, более низкого уровня.

Чтобы включить подготовительные и завершающие действия, мы сначала включаем setups, затем содержимое тестовой страницы, а затем teardowns.
Чтобы включить setups, мы включаем suite setup, если это набор тестов (suite), затем включаем обычный setup.
Чтобы включить suite setup, мы ищем в иерархии родительских страниц страницу “SuiteSetUp” и добавляем директиву include с путём к этой странице.
Чтобы выполнить поиск в родительской иерархии…


— Robert C. Martin, Clean Code, p. 37


Но это крутой инструмент не только для определения уровня абстракции функции, но и для определения её связности (cohesion).

Если функция имеет несколько несвязанных эффектов (коммуникационная и ниже связность), то её не получится описать в таком виде и без "и".

Например функция создания записей в дневнике в Проекте Э:

    override operator fun createEvents(
userId: Int,
eventsRqs: List<EditEventRq<out EventData>>,
): List<Event> {
val profileId = profilesRepo.lockOnProfile(userId)
val deduplicatedEvents = deduplicateEvents(eventsRequest, profileId)
when (deduplicatedEvents) {
is EventListWithInvalidDuplicates -> throw DifferentEventsWithSameId(userId, deduplicatedEvents.values)
is EventListWithFullDuplicates -> {
log.warn("...")
}

else -> {}
}

val existEventsIds = eventsRepo.findAllIdsByIdIn(deduplicatedEvents.values.map { it.id })
var actuallyNewEvents = deduplicatedEvents.values.filter { it.id !in existEventsIds }

eventsRepo.saveAll(actuallyNewEvents)

val lastUsedDeviceSerialNumber = eventsRepo.getLastUsedDeviceSerialNumberByProfile(profileId)
val domainEvents = actuallyNewEvents
.mapNotNull { DiaryEventCreated.fromDto(userId, it, lastUsedDeviceSerialNumber) }
eventsCreatedQueue.publishEvents(domainEvents)

return savedEvents
}


Её связность на первый взгляд может функциональной - сохранить записи дневника.

Но на самом деле - коммуникационная: Чтобы создать события мы блокируем профиль, дедуплицируем события, находим действительно новые события, сохраняем их в БД и публикуем сообщение об их создании. А публикуем мы сообщение - точно для того, "чтобы создать события"? Нет. Эта операция имеет две ответственности: создать события и оповестить об этом заинтересованные лица - "чтобы создать события и оповестить об этом мы...".
👍7