views:

209

answers:

3

Our code base uses several external libraries, in order to save time and focus on developing important features instead of reinventing the wheel.

Currently the code is littered with direct usage of the libraries. This means that switching to other libraries that have more-or-less the same features will mean rewriting almost everything from scratch. The ability to switch some of the libraries is important because of license issues and especially royalties.

Another important goal is to have better testing, currently writing unit tests and regression test is hard because of external dependencies (DLLs, licenses, etc.). A good wrapper will allow us to write mocks and stubs for library usage.

What are some best practices to use when wrapping the usage external libraries, so that it will be easier to replace them? Please consider the following when answering:

  • I know that it's not possible to achieve 100% generic wrappers. It still doesn't mean we shouldn't do anything.
  • The code and the libraries are Object Oriented, I didn't specify the exact language on purpose.
  • How to deal with data passes back and forth between our code and the libraries. For example, should we mirror enumerations and constants?
  • How can we minimize data conversion? For example, passing MyHashTable to an external function that accepts ExternalHashTable, or converting MyString to ExternalLibraryString.
  • How to design our class hierarchies. Should we mirror the same class hierarchies from the libraries?
  • How to deal with configuration methods? Some of the libraries are configured both in-code and in configuration files.

Please do not get too language specific. Code examples are OK as long as they don't feature a language-specific mechanism.

+4  A: 

The Bridge pattern comes to mind. My recommendation:

  • Create an abstract class that defines the protocol that your application will use for the specific functionaility you wish to wrap.
  • The protocol should be library independent and use application specific data structures, not data structures from the library headers.
  • Derive from this abstract class and implement the coupling with the libraries that you decide to use (one class per library). The derived class will translate the data structures as needed between your application and the library, through the protocol.
  • Your application will talk only using the protocol defined in the abstract base class, so the only change needed to swap out libraries, would be in the instantiation of the derived class.

How to deal with data passes back and forth between our code and the libraries. For example, should we mirror enumerations and constants?

The derived implementation can handle the necessary translation. You don't want to mirror them, instead define only those enums that make sense for your application (which don't even have to be enums/constants, for that matter). Different libraries might use different enums or not enums at all, so mirroring a certain library's enums will tie you down.

How to design our class hierarchies. Should we mirror the same class hierarchies from the libraries?

Design the class hierarchies so that it is most compatible with your application code. Different libraries could have very different class hierarchies, so it doesn't make sense to mirror it.

How to deal with configuration methods? Some of the libraries are configured both in-code and in configuration files.

All configuration can be handled in the derived implementation (maybe via an application configuration controller that is queried). You could also design your protocol so that it provides library independent methods to specify configuration options.

codelogic
A: 

This seems like premature optimization to me. Until you know that you'll be making a switch, and know what the new library will be, you have two problems:

  1. You don't know how to abstract things in a way that will work for both libraries.

  2. You're adding a lot of complexity that you don't currently need. This will mean more bugs, and more programmer effort required for any task.

RE: Testing - you do need to decouple to do good unit testing, but merely abstracting & mocking your libraries usually isn't the right approach.

Jay Bazuzi
+1  A: 

I've used the Static Gateway pattern discussed here by JP Boodhoo. I've used this in a recent project where I was able to replace my IoC implementation without having to change any code except the Application Startup Task.

Scott Muc