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

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

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

Сёня давно забытая рубриа хорошие книги:)

Прочитал тут Clojure Applied (чё думаете я про кложуру-то заговорил?:) ).

В целом хорошая книга, и ради 6ой главы (Creating Components) я бы порекомендовал её даже тем, кто кложурой не интересуется.

Там практически один в один расписаны компоненты ЭП. Даже называются так же:)

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

Так что оставайтесь на нашей волне:) Вторничный пост пока не обещаю - неделька реально тяжёлая - но небольшой прогресс есть:)

#books@ergonomic_code #clojure@ergonomic_code #ergo_approach@ergonomic_code #ergo_arch@ergonomic_code #design
Привет!

Дочитал Just Enough Software Architecture: A Risk-Driven Approach

Она прекрасна - пожалуй лучшая книга по архитектуре и роли архитектора, что я прочитал, рекомендую:)

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

Ковидно-депрессивные мысли вслух.

Что-то меня в последнее время жизнь посталкивала с энтерпрайзными Java-архитекторами в корпорациях, и эти события мне напомнили цитату:
> First of all, and sad to say, I think there has been a general abandonment of good design and development practices in the Java community.

И далее:
> Due to Jimmy’s good work and that of others promoting the Alt.NET mindset, there is a high tide of good design and development practices going on in the .NET community. Java developers need to take notice.

Из Implementing Domain-Driven Design - вторая по почетаемости после оригинала книга в ДДД тусовке от очень крутого чувака.

Плюс я могу накидать пачку хороших блоггеров от дотнета (раз, два, три) и даже пару неплохих от пхп (раз, два), а вот джависты мне что-то как-то не припоминаются (именно по дизайну, хардкорщиков хватает)

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

Хоть иди джуном в Дотнетчики, чтобы от Джававских адских традиций спастись.

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

Случайно наткнулся на прямой ответ на мой сакральный вопрос - как декомпозировать систему на модули?
Ответ - Parnas Partitioning.
Правда оригинальную статью даже за деньги нагуглить не могу.

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

Кажется, декомпозиция системы на модули (в современных условиях, по крайней мере) - это всё-таки вотчина гадалок и экстрасенсов.

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

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

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

#posts@ergonomic_code #design@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
abstactions.png
140.2 KB
Привет!

Разбираю сейчас легаси проект на .Net и подвернулась хорошая иллюстрация из реальной жизни предпредыдущего поста про абстракции.

Я вообще пока не понимаю был ли смысл оборачивать Context в UnitOfWork, но вводить IUnitOfWork вообще никакого смысла не было - из него утекают типы реализации.

Я бы ещё хоть как-то понял интерфейс, если бы у них были тесты на моках. Но даже их нет.

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

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

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

Я тут кажись придумал простое и понятное (по крайней мере мне 😂) определение функциональной связанности метода:)

Метод обладает функциональной связанностью, если он не обладает побочными эффектами.

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

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

Например, есть метод "одобрения" создания некоторой сущности. Он считывает сущность, меняет в ней флажёк и записывает назад - и то и то является эффектом.

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

Но как тогда реализовать эту функциональность?
Через шину событий. Метод одобрения сохраняет сущность и публикует событие "сущность одобрена".
А дальше в отдельном методе это событие обрабатывается и посылается пуш.

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

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

Таким образом помещение отправки пуша в метод одобрения сделает его методом с побочным эффектом (отправки пуша). И снизит связанность модуля до процедурной.

#terminology@ergonomic_code #cohesion@ergonomic_code #ergo_approach@ergonomic_code #design
Привет!

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

У них там тоже граф, но однородный - и операции и ресурсы представленны одинаково, плюс ещё есть понятие артефакта (выводимые данные). А вот связи между ними характеризуются 16-ю аспектами.

И вот если им этот граф загрузить - они могу его с помощью тула автоматически нарезать.
Только с этим тулом есть две проблемы:
1) он начал гнить
2) сформировать граф, и проставить характеристики связей надо руками:)

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

Посмотрел свежий доклад Рича Хикки о том как "делать дизайн". Как всегда очень крутой.

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

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

Потому что в 3-4 последних заметках были косяки, которые привели к к переделкам реализации в процессе первичной разработки или спустя время от нескольких часов до месяца 🤦‍♂️🤯.

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

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

Проживаю очередной кризис нигилизма:
1) ООП - нахер, эта фигня никогда не работала для информационных систем
2) ООД - нахер, эта фигня не масштабируется ([1], [2])
3) DDD - нахер, таш самая дичь, что и микросервисы - нужно и возможно только в 1% проектов, а в остальных - только удоржает разработку и тешит самолюбие разработчиков
4) Сокрытие информации - нахер, в рамках одного проекта над которым работает одна команда (а то и один человек) - это попахивает шизофринией
5) Open-Closed Principle и Dependency Inversion Principle и Чистая архитектура - нахер (пока реализация одна), эта хрень только усложняет кодовую базу и удорожает разработку
6) Low Coupling/High Cohesion - нахер, это какая-то непонятная дичь. На самом деле - тут тоже "пока что-то" или ещё какое-то условие, но вот что за условие - я ещё не понял.
7) Information Expert - нахер, эта фигня не масштабируется

А что не нахер?
1) DRY - это то, что позволяет снизить стоимость (гемморой для разработчика) внесения изменений
2) KISS - это то, что позволяет снизить стоимость (гемморой для разработчика) внесения изменений
3) Отсутствие циклов в зависимостях - это первое средство борьбы с Big Ball of Mud (упращения кодовой базы)
4) Неизменяемя модель данных - второе средство борьбы с Big Ball of Mud (упращения кодовой базы)
5) Структурный дизайн/функциональная архитектура - третье средство борьбы с Big Ball of Mud (упращения кодовой базы)
6) Единство уровня абстракции/SRP - четвёртое средство борьбы с Big Ball of Mud (упращения кодовой базы)
7) Очевидность связей (сцепленности?)/локальность рассуждений о коде - пятое средство борьбы с Big Ball of Mud (упращения кодовой базы)
8) Классическая школа ТДД - единственное (известное мне) надёжное средство борьбы с регрессиями -> возможность свободно улучашть качество кодовой базы
9) Базовая модель информационных систем в виде операций, ресурсов и эффектов - это то, чем информационные системы являются по своей сути

Вобщем "гамак-дривен" девелопмен эргономичной структуры программ в3 продолжается (второе полугодие), но вроде процесс начал сходиться.

P.s.

1) добротный и двольно свежий пост с обзором и сравнением основных архитектур
2) И в дополнение - более подробный разбор вертикальной архитектуры

#ergo_approach@ergonomic_code #oop@ergonomic_code #ddd@ergonomic_code #design@ergonomic_code
🔥11👍2🐳21
Привет!

В продолжение вчерашнего топика очень крутой доклад от Кента Бека про coupling и cohesion.

В докалде Бек утверждает, что в оригинальной книге сцепленность оценивается относительно некоторого изменения (хотя я сам такого не помню и в книге найти не смог).

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

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



Ещё одна мысль из доклада - "расстояние" между сцепленными элементами имеет значение. И это одна из основных причин, почему я перешёл от Эргономичной структуры в1 к в2. И в чём разочаровался по мотивам Проекта Э.

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



Ну и наконец книга - Tidy First?: A Personal Exercise in Empirical Software Design - добавлю в свой список на прочтение

#talks@ergonomic_code #design@ergonomic_code #coupling@ergonomic_code #cohesion@ergonomic_code
3🔥3👍2
И вот ещё хороший доклад про Coupling.

Там же, внезапно, мужик говорит про тот самый Connascence и объёдиняет его с классическим Coupling в ещё более современный Integration Strength. Ток эту штуку тексту нагуглить не получается.

И так же говорит про "расстояние" в коде.

#talks@ergonomic_code #design@ergonomic_code #coupling@ergonomic_code #cohesion@ergonomic_code
👍4🔥32
Привет!

Посмотрел Build Abstractions Not Illusions.

Любопытная мысль оттуда:
> лёгкий тест на то, является ли абстракцией то, что вы сделали:
Абстракция должна вводить новую терминологию.

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

#talks@ergonomic_code #design@ergonomic_code
❤‍🔥31
Привет!

Я ещё почти два года назад назад начал думать в сторону того, что пути эндпоинтов REST/JSON-over-HTTP API надо нарезать исходя из UX-клиентов, а не сущностей/ресурсов.

То есть, допустим, у нас есть пользователи и три эндпоинта:
1. Залогиниться
2. Посмотреть собвтенные данные
3. Посмотреть данные любого юзера для админов

И раньше я делал сам и наблюдал буквально во всех проектах, которые видел, эти эндпоинты замапили бы на:
1. POST /users/login
2. GET /users/profile
3. GET /users/profiles/{id}

А сейчас я бы это зампаил так:
1. POST /public/login
2. GET /user/profile
3. GET /admin/profiles/{id}

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

И, например, в TA я это так и сделал - если не считать вспомогательных пакетов infra и platform, в пакте app два подпакета:

1. public - "приложение"-точка входа, для регистрации и логина (по историческим причинам мапится на "/"...)
2. therapist - "приложение"-АРМ терапевта (мапится на "/therapist/")

Ещё есть "приложение"-сисадмина - Spring Boot Actuator (мапится на "/ops/**")

Такая схема, среди прочего ещё и существенно упрощает конфигурацию авторизации

Но это всё была прелюдия.

Я тут наткнулся на оригинальный пост про гексагональную архитектуру (ака порты и адаптеры), а там:
What exactly a port is and isn’t is largely a matter of taste. At the one extreme, every use case could be given its own port, producing hundreds of ports for many applications. Alternatively, one could imagine merging all primary ports and all secondary ports so there are only two ports, a left side and a right side.


Neither extreme appears optimal.


The weather system described in the Known Uses has four natural ports: the weather feed, the administrator, the notified subscribers, the subscriber database. A coffee machine controller has four natural ports: the user, the database containing the recipes and prices, the dispensers, and the coin box. A hospital medication system might have three: one for the nurse, one for the prescription database, and one for the computer-controller medication dispensers.


It doesn’t appear that there is any particular damage in choosing the “wrong” number of ports, so that remains a matter of intuition. My selection tends to favor a small number, two, three or four ports, as described above and in the Known Uses.



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


Ни один из крайних вариантов не кажется оптимальным.


Система прогнозирования погоды, описанная в "Известных вариантах использования", имеет четыре естественных порта: канал прогноза погоды, администратор, уведомленные подписчики, база данных подписчиков. Контроллер кофемашины имеет четыре естественных порта: пользователь, база данных, содержащая рецепты и цены, дозаторы и ящик для монет. Больничная система выдачи лекарств может состоять из трех компонентов: один для медсестры, один для базы данных рецептов и один для диспенсеров лекарств с компьютерным управлением.


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


И я в этом тексте вижу те же самые приложения (в "левых"/основных портах у Кокбёрна), что и у себя.

В общем советую подумать в сторону того, сколько UX-ов есть у ваших (монолитных) бакендов и отражено ли это в вашей архитектуре

#design@ergonomic_code #rest_api@ergonomic_code #hexagonal_architecture@ergonomic_code #trainer_advisor@ergonomic_code
🔥43👍2
Привет!

Я пару лет назад пинал декомпозицию по фичам, за то, что
Когда же вы сядете и попытаетесь декомпозировать систему по фичам, у вас тут же возникнет множество вопросов:


"А фича - это вообще что такое?", "Как мне из требований получить набор фич?", "Судя по примерам, фича - это таблица. Мне что, заводить по пакету на каждую таблицу?", "А что делать с таблицами связками?", "Что делать с функциями, которые затрагивают две и более таблицы - в какой пакет их помещать?", "А что делать с функциями, которые работают не с таблицами, а с REST API?", "А с S3?", "А куда мне положить DSL создания Excel файлов для нескольких фич? В utils?"


И тут я кажись познал дзен. Фичи надо искать не в требованиях, домене или таблицах/сущностях.
Их надо искать в порядке и этапах реализации требований и т.д.

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

Однако в целом я всё ещё не сторонник тотальной вертикальной декомпозиции в духе вертикальной архитектуры, декомпозиции по фичам или моей же декомпозиции по объектам (раз, два).
Потому что по моему опыту они ведут к слишком высокой сцепленности (явной или не явной) между слайсами/фичами/объектами.

Но вот использовать декомпозицию по фичам как вторичную - после разделения на слои приложения и домена (what-the-system-does и what-the-system-is в терминах Lean Architecture) - кажется вполне себе вариант.

#design@ergo_approach
3👍2
Привет!

С наступившим новым годом!

Принципы программирования от разработчика HTMX - Prefer if statements to polymorpism

Особенно понравилось:
It states that a high-level module can depend on a low-level module, because that’s how software works.

Сразу видно - человек давно в индустрии:)

#posts@ergonomic_code #design@ergonomic_code #htmx@ergonomic_code
👍42