-
Notifications
You must be signed in to change notification settings - Fork 1
/
architectural-decisions.xml
281 lines (251 loc) · 14 KB
/
architectural-decisions.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
<?xml version="1.0" encoding="UTF-8"?>
<architecturalDecisions xmlns="https://architectural-decision.cspray.io/schema/architectural-decision.xsd">
<architecturalDecision id="ConfigurationCannotBeAssignedProfiles" attribute="Cspray\AnnotatedContainer\ArchitecturalDecisionRecords\ConfigurationCannotBeAssignedProfiles">
<date>2022-08-10</date>
<status>Superseded</status>
<contents><![CDATA[# Configuration instances cannot be assigned profiles
## Context
Configuration instances are classes with properties that can have arbitrary values injected into them with the
#[Inject] Attribute. Like a Service, Configuration instances are shared with the Container. Unlike a Service,
Configuration cannot be assigned an explicit profile.
## Decision
We explicitly do no allow setting a profile on a Configuration. The Configuration is meant to use #[Inject] Attributes
to define values. Any value that should only be injected when certain profiles are active should have that reflected
in the #[Inject] Attribute. This way just 1 Configuration instance is required and any profile-specific values are
defined on the value itself.]]></contents>
<codeAnnotations>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Definition\ConfigurationDefinition</class>
</codeAnnotation>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Attribute\Configuration</class>
</codeAnnotation>
</codeAnnotations>
<meta>
<author>
<name>Charles Sprayberry</name>
<website>https://cspray.io</website>
<githubProfile>https://github.com/cspray</githubProfile>
</author>
<supersededBy>DeprecateConfigurationInFavorOfCustomServiceAttribute</supersededBy>
</meta>
</architecturalDecision>
<architecturalDecision id="SingleEntrypointDefinitionProvider" attribute="Cspray\AnnotatedContainer\ArchitecturalDecisionRecords\SingleEntrypointDefinitionProvider">
<date>2022-07-19</date>
<status>Accepted</status>
<contents><![CDATA[# Allow Single Entrypoint for DefinitionProvider
## Context
A DefinitionsProvider is intended to support adding third-party services that can't be annotated to a
ContainerDefinition. It could be beneficial to attach multiple consumers so that complex third-party service setup
does not have to happen entirely in 1 implementation.
## Decision
We explicitly only allow one DefinitionsProvider to be configured when compiling your ContainerDefinition.
It would be technically possible, and even straightforward, to allow configuring multiple providers. However, doing
so would have a significant cognitive overhead and, potentially, cause what services are used in a given situation to
be vague or unclear. Specifically, third-party packages could override your definitions without you being fully
aware of it.
If you need to use multiple providers or providers implemented by third-parties then you're required to provide your
own entrypoint and compose them together or explicitly define which third-party provider you'd like to use. This way
you know precisely what code is determining the services for your application.]]></contents>
<codeAnnotations>
<codeAnnotation>
<classMethod>
<class>Cspray\AnnotatedContainer\Bootstrap\XmlBootstrappingConfiguration</class>
<method>getContainerDefinitionProvider</method>
</classMethod>
</codeAnnotation>
<codeAnnotation>
<classMethod>
<class>Cspray\AnnotatedContainer\Bootstrap\BootstrappingConfiguration</class>
<method>getContainerDefinitionProvider</method>
</classMethod>
</codeAnnotation>
<codeAnnotation>
<classMethod>
<class>Cspray\AnnotatedContainer\StaticAnalysis\ContainerDefinitionAnalysisOptionsBuilder</class>
<method>withDefinitionProvider</method>
</classMethod>
</codeAnnotation>
<codeAnnotation>
<classMethod>
<class>Cspray\AnnotatedContainer\StaticAnalysis\ContainerDefinitionAnalysisOptions</class>
<method>getDefinitionProvider</method>
</classMethod>
</codeAnnotation>
</codeAnnotations>
<meta>
<author>
<name>Charles Sprayberry</name>
<website>https://cspray.io</website>
<githubProfile>https://github.com/cspray</githubProfile>
</author>
</meta>
</architecturalDecision>
<architecturalDecision id="ImplicitServiceCreationFromServiceDelegate" attribute="Cspray\AnnotatedContainer\ArchitecturalDecisionRecords\ImplicitServiceCreationFromServiceDelegate">
<date>2024-05-09</date>
<status>Accepted</status>
<contents><![CDATA[# ServiceDelegate Implicitly Creates ServiceDefinition if necessary
## Context
In versions 2.2.0 and below, if a ServiceDelegateAttribute was defined the type it creates MUST be defined as a
Service; either with the Attribute API or using low-level functions in a DefinitionProvider. The thought process
behind this decision was to make you be explicit about what services you define. However, there are valid designs
where this limitation leads to unnecessary boilerplate.
## Decision
In versions 2.3.0 and higher, if a ServiceDelegateAttribute is defined to create a type that is not already a
Service definition it will be added to the ContainerDefinition instead of an exception being thrown. This is
to make sure we're still doing all the other stuff we might do with services in the ContainerFactory and other
analysis tools that are expecting these values to be present. This will allow for a more varied usage of
Annotated Container instead of forcing down a more opinionated path.]]></contents>
<meta>
<author>
<name>Charles Sprayberry</name>
<website>https://cspray.io</website>
<githubProfile>https://github.com/cspray</githubProfile>
</author>
</meta>
</architecturalDecision>
<architecturalDecision id="DeprecateActiveProfilesInFavorOfConcreteValueObject" attribute="Cspray\AnnotatedContainer\ArchitecturalDecisionRecords\DeprecateActiveProfilesInFavorOfConcreteValueObject">
<date>2025-05-21</date>
<status>Accepted</status>
<contents><![CDATA[# Deprecate ActiveProfiles for Concrete Value Object
## Context
Profiles play a critically important role in Annotated Container. They define what services and parameters might
get injected and allows for a great amount of flexibility when wiring your services for a variety of environments
and runtimes. It might be important to programmatically know which profiles are active at any given time. As of 2.3.0,
that is handled by the Cspray\AnnotatedContainer\Profiles\ActiveProfiles interface.
This interface has been somewhat problematic from the get-go. Because of various bootstrapping concerns the ActiveProfiles
implementation is actually created a few times in duplication. This duplication extends into each ContainerFactory.
In addition, having a separate implementation for parsing profiles from a string leads to a general feeling of the
ActiveProfiles design being over-engineered.
## Decision
To simplify the amount of code being duplicated and to make profiles easier to reason about in internal code, the
existing implementations in the Cspray\AnnotatedContainer\Profiles namespace have been deprecated. They will be
replaced with a value object that has static constructors for creating a set of profiles in a variety of standardized
ways. This value object will also continue to provide the same functionality as the ActiveProfiles interface.
The deprecation of these implementations in 2.3 is meant to serve as a warning they will be removed in 3.0. For the
most part, transitioning from ActiveProfiles to Profiles in your code should be straightforward. You should only need
to adjust the type declaration to be the new type.]]></contents>
<codeAnnotations>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Profiles\ActiveProfilesBuilder</class>
</codeAnnotation>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Profiles\CsvActiveProfilesParser</class>
</codeAnnotation>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Profiles\ActiveProfiles</class>
</codeAnnotation>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Profiles\ActiveProfilesParser</class>
</codeAnnotation>
</codeAnnotations>
<meta>
<author>
<name>Charles Sprayberry</name>
<website>https://cspray.io</website>
<githubProfile>https://github.com/cspray</githubProfile>
</author>
<deprecation>
<since>2.3.0</since>
<scheduledForRemoval>3.0.0</scheduledForRemoval>
</deprecation>
</meta>
</architecturalDecision>
<architecturalDecision id="DeprecateObserversInFavorOfEventSystem" attribute="Cspray\AnnotatedContainer\ArchitecturalDecisionRecords\DeprecateObserversInFavorOfEventSystem">
<date>2024-05-15</date>
<status>Accepted</status>
<contents><![CDATA[# Deprecate Observers for Events
## Context
In 2.0 the Bootstrap Observer system was added. This system allows your integrating library or application to
perform some actions when a limited set of events occur within Annotated Container's provided bootstrapping. The
design was primarily geared toward providing the functionality found in
Cspray\AnnotatedContainer\Bootstrap\ServiceWiringObserver.
As part of Annotated Container 3.0 improvements, it was decided that the way logging is handled should be made
more test friendly and easier for you to be explicit about enabling that logging without being overly burdensome. It
would be ideal to put logging into an Observer implementation, however the limited amount of Observers available is
not sufficient to replace the existing logging output.
## Decision
A comprehensive, granular event system will be implemented as part of Annotated Container 3.0 that will resolve the
hurdles with using the existing Observer system. The existing Observer system will become obsolete and no longer
necessary. The deprecation of this system in 2.3 is meant to act as a warning that in 3.0 you'll need to update
your Observer implementations to use the corresponding Event. In practice this should be a relatively straight-forward
operation requiring implementation of a new interface, renaming a method, and perhaps adjusting a method signature.
All the data made available through the Observer system will also be made available through the Event system.]]></contents>
<codeAnnotations>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Bootstrap\ObserverFactory</class>
</codeAnnotation>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Bootstrap\PostAnalysisObserver</class>
</codeAnnotation>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Bootstrap\ServiceWiringObserver</class>
</codeAnnotation>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Bootstrap\ContainerCreatedObserver</class>
</codeAnnotation>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Bootstrap\ContainerAnalyticsObserver</class>
</codeAnnotation>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Bootstrap\PreAnalysisObserver</class>
</codeAnnotation>
</codeAnnotations>
<meta>
<author>
<name>Charles Sprayberry</name>
<website>https://cspray.io</website>
<githubProfile>https://github.com/cspray</githubProfile>
</author>
<deprecation>
<since>2.3.0</since>
<scheduledForRemoval>3.0.0</scheduledForRemoval>
</deprecation>
</meta>
</architecturalDecision>
<architecturalDecision id="DeprecateConfigurationInFavorOfCustomServiceAttribute" attribute="Cspray\AnnotatedContainer\ArchitecturalDecisionRecords\DeprecateConfigurationInFavorOfCustomServiceAttribute">
<date>2023-05-14</date>
<status>Accepted</status>
<contents><![CDATA[# ConfigurationAttribute is Deprecated
## Context
When Annotated Container launched it was decided to have a ConfigurationAttribute that could act as a type-safe,
container-managed way to handle app configs. Shared services attributed with a ConfigurationAttribute follow
slightly different rules than a ServiceAttribute. Specifically, they are not allowed to be assigned profiles,
cannot be marked primary, and can have values injected into a property without a constructor.
## Decision
In practice the limitations around ConfigurationAttribute were hard to work with. Of important note is the desire to
have a default configuration provided by a library and the app easily overriding it. This is possible with the
ServiceAttribute out-of-the-box. Additionally, the opinion that Configuration should not have profiles was arbitrary
in nature and only put limitations on the use of the Configuration without providing any real value. On top of all
that, the idea that Configuration would be the only type of services to injecting values directly onto a property
was made obsolete with constructor property promotion.
We could simply add these pieces of the ConfigurationAttribute but at that point we're effectively duplicating the
ServiceAttribute. Instead of that, we should discourage the use of the ConfigurationAttribute. If you require similar
functionality, you should implement your own custom ServiceAttribute.]]></contents>
<codeAnnotations>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Definition\ConfigurationDefinition</class>
</codeAnnotation>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Definition\ConfigurationDefinitionBuilder</class>
</codeAnnotation>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Attribute\ConfigurationAttribute</class>
</codeAnnotation>
<codeAnnotation>
<class>Cspray\AnnotatedContainer\Attribute\Configuration</class>
</codeAnnotation>
</codeAnnotations>
<meta>
<author>
<name>Charles Sprayberry</name>
<website>https://cspray.io</website>
<githubProfile>https://github.com/cspray</githubProfile>
</author>
<deprecation>
<since>2.1.0</since>
<scheduledForRemoval>3.0.0</scheduledForRemoval>
</deprecation>
</meta>
</architecturalDecision>
</architecturalDecisions>