-3

For instance, if we have a complex library with many functionalities, how can we make this lib a plugin such that it can be replaced with another lib more easily.

The answer obviously is the dependency inversion principle, but how would this be done.

If we try to create interfaces that have the same properties and methods as classes from this lib, as it has many functionalities, we would have to write a lot of code that would be a rewrite of interfaces that is already written in the lib.

1
  • 3
    Your question is too broad. This depends on the library, its semantics, functions, interfaces, its size, the programming language(s) involved, the languages ecosystem, the organizational environment (including users, developers and stakeholders), the operational environment and more specific requirements. One could write a book about this topic, but whole books don't fit into the answer box below. Commented Apr 25, 2022 at 5:47

1 Answer 1

2

In principle, you do it by writing an interface that serves the few needs specific to the application you are plugging into, instead of one that just repeats the many generic functionalities of the library. So, don't think of it as being the interface of the library; rather, it's a higher-level interface the application itself declares, for its own needs, in the format it wants. The plugin then needs to conform to this interface, and implement it in terms of library functions. Basically, the plugin is an application-specific wrapper around the library (an "adapter"), that translates back and forth between higher-level application requests, and lower-level library functions.

E.g. suppose it's a math/statistics library; instead of mirroring the many generic functions of a library (such as Mean(data), StdDeviation(data), ...), the interface would have methods that are more pertinent to the application's domain.

One of them might be something like

StatSummary CalculateCustomerRatingStats(List<Rating> ratings)

where StatSummary and Rating are types declared by the application.

So, the application is not calling individual library methods in order to "manually" calculate, collect and prepare information it needs in order to obtain customer rating statistics (that, perhaps, it needs to display), but is instead asking the plugin explicitly for the thing it needs, letting the plugin perform the fiddly, library-specific bits of the work, and produce the StatSummary. The methods of the interface explicitly embody what the application is actually trying to do. This is why it's an abstraction.
This interface is owned by the application, and you would package it together with the application (same DLL, JAR, ...), not with the library. That's the dependency inversion - the plugin (that represents/wraps the library) and is in one package, now implements, and thus depends on, this [interface + application] combo that is in a different package.

If you now decide to change the library, you don't have to change the interface; just implement these higher-level methods in terms of the new library functions.

That said, it may not be easy to come up with such an abstraction. E.g., there may be certain aspects to the problem that you can't truly ignore, that will then affect your design (e.g., if the library is calling remote services, you can't completely ignore the fact that it's not a local call). Or, the way the library in question is designed may go against you, and limit your ability to abstract it, etc. Or, the application you're making might also be comparatively generic in nature, and you can't come up with abstractions that are of a meaningfully higher level. So, in any particular case, you may end up weighing pros and cons to make a tradeoff - and decide either to abstract the library away, or to just call it directly.

Some applications have their own plugin systems, so if you wanted to plug into one of those, you'd have to familiarize yourself with the relevant documentation, and write a library wrapper that confirms to those requirements (or, if you're writing the library and you intend for it to only be used in that environment, you could just make the library itself compliant, no wrapper needed).

If the library is written by you, or if you have access to the source code, there's also the possibility of rewriting it (or parts of it) behind its public interface, so that it calls some other code of your choosing. This can be useful if you need to alter the implementation, but you haven't decoupled your application code from the library code. As long as you don't change the public API of the library, you can change its "guts" - e.g. to provide a more efficient implementation of a method, or to call into an entirely different library. Again, depending on the specific circumstances, your mileage may vary.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.