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

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

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

https://azhidkov.pro
Download Telegram
И для того, чтобы в будущем не врюхиваться в такие приключения, я решил написать для себя манифест блога, вики и этого канала.

Манифест блога
У меня есть определённое представление о том, как надо писать код, чтобы он был поддерживаемым:

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. Микропосты по прочей связанной тематике - индустриальные новости, управление проектами и организация разработки, разработка фронта, книги, посты, выступления, ИИ, технологии и т. п.;
👍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
👍3👀3❤2
Привет!

Навеяно интернетом.

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

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
❤9💯3
Привет!

Вести с полей 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
Привет!

Посмотрел кейнот КотлинКонф 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
1❤3🔥2💯2
И я тут 5 лет спустя прикрутил анонимную аналитику к блогу и узнал, что у меня на блог есть ссылки в:
1. конфе ВК на диаграмму эффектов
2. явно каком-то корпарате с MS Teams-ом на пост про структурный дизайн
3. конфе НСПК на пост про декомпозицию на базе эффектов

Запишу себе это в ачивки:)

#ergo_approach@ergonomic_code
👍3⚡2❤2
Привет!

Давненько я не писал на злобу дня.
Так что вот вам пара жизнеутверждающих мыслей для кожаных мешков-задротов вроде меня:)

Мысль первая: а что если "ум" ИИ растёт не по экспоненте, а по логарифму?

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

Затем в конце весны-летом, случился качественный скачок - Junie и Windsurf (не помню с какими моделями) у меня хоть как-то заработали и начали хоть что-то писать. Но толку от этого было крайне мало - они всё делали очень медленно, часто вообще не могли решить проблему, а когда могли - делали какую-то дичь.

Затем, в августе вышел GPT-5 и это был ещё один качественный скачёк, который меня изрядно шокировал и напугал - теперь гопатыч стал лучше меня раскапывать всякую дичь со спрингом.

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

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

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

Это, конечно, может быть наивная надежда на чудо, свойственная кожаным мешкам, но что уж тут поделаешь:)

#ai@ergonomic_code
❤4
Мысль вторая: компиляторщики всё ещё не вымерли

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

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

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

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

Если, конечно, ИИ растёт по логарифму или линейно.
Потому как если по экспоненте, то... я не берусь даже пытаться предсказывать, что будет.

#ai@ergonomic_code
Привет!

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

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

#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