Is the dependency inversion principle an instance of orthogonalization? Given the class dependency X -> Y a common solution is to introduce interface Z so that the dependencies become X -> Z <- Y. In the first case a change in Y might cause a change in X. After introduction of Z a change in X will not cause Y to change, and a change in Y will not cause X to change. In this sense X and Y are orthogonal. Does this sound correct?
What I'm interested in is what appears to be a higher scale version of this problem. Imagine a complex system. Component P runs a policy that has various effects on the system. The policy can be swapped out or modified. Component M is a monitor whose job is to observe effects of various policies running in the system and compute for each policy a score on the interval [0,1] where 0 is bad and 1 is good. Component M can't fully monitor the system, so the environment is partially-observable. However, assume the score is accurate enough.
Basically P causes various effects and M attempts to maintain a rating computed from the set of effects caused by P.
Here is the interesting part. What if I want to 'trick' M into maintaining the rating at a constant? The rating of P is not something P owns. It is a perception. The idea is to introduce component Z that has an intuitive idea of how M computes its ratings. Z is not a policy so M is not monitoring it. Z can also engage in behavior that is restricted within policies. Every action by P triggers Z to strategically generate effects in the system. The idea is that all the effects together will trick M into keeping the score constant. P can generate 'bad' effects and Z will cover up for them strategically. M will think P is doing just fine. This might not work perfectly because the environment is partially-observable, the algorithm of M is not exactly known, Z may not know what effects will cover up for P, and many other reasons.
The goal is that actions by P do not effect the rating decisions of M. The introduction of the component Z is vaguely similar to the introduction of interface Z in the first example. The idea is that Z is an attempt to orthogonalize P and M. It might not work perfectly, but it's the attempt to do so that I'm labeling as orthogonalization.
Would it be proper to say Z attempts to orthogonalize P and M? Are P and M orthogonal actually?
The initial dependency is something like P <-> M. P depends on M for its perception, and M depends on P to compute an accurate score. (perhaps P also depends on itself for its perception)
The ideal dependency is P -> Z <- M. P depends on a clever Z for its perception. M depends on Z for its rating. Effectively, P triggers Z and Z controls the decision of M.
However, perhaps the initial dependencies cant be fully removed. In that case a strength can be attached to the dependencies. For its perception P is weakly dependent on M and highly dependent on Z. For its decision M is weakly dependent on P and highly dependent on Z. In this case they are nearly orthogonal?
Now imagine I not only want to keep the score computed by M for P at a constant, but occasionally the score needs to be adjusted up or down slightly. Z will do what is necessary to cause this. Would the word orthogonal still be proper?
Overall, what I'm looking for is a word or phrase that best fits this situation where the effects of P on decisions of M are controlled. (where decisions of M are decided elsewhere and causally transferred into its decision making process)
Some ideas I have are: Policy-Monitor {Orthogonalization, Dependency Inversion, Dependency Separation, Decision Inversion, Decision Control, Inversion of Control}.
Thanks for any help. Also, any links to relevant discussion would be nice.
Edit for clarification: This is abstract for me because right now its only a thought experiment that might lead to something interesting.
M not only monitors direct effects of P but all possible n-th order effects originating from P. Z is introduced to attempt to indirectly control the decisions of M by causing effects such that M attributes them to n-th order effects of P. Z secretly knows how M makes decisions, so its effect can be specially designed to make M compute the target score.
The important part is that it's about perception. M has a perception of P and owns it. P might not like the perception. P can react to M and change its policy details to try to get a better score, but the idea is that P does not want to react to M.
Z is an attempt to allow P to ignore M. The purpose of Z is to indirectly control the perception of P. It works something like this: M is monitoring P, Z creates side effects whose origin can be traced to P, M attributes the effects of Z to P, M updates the score of its perception of P. The point of Z is that its secretly has the same decision process as M without anyone knowing, so it has its own idea of what M's score for P is and can 'control' the score for P indirectly. M effectively just uses the score that Z tricks it into computing. Because Z knows how M works it never has to interact with M, it only needs to know what P is doing and generate proper effects to get the proper score (I suppose that means Z is dependent on P. The other possibility is that Z never interacts with P but instead gets the perception of P from M, so Z would be dependent on M. Or..... The dependencies are getting complicated, and it seems to parallel DIP less than I thought. I'll have to delve more into this.)
Also, no one knows that Z is working on behalf of P. A casual observer would believe M is monitoring P and in control of perception. But really there is a hidden Z that is controlling M's perception of P through tricky manipulations.
The claim of orthogonalization between P and M is because P no longer has to worry about M's perception and can forget M even exists, and M's perception of P is no longer affected by the behavior of P. Z purely determines M's perception of P.
I will try to come up with a diagram and a concrete example because it is not easy to reason about.
Regardless of the particular details, the big goal here is to remove (behavioral?) dependencies between P and M by influencing M's decision context and come up with a phrase that describes it.
Edit 2: I've received some great responses, and it is clear that comparing the P-Z-M relationship to DIP is not a great idea. Upon digging deeper these things work differently than I had first thought.
Additionally, I believe that "Shadows In Rain" was correct when mentioning that this seems like a fit for control theory. After looking into control theory it appears that the concepts from that field can properly model the P-Z-M situation. I'll explain towards the end.
First, I will explain in better detail where I went wrong in thinking about this. I used a "knob turning" perspective. To explain I'll start with a linear algebra example.
Let's say I have the basis e1=(1,0) and e2= (0,1). I also have a targe state (5,7). There is a knob associated with e1 and e2. To enter (5,7) I can turn e1 up by 5 and e2 up by 7. Or I can do it in reverse order. In either case the two knob turns together are 5e1+7e2=(5,7). From the "knob turning" perspective these are orthogonal because the second turn of the knob does not need to take into account the amount the first knob was turned by. The target state can be achieved by conflict-free turns of the knobs. The knobs turns represent updates to the object they are associated to.
In the DIP example I was thinking from the view of code evolution rather then code executtion where the environment is multiple developers and the code. The developers keep updating the code. Let's say I have class X that is doing too much. I separate concerns by creating another class Y. X uses the functionality of Y so the dependency is X->Y (an instance of Y is either passed into X or X directly instantiates an instance). In this an interface is not yet used, but concerns have been separated. The only changes to Y that will force a change to X are basically a class name change, a function name change, or Y being removed or replaced by some other class. A change to the internals of Y can be made and in cases other than the ones mentioned X will not have to change. However, you can abstract Y to get the dependency X->-Z<-Y. At this point a class name change to Y will not force a change to X, a function name change can't be made if it is the implementation from the interface, and Y can be removed or replaced with another implementation of Z without having to touch X. From the knob turning perspective you have two initial items X and Y. Each one has a "knob". A knob turn represents a change in the code. Lets say you have a target code state (X*, Y*) such that aX + bY = (X*, Y*) where a and b represent code changes (knob turns). To me it seems like the linear algebra example where I can turn either knob first and the second knob turn does not need knowledge about the first knob turn to achieve the desired state. The reason I think DIP looks like orthogonalization is because abstracting Y into Z is sort of like an orthogonalization process that allows parallel updates to X and Y to achieve a target code state without conflicts. In linear algebra the Gram-Schmidt process takes two vectors and orthogonalizes them so then to achieve a target vector state you can scale your orthogonal vectors independently without conflicts to achieve the target state. Is it clear why I saw a parallel? Is there a problem with the reasoning?
However, the P-Z-M example breaks down. I'll use the lamp example from Flater but modified. Let P be the blue lamp, M be the white object with a sensor, and Z be a yellow lamp. Let's say the sensor on M will log a negative event if it appears blue for too long.
Lets think about default state (P=off, M=senses itself as white object). Lets have target state (P*=shining blue light onto M, M*=not sensing itself as blue). To achieve this state P can turn itself on to shine blue light and Z can turn on its yellow light and strategically cancel out P so that M does not sense itself as blue. However, there are two major differences: order matters and Z must be acting in the process to achieve the target state. To achieve target (P*, M*) you have to turn on P first and then Z activates to prevent M from sensing itself as blue. So aP + bZ = (P*, M*) where "a" turns on P and "b" turns on Z to cancel the light. You can't do bZ + aP because Z reacts to P so if you turn on Z first it wont know what level of blue it needs to cancel. P then turns on and M will sense itself as blue. However it is possible to make an exception and say that Z is not a single action, it is a continuous process, so when you turn on Z first it continuously and dynamically attempts to cancels the blue light, and in such a case order would not matter again. There are many other target examples to think about here, but it should now be clear that this a quite different situation to the code changes and DIP example. The goal is the same: remove dependencies between two things. However, the dependency removal is different, results in various complications, and Z is not passive.
In the umbrella example let's say you have non-extreme weather, an umbrella, and a state representing if your shirt is wet or not. Lets have default state (P=sunny day without rain, M=dry shirt). Z is the umbrella. With target state (P=rain, M=dry shirt) you can't exactly start the rain, but if it starts to rain the umbrella keeps the shirt dry. So to get to the target state you can wait for rain and then hold up the umrella while outside. The weather will be rainy and the shirt dry. You can hold up the umbrella then wait for rain, or wait for rain hold up the umbrella. Either way the order does not matter, but here again Z is not passive. However, let's look at (P=rain, M=wet shirt). To get to this state without dependencies between P and M you can wait for the rain, hold up an umbrella while outside, and then spill water on your shirt. Or you can reverse the order. Here Z made sure to prevent dependency between P and M, but another component (the water) had to be used to achieve the desired wet shirt state for M. In the umbrella example Z is not passive and additional components need to be introduced. This is also very different. Although, the reason for complication seems to be that M here is a state rather than an object with behavior like the other examples
Overall, it seems the common theme is removing dependencies between two objects X and Y by introducing at least another object or process. In the linear algebra example e1 and e2 already have dependencies removed (perhaps after gram-schmidt process), but in the other examples an object or process has to be added which continuously keeps or attempts to keep the objects dependency free. Sort of like a continuous orthogonalization process that never actually completes.
Is there a good word or a field of study that deals with removing/modifying dependencies between two objects X and Y so that they be used together conflict-free? Decoupling?
Finally, control theory seems to be a good fit for the P-Z-M situation. Here is a picture from Wikipedia.
The controller is Z and the system contains P and M. The sensor gives the controller perception of what is happening with P and M. The controller has its own reference value of what score it wants M to have in regard to P. It looks at its perception to see what P is doing and then determines what behavior needs to be input into the system to keep the score at the intended level. Although, if M never publishes its scores then Z only knows how M works but not its score for P. The sensor never gives perception of M. Z will have to guess from its knowledge of M what M's score is. In this sense, Z controls the perception of M with only observing P. However, in my real case Z can observe both P and M, so I think it will work.
Overall, Flater gave the best examples and explanations that made me see the errors in thinking. Shadows In Rain mentioned control theory which appears to have the concepts and terminology to model the P-Z-M relationship as intended.