1

I'm developing an application where one of the main components of the app heavily relies on a third-party framework to work. The choice of framework is highly volatile and it is likely that business requirements will change in the foreseeable future, meaning that there's a good chance the framework I currently am using will be replaced with a similar but different framework.

What are some measures I can take to minimize the amount of code I have to change when I inevitably do switch frameworks in order to avoid tying myself into the framework? I want to try to leave as much code untouched and limit the amount of changes I have to make to the classes that interact with the framework, allowing for easy plug and play.

RodYt
  • 69
  • 5
  • 2
    Do you currently have a choice which framework to pick? Do you know which framework specificially might replace your current one? – Doc Brown May 25 '20 at 09:48
  • 5
    Is it really a framework that you depend on, or is it a library/service? If the former, you will inevitably incur high costs when switching, but for libraries/services you can protect yourself by inserting a wrapper or facade layer which isolates your application from the third-party component. – Hans-Martin Mosner May 25 '20 at 09:57
  • @Hans-MartinMosner The framework is an important part of the application. To use a car analogy, it would be the engine. Therefore, quite a lot of the functionality of the app depends on the framework. However, there is also a good portion of the codebase that will never interact with the framework. – RodYt May 25 '20 at 11:34
  • @DocBrown I currently don't have a choice on which framework to pick right now, but I do know that the 2 frameworks share more than a few similarities in terms of their design and how they operate. – RodYt May 26 '20 at 02:52
  • 1
    Actually, I think your question would heavily improve if you tell us what kind of framework you are talking of - an UI framework like Qt? A web application framework like Angular? An ORM like Entity Framework? A framework for developing embedded software? A game engine like Unity? Being more specific would allow to give you a more specific answer. – Doc Brown May 26 '20 at 03:16
  • 1
    @DocBrown The framework I'm currently using is a 3D rendering API. The framework I might switch to in the future will behave similarly as it is also a 3D simulation/rendering framework. However, it is more niche and designed specifically for my application's domain. The problem is that this other framework will have more external dependencies, some incompatibilities with my current app, and a lot of unpolished features. Therefore it would be difficult for me to use the framework right now, but might be a possibility in the future. – RodYt May 26 '20 at 03:39

3 Answers3

4

The best you can do is to minimize the dependency on the framework in question, and to isolate the interactions with the framework to a single component or layer. So basically following good design principles like separation of concerns, program-to-interfaces and low coupling.

It is tempting to try to create a layer which abstracts away the differences between the frameworks - but this can easily end up being a worse solution, since it will be a lot of work writing adapters and you will end up being coupled to the lowest-common-denominator between the frameworks in question, which is most likely worse than being coupled to a single framework.

Good design principles is basically to assume that any business requirement may change in the future. At the same time, you should not preemptively prepare the code for a particular future which might not necessarily occur.

JacquesB
  • 57,310
  • 21
  • 127
  • 176
  • 1
    Could you elaborate a little more on the disadvantages of an abstraction layer? I realize that a framework switch will result in major refactoring of classes that heavily interact with it. However, with classes that have less of a dependency on the framework (e.g. only making a couple of calls or setting some parameters), wouldn't it make more sense to wrap the framework inside an adapter-like class that delegates/forwards the request to the framework's classes? (My thought is that this would reduce the amount of direct interaction with the framework). – RodYt May 25 '20 at 11:42
  • 2
    @RodYt: If the abstraction layer just directly replicate the interface of the underlying framework, then the layer doesn't really buy you anything. You will have to change the same amount of code in ether case to adapt to a new framework, but now you have an additional layer which translate from the interface of the old framework to the interface of the new framework. So you end up with a useless layer of code just for historical reasons, and you can't take advantage of any improvements in the interface of the new framework compared to the old. – JacquesB May 25 '20 at 12:16
  • 1
    I see what you mean now. My logic is that by providing an extra layer of abstraction, I can swap out the framework and implementations (the part under the hood) and any class that interacts with the layer of abstraction would not know about the underlying framework, thus reducing the impact a change of frameworks might have – RodYt May 26 '20 at 03:44
  • @RodYt: I'm arguing the impact of the change is the same - you have the change the same amount of code. – JacquesB May 26 '20 at 07:31
4

Interacting with a dependency

I want to try to leave as much code untouched and limit the amount of changes I have to make to the classes that interact with the framework

"classes that interact with the framework" will always have to be changed, because they interact with the framework.

The goal to abstracting your code is to minimize the amount of code/classes that directly touch anything belonging to the dependency.


Framework vs library

What separates a library from a framework? There's no hard and fast definition here, but developers will mostly agree on calling one thing a library and another a framework. The difference lies in the degree to which your code depends on it.

A library is a dependency, but one whose interface can be reasonably easily abstracted, allowing you to create a barrier between your code and the library, which minimizes the "collateral damage" (as you call it) when you change libraries.

A framework, however, cannot be easily abstracted. It generally requires you to write a bunch of code to integrate the framework into your codebase (or vice versa - depends how you look at it).
Abstracting a framework is going to be a massive undertaking, I doubt you're going to succeed in fully abstracting it, and I have yet to encounter a framework which could be gracefully swapped out (assuming a sufficiently large codebase which removes a full rewrite as a feasible option).


Distinguishing a framework from a library

I said there isn't a hard and fast definition of the distinction between a library and a framework, but the rule of thumb I apply in deciding whether something is a framework or a library is:

  • Can it be abstracted?
  • Will the abstraction allow me to continue to use the full range of features? (i.e. am I not limiting myself to only the features that I figured out how to abstract?)
  • Can I abstract this without requiring knowledge of this dependency's internals?
  • Is writing the abstraction a worthwhile venture on a cost-benefit-analysis?

If you answer 'yes' to every question, then it's a library, otherwise it's a framework.

Some examples here:

  • I've stressed in past answers that Entity Framework is appropriately named and should not be treated as a library. Treating it like a library and trying to abstract it leads to several problems (listed in my answer) which require several solutions. While all of these problems can be solved, the combined effort to do so generally doesn't outweigh the benefit from implementing the abstraction.
  • The .NET Framework (or Core) is a framework. The benefit of using it specifically hinges on using the toolkit that it provides. If you write your code in a way to not depend on these .NET specific tools, then there's no point to even using the framework to begin with.
  • Though .NET tends to default to using NewtonSoft.Json for serialization, it's a library that can quite easily be swapped out for another serialization library.
  • jQuery is a Javascript framework. Can its functionalities be abstracted by wrapping them in methods of your own and chaining those instead? Sure, but then you're just rewriting jQuery one method at a time. Abstracting it would defeat the purpose of using it.
  • Logging libraries such as NLog and Log4Net are libraries, not frameworks. The interface is minimal and can easily be wrapped in a custom wrapper of your own.
  • A calculator engine such as NCalc can be abstracted easily as you simply have define a wrapper for the operations you're going to be using. This means it's a library, not a framework.

Direct answers

What are some measures I can take to minimize the amount of code I have to change [..]?

All code that interacts with a dependency will have to be changed. Therefore you must minimize the amount of code that interacts with a given dependency.

If some of this code could be rewritten using a custom wrapper/interface of your own, then do it. All code that you rewrite to using only your own logic/wrappers/interfaces will therefore be "safe" when the dependency changes.

Think of it like radioactive waste and its impact on your workforce: people who interact with it will get sick, but people who interact with those sick people (= they are one layer removed from the waste itself) don't get sick themselves, since the sick people themselves don't become radioactive.
The aim of the game is to have as few of your employees (classes) work with the radioactive material (dependency) itself, because that's how we minimize the amount of radiation sickness (breaking changes).

What are some measures I can take [..] when I inevitably do switch frameworks [..]?

The choice of framework is highly volatile and [..] there's a good chance the framework I currently am using will be replaced

Given the tendency for frameworks (as opposed to libraries) to tightly integrate themselves in your codebase, you really should be as eager/expectant to swap out frameworks willy nilly.

That's not to say it shouldn't ever happen, but starting off under the assumption that you inevitably will change frameworks implies that you already knew beforehand that the framework isn't right for you and therefore shouldn't have been used from the get go.

What are some measures I can take [..] in order to avoid tying myself into the framework?

I want to [allow] for easy plug and play

By definition of a framework as opposed to a library (as supplied by me just now), the measures required for abstracting a framework are either incomplete, flawed, causing a cascade of other problems, or take up more effort than the problem they're trying to solve - in all cases rendering these measures moot (or even more harmful).

If your framework in question is indeed a framework and not a library (as per the above definition I supplied), then you're going to have to shift your expectations in how often you should jump from one framework to another, or how gracefully you could jump from one to the other.

Flater
  • 44,596
  • 8
  • 88
  • 122
2

You could try to abstract everything right now, but that isn’t useful if you don’t know yet what the next framework will be. If you use similar calls to access the framework, you can think about putting duplicate code into one method, just to reduce the lines of code you’ll have to change, but it’s too early to do any abstractions yet.

When the time comes, one developer can start a new branch to switch frameworks, with orders to everyone not to touch code using the old framework. That may mean changing priorities of tasks. When that person is fine, you have a huge code review and frameworks are changed.

gnasher729
  • 42,090
  • 4
  • 59
  • 119
  • I like the idea of isolating changes in one branch. In this case, I do know which framework I might switch to and this framework shares some similarities with my current one in terms of design and structure. – RodYt May 26 '20 at 03:47