DEV Community

Cover image for Using the Adapter pattern to migrate to a new library
Rogelio Gámez
Rogelio Gámez

Posted on

Using the Adapter pattern to migrate to a new library

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

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]

Adapter pattern from refactoring.guru
Adapter pattern image from refactoring.guru

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

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

  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

  3. We now implement SystemTextJsonAdapter.
    3 Implement adapter for new library

  4. Finally, we inject SystemTextJsonAdapter instead of NewtonsoftJsonAdapter. Optional: we can use a feature toggle to swap between easily.
    4 Inject new library

References

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

Further reading

Top comments (0)