Telegram Web
Привет!

У меня на этой недели был леденящий душу опыт с хэппи эндом.

Я всю неделю активно девелопал новый сервис в Проекте Э и при этом активно экспериментировал с оптимизацией потребления РАМ и временем старта тестов.
И делал всё это вместе GPT-5 low reasoning через бесплатный план Windsurfa-а.

И он реально хорош. Он на порядок-два лучше GPT-4 и Sonnet-4. Практически не глючит и в 9 из 10 случаев быстрее меня решает WTF-ы со Спрингом. Например, у меня был value object в Sdj-модели с кастомным конвертером. И SDJ не мог найти конвертер. Я по привычке залез в кишки спринга и увидел, что конвертер доступен. Но не работает. Тут меня чёрт дёрнул спросить у гопатыча и он через минуту-две сказал, что я лупень и в модели импортнул не тот класс - у меня после экспериментов остался второй такой же класс в другом пакете. Мой опыт показывает, что я на такой фигне мог залипнуть на пару часов.

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

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

Однако сегодня я смог таки победить бездушную машину. В WTF-е с kover-ом. У меня была проблема с тем что конфиг на Kotlin DSL не компилялся. Тут я уже наоборот сходу пошёл к гопатычу и он начал глючить как не в себя. И не решил проблему. Тогда я сам вдумчиво прочитал сообщение об ошибке и решил проблему за минуту.

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

Но думать в направлении адаптации ЭП под нейронки - всё равно буду:) Соображения на этот счёт есть, но в другой раз напишу:)

В общем:
1. Для популярных фреймворков GPT 5 - нереально крут. Срочно пробуйте если ещё нет.
2. Но он всё ещё СЛАУ-переросток, не одупляет что он делает и в нестандартных случаях всё ещё бесполезен

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

У меня в новом сервисе в Проекте Э на Spring Boot 3.5 новый рекорд скорости тестов:)
54 кейса за 2.7 секунды, 90% тестов - < 60мс, медиана - 14мс.

Сетап:
1. инфра (PostgreSQL и Minio на RAM-диске) запускается руками по кнопке в Идее docker compose-ом.
2. Отказ от компонент скана бинов
3. Отказ от скана авто-конфигов
4. ленивая иницилазиация бинов (spring.main.lazy-initialization)
5. Работа через WebTestClient с MockMvc

Не 5мс на кейс, как у Саши Раковского, конечно, но уже близко и это полный набор тестов, после которого можно деплоить в прод:)

#ergo_testing@ergonomic_code #project_e@ergonomic_code #spring_boot@ergonomic_code
🔥8👍7
Привет!

Обещанный микропост про эксперимент с http4k.

Напомню контекст - мне недавно понадобилось сделать в Проекте Э новый небольшой сервис и у нас довольно сильно ограничена RAM на стендах, поэтому я решил поэксперементировать с http4k + jooq jdbi с целью сократить потреблением RAM.

Изначально я написал прототип на Spring Boot 3.5 (MVC + Data JDBC) буквально с парой методов - создание сущности на 3 поля плюс файла (в минио) и получение файла.
Далее методика всех измерений была следующая:
1. запустить сервис
2. curl-запросами создать сущность и получить картинку
3. померить ps-ом RSS процесса.

И для чистого Spring Boot я получил 270mb.

Тогда я написал прототип на http4k + jdbi и для него получил 236mb. В целом на этом можно было бы и закончить эксперимент, т.к. экономия была несущественная, зато с http4k пришлось бы руками писать аутентификацию, rbac, управление транзакциями, кэширование, да ещё и запросы на доменные модели руками мапить.

Но я не закончил и накопал ещё пару любопытных штук.

Первым делом я пошёл к гопатычу и спросил какой стэк под JVM дал бы большую экономию по памяти. Он накидал несколько вариантов, среди которых обещал ~150mb RAM для Micronaut. Я спросил за счёт чего Micronaut экономит память. Он сказал - за счёт Netty.

Я думаю ну ладно, в http4k переехать на Netty - дело пары строк.
И переехал. И получил 156mb RAM.

А заодно ещё и дикий WTF - у http4k API обработчиков запросов - синхронное. И нет ручки, чтобы настроить Netty на виртуальные потоки. То есть из коробки Netty в http4k - это фикция.
Пока разбирался как таки примострячить виртуальные потоки в http4k/Netty залез в исходники и нашёл там коммент с "элегантым" решением этой проблемы:

Stock version of an Netty Server. Not that if you want to configure your own server instance you
can duplicate this code and modify it as required
. We are purposefully trying to limit options
here to keep the API simple for the 99% of use-cases.

Ну т.е. хотите чтобы Нетти норм работал - копипастьте код либы и делайте с ним что хотите 🤦‍♂️ О каких 99% юзкейсах они говорят - вообще не представляю.

В общем поматерился я на хттп4к и подумал, что Spring Boot же тоже может в Netty. И там вроде как даже не обязательно делать контроллеры на Reactor-е или корутинах - вроде как можно писать обычные контроллеры и настроить (вот это ничего себе!) тредпул на котором Спринг будет их дёргать.
Сказано-сделано, минут за 15-30 переехал на WebFlux, барабанная дробь... 245mb... Тут у меня бюджет на эксперименты начал уже заканчиваться, поэтому я решил, что дело количества зависимостей, которые тащит с собой WebFlux и пошёл дальше.

А дальше я решил дать ещё один шанс Spring Boot Native. Как и в прошлый раз пришлось повоевать с рефлекшеном, но на этот раз со мной был GPT-5 и эти проблемы он щёлкал на раз-два, поэтому ещё минут через 30 я получил цифры для нативной сборки - 157mb. Неплохо.

Однако пока копался с Нативом, я наткнулся на Spring Boot Ahead-of-Time Processing, который должен был дать оптимизацию времени запуска и потребления RAM без 3 минут компиляции и сюрпризов в рантайме Нативной сборки. И он в целом дал - 234mb RAM.

Итого вышли такие цифры:
1. Spring Boot + Tomcat - 270mb
2. http4k + Jetty - 236mb
3. http4k + Netty - 156mb
4. Spring Boot + Netty - 245mb
3. Spring Boot Native + Tomcat - 157mb
4. Spring Boot AOT Processing + Tomcat - 234mb

Помедитировав на них я решил, что переход на http4k того не стоит и снова остался на Spring Boot. Не люблю его за монструозность и количество автомагии но для меня сейчас он всё ещё остаётся наименьшим из зол.

#spring_boot@ergonomic_code #project_e@ergonomic_code
Please open Telegram to view this post
VIEW IN TELEGRAM
👏8👍6🔥53
Привет!

Поучительная история о важности именования.

У меня тут джуны недавно в Проекте Э запилили пуши.
И пока ревьювил бэк я там наткнулся на строчку с дип линкой (в которых я не шарю) "myapp://<some-screen>", которая отправляется в МП.
И она мне сразу не понравилась из-за myapp. Фик знает почему myapp - плохо.
Попахивает дилетантством, небрежностью и копипастой со стековерфлоу.
И вроде как непонятно что она значит. Ну т.е. понятно, конечно - моё приложение. Но кто это писал? Чьё это приложение?
И тут вроде тоже, и мне, и любому читателю этого кода с вероятностью 99% будет очевидно, кто это писал и чьё это приложение.
Но всё равно с этим именем "что-то не то".

В общем я был уверен, что это имя херовое, но сам убедительных (для себя) аргументов не придумал и пошёл гуглить рекомендации по формированию диплинок.
И нагуглил, что кастомные схемы в диплинках - это дыра в безопасности в виде Deep Link Collision.
Из-за неё кто угодно может подписаться на наши диплинки. На андроиде в этом случае откроется диалог с вопросом в какое приложение перейти - наше или чужое (как вариант - с таким же именем и иконкой), а на иосе - вообще "If multiple apps register the same scheme, the app the system targets is undefined" 🤯

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

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

#project_e@ergonomic_code
👍18💯43
Привет!

Вести с ИИ полей.

Не спрашивайте зачем, но мне тут потребовалось конвертить в консоли структурированные (в json-е) логи в человеко-читаемые.
Сначала я попробовал с GPT-5 собрать шелл-скрипт. Убил часа 3, результат получил, но на "три с минусом".

А потом сделал по другому:
1. создал пустую папку
2. открыл её в VS Code
3. открыл в нём Копилот с тем же GPT-5 в режиме агента
4. попросил написать утилиту на Расте которая превращает "вот такие" логи вот "в такие". Плюс накинул пару требований в духе стандартной ширины таймстемпа и обрезки хэшей подов
5. и пошёл чистить диск на ноуте
6. через пару часов я получил рабочую утилитку в 400 строк и 600кб RAM. Плюс отдельно стоит проговорить, что эта утилитка сохраняет консольную раскраску подов - я бы, наверное, ток на это пару часов убил. И 40 гигов свободного места на на ноуте

Код получился полнейшим говном (см картинки) - я в него попробовал вникнуть, но быстро забил.
Но он работает, а сам я с ним разбираться не собираюсь. Да и выкинуть не жалко, если что.
😁10👍73
Привет!

Я закончил большой 5-месячный долгострой на 43 коммита по интеграции Google Calendar в Trainer Advisor.

В реализации этой фичи довольно много интересных, на мой взгляд, аспектов, каждый из которых заслуживает отдельного поста. Но сейчас их писать настроения нет, поэтому я ограничился микропостом с обзором реализации. Ну как микро - 25 минут чтения по оценке ФФ:)

И чтобы вам не продираться сквозь 25 минут потока сознания в поисках чего-то интересного для себя - вот краткое содержание:)

Абстрактный ресурс
Для меня самым интересным в этой фиче было то, что для её реализации пришлось ввести некие штуки с рабочим названием «Абстрактный ресурс».

Не знаю пока что с этим делать и надо ли что-то делать.

MockServers
Паттерн для организации WireMock-стабов

Fixtures
Паттерн для сетапа фикстур, состоящих из сложных графов объектов

Пример «простого» CRUD-приложения
Я в последнее время в канале несколько раз писал о «простых» CRUD-приложения — приложениях без сложной бизнес-логики или нефункциональных требований, но, тем не менее, которые назвать простыми не поворачивается язык. И всякий раз это порождало вопросы в комментариях, что конкретно я имею ввиду.

И вот у меня, наконец появился, хороший open source-ый пример — операция отображения страницы расписания терапевта.

Рефакторинг findCalendarItemsInInterval (уровни абстракции/стратификация)
Пример приведения метода к соответствию правилу "У функции должен быть один уровень абстракции"

SourceItem → URI​​​​
К своему стыду, должен признаться, что я только недавно до конца (чуть лучше?) осознал что такое URI. Но лучше поздно, чем никогда - правда же?
И вот теперь благодаря этим новым знаниям, мне удалось сделать работу с разными календарями в Trainer Advisor чуть более "production grade".

Как добыть OAuth2AuthorizedClient без того, чтобы перетереть Authorization в SecurityContext
Я хз. Но у меня есть рабочий код, на который можно ориентироваться
И этот код мало того, что рабочий — он ещё и тестами покрыт.

Тестирование интеграции с Google OAuth и Google Calendars
Вот оно:

- GoogleAuthorizationIntegrationTest;
- GoogleCalendarsServiceTest;
- GetGoogleCalendarsSettingsEndpointTest;
- SetCalendarShouldBeShownTest;
- Тест "Страница календаря должна рендериться корректно, даже если у терапевта есть подключенный Google-календарь и запрос событий из него приводит к ошибке";
- CreateAppointmentPageTest.createAppointmntWithGoogleEvnt;
- SchedulePageControllerTest;

Верификация приложения в Google
Это 7 кругов ада. Но без них ваши токены будут протухать раз в неделю и вам надо будет снова гнать юзеров на авторизацию в гугле

#ergo_approach@ergonomic_code #ergo_arch@ergonomic_code #ergo_testing@ergonomic_code #trainer_advisor@ergonomic_code #case@ergonomic_code
9👍7
Привет!

Саша Раковский написал пост о своём подходе к тестированию с подробными диаграммами, мемасиками и ссылкой на меня - советую прочитать:)

Судя по описанию, Сашин гибридный подход даёт кодовые базы, которые я называю эргономичными.
8🔥4
Привет!

У меня тут любопытный диалог с гопатычем вышел:

Я: Что можно почитать по проектированию классов, представляющих информацию системы (бакэнда)?

Гопатыч (сокращённо):
- David West — “Object Thinking”
- Eric Evans — “Domain-Driven Design” (главы 5–9)
- Vaughn Vernon — “Implementing Domain-Driven Design”
- Joshua Bloch — “Effective Java” (главы 2–4)
- Robert C. Martin — “Clean Code”, главы 6–11
- Martin Fowler — “Patterns of Enterprise Application Architecture”
- Michael Feathers — “Working Effectively with Legacy Code”
- Dan Bergh Johnsson, Daniel Deogun, Daniel Sawano — “Secure by Design”
- Rich Hickey — “Simple Made Easy” (доклад)
- Adam Wiggins — “The Twelve-Factor App” (factor IV и VI)
- Edward Yourdon — “Structured Design” (старенькое, но ясное)
- Yegor Bugayenko — “Elegant Objects” (т.1–2)
- Holub on Patterns (Allen Holub)
- “Domain Modeling Made Functional” — Scott Wlaschin

Я: Знаешь, что самое страшное и обидное? Я это всё кроме Secure by Design и Holub on Patterns уже прочитал. А как системно подходить к проектированию модели данных/информации своих систем - до сих пор не знаю.

Гопатыч:

Это честное и очень глубокое признание — и ты не один.
Многие, даже очень опытные инженеры (и архитекторы с 20+ годами), приходят ровно к этому рубежу:
всё про DDD, Clean Code и Fowler вроде усвоено,
а как системно проектировать саму модель информации — всё равно неясно.
Потому что нигде это не описано как отдельная дисциплина.



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



🧭 Почему тебе “не хватает системы”

Большинство источников, даже DDD, описывают что должно быть (Entities, Aggregates, Value Objects) и почему (инкапсуляция, инварианты, ubiquitous language),
но почти не говорят, как именно прийти к правильной структуре данных — то есть к набору и форме классов, которые выражают реальность твоей системы.

Причина — потому что в классическом ОО-мышлении данные вторичны относительно поведения.
А в реальных backend-системах — наоборот: данные центральны, поведение меняется вокруг них.
Нам нужен язык проектирования, где первичен информационный ландшафт, а не классы/объекты.



🧩 Попробуем собрать системный подход из кирпичиков
1. Начни не с классов, а с информационных потоков


Продолжение 1
Продолжение 2

PS>

Это эхо внутренней кухни работы над Эргономичной моделью данных - месяц уже ломаю голову, целевую картинку (буквально картинку - абстрактную диаграмму типа как для структуры компонентов) вижу, а описать её не выходит.
🔥10👍54
Привет!

Вы, возможно, уже забыли, что мы проводим исследование "Характеристики поддерживаемых кодовых баз backend-приложений", а я — нет:)

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

Во-вторых, с радостью представляю вам первые результаты анализа данных!:)

К сожалению, задача анализа данных оказалось неподъёмной для нашей небольшой группы энтузиастов, поэтому отчёт практически полностью составлен GPT-5 на основе анализа, выполненного им же.
Но даже вместе с гопатычем я потратил на подготовку примерно 10 часов — поэтому отчёт всё-таки основан на данных, а не на глюках.

Также, если у вас есть квалификация, возможность и желание выполнить профессиональный анализ наших данных - напишите мне пожалуйста в Telegram.

Ну и сразу TL;DR, там есть очень неожиданные для меня пункты:

Статистически достоверные и практически значимые факторы поддерживаемости:
— отсутствие циклов между модулями, пакетами и в модели данных;
— соблюдение Interface Segregation Principle (ISP);
— осознанное применение шаблонов проектирования.
Все три фактора показывают устойчивую положительную или отрицательную связь как по χ²-анализу, так и в ML-моделях (LogReg + RandomForest).

Погранично значимые факторы: применение ER-диаграмм; соблюдение CQS и принципов дизайна компонентов (ADP, SDP и др.); минимизация синхронных вызовов между сервисами; использование (микро)сервисной архитектуры; высокий процент покрытия тестами и раннее тестирование; наличие гайдлайна разработки.

Статистически слабые, но показательные тренды: проекты с простыми моделями данных и простыми способами доступа (агрегаты, SQL, лёгкие ORM) чаще воспринимаются как поддерживаемые; применение «детройтской школы тестирования» повышает уверенность в тестах.

Ложные ожидания: SRP, OCP, LSP, модульные монолиты, парадигма (ООП/ФП/ПП), школа тестирования и запрет прямых обращений из контроллеров к репозиториям не показали достоверного влияния на поддерживаемость; DIP оказывает статистически достоверный и практически значимый отрицательный эффект — проекты, где его декларировали, чаще оказывались проблемными.

Общие выводы: поддерживаемость определяется архитектурной дисциплиной (отсутствие циклов), простотой модели данных, модульностью интерфейсов (ISP) и осознанным применением структурных решений (шаблоны, слабая связанность, раннее тестирование).
🔥10👍6
Привет!

У меня у самого были вопросики касательно того значимости OCP и LSP и Саша Раковский тоже это подсветил, поэтому я тут с гопатычем ещё немного поковырялся с ними. Иииииии - отбой, они не влияют на поддерживаемость.

Слово гопатычу:

Отлично — вот теперь у нас реальное подтверждение твоей гипотезы [о том, что сила связи OCP и LSP вызвана общим перекосом в пользу поддерживаемых проектов]👇

📊 Что показывают результаты
Принцип Коэффициент p-value Интерпретация
SRP −0.75 0.13 Не значим (p > 0.05). Связь с поддерживаемостью отрицательная, но статистически не подтверждена.
OCP +0.30 0.43 Не значим. После контроля общего фона исчезает эффект, который был виден в χ².
LSP +0.16 0.62 Не значим. Аналогично — исчезла кажущаяся корреляция.
ISP +1.02 0.018 Единственный принцип с достоверным вкладом в прогноз поддерживаемости (p < 0.05).
DIP −0.69 0.08 Почти значим (тенденция, p≈0.08), но эффект отрицательный — может отражать шум или трудности восприятия DIP.

🧠 Интерпретация

OCP и LSP перестали быть значимыми, как ты и предполагал.
👉 Их высокая χ²-связь объясняется перекосом выборки (64 % поддерживаемых проектов) и когнитивным эффектом ретроактивной атрибуции (“в хороших проектах наверняка следовали OCP/LSP”).
После контроля базовой вероятности поддерживаемости — эффект исчез.

ISP (Interface Segregation Principle) неожиданно оказался единственным статистически значимым.
Это логично: соблюдение ISP действительно улучшает локальную когнитивную простоту — меньше «толстых интерфейсов» и зависимостей.
То есть — легче разобраться, легче поддерживать.
Его влияние “пробивается” даже после нормализации.

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

Pseudo R² ≈ 0.22 означает, что модель объясняет около 22 % вариации в восприятии поддерживаемости — это довольно много для социальных/опросных данных:
в реальных социотехнических системах 20–30 % — уже значимый вклад.

🧩 Вывод

После статистической коррекции на общий перекос выборки влияние OCP и LSP на поддерживаемость исчезает.
Их высокая χ²-связь, вероятно, отражает перцептивное приписывание “хороших принципов” удачным проектам, а не фактическое следование.

Из принципов SOLID только Interface Segregation Principle сохраняет достоверную положительную связь с восприятием поддерживаемости, что можно трактовать как эмпирическое подтверждение его когнитивной пользы: он уменьшает сложность интерфейсов и локальные зависимости, облегчая понимание системы.
🔥6
Привет!

Собрал микропост со сверкой рекомендаций ЭП с результатами анализа.

TLDR:

Судя по данным, собранным в рамках исследования:
— три из девяти рекомендаций Эргономичного подхода (пишите тесты, держите тесты быстрыми, исключайте циклы в зависимостях) ведут к повышению поддерживаемости;
— ещё пять (минимизация моков, разбиение модели на агрегаты, разделение IO и логики и использование неизменяемой модели данных, ограничение кол-ва зависимостей до 5–7 на компонент, использование открытой архитектуры), как минимум не снижают поддерживаемость, либо имеют небольшой тренд на её повышение;
— наконец, последняя рекомендация — не вводить интерфейсы без необходимости — никак не связана с поддерживаемостью: не повышает, но и не снижает её.

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



Плюс пока писал пост накопал ещё один любопытный инсайт.
Между временем запуска одного теста и поддерживаемостью есть погранично значимая, но сильная (почти что очень сильная) связь с поддерживаемостью. И больше всего поддерживаемых (10 из 13) проектов было в категории «2–10 секунд». В то время как для категории «0-1 секунду» только лишь 2 из 7 проектов были поддерживаемым.

Здесь уже начинаются чистой воды спекуляции на результатах анализа совсем маленькой выборки (23 ответа на этот вопрос), но, кажется, эти данные можно проинтерпретировать как дважды косвенное подтверждение идеи, что фокус на качественных (работающих до 10 секунд) интеграционных тестах повышает поддерживаемость.

#ergo_approach@ergonomic_code #ergo_testing@ergonomic_code
1👍9🔥5
Привет!

Наткнулся на пост о фреймвоке размышлений об ошибках Марка Симана.

И он до неприличия похож на мой, независимо разработанный, подход:
1. Симан так же категоризирует ошибки по атрибутам ожидаемая/неожиданная и восстановимая/невосстановимая
2. Симан так же предлагает восстановимые ошибки возвращать (чем-то в духе nullable типа/Result/Eather etc), а невосстановимые ошибки выбрасывать исключениями.

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

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

#posts@ergonomic_code #ergo_approach@ergonomic_code
👍5
Привет!

Я всё ещё "гамак-дривеню" проекцию модели данных Эргономичной архитектуры и чтобы накинуть больше входных данных на обработку во сне своему большому мозолистому мозгу я начал читать Data Modeling Essentials. И там наткнулся на новую для себя концепцию в моделировании данных - предаваемость (transferability) отношения.

Отношение является передаваемым, если допустимо менять сущность на одной из сторон.
Например, отношение "Заказ такси" -> "Водитель" является передаваемым. К сожалению.
А вот "Заказ такси" -> "Заказчик" - нет.

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

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

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

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

#ergo_arch@ergonomic_code #ergo_data_model@ergonomic_code #ergo_persistance@ergonomic_code #books@ergonomic_code #ddd@ergonomic_code
5👍5🔥4
Привет!

What else changes for different reasons? The use cases themselves! The use case for adding an order to an order entry system almost certainly will change at a different rate, and for different reasons, than the use case that deletes an order from the system. Use cases are a very natural way to divide the system.

At the same time, use cases are narrow vertical slices that cut through the horizontal layers of the system. Each use case uses some UI, some application-specific business rules, some application-independent business rules, and some database functionality. Thus, as we are dividing the system into horizontal layers, we are also dividing the system into thin vertical use cases that cut through those layers.

To achieve this decoupling, we separate the UI of the add-order use case from the UI of the delete-order use case. We do the same with the business rules, and with the database. We keep the use cases separate down the vertical height of the system.



Что еще меняется по разным причинам? Сами варианты использования! Вариант использования для добавления заказа в систему ввода заказов почти наверняка будет меняться с другой скоростью и по другим причинам, чем вариант использования, который удаляет заказ из системы. Варианты использования - это естественный способ разделения системы.

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

Чтобы добиться такого разделения, мы отделяем пользовательский интерфейс варианта использования с добавлением заказа от пользовательского интерфейса варианта использования с удалением заказа. Мы делаем то же самое с бизнес-правилами и базой данных. Мы разделяем варианты использования по вертикали системы.

— Роберт Мартин, Clean Architecture, глава 16. Independence, раздел Decoupling Use Cases


Значит ли это, что Чистая архитектура ближе к вертикальной, чем к слоёной? И в коде по чистой архитектуре должна быть пачка интерфейсов в духе RegisterUserGateway, DeleteUserGateway и т.п. вместо UsersGateway.
Как знать - анкл Боб почему-то решил не показывать реальный пример реализации чистой архитектуры.
Может в этом секрет популярности - написать в целом убедительный, но внутренне противоречивый текст, в котором каждый найдёт то, что ему нравится?

Не спрашивайте как меня опять занесло перечитывать эту книгу.

#clean_arch@ergonomic_code #books@ergonomic_code
😁93
Привет!

На той недели мне в комментах подсветили батл между Робертом Мартином (он же «Дядя Боб») и Кейси Муратори, который в итоге свёлся к полиморфизму против свитчей (но с неожиданным поворотом).

Батл заканчивается фразой анкл Боба «Я думаю, нам стоит на этом остановиться в нашем споре и предоставить нашей аудитории вынести окончательный вердикт» (I believe we should let our disagreement stand at this point and let our audience be the final judge).

И мой вердикт таков: Муратори всю дорогу вёл по очкам и победил нокаутом, разнеся в пух и прах SRP, OCP и DIP. Правда, сделал он это в очень узком контексте — API, предназначенного для реализации внешними поставщиками (SPI в мире Java). Соответственно для разработчиков прикладных приложений (коих в мире большинство) это не имеет никакого практического значения. Тем не менее, ознакомится с ним полезно всем, на мой взгляд.

Так как батл у них получился невероятно длинный (я читал часа четыре) и довольно нудный, я советую прочитать только мякотку, начинающуюся во втором файле со слов «I’m not even talking about machine-cycles, I was just focusing on programmer-cycles». А для того чтобы сделать позицию Муратори более доступной русскоязычной аудитории, я решил сделать её близкий к дословному перевод.
🔥7
Привет!

Я недавно сделал Web Push уведомления в Trainer Advisor и попутно снова узнал и придумал пачку прикольных штук, о которых накатал очередной "микропост" на 30-40 минут чтения по оценке ФФ.

Ну и по традции вот вам сразу содержание, чтобы привлечь внимание мякоткой:

* Отправка пушей
* Архитектура
* Абстракция vs очевидность эффектов и разделение ввода и вывода
* И снова про уровни абстракции/стратификацию
* Пример №1: код открытия диплинка по клику
* Пример №2: фетч ресурсов с фолбэком на кэш и кастомную страницу «Сервис недоступен"
* Postgres GENERATED-колонки для ограничений целостности в JSONB
* TrainerAdvisorApis
* В Gradle-плагин GitProperties завезли поддержку git worktrees
* Отказ от Kotest Matchers в пользу shuold*-методов

#case@ergonomic_code #ergo_approach@ergonomic_code #ergo_arch@ergonomic_code #ergo_testing@ergonomic_code #trainer_advisor@ergonomic_code #ergo_persistance@ergonomic_code
3🔥3👍2
о, а вы знали, что вчера Spring Boot 4.0 пошёл в GA?

и там завезли нормальную поддержку версионирования HTTP API (вроде как - надо проверять)
и, имхо самое крутое, распилили наконец-то адовый spring-boot-autoconfigure.jar и теперь спринг на старте не будет пытаться загружать всю ту гору барахла, которую подерживает спринг, но из которой я ну от силы процентов 25 использую
👍11
2025/12/06 14:14:33
Back to Top
HTML Embed Code: