views:

495

answers:

15

A discussion I had with a colleague today.

He claims whenever you use a 3rd party library, you should always write for it a wrapper. So you can always change things later and accomodate things for your specific use.

I disagree with the word always, the discussion arose regarding log4j and I claimed that log4j has well tested and time proven API and implementation, and everything thinkable can be configured a posteriori and there is nothing you should wrap. Even if you wanted to wrap there are proven wrappers like commons-logging and log5j.

Another example that we touched in our discussion is Hibernate. I claimed that it has a very big API to be wrapped. Furthermore it has a layered API which lets you tweak its inside if you so need. My friend claimed that he still believes it should be wrapped but he didn't do it because of the size of the API (this co-worker is much veteran than me in our current project).

I claimed this, and that wrapping should be done in specific cases:

  • you are not sure how the library will fit your needs
  • you will only use a small portion of a libary (in which case you may only expose a part of its API).
  • you are not sure of the quality of the library's API or implementation.

I also maintained that sometimes you can wrap your code instead of the library. For example, puting your database related code in a DAO layer, instead of preemptively wrapping all of hibernate.

Well, in the end this is not really a question, but your insights, experiences and opinions are highly appreciated.

+1  A: 

The main factor for deciding to wrap a library or not is the impact a library change will have on the code. When a library is only called from 1 class the impact of changing library will be minimal. If on the other side a library is called in all classes a wrapper is much more likely.

stimpie
this is an argument for wrapping log4j, which is usually called from any class that does anything remotely complex.
flybywire
+3  A: 
  1. Any uncertainty around the choice of 3rd party library should be flushed out at the beginning of the project using prototypes to test the scalability/suitability/whatever of the 3rd party library.

  2. If you decide to go ahead and provide full de-coupling/abstraction support it should be costed up and ultimately approved by the project sponsor - ultimately it's a commercial decision as someone has to pay for it and the work required to do it (unless it's absolutely trivial, in which case the api is probably low risk anyway).

  3. Generally an experienced architect will chose a technology that they can be reasonably confident with, and have experience of, and that they are confident will last the lifetime of the app, OR else they will eliminate any risk in the decision early on in the project, thus removing any need to do this, most of the time

Joel
+2  A: 

I'd tend to agree with most of your points. Using absolutes often gets you into trouble and saying you should "always" do something limits your flexibility. I'd add some more points to your list.

When you use wrapping code around a very common API, like Hibernate or log4j you make it more difficult to bring on new developers. New developers now have to learn a whole new API, where if you hadn't wrapped the code they would have been very familiar right away.

On the flip side of that, you also limit your developers' view into the API. Using an advanced feature of the API takes more time because you have to make sure that your wrapper is implemented in a way that can handle it.

Many of the wrapping layers I've seen also are very specific to the underlying implementation. So, if you write a log wrapper around log4j, you are thinking in log4j terms. If some new cool framework comes out, it may change the whole paradigm, so your wrapping code doesn't migrate as well as you had thought.

I'm definitely not saying wrapping code is always bad, but as you stated, there are a lot of factors you have to consider.

Shaun
+3  A: 

Well, the obvious benefit is for switching technologies. If you have a library that becomes deprecated, and you want to switch, you may end up rewriting a lot of code to accommodate the change, whereas if it were wrapped, you'd have an easier time writing a new wrapper for the new lib, than changing all your code.

On the other hand, it would mean that you have to write a wrapper for every trivial library that you include, which is probably an unacceptable amount of overhead.

My industry is all about speed, so the only time I'd be able to justify writing a wrapper is if it was around some critical library that was likely to change dramatically on a regular basis. Or, more commonly, if I need to take a new library and shoehorn it into old code, which is an unfortunate reality.

It's definitely not an "always" situation. It's something that may be desirable. But the time isn't always going to be there, and, in the end, if writing a wrapper takes hours and the long term code library changes are going to be few, and trivial...Why bother?

Satanicpuppy
Nice even-handed look at both sides.
BryanD
+1  A: 

You should do it always, often, sometimes, rarely, or never. Not even your colleague does it always, but the instructive cases are always and never. Suppose that it is sometimes necessary. If you never wrapped a library, the worst consequence is that one day you discovered that it was necessary for a library that you had used all over the place. It would take you some time to wrap that library and to perform shotgun surgery on the clients. The question is whether that eventuality would take more time than habitually providing wrappers that are rarely necessary, but having never to perform the shotgun surgery.

My instinct is to appeal to the YAGNI (you ain't gonna need it) principle and opt for "rarely".

Ewan Todd
+28  A: 

It's a perfect example for YAGNI:

  • it is more work
  • it inflates your project
  • it may complicate your design
  • it has no immediate benefit
  • the scenarion you write it for may never manifest
  • when it does, your wrapper most likely needs to be re-written completely because it is tied too closely to the concrete library you were using and the new one's API simply doesn't match yours.
Michael Borgwardt
+1 This is absolutely the best reason. Why would you design, implement, and then maintain code on the off-chance it might happen? Wasted time and effort.
wheaties
+100 on your last bullet point
ChssPly76
Rewriting a wrapper completely is a *lot* less work than rewriting your application completely. Still, I agree with the YAGNI principle, and would hold off on writing a wrapper until the first time you *do* need it.
Bill the Lizard
If you rewrite the wrapper completely, you also have to change all the code using it - almost the same amount of work as introducing a new abstraction layer.
Michael Borgwardt
@Michael: No, the point of using a wrapper is that you keep the same API and the code using it doesn't have to change at all. The wrapper should only change internally.
Bill the Lizard
also refactoring is easy when the time really comes. we are not living in 1990's any more, get a good IDE.
irreputable
Yeah, that's the theory. The problem is, as I wrote, that the wrapper's API probably doesn't match the way the new library works - so you have to change the API as well.
Michael Borgwardt
If it's a complete mismatch then write an adapter. You're trying to reduce the wrapper problem to two options: write bad code or write no code. The third option is to write good code in the first place.
Bill the Lizard
+1 for the reasons. They are quite self explained never do this.
Nope, I'm saying that writing good code when you don't know the requirements (i.e. the purely hypothetical other library's API) is a matter of luck as much as skill. If you have bad luck, the mismatch can make writing a client-transparent adapter impossible, or just very inefficient.
Michael Borgwardt
accepted answer, by popular vote
flybywire
+1  A: 

Wrapping a whole library is boilerplate, ineffective, and wrong in most cases. It can be done in a much clever way. I'd say that wrapping a library is appropriate mostly in case of UI component libraries, and again, you have to be adding some additional core functionality of yours to all the components for this to be needed.

  • if too much modifications and additions are needed, this is most likely not the library you are looking for
  • if there is a moderate amount of additions and modifications - there are always the design patterns that come handy in those cases. The Decorator pattern (allows new/additional behaviour to be added to an existing object dynamically) , for example, is rather suitable for the most cases.
  • IDE search/replace and refactoring capabilities offer an easy way to change your code in all required places if some important change is needed and a wrapping object appears. (of course, unit-tests would be helpful here ;) )
Bozho
I mostly agree. But even when it is easy to do massive edits with IDEs (even if they are 100% accurate when you use a strongly typed language like java), they are very painful and they pollute you source control and make it difficult to later understand code changes that span your "mass refactoring".
flybywire
yeah, but if that's done quite rarely and if in cases when it's an absolute must, the problem isn't that big.
Bozho
+4  A: 

The problem here is partially the word 'wrapper', partially a false dichotomy, and partially a false distinction between the JDK and everything else.

The word 'wrapper'

Wrapping all of Hibernate, as you say, is a completely impractical enterprise.

Restricting the Hibernate dependencies to an identified, controlled, set of source files, on the other hand, may well be practical and achieve the same results.

The false dichotomy

The false dichotomy is the failure to recognize a third option: standards. If you use, say, JPA annotations, you can swap Hibernate for other things. If you are writing a web service and use JAX-WS annotations and JAX-B, you can swap between the JDK, CXF, Glassfish, or whatever.

The false distinction

Sure, the JDK changes slowly and is unlikely to die. But major open source packages also change slowly and are unlikely to die. Untold thousands of developers and projects use Hibernate. There's really no more risk of Hibernate disappearing or making radical incompatible API changes than there is of Java itself.

bmargulies
+1  A: 

The purpose of wrapping even a well-tested and time-proven 3rd-party library is that you might decide to switch libraries at some point in the future. Wrapping it makes it easier to switch without changing any code in your core application. Only the wrapper needs to change.

If you're absolutely sure that you'll never (another absolute) use a different logging framework in your project, go ahead and skip the wrapper. Even having said that, I'd probably hold off on writing the wrapper until I knew I needed it, like the first time I need to switch.

Bill the Lizard
+3  A: 

If the library you are planning to wrap is unique in its "access principles, metaphors and idioms" from other offerings in the same domain, then your wrapper is pretty much going to be similar to that library and won't do you any good if you one day switch to a different library since you will need a new wrapper.

If the library is accessed in a similar way to other libraries and the same wrapper can apply to these libraries, then they are probably written based on some existing standard and there is some common layer that already exists to access both of them.

I would only go with wrappers if I knew for sure that I would have to support multiple and substantially different libraries in production.

Uri
+1 for the expression "access principles, metaphors and idioms"
flybywire
+2  A: 

This is kind of a funny question.

I've worked in systems where we've found showstopper bugs in libraries we were using, and which upstream was either no longer maintaining, or not interested in fixing. In a language like Java, you usually can't fix internal bugs from a wrapper. (Fortunately, if they're open-source, you can at least fix them yourself.) So it's no help here.

But I'm often working in a language where you can easily modify libraries at any time, without seeing or even having their source code -- I commonly add new methods to existing classes, for example. So in this case, there's no point in wrapping: just make the change you want.

Also, does your colleague draw the line at things called "libraries"? What about Java itself? Does he wrap built-in classes? Does he wrap the filesystem? The thread scheduler? The kernel? (That is, with his own wrappers -- in a sense, everything is a wrapper around the CPU, but it sounds like he's talking about wrappers in your source repo that are completely under your control.) I've had built-in functionality change or disappear when new versions of it appear. Java is not immune from this.

So the idea to always write a wrapper comes down to a bet. Assuming he's only wrapping third-party libraries, he seems to be implicitly betting that:

  • "first-party" functionality (like Java itself, the kernel, etc.) will never change
  • when "third-party" functionality changes, it will always be done in a way that can be fixed in a wrapper

Is that true in your case? I don't know. Of the medium-large Java projects I've done, it's rarely true for me. I wouldn't spend effort wrapping all third-party libraries, because it seems like a poor bet, but your situation is certainly different from mine.

Ken
+1  A: 

I would not wrap it as a one to one thing, but I would layer the app so that each part it replaceable as much as possible. The ISO OSI model works well for all types of software :-)

TofuBeer
+1  A: 

There is one situation where you with good reason can wrap. Namely if you need to test stuff, and the default third party object is heavy weight. Then having an interface can really make a difference.

Note, this is not to replace the library ,but make it manageable where it doesn't matter much.

Thorbjørn Ravn Andersen
+1  A: 

No. Java architects/wanna-bees are too busy designing against imaginary changes.

With modern IDE, it's a piece of cake when you do need change. Until then, keep it simple.

irreputable
+1 for "too busy designing against imaginary changes"
flybywire
+1  A: 

I agree with everything that's been said pretty much.

The only time wrapping third party code is useful (bar violating YAGNI) is for unit testing.

Mocking statics and so forth requires you to wrap the code, this is a valid reason to write wrappers for third party code.

In the case of logging code, its not needed though.

Finglas