When designing an application architecture, one of the things to consider is how to deal with lock-in on third party components. The problem is generally multi-faced (a component might be freely available as open source, or being tied to a license fee) and is generally managed on a risk analysis basis. It can also be tied to large scale aspects such has hardware choices, Operative systems etc. I'll focus here on choosing 3rd party libraries and components for a generic enterprise application (thinking of JEE, but not necessarily only of it). On the practical side this is managed by taking care that the component substitution cost is kept as low as possible. Typical approaches were to intercept and wrap dependencies, with a proxy or an adapter class: no direct access to the 3rd party component is allowed, access to the provided service is available only via the adapter class. In a J2EE context looked like everybody was concerned about Log4J, so the logger wrapper became the architect-level counterpart of the String-manipulation class that every developer felt obliged to write at a certain point of his career.
Technically speaking, you want to reduce coupling between the caller and the provider of a given service, so you extract a more or less generic interface from the service, and provide a (usually brainless) adapter to the 3rd party component. This way you achieve compile time decoupling from the component, at the price of a small increase in complexity (a bit in the code, a little more in documentation, guidelines and control). This price is generally proportional to the complexity of the used portion of the component API (which is one of the reasons why everybody wrapped Log4J…).
The point is that this effort is not really worth a lot of times. For basically two reasons:
- You are trading a certain cost now for a possible one in the future (ok, you've done risk analysis on the subject, but… you've got the point.)
- You are probably overestimating substitution cost. Ok, I am telling you but I am thinking me, 'cause I know I did… Common refactoring techniques, enhanced IDE support, or even a trivial search and replace capability make this type of code-level change really faster. Developers are generally worried about the number of occurrences of a given required change more than the diversity of the single ones.
What's left out, is more subtle effects of lock in… which results in way of organizing the surrounding components, or in the way to structure the application. In those cases, you can still enhance the capability of your adapter, providing an higher level of service abstraction, but as before you end up paying more at the early stages for a possible risk that could be better mitigated some other way.