DI: problem of misconfiguration for service access

This is a tricky problem an an immediate consequence of the dynamic configuration
favoured by this design. We avoid a centralised configuration and thus there
are no automatic rules to enforce consistency. It would thus be possible
to start using a dependency in singleton style, but to switch to service
style later, after the fact.

An attempt was made to prevent such a mismatch by static initialisiation;
basically the presence of any Depend<SRV>::ServiceInstance<X> would disable
any usage of Depend<SRV> in singleton style. However, such a mechanism
was found to be fragile at best. It seems more apropriate just to fail
when establishing a ServiceInstance on a dependency already actively in
use (and to lock usage after destroying the ServiceInstance).

This issue is considered rather an architectural one, which can not be
solved by any mechanism at implementation level ever
This commit is contained in:
Fischlurch 2018-03-18 17:19:30 +01:00
parent 5516700523
commit 786f051132
3 changed files with 65 additions and 9 deletions

View file

@ -116,7 +116,6 @@ class DependInject;
template<class SRV>
class Depend
{
public:
using Factory = std::function<SRV*()>;
static SRV* instance;
@ -125,6 +124,7 @@ class Depend
static InstanceHolder<SRV> singleton;
friend class DependInject<SRV>;
public:
SRV&
operator() ()
@ -209,6 +209,7 @@ class DependInject
"but another instance has already been dependency-injected."
, error::LUMIERA_ERROR_LIFECYCLE);
Depend<SRV>::instance = &newInstance;
Depend<SRV>::factory = Depend<SRV>::disabledFactory;
}
static void
@ -362,7 +363,7 @@ main (int, char**)
SHOW_EXPR( checksum );
}
SHOW_EXPR( checksum );
SHOW_EXPR( dep3().probe() );
VERIFY_ERROR (LIFECYCLE, dep3().probe() );
VERIFY_ERROR (LIFECYCLE, DependInject<Dum>::ServiceInstance<SubDummy>{} );
SHOW_EXPR( checksum );

View file

@ -1927,7 +1927,7 @@ As we don't have a Prolog interpreter on board yet, we utilize a mock store with
{{{default(Obj)}}} is a predicate expressing that the object {{{Obj}}} can be considered the default setup under the given conditions. Using the //default// can be considered as a shortcut for actually finding an exact and unique solution. The latter would require to specify all sorts of detailed properties up to the point where only one single object can satisfy all conditions. On the other hand, leaving some properties unspecified would yield a set of solutions (and the user code issuing the query had to provide means for selecting one solution from this set). Just falling back on the //default// means that the user code actually doesn't care for any additional properties (as long as the properties he //does// care for are satisfied). Nothing is said specifically on //how//&amp;nbsp; this default gets configured; actually there can be rules //somewhere,// and, additionally, anything encountered once while asking for a default can be re-used as default under similar circumstances.
&amp;rarr; [[implementing defaults|DefaultsImplementation]]</pre>
</div>
<div title="DependencyFactory" creator="Ichthyostega" modifier="Ichthyostega" created="201803110155" modified="201803180023" tags="def Concepts draft" changecount="9">
<div title="DependencyFactory" creator="Ichthyostega" modifier="Ichthyostega" created="201803110155" modified="201803181619" tags="def Concepts draft" changecount="10">
<pre>//Access point to dependencies by-name.//
In the Lumiera code base, we refrain from building or using a full-blown Dependency Injection Container. A lot of FUD has been spread regarding Dependency Injection and Singletons, to the point that a majority of developers confuses and conflates the ~Inversion-of-Control principle (which is essential) with the use of a ~DI-Container. Today, you can not even mention the word &quot;Singleton&quot; without everyone yelling out &quot;Evil! Evil!&quot; -- while most of these people just feel comfortable living in the annotation hell.
@ -1964,6 +1964,8 @@ Deliberately, we do not enforce global consistency statically (since that would
:the generated object again acts as lifecycle handle and smart-ptr to access the {{{SubBlah}}} instance like {{{mock-&gt;doItSpecial()}}}
:when this handle goes out of scope, the original configuration of the dependency factory is restored
We consider the usage pattern of dependencies a question of architecture rather -- such can not be solved by any mechanism on implementation level.
For this reason, DependencyFactory prevents reconfiguration after use, but does nothing exceeding such basic sanity checks
</pre>
</div>
<div title="DesignDecisions" modifier="Ichthyostega" created="200801062209" modified="201505310104" tags="decision design discuss Concepts" changecount="5">

View file

@ -26792,6 +26792,7 @@
<node CREATED="1521208242178" ID="ID_539882602" MODIFIED="1521208246821" TEXT="erforderliche Mechanismen">
<node CREATED="1521208254376" ID="ID_1933406851" MODIFIED="1521208256603" TEXT="Singleton">
<node CREATED="1521208339124" ID="ID_287433738" MODIFIED="1521209063045" TEXT="Closure &#xfc;ber konkreten Ctor"/>
<node CREATED="1521208339124" ID="ID_826329078" MODIFIED="1521387972747" TEXT="(optional)Closure mit speziellen Argumenten"/>
<node COLOR="#338800" CREATED="1521209708336" ID="ID_1667188609" MODIFIED="1521332921903" TEXT="Storage f&#xfc;r UnterBla-Instanz bereitstellen">
<icon BUILTIN="button_ok"/>
</node>
@ -26806,7 +26807,9 @@
</node>
</node>
<node CREATED="1521208257336" ID="ID_1129640741" MODIFIED="1521208261323" TEXT="ServiceInstance">
<node CREATED="1521208859989" ID="ID_549061661" MODIFIED="1521208874756" TEXT="Lazy-Init-Factory deaktivieren"/>
<node COLOR="#338800" CREATED="1521208859989" ID="ID_549061661" MODIFIED="1521387920055" TEXT="Lazy-Init-Factory deaktivieren">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1521208793630" ID="ID_1357481546" MODIFIED="1521335430941" TEXT="Service-Zugang in Depend&lt;Bla&gt; injizieren">
<icon BUILTIN="button_ok"/>
</node>
@ -26833,6 +26836,7 @@
<node COLOR="#338800" CREATED="1521208724943" ID="ID_1527628667" MODIFIED="1521335442003" TEXT="smart-ptr-artiger Zugriff auf die Service-Impl">
<icon BUILTIN="button_ok"/>
</node>
<node CREATED="1521208339124" ID="ID_1092066450" MODIFIED="1521387948246" TEXT="(optional)Closure &#xfc;ber konkreten Ctor"/>
</node>
<node CREATED="1521208261887" ID="ID_384054163" MODIFIED="1521208264827" TEXT="Local">
<node CREATED="1521209044203" ID="ID_1994153994" MODIFIED="1521209058181" TEXT="Closure &#xfc;ber konkreten Ctor"/>
@ -27093,14 +27097,63 @@
<node COLOR="#338800" CREATED="1521253803963" ID="ID_100415207" MODIFIED="1521332991888" TEXT="Installation wenn Factory bereits genutzt wurde">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1521253831776" ID="ID_1332033733" MODIFIED="1521303545433" TEXT="Zugriff auf Service bevor er hochgefahren wurde">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1521253858692" ID="ID_442301762" MODIFIED="1521253866011" TEXT="t&#xfc;ckisch">
<icon BUILTIN="flag-pink"/>
<node COLOR="#338800" CREATED="1521253831776" ID="ID_1332033733" MODIFIED="1521387909137" TEXT="Zugriff auf Service bevor er hochgefahren wurde">
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1521253858692" ID="ID_442301762" MODIFIED="1521385565612" TEXT="t&#xfc;ckisch">
<icon BUILTIN="broken-line"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1521253867787" ID="ID_662728746" MODIFIED="1521253891037" TEXT="beachte Lifecycle-Handle existiert noch nicht">
<node CREATED="1521253867787" ID="ID_662728746" MODIFIED="1521385616988" TEXT="Lifecycle-Handle existiert erst viel sp&#xe4;ter">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1521385652999" ID="ID_1974848336" MODIFIED="1521385657839" TEXT="statischer Schutz">
<icon BUILTIN="button_cancel"/>
<node CREATED="1521385660206" ID="ID_200575604" MODIFIED="1521385685919" TEXT="fragil">
<icon BUILTIN="stop-sign"/>
<node CREATED="1521385687874" ID="ID_1561975152" MODIFIED="1521386168998" TEXT="C++ kennt keine statische Klassen-Initialisierung">
<icon BUILTIN="info"/>
</node>
<node CREATED="1521385709463" ID="ID_713439022" MODIFIED="1521385757820" TEXT="workaround">
<node CREATED="1521385721637" ID="ID_1822970415" MODIFIED="1521386025178" TEXT="Initialisieren eines statischen member">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1521385768359" ID="ID_1123247553" MODIFIED="1521385776914" TEXT="ist unzuverl&#xe4;ssig">
<node CREATED="1521385782861" ID="ID_1190214158" MODIFIED="1521385787152" TEXT="erfordert non-const member"/>
<node CREATED="1521385787980" ID="ID_81600101" MODIFIED="1521385794375" TEXT="wird vom Compiler wegoptimiert"/>
<node CREATED="1521385795059" ID="ID_1426898485" MODIFIED="1521386008204" TEXT="sofern er Wirkungslosigkeit nachweisen kann...">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Und das h&#228;ngt nur von den Umst&#228;nden ab.
</p>
<p>
In einem einfachen statisch gelinkten Executable entfernt gcc die gesamte Variable sogar ohne Optimierung.
</p>
<p>
</p>
<p>
In Zukunft k&#246;nnten Compiler/Linker noch &quot;schlauer&quot; werden...
</p>
</body>
</html>
</richcontent>
</node>
</node>
<node CREATED="1521386182598" ID="ID_1671815821" MODIFIED="1521386187993" TEXT="ist undurchsichtig">
<icon BUILTIN="smily_bad"/>
</node>
</node>
</node>
<node CREATED="1521386206627" ID="ID_1928841192" MODIFIED="1521386214661" TEXT="erzeugt eh blo&#xdf; eine Fehlermeldung"/>
<node CREATED="1521386219297" ID="ID_1181038545" MODIFIED="1521386233755" TEXT="...was auch noch beim Hochfahren des Service passieren kann"/>
</node>
<node CREATED="1521386241406" ID="ID_1481722887" MODIFIED="1521386259129" TEXT="es ist ein Architektur-Problem">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="yes"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1521253986491" ID="ID_546204807" MODIFIED="1521254005609" TEXT="Singleton wenn Interfaceklasse abstrakt ist">
<icon BUILTIN="flag-yellow"/>