I think the dichotomy between frameworks and libraries appears from the observation that both concepts are good at what they do when they are designed with the opposite principle in mind, to which they are implemented themselves.
In programming, everything sits between two poles.
Pure and impure, centralized and distributed, limiting and freeing.
Without limits, there is no experience of freedom.
Keeping you in line on the highway will ensure your freedom to move on it.
Limits are not always limiting, and a lot of freedom can be confusing as heck.
As Clojure and C++ developers ;)
The same I observe around libraries and frameworks.
I used to think as the linked article describes it (and there is a lot of truth to it)
And I think I found a couple of other layers to it.
Libraries let you call them and frameworks call you.
Libraries are imported by you, and that means you are in charge.
Frameworks are the opposite:
They "import" you, and you do as they desire.
They are restrictive and style your code.
Frameworks dictate how you code - libraries deliver to you, what and when you need it.
The issue is, that libraries are the best, if they are as limited in scope as possible, and frameworks are best when they are the opposite.
I think that is, what confuses most people about it:
Frameworks introduce a certain coding style and dictate the way things are implemented.
But that doesn't mean, it has to be limiting.
The Node system in Godot allows you to compose your actions very freely, allowed by using composition over inheritance, and certain other decisions.
The implementation of this specific framework allows you to move freely despite that you have simply no other way, besides using it.
You are forced to freedom, basically.
It is limiting, but it is not.
That contradiction is probably, what causes many people to dislike frameworks at all.
They experience mostly bad ones.
A framework can be limiting on HOW you can do things, and this can still result in a lot of flexibility.
A library can offer a lot of things, but this might turn out bad if the consequences are not easy to foresee.
How often did you load a library, that behaved unpredictably, changed its behaviour from one update to the next, or was simply implemented badly?
If all libraries were that way, we would dislike them as well.
That is also where the saying "do one thing, and do it good" fits right in.
It is simply a guide to good library design.
So, when looking at frameworks and libraries, we have to differentiate between the respective way they interact with the rest of the code and the practical effect they bring to our code.
We should not mistake the way they are implemented, with the effect it has on us.
This sounds easy enough, although I think it's tempting to believe, that the face value is always mirroring the inside.
So, all that doesn't take away from the practical limitations, that were raised in the article (and other articles of its kind, see ¹ and ².
So far as I can see, the argument is always down to a 'badly implemented framework, that is not enabling a lot of freedom' and things like a framework simply not being the right choice for the task.
If frameworks are about *consciously* limiting freedom, to grant just that, then it's about the one thing that we can say computing (and life) is all about:
Finding the right tool for the task.
Doesnt sound very spectacular, but considering the vast majority of people to whom I talked about this today, did not even know there is a difference between frameworks and libraries and even less so, which one that is, I feel like it warrants a post.
Another case, where libraries make more sense than frameworks, is on the level of polyglot programming, so compatability with other languages.
Implementing a library for the JVM is exactly that:
Clojure can use it, Scala can use it, and Kotlin can use it.
Even if it's written in Java.
If a framework is implemented for a certain language, even though it might run on the same platform, or if you use a transpiler to said language, the port is practically mandatory.
This comes with an astonishing insight: There is always a framework. When you start a piece of code, and you import libraries, from the perspective of the libraries, you are the framework.
It's just that you are under the control of the code, and you pick the libraries that fit into your design.
The whole process of fitting into an existing structure is so fluid, that you don't even notice the concept of a framework being in place.
Even a programming language has an inherent framework in place:
The coding architecture of any language is its framework - and every other concept that some user of said language wants to implement itself has to fit into it.
And now, you see how smart languages give you freedom and simultaneously provide enough guidance to avoid writing yourself into a corner.
It is limiting, and thus that provides freedom.
It provides freedom, by constraining itself.
A syntax is a set of constraints.
All semantics is.
It is always the same principle, and frameworks/libraries are simply that principle, reflected on the API level.
I also wondered, why bad frameworks are so widespread, so why they are used, when they are not appropriate.
I assume that business application developers prefer the concept of frameworks because this allows you to provide extensibility to the user, without having to open the source code, or leaving yourself open to vulnerabilities.
A typical use case for polymorphism.
They can join in, and you are in control.
Sounds like something the average ~~Joe~~ CEO would want?
The average ~~Joe~~ programmer would then go on and create their open source web framework - with the very same principles in mind.
It’s like houses vs furniture. Houses don’t compose, shape what you put where in your house, but that doesn’t make them evil.
A framework is less flexible than a set of libraries, but also less hassle to use, if you want to build something that it’s made for.
A framework that’s flexible enough to build a wide palette of things can be quite useful.