3

My project relies on a specialized component which is stuck (by its configuration) to an older version of the framework my project is using. This makes updating to the latest version of the framework impossible.

What are the best practices when dealing with this type of issue?

  • 1
    This question is very broad, but I think it can be answered general manner. However, I am not sure if such an answer will really help you with your specific issue. If you really want useful help, give some details: what kind of framework, what kind of dependency. – Doc Brown Jan 21 at 9:45
5

Because of reasons like this, dependencies are not just an asset but also a kind of liability: today's rapid development is tomorrows technical debt. Depending on the risks you forsee and want to mitigate, it can make sense to use a dependency only if

  • you insulate yourself from the dependency as far as possible, e.g. as described in candied_orange's answer.
  • you have a plan to either migrate away from the dependency, or can ensure timely fixes to the problems you encounter.
  • for proprietary dependencies you have contracts in place with clear support levels, for example that lay out how fast security issues will be fixed, and whether there will be any penalties if that support level is not met.
  • for open source dependencies you are prepared to fork the code and fix the bugs yourself, or have retained a consultant who can fix these bugs for you on short notice.
  • alternatively, you are prepared to shoulder remaining risk. This might be a sensible approach for well-supported problems with a sizeable community.

E.g. for most companies it does not make sense to maintain their own Linux kernel. On the other hand, that NPM package with only a few thousand downloads? Better fork it right now.

In general, it is a good idea to have your own copies of all open source dependencies that you rely on. It is also preferable to host any packages yourself. This not only gives you the ability to fix any problems, it also gives you more control over updates, and an opportunity to review and test updates.

To which degree that is sensible depends also on how the transitive dependencies are loaded. E.g. dynamically linked libraries that will be updated through your operating system (e.g. Debian) are a lot less problematic than a statically linked binary blob.

Here, your best bet is likely to fork the problematic dependency and perform the fix yourself. If source code is not available you may need to decompile or reverse engineer it. Note that this may not be legal if the dependency was provided to you under a proprietary license, so check that first.

If the dependency cannot be fixed by you, you might need to mitigate the security risk through another approach, e.g.:

  • temporarily disable your service in whole or in part.
  • detect and block or sanitize inputs that could trigger the security vulnerability.

Temporarily taking down your service can give you the time needed to figure out a more permanent solution, e.g. to extract the problematic dependency to a separate process or service so that it can be deployed independently of the framework.

Note that you may be required to take reasonable steps to ensure the security of the data you process if you are subject to various privacy regulations such as the GDPR. Temporarily shutting your service down until the vulnerability can be fixed may be a reasonable measure if you have no way to fix the problem immediately.

  • Thank you for your input! This makes complete and total sense. I will be passing this information along to my colleagues. – afontalv Jan 22 at 11:36
3

The critical thing to sort out is the nature of your dependency. Does the older version provide one thing that your project needs or many things? Does the newer version provide one thing or many things for your project?

It's very important to look at the framework through the lens of your projects needs. This keeps you from fixing problems that you don't need to care about.

If you can identify a few needs that your project has that are creating a dependency on some version of the framework you can externalize these dependencies as library calls. Remove direct knowledge of the framework from the inner parts of your app that depends on it. Satisfy those needs through calls to adapters that hide which version or even which framework is satisfying them.

Configure those adapters at the top of your call stack. This is usually in main. Here is where you decide what will satisfy what needs.

Doing that will reduce the amount of code that has any idea which version of the framework is being used. You would be free to use multiple versions for different parts, create adapters that give you the old features with the new version, or write your own solutions that reduce your reliance on the framework.

If that sounds like a lot of work that's only because it is. Frameworks love to make you dependent on them. Keeping them at arms length so that you remain in charge takes effort.

  • Specifically with frameworks, though, it is hard to keep them at arm's length. In fact, I would even take it as a characteristic of a framework that that is not easily possible. In particular, the defining characteristic of a framework is inversion of control, so the "top of the control stack" is the framework. Hence: choose your framework wisely! – Jörg W Mittag Jan 20 at 21:26
  • @JörgWMittag true but something's a framework provides aren't things that have to be provided in a framework way. So it's nice when you can get those things without letting the framework be in charge of everything. For example I've had great success making sure my POJOs don't know spring exists. Only thing that knows about spring is main. – candied_orange Jan 20 at 21:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.