“Guns don’t kill people. Wrappers do.”
I doubt Welsh satirical rap crew Goldie Lookin Chain were thinking of the same wrappers as me when they wrote the above lyric. Nonetheless, the subject of when to rap and when to wrap is far more contentious amongst developers and their technical managers than I’d ever imagined.
The situation is something like this: Your project needs to use functionality provided by a third-party – most likely in the form of a library to link into your application. You have two choices:
- Throw caution to the wind, and use the library API directly
- Painstakingly write a wrapper for the library to mitigate against the risks inherent in using code over which you have no control
How do you decide? I believe this is, or at least should be, a business decision. Is it more cost-effective to wrap the third-party library than to not wrap it over the life of the software: Yes or No?
Pros and cons
- Insulate against future API changes in the library – useful if the library is likely to be used from many places in our own code
- Keep open the option of swapping out the library for an alternative in future. This decreases dependence on the library vendor.
- The cost of writing, debugging, testing and maintaining the wrapper.
- The cost of having a non-standard API to the library functionality
Hiring: You can probably hire programmers with knowledge of the third-party library in question. There may be a very large, and growing, number of knowledgeable programmers with experience of this particular API in the market and eager for a job. They require no training cost, or months to acclimatise to a unique coding environment. Hiring developers is expensive in time before they become productive – and you’re probably planning on using the new library precisely so you can have programmers being more productive. The prospect of a job working with the API directly may be attractive to potential recruits – it is something they know they can bring to the job. The prospect of working with a proprietary, undocumented, and doubtless buggy wrapper is not.
Documentation: Many third part libraries are excellently documented. Even if the documentation is not perfect it is nearly always superior to in-house API documentation, because this API is their product so it has to be good if they want you to use it. Furthermore, there may be an active mailing list and user community out there providing support in addition to library vendor.
User base: The library may be widely used – probably more widely used than the application you are thinking of integrating it into. Your code may only have tens or hundreds of users. The library code may have many thousands or even millions of users. It goes without saying that the third-party library has already received vastly more real-world testing than your own code will ever receive. Remember, the reason that you are considering it is that it is tried and tested.
Core Business: Is the functionality provided in the third-part library your business? If your core business is database software, should you be spending your time on a user interface toolkit wrapper? Probably not. You should stick to innovating in your own area, and supporting that process with off-the-shelf solutions for the peripheral services you need. You create value for your customers by delivering your core technology. What is the value proposition for the client the paying you to create a user interface toolkit wrapper? Or is this just architecture astronautics?
Russian Dolls: Is the third-party library already a wrapper? Many libraries exist largely to abstract-away implementation differences between platforms – for example threading libraries or user-interface toolkits. If this is a purpose you had in mind for your wrapper, don’t bother. Its been done already.
A derivative of GFDL image from Wikipedia article Russian Dolls
Fear and Risk: What are you afraid of? What is your attitude to risk? Wrapping all third-party libraries is a risk-averse strategy. Lets examine some possible scenarios that could cause you future problems:
- You find a bug in the library. Either the vendor fixes it in their next release, or if you are fortunate enough to have access to the library source, you fix it yourself.
- The library vendor is subject to a hostile takeover in an attempt to ‘embrace and extend’ their success. This is potentially the most damaging scenario – but you need to look carefully at the real risks here. Is a new owner likely to stop supporting the library? If you have access to the source code the risk is reduced. Will the product be withdrawn? Are alternatives available?
- A fabulous alternative but currently hypothetical library is released five years from now. You’re worried that at as some indeterminate time in the future you might want to use that instead. No problem: Why not defer writing a wrapper until the new-fangled alternative library is a reality, and then write a wrapper for the new library that makes it API compatible with the existing library? If it never happens, we save the cost of writing and maintaining a wrapper!
- The library vendor introduces some radical API changes between major versions: Your invest some time an effort in porting the code – this will probably be less effort than the cumulative effort of maintaining a wrapper. Maybe they even supply tools to help you. Has the library historically had a stable API? If its version 0.9 you should be more concerned than if its version 6.4. Are changes likely to me minor or earth shattering? Probably the former. Is this upgrading effort so much more than maintaining your own wrapper for years? Obviously you should take the nature of the library into account. For example DirectX is continually chasing the breakneck release of new graphics hardware – whereas OpenGL has historically been a stable API
Wrapper Design: How much effort would you be prepared to invest in writing a wrapper? Are you going to hide all the details of the library? To wrap every type returned or passed to it? If you’re using C++ will you use the Cheshire Cat idiom to prevent any types from the library being visible in your wrapper API – even though doing this essentially requires to write both an inner wrapper and out wrapper – a great concept but certainly more effort.
Leaky Abstractions: How ‘thick’ will you wrapper be? Are you planning to add behaviour or present different abstractions to clients of the functionality? If so, be wary of combining a simple wrapper which merely insulates from changes or bugs in the third-party library with a library which layers substantial new behaviour or abstractions. These different tasks may be better separated into different layers. Any abstraction written around a single reference implementation will leak like a sieve.
Multiple Languages: Is your wrapper to provide an existing API in another language? Mixing language can be a powerful technique but beware if your wrapper needs to overcome a significant ‘impedance mismatch’ between the languages in question. Using Java from Jython is easy whereas using C++ from Java through JNI requires much more discipline and understanding.
Ultimately its for you to decide, based on your own circumstances – but in general I would suggest that the effort involved in wrapping third-party libraries rarely pays off.