You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/docs/models/ergo-arch.adoc
+65-39Lines changed: 65 additions & 39 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -58,68 +58,87 @@ weight: 875
58
58
59
59
== Проекция структуры данных (модель данных)
60
60
61
-
Проекция структуры данных по большому счёту является комбинацией проверенных идей из DDD, Функциональной архитектуры и Entity-Relation-модели с небольшими отличиями.
61
+
Проекция структуры данных является комбинацией идей из DDD, Функциональной архитектуры, Entity-Relation-модели и ECS архитектуры.
62
62
63
63
=== Номенклатура блоков
64
64
65
-
Концептуальными базовыми блоками этой проекции являются:
65
+
Модель данных ЭА состоит из сущностей, которые, в свою очередь могут включать компоненты.
66
+
Компоненты могут принадлежать только одному владельцу - сущности или другому компоненту.
67
+
Сущность со всеми своими компонентами является единицей хранения - она загружается из хранилища и сохраняется в нём целиком со всеми компонентами.
66
68
67
-
. Сущности - объекты обладающие идентичностью;
68
-
. Объекты-значения - доменно-специфичные составные объекты, не обладающие идентичностью;
69
-
. Агрегаты - кластер сущностей и объектов-значений, жёстко объединённых общим жизненным циклом.
69
+
И у сущностей, и у компонентов есть атрибуты.
70
+
Атрибут может быть простым (имя, цена) или составным - то есть компонентом (позиция заказа с количеством и ссылкой на продукт).
71
+
Кроме того, атрибуты могут быть скалярами (цена заказа) и коллекциями примитивов или компонентов (список позиций заказа).
70
72
71
-
Номинально, номенклатура блоков полностью совпадает с DDD.
72
-
Однако есть ряд отличий:
73
+
Сущности бывают двух типов:
73
74
74
-
. В ЭА допустимо ссылаться на сущности, не являющиеся корнем агрегата;
75
-
. Базовым критерием объединения сущностей в агрегаты является их жизненный цикл, а не инварианты, которые необходимо обеспечить.
75
+
. Коренная сущность.
76
+
Это самостоятельная сущность обладающая собственной идентичностью - заказ, клиент, продукт и т. д.;
77
+
. Аспект другой сущности.
78
+
Сущность-аспект, это фактически компонент, который был повышен до сущности по дизайнерским или техническим причинам.
79
+
Например, если в предметной области встречаются заказы с сотнями позиций, то в модели позиция может быть сделана сущностью-аспектом, для того чтобы повысить эффективность работы с БД в реализации модели.
80
+
Или компонент "Адрес доставки" сущности "Заказ" может быть сделан сущностью-аспектом, если эта информация нужна модулю, отличному от того, который управляет коренной сущностью "Заказ";
76
81
77
-
=== Связи между блоками
78
-
79
-
У связи между блоками есть два атрибута: сила (слабая или сильная) и кардинальность (один, немного, много).
80
-
81
-
Сила связи это аналог связей внутри и между агрегатами в DDD и связей между обычными и стержневыми и слабыми сущностями в ER-модели.
82
+
Коренная сущность со всеми её компонентами и аспектами называется агрегатом.
82
83
83
-
Для владеющих связей, при удалении блока-владельца удаляются и все блоки, с которым он связан владеющей связью.
84
-
Для невладеющих связей недопустимо удалять целевой блок, при наличии ссылающихся на неё блоков.
84
+
=== Связи между блоками
85
85
86
-
ЭА разделяет связи 1-к-немногим и 1-ко-многим.
87
-
Связь один к немногим - это частый случай связи 1-ко-многим про который вы на этапе проектирования можете сказать, что в этой связи связи будет участвовать определённое, ограниченное и небольше количество сущностей.
86
+
В модели данных ЭА есть только связи один-к-одному и один-ко-многим.
87
+
Связей многие-ко-многим нет.
88
88
89
-
Связей многие-ко-многим в ЭА нет.
90
-
Если два класса/типа агрегата могут быть связаны отношением многие-ко-многим, то в модели они отображаются одним из двух вариантов:
89
+
Так же связь может быть владеющей и не владеющей.
90
+
Связи между сущностями и компонентами (и между компонентами), а также между коренной сущностью и сущностью-аспектом является владеющей.
91
+
Связи между агрегатами являются не владеющими.
91
92
92
-
. Если на самом деле отношение является многие-к-немногим, то в агрегат на стороне "многие" добавляется объект-значение с невладеющей связью с другим агрегатом, который связан отношениме немногие-к-одному с одной из сущностей или объектов-значения агрегата;
93
-
. В противном случае для отношения заводится самостоятельный агрегат с двумя невладеющими связями с основными агрегатами (аля связующая таблица в реляционной модели)
94
93
95
-
Ограничения на связи между блоками:
96
94
97
-
. Сущность не может быть "владеемой" несколькими другими сущностями (читай: сущность может входить только в один агрегат);
98
-
. Связи между сущностями должны образовывать направленный ацикличный граф.
95
+
=== Кодирование блоков
99
96
100
-
При следовании этим правилам в графе структуры данных образуется три слоя:
97
+
[NOTE]
98
+
====
99
+
Здесь и далее в качестве примеров кодирования я использую терминологию Kotlin.
100
+
Однако ЭА может быть реализована на любом тюринг-полном языке - хоть Си, хоть Хаскель, разница лишь в том, придётся ли при этом бороться с сами языком.
101
+
Борьбы с языком не будет, если он мультипарадигменный - поддерживает и императивную, и объектную и функциональную модель программирования.
102
+
====
101
103
102
-
. слой генеричных/универсальных агрегатов;
103
-
. слой ключевых сущностей системы;
104
-
. слой вспомогательных сущностей системы.
104
+
И сущности и компоненты кодируются неизменяемыми `data class`-ами.
105
105
106
-
=== Кодирование блоков
106
+
Связи между сущностями и компонентами кодируются атрибутом сущности с типом компонента
107
107
108
-
В код попадают только сущности и объекты-значения.
109
-
И те и другие кодируются в виде неизменяемых классов и различаются наличием или отсутствием поля-идентификатора.
108
+
Связи между сущностью-аспектом и коренной сущностью кодируются атрибутом сущности-аспекта с типом идентификатора^*^.
110
109
111
110
[NOTE]
112
111
====
113
-
Здесь и далее в качестве примеров кодирования я использую терминалогию Kotlin.
114
-
Однако ЭА может быть реализована на любом тюринг-полном языке - хоть Си, хоть Хаскель, разница лишь в том, придётся ли при этом бороться с сами языком.
115
-
Борьбы с языком не будет, если он мультипарадигменный - поддерживает и императивную, и объектную и функциональную модель программирования.
116
-
И, на самом деле, большинство современных языков таковыми являются - Java, C#, Python, JavaScript, TypeScript, Swift, Rust, F#, Clojure - только то, про что я сходу могу сказать, что точно подходит.
112
+
^*^ Здесь и далее под "типом идентификатора" подразумевается простой тип, как правило - UUID, Long или String.
117
113
====
118
114
119
-
Владеющие связи кодируются полем со ссылкой на целевой объект.
120
-
Не владеющие связи кодируются полем с типом-обёрткой вокруг идентификатора целевого агрегата.
115
+
Для связи один-к-одному атрибут идентификатора является одновременно и ссылкой на коренную сущность.
116
+
Для связи один-ко-многим атрибут идентификатора сущности-аспекта делается составным и включает в себя ссылку на коренную сущность и идентификатор сущности-аспекта.
121
117
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
+
----
123
142
124
143
=== Примеры/Паттерны
125
144
@@ -200,6 +219,10 @@ weight: 875
200
219
А совсем вымышленной фичей могла бы возможность для терапевтов и клиентов превращаться друг в друга.
201
220
Условно когда терапевт по свеому номеру телефона записывается на приём к другому терапевту, то ему не заводится отдельный юзер, а заводится новый клиент, который привязывается к тому же юзеру.
202
221
222
+
==== Иерархия компонентов
223
+
224
+
(#todo: #)
225
+
203
226
== Проекция структуры компонентов
204
227
205
228
Концептуальной моделью структуры состояния является 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
247
270
248
271
Количество публичных методов в портах и ресурсах ограниченно разумными на ваш взгляд пределами.
249
272
273
+
Методы портов могу содержать в себе только один вызов операции или ресурса.
274
+
Когнитивная сложность метода порта не может превышать 1.
275
+
250
276
Классы операций могут иметь только один публичный метод.
251
277
252
278
Доменные операции кодируются либо процедурами (top-level функциями или статическими методами), получающими все необходимые ресурсы в параметрах, либо классами, которые инстанциируются "вручную" внутри операций и могут обращаться только к ресурсам операции.
0 commit comments