On Writing Wrapper Libraries

A wrapper library is a thin layer of abstraction around an existing library, dependency, or functionality. A wrapper library offers a better and cleaner interface or rather hides the dependency or library. Writing a wrapper library can be a hard decision since it requires more work and expands the project scope. On the other hand, it has long-term benefits like better validation, good default parameters, and the ability to replace existing wrapped artifacts. I’d like to discuss some of the aspects of writing a wrapper library in this post.

At its core, a wrapper library is a bet: you trade a bit of upfront cost for future flexibility and control.
Sometimes that bet pays off massively; other times it becomes yet another layer you have to maintain. The real challenge is knowing when a wrapper solves a problem and when it simply adds another one.

Writing Wrapper Libraries

When to Write

Nowadays most of the projects depend on open source projects a lot. One can’t just write wrapper libraries around all 3rd party libraries and dependencies. At the end of the day, writing and maintaining wrapper libraries has its costs and can be a technical debt in the future. A wrapper should solve a real problem, not just satisfy an aesthetic preference for “cleaner code.” Thus, we have to make a call when to write them. I believe the following scenarios justify writing wrapper libraries.

  • When you only use a small subset of the third-party library, you may want to hide the third-party library. You can then prevent exposing a huge API to your own codebase. This helps your team focus on what you actually need instead of wading through an overwhelming surface area.
  • When you expect the third-party library to change a lot, you may want to expose your own interface. It’s easier to adapt to changes in one place rather than many codebases. A wrapper turns a moving target into a fixed point of contact.
  • When you expect to change the underlying technology altogether, you may want to encapsulate details of the dependent technology. If the future is uncertain, a wrapper gives you an escape hatch.
  • When you need additional functionality or validation around the existing dependency, you may want to handle these improvements in the wrapper. This keeps your business logic clean and reduces duplication across services.
  • When you cope with a poor or complicated interface, you may want to get around it by having a layer of abstraction. You can then avoid binding this poor/complicated dependency to your project. You’re shielding the rest of your codebase from its quirks.
  • When you have an incompatibility between the library and your codebase, you may want to deal with the compatibility issues in the wrapper. This isolates the awkward “glue code” where it belongs, instead of scattering it everywhere.

When Not to Write

The economy of writing wrapper libraries depends on one shop to another. If you are working in a big shop, it might be easy to decide since you have more people to benefit from the wrapper. However, if you are working in a small shop, writing a wrapper library can be an immense waste of time. So, writing wrapper libraries can be largely about the environment. Nevertheless, I believe one shouldn’t write wrapper libraries for the following scenarios.

  • When your dependent library is battle proof and exposing a consistent interface that rarely changes, you shouldn’t need a wrapper. Adding an extra layer here gives you no leverage. It only increases the maintenance surface.
  • When you depend on a library as one of your core components, you should reflect on future changes rather than dealing with the wrapper. If the library is your system, wrapping it often does more harm than good.
  • When your project is small enough that writing a wrapper can’t be justified at all. In this case, you should avoid the wrapper. Perhaps, you can apply the façade pattern. Sometimes simplicity wins: a direct import and a few helper functions are all you really need.

In short, not every dependency deserves a layer on top of it. A wrapper should reduce complexity, not manufacture new forms of it.

Additional Advantages of Wrapper Library

The need for a wrapper already demonstrates its advantages. A wrapper library can give further positive leverage to the project. I’d like to visit some of these extra advantages of wrapper libraries.

  • Defining the interface of the wrapper can be independent of the wrapped dependency. This gives you the freedom to design an API that fits your use case, not the constraints of the underlying library.
  • Testing can become much easier i.e. mocking your own wrapper vs. third-party library. A smaller, cleaner surface area usually leads to cleaner tests and fewer brittle mocks.
  • Requesting additional functionality from the wrapper author becomes an option. If the wrapper is shared across teams, it becomes a natural place to collect improvements that benefit everyone.

In many cases, a wrapper becomes the “gateway” to how your organization uses a dependency and that consistency pays off long after the initial work is done.

A Practical Example

I’d like to briefly touch on a practical example where you want to provide a company-wide key/value store infrastructure. There are many technologies to choose like Memcached, Redis, MongoDB, or simply MySQL. We don’t want to tie the company to any of the technologies but we also need a solution. In this case, we can simply have an interface for a key/value store as simple as the following.

This is a common situation in larger engineering organizations: different teams experiment with different tools, but eventually someone has to unify the chaos. A wrapper gives you one stable door to walk through, regardless of what sits behind it.

package com.yusufaytas.database;
/**
 * A simple interface for key/value database
 */
public interface KeyValueDatabase
{
    /**
     * Returns payload associated with the key
     *
     * @param key
     * @return payload
     */
    String get(String key);

    /**
     * Stores the payload with the associated key
     *
     * @param key
     * @param payload
     */
    void put(String key, String payload);
}

This example is nothing more than a simple interface. You can potentially apply the inversion of control pattern to attach different implementations of the key/value store. In the actual implementations, you can handle the connection to the different technologies. Moreover, you can apply various different configurations options that are relevant to your shop e.g. performance optimizations. The consumer of the wrapper library doesn’t need to know anything about the technology stack. The consumer can also easily mock the above interface for testing purposes. The interface can be further improved like adding multi put operations. All in all, the wrapper gives huge flexibility.

The real value shows up months later, when a new storage technology appears or an existing one becomes too expensive or unreliable. Instead of rewriting every call site across dozens of services, you just swap the implementation behind the wrapper. That’s the payoff: freedom to evolve without breaking your entire codebase.

In Consequence

I’ve tried to explain when it’s appropriate to write a wrapper library around a dependency or technology. I’ve then briefly discussed additional advantages of having a wrapper library as well as a simple practical example. Before rushing into writing one, I highly suggest holding a meeting to discuss the pros and cons.

A wrapper can save you months of pain or create months of unnecessary maintenance depending on why you build it. The point is not to wrap everything; the point is to wrap with intention. If the abstraction simplifies your world, protects you from churn, or gives your team a cleaner way to work, it’s usually worth it. If not, it’s probably just another layer you’ll need to carry.

As with most engineering choices, clarity beats cleverness. Know the cost, know the benefit, and make the decision with your future self in mind.

Stay updated

Receive insights on tech, leadership, and growth.

Subscribe if you want to read posts like this

No spam. One email a month.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.