Skip to content

Commit 291a47b

Browse files
committed
В статью об Эргономичной архитектуре добалены правила кодирования портов
1 parent b155638 commit 291a47b

1 file changed

Lines changed: 65 additions & 39 deletions

File tree

content/docs/models/ergo-arch.adoc

Lines changed: 65 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -58,68 +58,87 @@ weight: 875
5858

5959
== Проекция структуры данных (модель данных)
6060

61-
Проекция структуры данных по большому счёту является комбинацией проверенных идей из DDD, Функциональной архитектуры и Entity-Relation-модели с небольшими отличиями.
61+
Проекция структуры данных является комбинацией идей из DDD, Функциональной архитектуры, Entity-Relation-модели и ECS архитектуры.
6262

6363
=== Номенклатура блоков
6464

65-
Концептуальными базовыми блоками этой проекции являются:
65+
Модель данных ЭА состоит из сущностей, которые, в свою очередь могут включать компоненты.
66+
Компоненты могут принадлежать только одному владельцу - сущности или другому компоненту.
67+
Сущность со всеми своими компонентами является единицей хранения - она загружается из хранилища и сохраняется в нём целиком со всеми компонентами.
6668

67-
. Сущности - объекты обладающие идентичностью;
68-
. Объекты-значения - доменно-специфичные составные объекты, не обладающие идентичностью;
69-
. Агрегаты - кластер сущностей и объектов-значений, жёстко объединённых общим жизненным циклом.
69+
И у сущностей, и у компонентов есть атрибуты.
70+
Атрибут может быть простым (имя, цена) или составным - то есть компонентом (позиция заказа с количеством и ссылкой на продукт).
71+
Кроме того, атрибуты могут быть скалярами (цена заказа) и коллекциями примитивов или компонентов (список позиций заказа).
7072

71-
Номинально, номенклатура блоков полностью совпадает с DDD.
72-
Однако есть ряд отличий:
73+
Сущности бывают двух типов:
7374

74-
. В ЭА допустимо ссылаться на сущности, не являющиеся корнем агрегата;
75-
. Базовым критерием объединения сущностей в агрегаты является их жизненный цикл, а не инварианты, которые необходимо обеспечить.
75+
. Коренная сущность.
76+
Это самостоятельная сущность обладающая собственной идентичностью - заказ, клиент, продукт и т. д.;
77+
. Аспект другой сущности.
78+
Сущность-аспект, это фактически компонент, который был повышен до сущности по дизайнерским или техническим причинам.
79+
Например, если в предметной области встречаются заказы с сотнями позиций, то в модели позиция может быть сделана сущностью-аспектом, для того чтобы повысить эффективность работы с БД в реализации модели.
80+
Или компонент "Адрес доставки" сущности "Заказ" может быть сделан сущностью-аспектом, если эта информация нужна модулю, отличному от того, который управляет коренной сущностью "Заказ";
7681

77-
=== Связи между блоками
78-
79-
У связи между блоками есть два атрибута: сила (слабая или сильная) и кардинальность (один, немного, много).
80-
81-
Сила связи это аналог связей внутри и между агрегатами в DDD и связей между обычными и стержневыми и слабыми сущностями в ER-модели.
82+
Коренная сущность со всеми её компонентами и аспектами называется агрегатом.
8283

83-
Для владеющих связей, при удалении блока-владельца удаляются и все блоки, с которым он связан владеющей связью.
84-
Для невладеющих связей недопустимо удалять целевой блок, при наличии ссылающихся на неё блоков.
84+
=== Связи между блоками
8585

86-
ЭА разделяет связи 1-к-немногим и 1-ко-многим.
87-
Связь один к немногим - это частый случай связи 1-ко-многим про который вы на этапе проектирования можете сказать, что в этой связи связи будет участвовать определённое, ограниченное и небольше количество сущностей.
86+
В модели данных ЭА есть только связи один-к-одному и один-ко-многим.
87+
Связей многие-ко-многим нет.
8888

89-
Связей многие-ко-многим в ЭА нет.
90-
Если два класса/типа агрегата могут быть связаны отношением многие-ко-многим, то в модели они отображаются одним из двух вариантов:
89+
Так же связь может быть владеющей и не владеющей.
90+
Связи между сущностями и компонентами (и между компонентами), а также между коренной сущностью и сущностью-аспектом является владеющей.
91+
Связи между агрегатами являются не владеющими.
9192

92-
. Если на самом деле отношение является многие-к-немногим, то в агрегат на стороне "многие" добавляется объект-значение с невладеющей связью с другим агрегатом, который связан отношениме немногие-к-одному с одной из сущностей или объектов-значения агрегата;
93-
. В противном случае для отношения заводится самостоятельный агрегат с двумя невладеющими связями с основными агрегатами (аля связующая таблица в реляционной модели)
9493

95-
Ограничения на связи между блоками:
9694

97-
. Сущность не может быть "владеемой" несколькими другими сущностями (читай: сущность может входить только в один агрегат);
98-
. Связи между сущностями должны образовывать направленный ацикличный граф.
95+
=== Кодирование блоков
9996

100-
При следовании этим правилам в графе структуры данных образуется три слоя:
97+
[NOTE]
98+
====
99+
Здесь и далее в качестве примеров кодирования я использую терминологию Kotlin.
100+
Однако ЭА может быть реализована на любом тюринг-полном языке - хоть Си, хоть Хаскель, разница лишь в том, придётся ли при этом бороться с сами языком.
101+
Борьбы с языком не будет, если он мультипарадигменный - поддерживает и императивную, и объектную и функциональную модель программирования.
102+
====
101103

102-
. слой генеричных/универсальных агрегатов;
103-
. слой ключевых сущностей системы;
104-
. слой вспомогательных сущностей системы.
104+
И сущности и компоненты кодируются неизменяемыми `data class`-ами.
105105

106-
=== Кодирование блоков
106+
Связи между сущностями и компонентами кодируются атрибутом сущности с типом компонента
107107

108-
В код попадают только сущности и объекты-значения.
109-
И те и другие кодируются в виде неизменяемых классов и различаются наличием или отсутствием поля-идентификатора.
108+
Связи между сущностью-аспектом и коренной сущностью кодируются атрибутом сущности-аспекта с типом идентификатора^*^.
110109

111110
[NOTE]
112111
====
113-
Здесь и далее в качестве примеров кодирования я использую терминалогию Kotlin.
114-
Однако ЭА может быть реализована на любом тюринг-полном языке - хоть Си, хоть Хаскель, разница лишь в том, придётся ли при этом бороться с сами языком.
115-
Борьбы с языком не будет, если он мультипарадигменный - поддерживает и императивную, и объектную и функциональную модель программирования.
116-
И, на самом деле, большинство современных языков таковыми являются - Java, C#, Python, JavaScript, TypeScript, Swift, Rust, F#, Clojure - только то, про что я сходу могу сказать, что точно подходит.
112+
^*^ Здесь и далее под "типом идентификатора" подразумевается простой тип, как правило - UUID, Long или String.
117113
====
118114

119-
Владеющие связи кодируются полем со ссылкой на целевой объект.
120-
Не владеющие связи кодируются полем с типом-обёрткой вокруг идентификатора целевого агрегата.
115+
Для связи один-к-одному атрибут идентификатора является одновременно и ссылкой на коренную сущность.
116+
Для связи один-ко-многим атрибут идентификатора сущности-аспекта делается составным и включает в себя ссылку на коренную сущность и идентификатор сущности-аспекта.
121117

122-
Очевидно, связи один-к-одном кодируются скалярным типом, а связи один-к-немногим - типом-коллекцией - списком, множеством или мапой
118+
Связи между агрегатами кодируются атрибутом ссылающейся сущности или компонента с типом.
119+
120+
[source,kotlin]
121+
----
122+
// Компонент
123+
data class OrderItem(
124+
val quantity: Int,
125+
val productRef: ProductRef<UUID>
126+
)
127+
128+
// Коренная-сущность
129+
data class Order(
130+
val id: UUID,
131+
val number: String,
132+
val items: List<OrderItem>
133+
)
134+
135+
// Сущность-ассоциация
136+
data class ShippingAddress(
137+
val id: OrderRef<UUID>,
138+
val city: String,
139+
val street: String
140+
)
141+
----
123142

124143
=== Примеры/Паттерны
125144

@@ -200,6 +219,10 @@ weight: 875
200219
А совсем вымышленной фичей могла бы возможность для терапевтов и клиентов превращаться друг в друга.
201220
Условно когда терапевт по свеому номеру телефона записывается на приём к другому терапевту, то ему не заводится отдельный юзер, а заводится новый клиент, который привязывается к тому же юзеру.
202221

222+
==== Иерархия компонентов
223+
224+
(#todo: #)
225+
203226
== Проекция структуры компонентов
204227

205228
Концептуальной моделью структуры состояния является https://azhidkov.pro/effects-diagram/specification-html/#_%D0%BA%D0%BE%D0%BD%D1%86%D0%B5%D0%BF%D1%82%D1%83%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C[диаграмма эффектов] - диаграмма описывающая элементы состояния системы - ресурсы, операции системы и, ключевое, связи операций с ресурсами - эффекты.
@@ -247,6 +270,9 @@ weight: 875
247270

248271
Количество публичных методов в портах и ресурсах ограниченно разумными на ваш взгляд пределами.
249272

273+
Методы портов могу содержать в себе только один вызов операции или ресурса.
274+
Когнитивная сложность метода порта не может превышать 1.
275+
250276
Классы операций могут иметь только один публичный метод.
251277

252278
Доменные операции кодируются либо процедурами (top-level функциями или статическими методами), получающими все необходимые ресурсы в параметрах, либо классами, которые инстанциируются "вручную" внутри операций и могут обращаться только к ресурсам операции.

0 commit comments

Comments
 (0)