Эргономичный код
Кажется, общий ход алгоритма получилось описать достаточно чётко:) А если учесть то, что сейчас могут нейронные сети, то, кажется, они вполне могут справиться с реализацией функций isPrimaryResource и findBestMatch не как боженька, конечно, но не хуже джуна уж точно.
Т.е. гипотетически, алгоритм объектно-ориентированной декомпозиции действительно можно сделать полностью автоматическим. Подаёшь на вход .drawio файл с диаграммой эффектов и на выход получаешь .drawio файл, с декомпозицией, которую надо просто перепроверить. Ну а генератор скелета проекта по drawio файлу с декомпозицией я прямо сейчас без всяких нейронных сетей за вечерок напишу.
А с учётом того, что нейронные сети уже умеют писать код и моих склонностей к мании величия и нарциссизму, у меня в мечтах диаграмма эффектов уже стала самым распространённым языком программирования 5-ого поколения:) М? Мощно задвинул?:)
Осталась только самая мелочь - забутстрапить систему и нарисовать диаграмму эффектов, по которой GitHub copilot сможет сгенерировать
Т.е. гипотетически, алгоритм объектно-ориентированной декомпозиции действительно можно сделать полностью автоматическим. Подаёшь на вход .drawio файл с диаграммой эффектов и на выход получаешь .drawio файл, с декомпозицией, которую надо просто перепроверить. Ну а генератор скелета проекта по drawio файлу с декомпозицией я прямо сейчас без всяких нейронных сетей за вечерок напишу.
А с учётом того, что нейронные сети уже умеют писать код и моих склонностей к мании величия и нарциссизму, у меня в мечтах диаграмма эффектов уже стала самым распространённым языком программирования 5-ого поколения:) М? Мощно задвинул?:)
Осталась только самая мелочь - забутстрапить систему и нарисовать диаграмму эффектов, по которой GitHub copilot сможет сгенерировать
Смотрите, кстати, что вспомнил и откапал. Практически в трёхлетний юбилей поста.
Кто бы мне тогда сказал, что через три года я буду говорить гопатычу "Реверс-инжерни-ка диаграмму эффектов этой операции. Потом спроектируй и покажи мне диаграмму компонентов для реализации этой операции, а потом реализуй" - не поверил бы.
Кто бы мне тогда сказал, что через три года я буду говорить гопатычу "Реверс-инжерни-ка диаграмму эффектов этой операции. Потом спроектируй и покажи мне диаграмму компонентов для реализации этой операции, а потом реализуй" - не поверил бы.
🔥3
Привет!
Знаете старую преподскую шутку - "Я им 5 раз объяснил, сам уже начал понимать, а они - не в какую!"?
Так вот я тут в попытках объяснить ИИ как писать хороший код, сам сделал хороший шаг в понимании этого:)
Жемчужину откопал там где не ждал - в "Чистом коде" анкл Боба в разделе про единственный уровень абстракции. Который, кстати, перечитывал недавно, но в тот раз пропустил.
Так вот жемчужина - техника объяснения кода в терминах "Чтобы ...".
Но это крутой инструмент не только для определения уровня абстракции функции, но и для определения её связности (cohesion).
Если функция имеет несколько несвязанных эффектов (коммуникационная и ниже связность), то её не получится описать в таком виде и без "и".
Например функция создания записей в дневнике в Проекте Э:
Её связность на первый взгляд может функциональной - сохранить записи дневника.
Но на самом деле - коммуникационная: Чтобы создать события мы блокируем профиль, дедуплицируем события, находим действительно новые события, сохраняем их в БД и публикуем сообщение об их создании. А публикуем мы сообщение - точно для того, "чтобы создать события"? Нет. Эта операция имеет две ответственности: создать события и оповестить об этом заинтересованные лица - "чтобы создать события и оповестить об этом мы...".
Знаете старую преподскую шутку - "Я им 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
В данном случае это не плохо, а с учётом того, что публикация должна быть сделана через Transactional Outbox - неизбежно. Но если у функции появляется 2 и более подобных смежных ответственностей - это уже хороший повод, чтобы их отцепить как раз через события. Это и упростит код реализации, и надёжность работы функции повысит, и тесты ускорит и упростит.
Или, если на самом деле в зависимости от параметров функция делает "(А и Б) либо (А и В)" - то её надо разбить на две отдельных функции, переиспользующие "А".
#ergo_approach@ergonomic_code #books@ergonomic_code #project_e@ergonomic_code
Или, если на самом деле в зависимости от параметров функция делает "(А и Б) либо (А и В)" - то её надо разбить на две отдельных функции, переиспользующие "А".
#ergo_approach@ergonomic_code #books@ergonomic_code #project_e@ergonomic_code
👍3🤔1
Привет!
ИИ похмелье...
Третий день разгребаю то, что у меня тут гопатыч по моему фреймворку наворотил в Проекте Э.
Это ужас. Он там и найденные правила гайдлайна нарушил, и не нашёл нужные правила (но тут косяк фреймворка, наверное) и не реализовал требования, которые явно были в ТЗ.
Единственное, что он сделал так же хорошо как и я - пропустил несколько мест, которые тоже аффектились изменениями. Но, в отличие от меня, прикрыл их подорожником, когда наткнулся...
Отдельную пикантность ситуации придаёт то, что буквально на этой неделе OpenAI релизнули версию Codex с очень бесячим и очевидным багом, который сводит автономность агента практически к нулю.
Когда-то слышал, что есть два типа гонищков:
1. первых находит предел сцепления машины с дорогой снизу - начинает ехать медленно и разгоняется пока не улетит
2. второй находит предел сцепления сверху - сразу топит на все деньги, а улетев превращается в первый тип
Вот я в этот раз был гонщиком второго типа. Теперь стал первого:)
От идеи делегации работы ИИ я не отказался, но решил начать с разработки и полировки небольших сфокусированный скиллов*, которые ускоряют мою работу. И потом, по мере развития моделей, фреймворка и меня как погонщика ии, пытаться выстраивать их в более длинные цепочки для более автономной работы.
И немного инсайтов:
1. используйте тайм блокинг между разработкой продукта и ии контекста агента. Когда пилите фичи - не допиливайте контекст сразу, если агент лажанул (как максимум - дополняйте туду). Когда пилите контекст - не пилите продукт по настоящему. Берёте одну задачу, один промпт и повторяете его до тех пор, пока результат не окажется нужным (или хотя бы заметно лучше, чем был).
2. Попробуйте добавить в системные инструкции "Chat answers must be at least 2x shorter than your natural default." - это заметно снижает объём ии слопа для ревью, а просадки в качестве я не заметил.
3. пишите файлы контекста своими руками, а потом отдавайте на ревью/перевод ИИ.
—
* примеры скиллов: "определить границы фичи", "составить список эндпоинтов, которые будут затронуты", "составить список критериев приёмки", "спроектировать рест апи", "закодировать приёмочный тест", "реализовать модель", "реализовать операцию"
#ai@ergonomic_code
ИИ похмелье...
Третий день разгребаю то, что у меня тут гопатыч по моему фреймворку наворотил в Проекте Э.
Это ужас. Он там и найденные правила гайдлайна нарушил, и не нашёл нужные правила (но тут косяк фреймворка, наверное) и не реализовал требования, которые явно были в ТЗ.
Единственное, что он сделал так же хорошо как и я - пропустил несколько мест, которые тоже аффектились изменениями. Но, в отличие от меня, прикрыл их подорожником, когда наткнулся...
Отдельную пикантность ситуации придаёт то, что буквально на этой неделе OpenAI релизнули версию Codex с очень бесячим и очевидным багом, который сводит автономность агента практически к нулю.
Когда-то слышал, что есть два типа гонищков:
1. первых находит предел сцепления машины с дорогой снизу - начинает ехать медленно и разгоняется пока не улетит
2. второй находит предел сцепления сверху - сразу топит на все деньги, а улетев превращается в первый тип
Вот я в этот раз был гонщиком второго типа. Теперь стал первого:)
От идеи делегации работы ИИ я не отказался, но решил начать с разработки и полировки небольших сфокусированный скиллов*, которые ускоряют мою работу. И потом, по мере развития моделей, фреймворка и меня как погонщика ии, пытаться выстраивать их в более длинные цепочки для более автономной работы.
И немного инсайтов:
1. используйте тайм блокинг между разработкой продукта и ии контекста агента. Когда пилите фичи - не допиливайте контекст сразу, если агент лажанул (как максимум - дополняйте туду). Когда пилите контекст - не пилите продукт по настоящему. Берёте одну задачу, один промпт и повторяете его до тех пор, пока результат не окажется нужным (или хотя бы заметно лучше, чем был).
2. Попробуйте добавить в системные инструкции "Chat answers must be at least 2x shorter than your natural default." - это заметно снижает объём ии слопа для ревью, а просадки в качестве я не заметил.
3. пишите файлы контекста своими руками, а потом отдавайте на ревью/перевод ИИ.
—
* примеры скиллов: "определить границы фичи", "составить список эндпоинтов, которые будут затронуты", "составить список критериев приёмки", "спроектировать рест апи", "закодировать приёмочный тест", "реализовать модель", "реализовать операцию"
#ai@ergonomic_code
GitHub
bwrap: Approval prompt shown for almost every command · Issue #14936 · openai/codex
What version of Codex CLI is running? CLI 0.115.0 What subscription do you have? GPT Plus Which model were you using? gpt-5.3-codex medium What platform is your computer? Linux 6.17.0-19-generic x8...
👍4❤2
Привет!
Судя по всему, в обозримом будущем выйти в белом костюме и сделать большой релиз полного красивого идеального и законченного фреймворка для ии агентов не выйдет, поэтому делюсь, тем что есть.
1. d-r-q/dot-agents - мои личные предпочтения и скиллы для работы агентов.
2. ergonomic-code/dot-agents - актуальная версия фреймворка.
3. ergonomic-code/dot-ai - архив с первым подходом к фреймворку.
Ну и первый, на мой взгляд полезный кусочек нового фреймворка - скилл генерации человеко-читаемого описания REST API.
С ним можно написать Codex-5.3 low:
И получить такую штуку.
Или можно попросить Codex-5.3 medium:
И получить такую штуку.
Отказ от ответственности: как с любым сгенерированным контентом, в сгенерённых доках могут быть ошибки.
—
С этим скиллом у меня история тоже довольно поучительная. Сначала я пытался заставить гопатыча сразу писать маркдаун. Но формат результатов плясал как выпускники на последнем звонке. Тогда я перешёл к схеме с json-внутренним представлением, и процедурными валидацией и рендерингом. С стабильностью формата стало хорошо (но есть мелкие баги), а вот семантика всё равно плавает в сложных случаях.
И вот с семантикой диффа, видимо, надо делать не один скилл/промпт, а многошаговый workflow:
1. собираем что вообще надо описать
2. с новым контекстом собираем ir что было и здесь и далее процедурно валидируем его
3. с новым контекстом собираем ir как стало
4. с новым контекстом, из что было, что стало, кодом и историей гита, собираем хинты диффов - какие эндпоинты поменяли пути, имена и структуру моделей, но продолжают выполнять ту же роль
5. с новым контекстом из данных пп 2-4 собираем ir с диффом
6. процедурно генеряем md
Такие вот дела. Пололжа руку на сердце - это просто магия, что можно дать машине инструкции на разговорном русском и она будет очень близко им следовать. Но чтобы получать стабильный и качественный результат - лучше бы по максимуму эти инструкции писать на старых добрых языках 3-ого поколения:)
#ai@ergonomic_code #tools@ergonomic_code
Судя по всему, в обозримом будущем выйти в белом костюме и сделать большой релиз полного красивого идеального и законченного фреймворка для ии агентов не выйдет, поэтому делюсь, тем что есть.
1. d-r-q/dot-agents - мои личные предпочтения и скиллы для работы агентов.
2. ergonomic-code/dot-agents - актуальная версия фреймворка.
3. ergonomic-code/dot-ai - архив с первым подходом к фреймворку.
Ну и первый, на мой взгляд полезный кусочек нового фреймворка - скилл генерации человеко-читаемого описания REST API.
С ним можно написать Codex-5.3 low:
[$describing-rest-api](skills/describing-rest-api/SKILL.md)
Опиши апи [NewsAdminController.kt](NewsAdminController.kt) .createNews
И получить такую штуку.
Или можно попросить Codex-5.3 medium:
[$skills/describing-rest-api/SKILL.md)
Опиши как изменилось апи NewsAdminController.kt .createNews в коммитах 39b4bf9d, 1abf8b1e, 05f01a28, f4622e63, b60daa6d, 0f4e2031
И получить такую штуку.
Отказ от ответственности: как с любым сгенерированным контентом, в сгенерённых доках могут быть ошибки.
—
С этим скиллом у меня история тоже довольно поучительная. Сначала я пытался заставить гопатыча сразу писать маркдаун. Но формат результатов плясал как выпускники на последнем звонке. Тогда я перешёл к схеме с json-внутренним представлением, и процедурными валидацией и рендерингом. С стабильностью формата стало хорошо (но есть мелкие баги), а вот семантика всё равно плавает в сложных случаях.
И вот с семантикой диффа, видимо, надо делать не один скилл/промпт, а многошаговый workflow:
1. собираем что вообще надо описать
2. с новым контекстом собираем ir что было и здесь и далее процедурно валидируем его
3. с новым контекстом собираем ir как стало
4. с новым контекстом, из что было, что стало, кодом и историей гита, собираем хинты диффов - какие эндпоинты поменяли пути, имена и структуру моделей, но продолжают выполнять ту же роль
5. с новым контекстом из данных пп 2-4 собираем ir с диффом
6. процедурно генеряем md
Такие вот дела. Пололжа руку на сердце - это просто магия, что можно дать машине инструкции на разговорном русском и она будет очень близко им следовать. Но чтобы получать стабильный и качественный результат - лучше бы по максимуму эти инструкции писать на старых добрых языках 3-ого поколения:)
#ai@ergonomic_code #tools@ergonomic_code
GitHub
dot-agents/src/skills/describing-rest-api/SKILL.md at master · ergonomic-code/dot-agents
Эргономичный подход для ИИ агентов. Contribute to ergonomic-code/dot-agents development by creating an account on GitHub.
👍9❤3
Привет!
Саша Раковский наконец-то опубликовал обновленную версию своего ии-фреймворка /continue.
И меня этот фреймворк вверг в комплекс неполноценности.
Не столько размером и полнотой фреймворка, которые тоже впечатляют, сколько кристальной чёткостью процесса в Сашиной голове, которая стоит за этим фреймворком. Я сейчас буксую именно на процессной части, хотя мне казалось, что у меня процесс тоже хорошо отстроен и формализован. Но на деле - только лишь казалось.
Саша Раковский наконец-то опубликовал обновленную версию своего ии-фреймворка /continue.
И меня этот фреймворк вверг в комплекс неполноценности.
Не столько размером и полнотой фреймворка, которые тоже впечатляют, сколько кристальной чёткостью процесса в Сашиной голове, которая стоит за этим фреймворком. Я сейчас буксую именно на процессной части, хотя мне казалось, что у меня процесс тоже хорошо отстроен и формализован. Но на деле - только лишь казалось.
Telegram
Саша Раковский
Мой маленький канал про экстремальное программирование и разработку программного обеспечения.
👍4❤3
С другой стороны, я планирую вернуться в большой (очень большой) постинг и чутка отвлечься от ии-темы.
В рамках чего я продолжил писать серию постов про миграцию на Spring Boot 4 - на той неделе я выкатил в прод ядро Проекта Э на Spring Boot 4 - и не единого разрыва, если вы понимаете о чём я.
Так как материала получается реально много и прорабатывать его реально тяжело - буду публиковаться по частям. И в первой части расскажу о потенциальных проблемах с автоконфигурациями и Jackson-ом.
В рамках чего я продолжил писать серию постов про миграцию на Spring Boot 4 - на той неделе я выкатил в прод ядро Проекта Э на Spring Boot 4 - и не единого разрыва, если вы понимаете о чём я.
Так как материала получается реально много и прорабатывать его реально тяжело - буду публиковаться по частям. И в первой части расскажу о потенциальных проблемах с автоконфигурациями и Jackson-ом.
🔥7
Привет!
Пост про пробемы с Jackson-ом при миграции на Spring Boot 4 движется, но с трудом - я по каждой проблеме восстанавливаю исходное состояние, снимаю ошибки и в неочевыдных местах разбираюсь что именно поменялось и/или почему фикс работает. Довльно нудная и утомительная работа, поэтому решил развеяться и добавил на вики первое приближение статьи с шаблоном именования тесткейсов.
А когда пошёл её публиковать, увидел, что у меня в застейдженных правках зависла статья с паттерном базового доменного исключения. Правда её, повидимому, гопатыч написал - потому и повисла, наверное:) Но код там мой:)
Пост про пробемы с Jackson-ом при миграции на Spring Boot 4 движется, но с трудом - я по каждой проблеме восстанавливаю исходное состояние, снимаю ошибки и в неочевыдных местах разбираюсь что именно поменялось и/или почему фикс работает. Довльно нудная и утомительная работа, поэтому решил развеяться и добавил на вики первое приближение статьи с шаблоном именования тесткейсов.
А когда пошёл её публиковать, увидел, что у меня в застейдженных правках зависла статья с паттерном базового доменного исключения. Правда её, повидимому, гопатыч написал - потому и повисла, наверное:) Но код там мой:)
Эргономичный подход
Шаблон именования тест-кейсов (v1.0.1)
Общие правила Имена тест-кейсов формулируются как требования к желаемому свойству поведения SUT в терминах конечного пользователя/заказчика/продакта. В частности, в формулировке кейсов на операции системы не должны фигурировать символы из контрактов, схемы…
👍2
Привет!
Реклама
Недавно я в дружественном канале узнал новое слово — вайб-дебаггинг.
Первым делом я подумал, что это очередной хайп типа вайб-кодинга.
Однако при ближайшем рассмотрении оказалось, что на самом деле это означает боль решения проблем, созданных вайб-кодингом.
Я же, несмотря на то что последние четыре месяца занимаюсь вайб-кодингом и руками код практически не пишу, вайб-дебагином не занимался ни разу.
В чём мой секрет?
В тестах.
Мой подход к тестам имеет одну очень крутую в текущих условиях особенность — его можно внедрить ретроспективно практически в любой проект. При наличии политической воли и ресурсов.
Поэтому, если вы хотите вайб-кодить, но не хотите вайб-дебажить — приходите ко мне. Я научу вас лично или вашу компанию:
1. Писать быстрые, показательные и устойчивые к рефакторингу тесты;
2. Работать в цикле TDD;
3. Учить ИИ работать в цикле TDD.
На консультациях/тренингах в зависимости от вашего запроса или запроса вашей компании, я могу:
1. Помочь разобраться с теорией: TDD, проектирование тест-кейсов, архитектура кода тестов;
2. Показать на практике, как это всё работает в реальном проекте;
3. Помочь найти решение ваших конкретных проблем (подпишу NDA);
4. Помочь спланировать проект по внедрению тестов в вашу кодовую базу и спроектировать требуемую для них тестовую инфраструктуру.
Стоимость разовой часовой индивидуальной консультации — 4000 р.
Стоимость пакета из 4+ консультаций — 3000 р. за консультацию.
Стоимость для организаций — по договорённости.
Задать вопрос и обсудить план обучения можно в личке в Телеграме: @d_r_q. Или по старинке по почте: biz@azhidkov.pro.
Реклама
Недавно я в дружественном канале узнал новое слово — вайб-дебаггинг.
Первым делом я подумал, что это очередной хайп типа вайб-кодинга.
Однако при ближайшем рассмотрении оказалось, что на самом деле это означает боль решения проблем, созданных вайб-кодингом.
Я же, несмотря на то что последние четыре месяца занимаюсь вайб-кодингом и руками код практически не пишу, вайб-дебагином не занимался ни разу.
В чём мой секрет?
В тестах.
Мой подход к тестам имеет одну очень крутую в текущих условиях особенность — его можно внедрить ретроспективно практически в любой проект. При наличии политической воли и ресурсов.
Поэтому, если вы хотите вайб-кодить, но не хотите вайб-дебажить — приходите ко мне. Я научу вас лично или вашу компанию:
1. Писать быстрые, показательные и устойчивые к рефакторингу тесты;
2. Работать в цикле TDD;
3. Учить ИИ работать в цикле TDD.
На консультациях/тренингах в зависимости от вашего запроса или запроса вашей компании, я могу:
1. Помочь разобраться с теорией: TDD, проектирование тест-кейсов, архитектура кода тестов;
2. Показать на практике, как это всё работает в реальном проекте;
3. Помочь найти решение ваших конкретных проблем (подпишу NDA);
4. Помочь спланировать проект по внедрению тестов в вашу кодовую базу и спроектировать требуемую для них тестовую инфраструктуру.
Стоимость разовой часовой индивидуальной консультации — 4000 р.
Стоимость пакета из 4+ консультаций — 3000 р. за консультацию.
Стоимость для организаций — по договорённости.
Задать вопрос и обсудить план обучения можно в личке в Телеграме: @d_r_q. Или по старинке по почте: biz@azhidkov.pro.
👍9🔥3
Привет!
Наконец-то осилил пост про миграцию на Spring Boot 4.
Ну как осилил - процентов 10-20 от того, что реально можно было написать.
Но даже на это у меня ушли какие-то несуразные и невероятно утомительные часов 30-60 работы (включая собственно миграцию и разбивку на коммиты так, чтобы потом можно было сделать структурированное описание проблем) и 4 календарных месяца.
При том что Spring Boot вообще не моя тема и эта работа никак не продвинула меня к финализации Эргономичного подхода.
Поэтому я решил, что описать только проблемы с наиболее распространёнными технологиями - автоконфигами и Jackson-ом - будет вполне себе "good enough" ™️.
А остальное - никогда-нибдуь потом, микропостом, если будут вопросы по моему опыту.
#spring@ergonomic_code
Наконец-то осилил пост про миграцию на Spring Boot 4.
Ну как осилил - процентов 10-20 от того, что реально можно было написать.
Но даже на это у меня ушли какие-то несуразные и невероятно утомительные часов 30-60 работы (включая собственно миграцию и разбивку на коммиты так, чтобы потом можно было сделать структурированное описание проблем) и 4 календарных месяца.
При том что Spring Boot вообще не моя тема и эта работа никак не продвинула меня к финализации Эргономичного подхода.
Поэтому я решил, что описать только проблемы с наиболее распространёнными технологиями - автоконфигами и Jackson-ом - будет вполне себе "good enough" ™️.
А остальное - никогда-нибдуь потом, микропостом, если будут вопросы по моему опыту.
#spring@ergonomic_code
Алексей Жидков
Мигрируем на Spring Boot 4. Что может пойти не так - Алексей Жидков
https://azhidkov.pro/
И для того, чтобы в будущем не врюхиваться в такие приключения, я решил написать для себя манифест блога, вики и этого канала.
Манифест блога
У меня есть определённое представление о том, как надо писать код, чтобы он был поддерживаемым:
1. Код должен быть покрыт тестами (ATDD);
* Потому что это развязывает руки команде рефакторить код и поддерживать его в хорошем состоянии
2. Эти тесты должны быть преимущественно приёмочными/клиентскими/граничными (ATDD);
* Потому что такие тесты являются наиболее показательными и устойчивыми к рефакторингу и их надо наименьшее количество для того, чтобы убедиться в работоспособности системы. А современные инструменты и оборудование практически снимают их проблемы со скоростью (легко можно добиться времени выполнения 5 секунд на старт тестов плюс 20-50мс на тест) и стабильностью (сброс состояния инфраструктуры перед каждым тестом);
3. Тесты должны писаться преимущественно до кода (ATDD);
* Потому что это:
- гарантирует вообще наличие тестов и то, что тесты вообще что-то проверяют;
- задаёт ритм разработки небольшими шагами, которые легко делать, отлаживать и ревьювить.
4. Модель должна быть разбита на небольшие слабосвязанные агрегаты (DDD);
* Потому что это помогает поддерживать высокую связанность (cohesion) элементов модели;
5. Модель должна образовывать направленный ацикличный граф (DDD, FA);
* Потому что это задаёт "начало" (важные и фундаментальные части) и "конец" (вторичные, вспомогательные и периферийные части) модели и тем самым упрощает её понимание;
6. Модель должна состоять из неизменяемых классов (FP, FA);
* Потому что это:
- Способствует исключению циклов;
- Упрощает понимание кода, работающего с ними;
7. Модель должна явно кодировать свои допустимые состояния (FP, OOP);
* Потому что это повышает наглядность/упрощает понимание модели и предотвращает ошибки;
8. Сложные алгоритмы и бизнес-правила должны быть оформлены в виде чистых функций (FP);
* Потому что это упрощает их понимание, тестирование и отладку;
9. Операции должны стремиться к сбалансированной форме (ака Recawr Sandwich) (SD, FA)
* Потому что это упрощает их понимание и, как следствие, предотвращение, поиск и устранение ошибок и проблем производительности;
10. Операции должны должны иметь высокую (функциональной, последовательной или коммуникационной) связанность (cohesion) (SD);
* Потому что это упрощает их понимание, тестирование, изменение и переиспользование;
11. Компоненты должны иметь высокую связность (cohesion) (OOD);
* Потому что это упрощает их понимание, тестирование, изменение и переиспользование;
И есть мой базовый стек - Kotlin, Spring, Spring Data JDBC, PostgreSQL.
И в блоге я пишу о том, как на этом стеке писать поддерживаемый код:
1. Как писать быстрые клиентские тесты на Kotlin, Spring, WebTestClient, JUnit, Kotest, Testcontainers, PostgreSQL;
2. Как проектировать тест-кейсы;
3. Как начинать разработку с тестов;
4. Как проектировать агрегаты. Без доступа к экспертам;
5. Как кодировать агрегаты с помощью Spring Data Jdbc и мапить их на таблицы PostgreSQL;
6. Как писать код, работающий с неизменяемой моделью на Kotlin;
7. Как проектировать точные модели, исключающие недопустимые состояния на Kotlin;
8. Как разделять бизнес-логику и ввод-вывод на Kotlin;
9. Как группировать ввод и как группировать вывод на Kotlin, Spring и Spring Data Jdbc;
10. Как проектировать операции с высокой связанностью;
11. Как проектировать Spring beans с высокой связанностью;
12. Как все эти правила затолкать в ИИ-агента;
13. Разбор конкретных кейсов из моей практики по темам выше.
Манифест вики
Вики содержит статьи на темы №1-11 из блога.
Разница в том, что в блоге эти темы раскрываются как туториалы и кейсы, а на вики - как абстрактный справочный материал.
#ergo_approach@ergonomic_code
Манифест блога
У меня есть определённое представление о том, как надо писать код, чтобы он был поддерживаемым:
1. Код должен быть покрыт тестами (ATDD);
* Потому что это развязывает руки команде рефакторить код и поддерживать его в хорошем состоянии
2. Эти тесты должны быть преимущественно приёмочными/клиентскими/граничными (ATDD);
* Потому что такие тесты являются наиболее показательными и устойчивыми к рефакторингу и их надо наименьшее количество для того, чтобы убедиться в работоспособности системы. А современные инструменты и оборудование практически снимают их проблемы со скоростью (легко можно добиться времени выполнения 5 секунд на старт тестов плюс 20-50мс на тест) и стабильностью (сброс состояния инфраструктуры перед каждым тестом);
3. Тесты должны писаться преимущественно до кода (ATDD);
* Потому что это:
- гарантирует вообще наличие тестов и то, что тесты вообще что-то проверяют;
- задаёт ритм разработки небольшими шагами, которые легко делать, отлаживать и ревьювить.
4. Модель должна быть разбита на небольшие слабосвязанные агрегаты (DDD);
* Потому что это помогает поддерживать высокую связанность (cohesion) элементов модели;
5. Модель должна образовывать направленный ацикличный граф (DDD, FA);
* Потому что это задаёт "начало" (важные и фундаментальные части) и "конец" (вторичные, вспомогательные и периферийные части) модели и тем самым упрощает её понимание;
6. Модель должна состоять из неизменяемых классов (FP, FA);
* Потому что это:
- Способствует исключению циклов;
- Упрощает понимание кода, работающего с ними;
7. Модель должна явно кодировать свои допустимые состояния (FP, OOP);
* Потому что это повышает наглядность/упрощает понимание модели и предотвращает ошибки;
8. Сложные алгоритмы и бизнес-правила должны быть оформлены в виде чистых функций (FP);
* Потому что это упрощает их понимание, тестирование и отладку;
9. Операции должны стремиться к сбалансированной форме (ака Recawr Sandwich) (SD, FA)
* Потому что это упрощает их понимание и, как следствие, предотвращение, поиск и устранение ошибок и проблем производительности;
10. Операции должны должны иметь высокую (функциональной, последовательной или коммуникационной) связанность (cohesion) (SD);
* Потому что это упрощает их понимание, тестирование, изменение и переиспользование;
11. Компоненты должны иметь высокую связность (cohesion) (OOD);
* Потому что это упрощает их понимание, тестирование, изменение и переиспользование;
И есть мой базовый стек - Kotlin, Spring, Spring Data JDBC, PostgreSQL.
И в блоге я пишу о том, как на этом стеке писать поддерживаемый код:
1. Как писать быстрые клиентские тесты на Kotlin, Spring, WebTestClient, JUnit, Kotest, Testcontainers, PostgreSQL;
2. Как проектировать тест-кейсы;
3. Как начинать разработку с тестов;
4. Как проектировать агрегаты. Без доступа к экспертам;
5. Как кодировать агрегаты с помощью Spring Data Jdbc и мапить их на таблицы PostgreSQL;
6. Как писать код, работающий с неизменяемой моделью на Kotlin;
7. Как проектировать точные модели, исключающие недопустимые состояния на Kotlin;
8. Как разделять бизнес-логику и ввод-вывод на Kotlin;
9. Как группировать ввод и как группировать вывод на Kotlin, Spring и Spring Data Jdbc;
10. Как проектировать операции с высокой связанностью;
11. Как проектировать Spring beans с высокой связанностью;
12. Как все эти правила затолкать в ИИ-агента;
13. Разбор конкретных кейсов из моей практики по темам выше.
Манифест вики
Вики содержит статьи на темы №1-11 из блога.
Разница в том, что в блоге эти темы раскрываются как туториалы и кейсы, а на вики - как абстрактный справочный материал.
#ergo_approach@ergonomic_code
Алексей Жидков
Посты - Алексей Жидков
Разработка и реинжиниринг ПО
👍8❤5🔥3
Манифест канала
В канале я пишу:
1. Анонсы постов в блоге и статей на вики;
2. Микропосты по тем же темам, что и в блоге;
3. Микропосты по прочей связанной тематике - индустриальные новости, управление проектами и организация разработки, разработка фронта, книги, посты, выступления, ИИ, технологии и т. п.;
В канале я пишу:
1. Анонсы постов в блоге и статей на вики;
2. Микропосты по тем же темам, что и в блоге;
3. Микропосты по прочей связанной тематике - индустриальные новости, управление проектами и организация разработки, разработка фронта, книги, посты, выступления, ИИ, технологии и т. п.;
👍2
Привет!
Если вы как и я:
1. любите текстовые редакторы
2. с поддержкой вим-режима
3. и при этом красивые
4. и быстрые
5. и не глюкавые
- попробуйте посмотреть Zed.
Меня в последнее время VS Code задолбал тем, что периодически выжирал на 100% одно ядро. В этом, почти, наверняка виноваты Kotlin LSP или Codex, но это подтолкнуло меня снова глянуть на Zed. Который по счастливой случайности зарелизал версию 1.0 пару недель назад.
И я приятно удивился - на мой вкус и субъективный взгляд, он симпатичнее и быстрее ВС Кода.
Экосистема у него беднее - нет JB-шного Kotlin LSP и официального плагина Codex - но оно и к лучшему, судя по всему:)
Ещё нет превью для asciidoc и mermaid (отдельного, в markdown превью mmd-вставки рендярятся).
Но, тем не менее, я уже неделю в нём пишу тексты и ИИ фреймворк, пока доволен и поставил его дефолтным текстовым редактором в системе. Посмотрим как пойдёт.
#tools@ergonomic_code
Если вы как и я:
1. любите текстовые редакторы
2. с поддержкой вим-режима
3. и при этом красивые
4. и быстрые
5. и не глюкавые
- попробуйте посмотреть Zed.
Меня в последнее время VS Code задолбал тем, что периодически выжирал на 100% одно ядро. В этом, почти, наверняка виноваты Kotlin LSP или Codex, но это подтолкнуло меня снова глянуть на Zed. Который по счастливой случайности зарелизал версию 1.0 пару недель назад.
И я приятно удивился - на мой вкус и субъективный взгляд, он симпатичнее и быстрее ВС Кода.
Экосистема у него беднее - нет JB-шного Kotlin LSP и официального плагина Codex - но оно и к лучшему, судя по всему:)
Ещё нет превью для asciidoc и mermaid (отдельного, в markdown превью mmd-вставки рендярятся).
Но, тем не менее, я уже неделю в нём пишу тексты и ИИ фреймворк, пока доволен и поставил его дефолтным текстовым редактором в системе. Посмотрим как пойдёт.
#tools@ergonomic_code
Zed
Zed — Your last next editor
Zed is a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter.
👍3👀3❤2
Привет!
Навеяно интернетом.
Многие думают, что тесты нужны для того, чтобы проверить код, который программист написал только что.
Некоторые из них вспоминают, что Дейкстра писал:
И говорят: «Тесты не нужны» (c).
И (по крайней мере для тестов на базе примеров, а не тестов свойств) в каком-то смысле они правы — я как человек, который "пишет тесты. не так много. в основном интеграционные", отлично знаю, что Корпоративный Разработчик из Ада обдурит львиную долю моих интеграционных тестов на базе примеров как младенцев.
Но, несмотря на это, у меня другое мнение по вопросу "нужны ли тесты?" (вот это каминг аут у меня тут вышел🤦♂️ ).
Тесты нужны. Но не для того, чтобы продемонстрировать отсутствие ошибок в коде, который я только что написал. А для того, чтобы продемонстрировать отсутствие ошибок в коде, который я только что изменил. И во всех его зависимостях.
И с учётом этого, тесты начинают играть новыми красками.
Если вы только что сделали новую фичу и все тесты зелёные — то действительно, в ней всё ещё могут быть баги.
Но можно фикс каждого бага начинать с теста.
И тогда после того, как ваша фича пройдёт QA и покрутится месяц в проде, она обрастёт набором тестов на кейсы, которые действительно важны пользователям.
И этот набор уже можно будет считать достаточно адекватным способом продемонстрировать отсутствие ошибок в фиче.
И это — быстрая проверка кода тестами на отсутствие ошибок — единственный известный мне реальный способ уйти от установки "работает — не трожь" и спокойно менять работающий код тогда, когда это надо.
Что, в свою очередь, является единственным известным мне способом своевременно отдавать техдолг: менять уже работающий код.
Что, наконец, является единственным известным мне способом гордиться тем, что я делаю, и с радостьюприходить утром на работу переключаться в обед на рабочий воркспейс. Ну и не терять темп разработки со временем.
—
Теоретически адекватных тестов можно можно добиться и без TDD.
Но дисциплина работы по TDD даёт простым смертным:
1. Гарантию того, что вы действительно напишете тесты (а не спишите их написание в техдолг).
2. Гарантию того, что эти тесты будут проверять все требования о которых вы и постановщик задачи подумали (а не только те, о которых вы вспомнили и на которые хватило времени).
3. Гарантию того, что эти тесты действительно что-то проверяют, а не зелёные всегда (вы же не пишете тесты на тесты?).
В общем: Пишите тесты. Сначала. Не так много. В основном интеграционные.
#ergo_testing@ergonomic_code
Навеяно интернетом.
Многие думают, что тесты нужны для того, чтобы проверить код, который программист написал только что.
Некоторые из них вспоминают, что Дейкстра писал:
Program testing can be a very effective way to show the presence of bugs, but it is hopelessly inadequate for showing their absence.
—
Тестирование программ может быть очень эффективным способом продемонстрировать наличие ошибок, но оно безнадёжно неадекватно для демонстрации их отсутствия.
И говорят: «Тесты не нужны» (c).
И (по крайней мере для тестов на базе примеров, а не тестов свойств) в каком-то смысле они правы — я как человек, который "пишет тесты. не так много. в основном интеграционные", отлично знаю, что Корпоративный Разработчик из Ада обдурит львиную долю моих интеграционных тестов на базе примеров как младенцев.
Но, несмотря на это, у меня другое мнение по вопросу "нужны ли тесты?" (вот это каминг аут у меня тут вышел
Тесты нужны. Но не для того, чтобы продемонстрировать отсутствие ошибок в коде, который я только что написал. А для того, чтобы продемонстрировать отсутствие ошибок в коде, который я только что изменил. И во всех его зависимостях.
И с учётом этого, тесты начинают играть новыми красками.
Если вы только что сделали новую фичу и все тесты зелёные — то действительно, в ней всё ещё могут быть баги.
Но можно фикс каждого бага начинать с теста.
И тогда после того, как ваша фича пройдёт QA и покрутится месяц в проде, она обрастёт набором тестов на кейсы, которые действительно важны пользователям.
И этот набор уже можно будет считать достаточно адекватным способом продемонстрировать отсутствие ошибок в фиче.
И это — быстрая проверка кода тестами на отсутствие ошибок — единственный известный мне реальный способ уйти от установки "работает — не трожь" и спокойно менять работающий код тогда, когда это надо.
Что, в свою очередь, является единственным известным мне способом своевременно отдавать техдолг: менять уже работающий код.
Что, наконец, является единственным известным мне способом гордиться тем, что я делаю, и с радостью
—
Теоретически адекватных тестов можно можно добиться и без TDD.
Но дисциплина работы по TDD даёт простым смертным:
1. Гарантию того, что вы действительно напишете тесты (а не спишите их написание в техдолг).
2. Гарантию того, что эти тесты будут проверять все требования о которых вы и постановщик задачи подумали (а не только те, о которых вы вспомнили и на которые хватило времени).
3. Гарантию того, что эти тесты действительно что-то проверяют, а не зелёные всегда (вы же не пишете тесты на тесты?).
В общем: Пишите тесты. Сначала. Не так много. В основном интеграционные.
#ergo_testing@ergonomic_code
Please open Telegram to view this post
VIEW IN TELEGRAM
Kentcdodds
Write tests. Not too many. Mostly integration.
[Guillermo Rauch](https://x.com/rauchg) [tweeted](https://x.com/rauchg/status/807626710350839808) this a while back. Let's take a dive into what it means.
❤9💯3
Привет!
Вести с полей Spring Data Jdbc.
Я года 2 назад запилил небольшой DSL для SDJ, который позволяет писать запросы так:
Но в котором есть гора дублей с типизацией и без:
--
А недавно запилил фрагмент, который позволяет делать merge/upsert с кастомным SQL-ем:
И вот, в SDJ 4.1 завозят типизированные пути в Criteria API и merge из коробоки. Мелочь, а приятно.
В целом эти пара плюшек и RestTestClient (и ускорение тестов процентов на 10% за счёт перехода на него с WebTestClient) - вполне окупают заморочки на миграцию на Spring Boot 4, имхо.
#spring_data_jdbc@ergonomic_code #tools@ergonomic_code
Вести с полей Spring Data Jdbc.
Я года 2 назад запилил небольшой DSL для SDJ, который позволяет писать запросы так:
jdbcAggregateOperations.findAll(
query(CountryCode::code isEqualIfNotNull countryCode.code),
Country::class.java
)
Но в котором есть гора дублей с типизацией и без:
infix fun String.isEqualIfNotNull(value: String?): Criteria {
return if (value != null) {
this.isEqual(value)
} else {
Criteria.empty()
}
}
infix fun <T, V> KProperty1<T, V>.isEqualIfNotNull(value: String?): Criteria {
return this.columnName().isEqualIfNotNull(value)
}--
А недавно запилил фрагмент, который позволяет делать merge/upsert с кастомным SQL-ем:
interface DomainEventsRepo :
CrudRepository<DomainEvent, UUID>,
MergeExecutor<DomainEvent> {
fun mergeIgnoringNew(entity: DomainEvent): DomainEvent? {
return mergeIgnoringNew(
insertSql = """
INSERT INTO domain_event_inbox ( id, event_id, domain_event, created_at, updated_at, processed, version )
VALUES ( :id, :event_id, :diary_domain_event, :created_at, :updated_at, :processed, :version )
ON CONFLICT (id) DO NOTHING
RETURNING *
""",
entity = entity
)
}
И вот, в SDJ 4.1 завозят типизированные пути в Criteria API и merge из коробоки. Мелочь, а приятно.
В целом эти пара плюшек и RestTestClient (и ускорение тестов процентов на 10% за счёт перехода на него с WebTestClient) - вполне окупают заморочки на миграцию на Spring Boot 4, имхо.
#spring_data_jdbc@ergonomic_code #tools@ergonomic_code
GitHub
Support TypedPropertyPath for queries and update. by christophstrobl · Pull Request #2227 · spring-projects/spring-data-relational
This PR adds overloads for methods accepting a column name to also deal with TypedPropertyPath by obtaining the property and passing that on as column name.
Привет!
Посмотрел кейнот КотлинКонф 26
Из любопытного (для меня):
1. Kotlin LSP перешёл в альфу
2. Гугл переписал "web serving stack" страницы поиска на Котлин (с корутинами). Любопытно, почему слезли (или не залезли на) с Go?
3. И в гугле сейчас на Котлине пишут больше бакендеры, чем андроидщики
4. Гуглодоки на Web/iOS переписали на Kotlin Multiplatform
5. Гопатыч лучше клода в андроид (Kotlin?) разработке
6. А вот чувак из антрофика говорит, что клод пишет на Kotlin лучше "неуказанного соперника"
7. ~10 лет спустя Exposed вышел в 1.0
8. Без пруфов - использование Котлин ускоряет разработку до 15-20%
9. У JB есть некий плагин для Lambok-а и он недавно вышел в Альфу
10. Только 5% ИИ продуктов дошли до прода
11. По какому-то бенчу MCP Java 30 раз быстрее Python-а, в 10 раз быстрее NodeJs и практически 1 в 1 как Go. Хз в чём, Лонг супер быстро и супер кратко говорит.
12. Compose на web-е пошёл в бету
#kotlin@ergonomic_code #talks@ergonomic_code
Посмотрел кейнот КотлинКонф 26
Из любопытного (для меня):
1. Kotlin LSP перешёл в альфу
2. Гугл переписал "web serving stack" страницы поиска на Котлин (с корутинами). Любопытно, почему слезли (или не залезли на) с Go?
3. И в гугле сейчас на Котлине пишут больше бакендеры, чем андроидщики
4. Гуглодоки на Web/iOS переписали на Kotlin Multiplatform
5. Гопатыч лучше клода в андроид (Kotlin?) разработке
6. А вот чувак из антрофика говорит, что клод пишет на Kotlin лучше "неуказанного соперника"
7. ~10 лет спустя Exposed вышел в 1.0
8. Без пруфов - использование Котлин ускоряет разработку до 15-20%
9. У JB есть некий плагин для Lambok-а и он недавно вышел в Альфу
10. Только 5% ИИ продуктов дошли до прода
11. По какому-то бенчу MCP Java 30 раз быстрее Python-а, в 10 раз быстрее NodeJs и практически 1 в 1 как Go. Хз в чём, Лонг супер быстро и супер кратко говорит.
12. Compose на web-е пошёл в бету
#kotlin@ergonomic_code #talks@ergonomic_code
YouTube
Keynote | KotlinConf ’26
KotlinConf is the premier event connecting professional developers and companies shaping the future with cutting-edge technologies.
#kotlin #kotlinconf2026
#kotlin #kotlinconf2026
1❤3🔥2💯2