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

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

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

Объявляю идейный кризис эргономичного подхода успешно преодолённым:) В частности с агрегатами и Spring Data JDBC всё так, это у меня была ошибка в ДНК.

Вышел я из кризиса с уточнённым понимаем того, что делаю и об этом будет сегодняшний микропост.

Эргономичный подход - это подход к разработке ПО с минимальной связанностью (coupling) и как следствие с максимальной связностью (cohesion).
Программы с минимальной связностью дёшевы и легки в поддержке благодаря простоте понимания и лёгкости модификации.

Эргономичный подход стоит на трёх столпах:
1) Декларативный стиль программирования
* Это позволяет минимизировать связанность по общей области и управлению (common & control coupling)
2) Декомпозиция системы на модули с высокой связностью и низкой связанностью
* Это и делает систему простой для понимания и лёгкой в поддержке
3) Детройтская школа тестирования
* Это минимизирует связанность между тестами и деталями реализации

От мейнстримового подхода Эргономичный подход отличается следующим:
1) Использование модели неизменяемых связанных данных (Immutable Relation Data) на базе агрегатов DDD и эпохальной модели времени для моделирования информации системы (а не модели графа изменяемых объектов)
2) Стремление максимум кода вынести в функции без побочных эффектов (а не бессистемное разбрасывание побочных эффектов по всему коду)
3) Применение архитектурного стиля функциональное ядро/императивная оболочка (а не классической слоёной архитектуры)
4) Разделение слоя бизнес-логики на подслой приложения (оркестрация выполнения операции системы) и подслой предметной области (сложные бизнес-правила, задействующие несколько агрегатов) (а не единый слой сервисов)
5) Верхнеуровневое разбиение на модули системы (а не слои)
6) Минимизация зависимостей между модулями системы (а не произвольное добавление новых зависимостей в систему)
7) Тестирование системы на соответствие требованиям (а не покрытие тестами классов и методов)
8) Мокирование только дорогих или нестабильных внешних систем (а не всех классов, помимо тестируемого)
9) Для достижения пп 1-3 и 6 - использование Spring Data JDBC (а не Spring Data JPA)
10) Для достижения п. 6 - ручное управление зависимостями (а не Spring Component Scan)

P. S>
это ещё и линко пост был:)
Immutable Relational Data - коротенько (30 минут) о там как жить с неизменяемой моделью данных (в данном конкретном случае на примере веб-фронта на Elm-е)
эпохальная модель времени - как моделировать изменения в неизменяемой модели данных

P.P.S>
Промахунлся:(

#immutable_domain_model@ergonomic_code #ergo_approach@ergonomic_code
Привет!

Отвлёкся от поста про агрегаты, чтобы быстро написать свою версию ответа на вопрос "Что почитать по проектированию приложений?"

#books@ergonomic_code
Привет!

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

Итем 1
(Уже вчера) вышел Котлин 1.6.20 с превью фичи множества ресиверов (дизайн фичи)
Фича довольно жёсткая - даже не буду пытаться тут на пальцах её объяснять.
Поэтому, не уверен, что несёт больше пользы, чем вреда (см сколько "не делайте так" в дизайне).
Но если аккуратно применять, то позволит писать ещё более выразительные ДСЛи

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

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

Зато, подумал, что если бы у меня были только функции, в том числе высшего порядка, то мне было бы намного проще объяснить.
Попробовал объяснить это жене (она 15 лет назад прошла курс по ООП, а сейчас продвинутый пользователь экселя) - и про функции мы смогли нормально поговорить, а с объектами очень быстро дошли до "ой всё":)
И у меня нет ощущения, что сложность ООП как-то окупается.

В общем ФП - наше всё:)

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

А тут я добрался наконец до дисера по REST и там чуть ли не на первой странице Филдинг пишет:
> The hyperbole of The Architects Sketch may seem ridiculous, but consider how often we see software projects begin with adoption of the latest fad in architectural design, and only later discover whether or not the system requirements call for such an architecture. Design-by-buzzword is a common occurrence

22 года спустя, заказчики всё ещё продолжают требовать делать модную, а не обоснованную требованиями архитектуру...
Привет!

Рубрика "ссылки наших читателей":) Один из читателей канала скинул ссылку на пост, о том как наши западные коллеги изобретают эргономичный подход:). Только я буду разбирать первоисточник, т.к. не верю переводчикам.

ТЛДР- мальчик становится мужчиной 5-летний "техлид" начинает понимать суть своего карго культа, нахапанного в интернете, и встаёт на путь к эргономичному подходу:)

А теперь подробнее:)

Во-первых, заголовок явно кликбейтный (или как оно называется?). Я работал с кодом стартапа из долины и постоянно читаю про "зарубежный опыт" - у них там буквально всё тоже самое, один в один.
Во-вторых, это личное мнение одного автора, а не всего "зарубежа".
В-третьих, автор закончил в универ в 17ом году - а я не верю в техлидов с 5 годами опыта (добавка после прочтения поста - и правильно делаю, что неверю)
Но, справедливости ради, у него есть пост про отказ от юнит тестов - плюсик.


> For us, this has reduced the size of a regular feature, such as a new microservice endpoint for updating or reading data, from a total of approximately 25 files down to just 5, that’s an 80% reduction with the majority of code simply having been deleted, all while simultaneously improving code readability
Ох, ну у меня по дефолту на эндпоинт надо вообще 4-5 классов - контроллер, сервис приложения, репоз, агрегат и опциональный сервис домена
А на фоне оверхеда который приносят микросервисы всё что описано позже - экономия на спичках. Из поста не ясно, есть ли к системе требования, обосновывающие применение МС.

> meaning that we want to keep abstractions to a minimum and only introduce complexity when it provides a significant and real benefit
С этим тезисом в целом согласен - поэтому, например, отказался от чисто архитектуры по дефолту и практически никогда не завожу интерфейсы с одной реализацией.
С другой стороны, не опробовав на практике идею отказаться от сервисов-обёрток вокруг репозов, типа: fun findById(id: Long) = repo.findbyId(id), я снова начинаю склоняться к тому, что они всё-таки нужны для определения публичного интерфейса модуля. Но тут ещё буду думать.

> each class should only have one reason to change, or, they should only have one job
Чувак не понимает SRP
Но при том понимает, что SRP в его интерпретации - вреден - плюсик

Судя по второй картинке - он юзал заголовочные интерфейсы. Понял что это лишнее - плюсик
Судя по ней же - он поклонник карго культа - использует концепцию repository для read model. Насколько я знаю, не существует альтернативной ДДДшной и распространённой концепции репозитория. А в ДДД репозитории используются только для write-модели.

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

> Introducing various programming design patterns before their benefit is really needed is another common pitfall
вот поэтому техлиды должны иметь хотя бы лет 10 опыта - чтобы успеть наигарться во всякие прикольные штуки.
Я паттернами сейчас практически не пользуюсь.
Плюсик, что понял

> Another pattern used extensively is the Command and Publish-Subscribe Pattern
В целом согласен. Я видел как эвент басы используют для вызова методов в одном процессе - это характеризуется "событиями", названы как указания - SendHttpRequest(dest), ровно одним обработчиком "события", катастрофичными последствиями, если событие не будет обработано мгновенно.
Но если вам над расцепить слабосвязанные компоненты (т.е. вам ок, если обработчик сработает завтра) - то эвент бас один из основных инструментов для этого.

#posts@ergonomic_code #ergo_approach@ergonomic_code
> CQRS essentially implies that you have two separate data models ... The huge downside of this pattern is the fact that a whole separate data model needs to be built and maintained
С этим я и согласен и не согласен.
Я применяю разные модели для записи и чтения не столько из соображений производительности (что является следствием), сколько из соображений декомпозиции информации на управляемые кусочки. Но я согласен что это существенный оверхед, оправданность которого весьма спорна и ищу способы уменьшить его.
Так же, http - это одна из самых жёстких системных границ и если что и стоит усилий дизайна - так это хттп интерфейс. Особенно апи опубликовано (список клиентов не известен), либо среди клиентов есть мобильные приложения (которые невозможно обновить без согласия пользователя). И в этом случае использовать единую модель и внутри и в АПИ записи и в АПИ чтения - дорога в ад.

> Low coupling introduced everywhere
Парень забыл про high cohesion - coupling & cohesion всегда идут вместе
> An isolated feature does not need low coupling and interfaces between the elements inside it
Бинго! "isolated feature" по определению является высоко связной - а декаплинг реализации изолированной фичи запрещён конвенцией по правам фичей.

> Also, if you are merely using interfaces to allow mocking in tests, seriously consider switching to a mocking library that allows mocking concrete classes to avoid the overhead.
А вот тут парню ещё предстоит пролить пот и кровь - правильный ответ "следует отказаться от мокирования на уровне классов"

> If you are feeling particularly adventurous, you can go the extra mile and move separate classes into the same file
парень открыл рискованную штуку, рекомендованную в официальном соглашении о кодировании Котлина.

> This is essentially favoring a Vertical Slice Architecture over the more classical Onion Architecture
А вот он дошёл и до концептульной декомпозиции. Только непонятно почему он поместил это в раздел для особо смелых.

> For this reason, we have dropped this kind of unit testing entirely and opted for a completely different approach to automated testing
А вот он таки и дошёл до нормального тестирования.

И того, для того чтобы избавиться от 80% кода наши зарубежные коллеги открыли эргономичный подход:
1) интеграционное тестирование, вместо моков
2) концептуальная декомпозиция, вместо слоёной
3) заявка на декларативный стиль через разделения команд и запросов (CQRS), вместо повсеместного императивного стиля. Но тут нашим молодым западным коллегам ещё предстоит нас догнать, в понимании, что в императивных командах так же надо стремиться выделять декларативный трансформации

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

У меня есть две новости:)

1) Я собрал первый черновик поста про агрегаты. Он на 20 минут
2) К нему будет ещё 3 поста-приквела. И потом ещё будет отдельный пост сиквел с примером:)

Поэтому сегодня линка на чужой, но готовый пост по агрегатам:)

#posts@ergonomic_code #ddd@ergonomic_code
Привет!

Тихой сапой прочитал Next Generation Databases.
В целом хорошее краткое изложение (по сути - 200 страниц с картинками) истории, текущего состояния и будущего систем хранения данных.
Книги уже 7 лет, но на удивление с тех пор ничего особо не поменялось.
Любопытный факт - по мнению автора РСУБД всё ещё лучший выбор для подавляющего большинства приложений.
Хотя архитектура всех основных современных РСУБД, уходящая корнями в System R 70-ых годов изрядно устарела.

О чём пишет Стоунбрейкер в The End of an Architectural Era (It's Time for a Complete Rewrite)
В этой статье он расписывает почему текущие архитектуры устарели и как надо по другому.
"По другому" можно уже сейчас попробовать в его VoltDB и Datomic Рича Хикки.

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

При том и VoltDB и Datomic требует, чтобы хранимки были чистыми. Так что ФП - наше всё.

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

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

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

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

В общем у нас впереди предстоит много интересного:)

#books@ergonomic_code #databases@ergonomic_code
⚡️Spring рекомендует концептуальную декомпозицию!
И называет это разумным способом структурирования приложения

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

#posts@ergonomic_code #ergo_arch@ergonomic_code #spring@ergonomic_code
Привет!

В догонку к понедельничному посту - ещё одна СУБД с похожей архитектурой.
Mnesia - Erlang-овская СУБД, которая объединяет код и данные на одной машине и требует, чтобы функции транзакций были чистыми.

Для Джавы тоже есть встроенная СУБД - MicroStream. Но у них нет транзакций из коробки, хотя они позволяют атомарно сохранять несколько объектов

Ну и кубит тоже в ту же сторону:) Там прямо сейчас есть традиционное АПИ с begin-commit-rollback, но я его выпилю, как руки дойдут.

#ergo_persistance@ergonomic_code
Привет!

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

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

Затем в середине он говорит о выделении кода в слой домена, и с учётом того, что работу с БД он оставляет на уровне выше, то этот код становится чистым и это всё очень начинает напоминать архитектуру функциональное ядро/императивную оболочку.

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

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

#talks@ergonomic_code
Привет!

Пока пост про агрегаты варится (настаивается уже), радую вас линко-постами:)

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

#posts@ergonomic_code #design@ergonomic_code
Привет!

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

И вот наткнулся на этот же тезис у Фаулера в статье об анемичной доменной модели:
> The anemic domain model is really just a procedural style design, exactly the kind of thing that object bigots like me (and Eric) have been fighting since our early days in Smalltalk. What's worse, many people think that anemic objects are real objects, and thus completely miss the point of what object-oriented design is all about.

#posts@ergonomic_code #oop@ergonomic_code
Привет!

Прочитал Philosophy of Software design, впечатления не однозначные.

Поначалу казалось, что читаю свою книгу, только вместо связанности (copuling) все беды возлагаются на сложность (complexity).

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

Автор также симптомами высокой сложности/связанности называет чрезмерные трудоёмкость изменений и "понимания" софта и невидимые связи.

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

Но как только дело доходит до мяса, начинает обнаруживаться расхождения во взглядах.

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

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

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

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

Ещё интересные тезисы:
1) проблемы дизайна имеют свойство накапливаться. Каждая отдельная проблема выглядит безобидно. Но когда их набирается сотня - развитие проекта парализуется.
2) сложность лучше видна читателю. Если вам на ревью говорят, что код сложно читать, а вы не согласны - лучше привлечь третьего и выбрать вариант, более понятный ему.
3) иногда больше кода - лучше. Например, длинные цыпочки трансформации данных лучше разбавлять присвоением в переменные с промежуточными результатами.
4) при проектировании интерфейсов (в самом широком смысле этого слова) необходимо делать самый распространённый юз кейс максимально простым. А неправильное использование - невозможным.
5) первый шаг к написанию хороших комментариев - использовать в них слова отличные от слов в коде
6) побочный эффект - это любое влияние вызова метода на дальнейшее поведение системы, помимо возврата результата
7) ПО должно проектироваться для упрощения чтения, а не написания

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

#books@ergonomic_code #design@ergonomic_code
👍1
Привет!

Наконец-то опубликовал долгожданный (надеюсь:)) пост про агрегаты:)
И это не первоапрельская шутка:)

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

#posts@ergonomic_code #ddd@ergonomic_code #immutable_domain_model@ergonomic_code
🔥10
эгегей, я включил реакции в канале - не стесняемся, ставим лайки:)
👍82👏2🔥1🤩1
image_2022-04-01_19-02-02.png
85.2 KB
😳😱
Я тут внезапно выяснил, что в идее можно искать зависимости в мавенцентрале не отходя от кассы

#tools@ergonomic_code
👍2
Привет!

Прочитал Implementation Patterns Бека.
Я не сторонник императивного ООП, с активным использованием наследования, поэтому опять же не готов занести эту книгу в маст рид.

Но лучше писать код так, как пишет Бек, чем в процедурном стиле с классами.

Что поддерживаю:
1) Код должен хорошо передавать собственный смысл
2) Симметрия и эстетика являются признаками хорошего кода с практической и экономической точки зрения
3) В целом на главах 1-4 у меня было по несколько закладок на каждой странице - в базовых ценностях и философии программирования мы с Беком сходимся
4) Следует избегать использования геттеров и сеттеров
5) Явное разделение рекомендаций для разработки прикладных программ и фреймворков. Всегда надо держать в голове над каким типом кода вы работаете и принимать это во внимание при принятии всех решений. Например, тот же OCP, значительно менее актуален для разработки прикладных програм

#books@ergonomic_code #oop@ergonomic_code
Привет!

Сегодня для меня и Эргономичного подхода знаменательный день - я объявляю о переходе от прототипирования и проверки гипотезы к стабилизации и продуктизации Эргономичного подхода.

Хочу так же постануть об этом на хабре в "Я пиарюсь", но мне не хватает трёх пунктов кармы - накиньте пожалуйста, у кого есть возможность:)
🔥3🎉3
Привет!

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