Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Most projects I am involved with use several open-source components. As a general principle, is it a good idea always to avoid binding all components of the code to the third-party libraries and instead go via an encapsulating wrapper to avoid the pain of change?

As an example, most of our PHP projects directly use log4php as a logging framework, i.e. they instantiate via \Logger::getLogger(), they use ->info() or ->warn() methods, etc. In the future, however, a hypothetical logging framework may appear which is better in some way. As it stands, all the projects which closely couple to the log4php method signatures would have to change, in dozens of places, in order to fit the new signatures. This would obviously have a wide impact on the codebase and any change is a potential problem.

To future-proof new codebases from this kind of scenario, I often consider (and sometimes implement) a wrapper class to encapsulate the logging functionality and make it easier, though not foolproof, to alter the way in which logging works in future with minimal change; the code calls the wrapper, the wrapper passes the call to the logging framework du jour.

Bearing in mind that there are more complicated examples with other libraries, am I over-engineering or is this a wise precaution in most cases?

EDIT: More considerations - using dependency injection and test doubles practically requires that we abstract out most APIs anyway ("I want to check my code executes and updates its state, but not write a log comment/access a real database"). Isn't this a decider?

share|improve this question
1  
log4XYZ is such a strong trademark. Its API will change not sooner than when the API for a linked list will. Both are a long solved problem now. –  Job Sep 11 '11 at 15:20
    
Exact duplicate of this SO question: stackoverflow.com/questions/1916030/… –  Michael Borgwardt Sep 11 '11 at 15:26

6 Answers 6

If you only use a small subset of the third party API, it makes sense to write a wrapper - this helps with encapsulation and information hiding, ensuring you don't expose a possibly huge API to your own code. It can also help with making sure that any functionality you don't want to use is "hidden".

Another good reason for a wrapper is if you expect to change the third party library. If this is a piece of infrastructure you know you will not change, do not write a wrapper for it.

share|improve this answer
    
Good points, but we are taught that closely-coupled code is bad, for many well-understood reasons (harder to test, harder to refactor, etc). An alternative wording of the question is "if coupling is bad, why is it OK to couple to an API?". –  lotsoffreetime Sep 11 '11 at 8:53
2  
@lotsoffreetime You can't avoid some coupling to an API. Therefore, it's better to couple to your own API. That way, you can change out the library and generally not need to change the API provided by the wrapper. –  George Marian Sep 11 '11 at 9:06
    
@george-marian If I can't avoid using a given API, I can certainly minimise the touch points. The question is, should I be trying to do this all the time or is that overdoing things? –  lotsoffreetime Sep 11 '11 at 9:34
1  
@lotsoffreetime That is a difficult question to answer. I've expanded on my answer to that end. (Basically, it's down to a lot of ifs.) –  George Marian Sep 11 '11 at 9:49
1  
@lotsoffreetime: if you have lots of free time, then you can do either. But I'd recommend against writing an API wrapper, except under this condition: 1) the original API is very low level, so you write a higher level API to suit your specific project need better, or 2) you have a plan in the near future to switch libraries, you're using the current library only as a stepping stone while searching for a better one. –  Lie Ryan Sep 11 '11 at 9:57

Without knowing what super-great new features this alleged future improved logger will have, how would you write the wrapper? The most logical choice is to have your wrapper instantiate some sort of logger class, and have methods like ->info() or ->warn(). In other words, essentially identical to your present API.

Rather than future-proof code that I may never need to change, or that may require an unavoidable rewrite anyway, I prefer to "past-proof" code. That is, on the rare occasions when I do significantly change a component, that's when I write a wrapper to make it compatible with past code. However, any new code uses the new API, and I refactor old code to use it whenever I'm making a change in the same file anyway, or as schedule permits. After a few months, I can remove the wrapper, and the change has been gradual and robust.

Put another way, wrappers really only make sense when you already know all the APIs you need to wrap. Good examples are if your application currently needs to support many different database drivers, operating systems, or PHP versions.

share|improve this answer
    
"...wrappers really only make sense when you already know all the APIs you need to wrap." This would be true if I were matching the API in the wrapper; perhaps I should be using the term "encapsulation" more strongly than wrapper. I would be abstracting these API calls to "log this text somehow" rather than "call foo::log() with this parameter". –  lotsoffreetime Sep 11 '11 at 8:34
    
"Without knowing what super-great new features this alleged future improved logger will have, how would you write the wrapper?" @kevin-cline below mentions a future logger with better performance, rather than a newer feature. In this case, no new API to wrap, just a different factory method. –  lotsoffreetime Sep 11 '11 at 8:35

I think that wrapping third-party libraries today in case something better comes along tomorrow is a very wasteful violation of YAGNI. If you are repeatedly calling third-party code in a manner peculiar to your application, you will (should) refactor those calls into a wrapping class to eliminate the repetition. Otherwise you are fully using the library API and any wrapper would look just like the library itself.

Now suppose a new library appears with superior performance or whatever. In the first case, you just rewrite the wrapper for the new API. No problem.

In the second case, you create a wrapper adapting the old interface to drive the new library. A little more work, but no problem, and no more work than you would have done if you had written the wrapper earlier.

share|improve this answer
    
"...adapting the old interface..." reminds me that when using APIs I should be trying to code to the interface anyway and abstract out instantiation methods to a factory. I don't think YAGNI applies when "it" is "good design". –  lotsoffreetime Sep 11 '11 at 8:49
1  
I don't think that YAGNI necessarily applies in this situation. It isn't about building in functionality in case you may need it in the future. It is about building flexibility into the architecture. If that flexibility is unnecessary, then, yes, YAGNI applies. However, that determination tends to be made sometime in the future when making the change will likely be painful. –  George Marian Sep 11 '11 at 9:29
1  
@George Marian: the problem is 95% of the time, you will never need the flexibility to change. If you need to switch to a future new library that has superior performance, then it should be fairly trivial to search/replace calls or write a wrapper when you need it. On the other hand, if your new library comes with different functionalities, the wrapper now becomes a hindrance since now you have two problems: porting old code to exploit the new features and maintaining the wrapper. –  Lie Ryan Sep 11 '11 at 10:09
    
@lotsoffreetime: The purpose of "good design" is to minimize the total cost of the application over it's life. Adding layers of indirection for imagined future changes is very expensive insurance. I have never seen anyone realize any savings from that approach. It just creates trivial work for programmers whose time would be much better spent on customer-specific requirements. Most of the time, if you are writing code that is not specific to your customer, you are wasting time and money. –  kevin cline Sep 11 '11 at 14:14
    
@George: if these changes are painful, I think that is a process smell. In Java, I would create new classes with the same names as the old classes, but in a different package, change all occurrences of the old package name, and rerun the automated tests. –  kevin cline Sep 11 '11 at 17:08

The basic reason to write a wrapper around a third-party library is so that you can change that third-party library without changing the code that uses it. You can't avoid coupling to something, so the argument goes that it is better to couple to an API you've written.

Whether this is worth the effort is a different story. That debate will likely continue for a long time.

For small projects, where the likelihood that such a change will be necessary is low, it is probably unnecessary effort. For larger projects, that flexibility may very well outweigh the extra effort to wrap the library. However, it is difficult to know whether that is the case beforehand.

Another way to look at it is that basic principle of abstracting what is likely to change. So, if the third-party library is well established and unlikely to be changed, it may be fine not to wrap it. However, if the third-party library is relatively new there is a greater chance that it will need to be replaced. That said, development of established libraries has been abandoned plenty of times. So, this is not an easy question to answer.

share|improve this answer
    
In the case of unit testing where being able to inject a mock of the API serves to minimise the unit under test, "change potential" isn't a factor. Having said that, this is still my favourite answer as it is closest to how I think. What would Uncle Bob say? :) –  lotsoffreetime Sep 11 '11 at 11:26
    
Also, small projects (no team, basic spec, etc) have their own rules in which you can violate good practice such as this and get away with it, to a degree. But that's a different question... –  lotsoffreetime Sep 11 '11 at 11:27

In addition to what @Oded already said, I'd just like to add this answer for the special purpose of logging.


I always have an interface for logging but I never had to substitute a log4foo framework yet.

It takes only half an hour to provide the interface and write the wrapper, so I guess you don't waste too much time if it turns out to be unecessary.

It's a special case of YAGNI. Although I don't need it it doesn't take much time and I feel safer with it. If the day of exchanging the logger really comes, I'll be glad I invested half an hour because it'll save me more than a day exchanging calls in a real world project. And I've never written or seen a unit test for logging (apart from tests for the logger implementation itself), so expect defects without the wrapper.

share|improve this answer
    
I don't expect to change log4foo, but it's widely known and serves as an example. It is also interesting how the two answers so far are complementary - "don't always wrap"; "wrap just in case". –  lotsoffreetime Sep 10 '11 at 21:34
    
@Falcon: do you wrap everything? ORM, log interface, core language classes? After all, one never can tell when a better HashMap may be needed. –  kevin cline Sep 12 '11 at 23:50

I'm dealing with this exact issue on a project I'm currently working on. But in my case the library is for graphics and thus I am able to restrict it's use to a small number of classes that deal with graphics, versus sprinkling it throughout the entire project. Thus it's pretty easy to switch APIs later if I need to; in the case of a logger the matter becomes a lot more complicated.

Thus I would say the decision has a lot to do with what exactly the 3rd-party library is doing and how much pain would be associated with changing it. If changing all the API calls would be easy regardless then it's probably not worth doing. If however changing the library later would be really hard then I would probably wrap it now.


Beyond that, other answers have covered the main question very well so I just want to focus on that last addition, about dependency injection and mock objects. It depends of course on how exactly your logging framework works, but in most cases no that wouldn't require a wrapper (although it will probably benefit from one). Just make the API for your mock object exactly the same as the 3rd-party library and then you can easily swap in the mock object for testing.

The main factor here is whether or not the 3rd-party library is even implemented through dependency injection (or a service locator or some such loosely coupled pattern). If the library functions are accessed through a singleton or static methods or something then you will need to wrap that in an object that you can work with in dependency injection.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.