On occasion, versioning requires changes in behavior that are not manifest in the interface of the system. For example, we may have an operation that performs some work, such as:
The same operation on the same interface exists in both versions, but the behavior of
doSomething in version 2 differs from that in version 1. The question is, how do we best deal with such behavioral changes?
Of course, one option is to simply create a version 2 facet and to carry that facet alongside the original version 1 facet. For example:
This works fine, as far as it goes: a version 2 client asks for the “V2” facet and then calls
doSomething to get the desired effect. Depending on your circumstances, this approach may be entirely reasonable. However, if there are such behavioral changes on several interfaces, the approach leads to a more complex type system because it duplicates each interface with such a change.
A better alternative can be to create two facets of the same type, but have the implementation of those facets differ. With this approach, both facets are of type
::Foo::doSomething. However, the implementation of
doSomething checks which facet was used to invoke the request and adjusts its behavior accordingly:
This approach avoids creating separate types for the different behaviors, but has the disadvantage that version 1 and version 2 objects are no longer distinguishable to the type system. This can matter if, for example, an operation accepts a
Foo proxy as a parameter. Let us assume that we also have an interface
FooProcessor as follows:
If FooProcessor also exists as a version 1 and version 2 facet, we must deal with the question of what should happen if a version 1
Foo proxy is passed to a version 2
processFoo operation because, at the type level, there is nothing to prevent this from happening.
•
If some of the mixed-version combinations are disallowed (such as passing a version 1
Foo proxy to a version 2
processFoo operation), you can detect the version mismatch in the server by looking at the
Current::facet member and throwing an exception to indicate a version mismatch. Simultaneously, write your clients to ensure they only pass a permissible version to
processFoo. Clients can ensure this by checking the facet name of a proxy before passing it to
processFoo and, if there is a version mismatch, changing either the
Foo proxy or the
FooProcessor proxy to a matching facet: