Framework or Library
When speaking about dependencies, both terms can be used, sometimes in a (dangerous) interchangeable way. Is React a framework or a library? What about Bootstrap, or Lodash? Both are “packages” after all, right?
Sure thing, but they definitely not have the same impact on your app.
A library (“bibliothèque” in french, but most french people say “librairie” which actually means “bookstore” in french, but matches the english pronunciation of “library”) is a set of functions for general purposes (like underscore.js) or specialized ones (like moment.js).
You call library functions whenever you need them, like you pick tools in a toolbox. They do not require any changes in your software design.
As a dependency, however, they require you to call their proprietary API, thus “locking” your code with them (or even possibly a version of them), so that a library call should rather look like this:
Such locking will increase with the number of calls you’re issuing: the more you call the library, the more your code is being dependent to it (or to a version of it):
Single point of dependency
To limit such a dependency however, you can hide it behind a wrapper:
Such a wrapper can actually serve more than one purpose. Aside reducing locking to a single point in your code base, it allows you to expose your own api to callers. Such an adaptation of the library will only feature the API that make sense for your app, as well as I/O types that are specific not your app, not to the library.
However, implementation speaking, step by step, your code is still dependent to the library’s.
Hopefully, as the late David J. Wheeler used to say:
All problems in computer science can be solved by another level of indirection.
Indeed, you can avoid such dependency by adding an interface:
- callers will depend on that API declaration ;
- the adapter will have to implement it (note that this would also ease mocking libraries when testing).
But your app code can now compile without the library. You are now able to replace/upgrade the library without changing caller’s code. All you may have to do is to replace the adapter’s implementation.
Frameworks (“quadriciels” in official french, but everybody says “framework”) are different, as they provide a different type of service: they offer to manage things for you, instead of letting you devise what to do.
Handing over control
To do so, they implement the backbone (the “frame”) of an application, and let you fill the blanks. But those blanks are left in defined places and have defined shapes.
That means that:
- the app starts with the framework: you have to hand over the steering wheel.
- since the framework drives the app, you’re not the one making calls anymore: instead, you will be called back by the framework when appropriate.
This is the principle of Inversion of Control (IoC) or, more trivially, the “Hollywood principle”.
Of course nothing prevents you to manually call some code of your own, a third-party library or even some framework API, but at your own risks. This may or may not work as you expect. Frameworks have rules that you are supposed to follow and, should you break them, the framework could not be accounted responsible for any failure.
Typically a framework will allow you to write components that will fit into their containers through the implementation of a contract:
The container will then be able to handle your code as a framework-compatible software piece whose life cycle can be managed, and will call you back at times that are relevant to perform some kind of operation or another.
As you can see, this is a much more structural choice that libraries for your application design: all your components become specific to that framework. The won’t be portable (i.e. not understood by another framework) nor interoperable (i.e. an Angular component will hardly interact with a React component).
One may argue, however, that the adapter pattern could be used to limit framework dependency, just like we did to limit the dependency on libraries:
This may look as useful… if the dependency direction was the same. But it is not: libraries adapters used to take a shape required by the app, whereas here component adapters can only take the shape of what the framework expects. As a result, the supposedly “free” app component can only mimic the initial contract (lifecycle, semantic, granularity).
Inside frameworks, components adapters would be unnecessary layering then.
Libraries can also comply with frameworks. Instead of providing an API, they provide components implementations for a given framework.
As frameworks bacome popular, a number of framework libraries became available. Most of them are about widgets, though: for instance the Material Design components have been ported from Android to Web Components, Angular, React, Vue and even iOS frameworks.
Anybody can imagine the tremendous cost of porting the same library (and its subsequent versions) on each of those frameworks.
IBM has devised a solution about this: instead of porting they Carbon Design System on each of the past, current and future hyped frameworks, they invested in a port on the standard Web Component framework, which can be used in any context.
So, not only this allows to use their components from frameworks:
But the same components can also be used from a plain app:
Frameworks and libraries are very different third-party options:
- frameworks provide you application blueprints with built-in services but enforces predefined contracts to call your code. As such, they imply a strong dependency.
- libraries won’t help you design your application, but can be called only when you need them. You can devise a design that limits dependency to them.
They are not mutually exclusive, but it is recommended that libraries called from frameworks are framework-compatible.