Using the Adapter pattern to migrate to a new library
Tags: programming, tutorial, designpatterns, beginners
Published: 2023-10-08 20:01:56

## Problem statement: migrating to a new library

For one reason or another, library A has been deprecated and you are tasked to migrate to library B. 

The problem is that library A is spread all around your production and test codebases with direct calls to its classes without any interface in between. This poses the following challenges:
- Since library A is used directly in code, it is called an implicit dependency, which obfuscates how it is being used making it harder to migrate.
- If library A is used 100 times, and you happen to misuse its equivalent in library B, then you would need to go back and change all of them. 
- What if two years from now you now need to migrate to library C? 
- You may also want to swap between A and B using a feature toggle which becomes a hassle if library A is used 100 times. You can read more about feature toggles here: [Don't break production when you add new features! - Feature Toggles in C# @ dev.to](https://dev.to/rogeliogamez92/dont-break-production-when-you-add-new-features-feature-toggles-in-c-50p9)

Surely there is a better way to attack this problem.

## Solution: implement the adapter pattern before migrating 

### The adapter pattern

**Adapter** is a structural design pattern that allows objects with different interfaces to collaborate. An adapter is a special object that converts the interface of one object so that another object can understand it. [[1]](https://refactoring.guru/design-patterns/adapter)

![Adapter pattern from refactoring.guru](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ebssomclayv66spyp84e.png)
*Adapter pattern image from [refactoring.guru](https://refactoring.guru/design-patterns/adapter)*

Using the adapter pattern can help in our task by:
- Since we will be refactoring to dependency injection we are making the dependency on the library explicit, making it easier to understand where it is being used.
- We can swap between both libraries easily in our composition root. 
- If we happen to add a bug while implementing the new library, we can just fix the adapter implementation instead of the hundred implicit calls in the codebase. 
- If you need to migrate again to a new library, we can just implement the adapter for it. We only need to refactor to an adapter once!

### Migrating to a new library

We will follow 4 straight forward steps:
1. Implement the adapter pattern for the existing library.
2. Change all dependencies of the existing library to the created adapter interface using dependency injection.
3. Implement the same adapter interface for the new library.
4. Inject the new library instead of the old library.

## Example: from Newtonsoft.Json to System.Text.Json

*Disclaimer: this is a purely informative/basic example. You are probably dealing with more complex situations.*

You are currently using `NewtonSoft.Json` in your codebase and you want to migrate to `System.Text.Json`. You also want to avoid the already discussed problems, so you decide to implement an adapter first.

![Step 0. Before refactoring](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7oha8efkg8nbjpl15twz.png)

Following the steps above we do the following:
1. Create an adapter interface called `IJsonAdapter` in which we declare common methods such as `Serialize` and `Deserialize`. We then create `NewtonsoftJsonAdapter` where we implement the `IJsonAdapter` interface.
![1 Implement adapter](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9owprclayunmmlq0osbh.png)

2. In our codebase we then inject the `IJsonAdapter` interface and use that instead of `NewtonSoft.Json`.
![2 Use the adapter interface in the codebase](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cbhrz0gwvry9lxr8z10w.png)

3. We now implement `SystemTextJsonAdapter`.
![3 Implement adapter for new library](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vzjjce4eo7enuclhgplh.png)

4. Finally, we inject `SystemTextJsonAdapter` instead of `NewtonsoftJsonAdapter`. Optional: we can use a feature toggle to swap between easily.
![4 Inject new library](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/25ka1i0y8gfq07hnwhk4.png)

## References

[1] Adapter. Refactoring.Guru. (n.d.). https://refactoring.guru/design-patterns/adapter 

## Further reading

- [Anti-corruption Layer pattern - Microsoft Learn](https://learn.microsoft.com/en-us/azure/architecture/patterns/anti-corruption-layer)

- [Wrapping third party library is best practice - StackExchange](https://softwareengineering.stackexchange.com/questions/298145/wrapping-third-party-library-is-best-practice)