> perhaps all of them (every single one) have not actually experienced writing an application without a framework
I actually have written software without a framework, so by this standard I feel qualified to comment.
Not all software has an implied framework within it. Most Unix command-line utilities do not, for example, with only a few exceptions, and discounting the C standard library as something worthy of the label “framework”. Nevertheless even they exist within an overall architecture that starts to look like one, if you squint, and realise the enormous power of piping stdout around.
However, many line-of-business applications do develop sufficient complexity, as the owner/operator adds new features to support their expanding operations, that the subsequent edifice either accretes random code into a horrifying fatberg of unmaintainability, or some wiser developer refactors substantial parts of the interface, business logic, persistence, and runtime configuration, effectively creating a framework within that application on which the logic and interface and so forth subsequently hang, and with a pinch of skill and luck, in a fashion that is more readily reasoned about and amended.
Whether that informally-specified framework might be considered worthy of extraction into a unit of software for itself is another matter, and largely a case of programmer hubris.
> or some wiser developer refactors substantial parts of the interface, business logic, persistence, and runtime configuration, effectively creating a framework within that application
That's not what people commonly understand as a "framework". Nor is it a helpful definition because then where does "abstracting things" and "framework" start and end?
No, the main difference between frameworks and what you describe is the IOC. In the framework world, the framework calls you and then something happens behind the scenes until the framework decides to call some code that you provided via the frameworks API.
With libraries it's the other way around: you call the library and then you do something with the result and then use it to call the library again and so on until you have the desired outcome.
The difference is, for example, that you can call the library and when it returns something to you, you can inspect it and choose to ignore it. You can do so in an arbitrary way. In the framework case, if the framework does not provide any way for you to interact with it in the way you want, then you are screwed.
Sorry, I don't accept this very mechanical definition; not only is it a needlessly narrow one, it's downright meaningless in some paradigms, such as when implementing coroutines via continuations, but that doesn't mean you can't have frameworks in Scheme. Conversely, we could describe tuplespaces (a la Linda), or many event- or interrupt- driven systems (like an Ethernet port), as an inversion of control, but whether they're frameworks or not would be an open question, and indeed in the end almost everything happening inside a modern computer consists of one element calling back to another, up and down a stack.
Heck, it's not even true of some of those specifically called out in the article above. For example, I've written programs that use Rails as a library - or rather, suite of libraries - of functions and classes to be called, but anyone suggesting that Rails is somehow "not a framework", on the flimsy grounds that it did not dictate the flow of control, is gonna get some funny looks at morning standup.
But the greater problem is that narrow, mechanical definitions omit purpose, and talking about software without purpose being front-and-center becomes rapidly theological. If you're wondering what I mean by that, look up the wikipedia article for "Software framework", scroll through its desultory talk page, and recognize the inevitability of the boilerplate it got stuck with: "This section is written like a personal reflection, personal essay, or argumentative essay that states a Wikipedia editor's personal feelings".
I‘d say Rails is a combination of framework and libraries.
Some parts (ActiveSupport, the part that simplifies e.g. date calculations) are clearly libraries. They can be used outside of Rails as well, because they totally ignore the shape of your other code.
Other parts (ActionPack, the component that calls your code depending on the incoming web request) are working like a framework. Your code must adhere to their requirements, otherwise it won‘t work.
I think it might be better if instead of trying to redefine libraries and frameworks we instead used the terms impure application(frameworks) and pure application(libraries). That would make it evident as to which libraries are actually tainted with impure work and need to be redefined as impure.
When you extend this pure/impure idea all the way throughout the computing eco-system, it quickly becomes apparent that something went wrong a long time ago, and every-time, instead of untangling the mess that is pure and impure into their own buckets, we find a way to run a framework in a framework.
What is an Operating System? What is a container? What is k8s? What is a Programming Language? What is a browser? What is a website? What is next?
One of the most useful definitions I found was from Luciano Ramalho, the author of Fluent Python (and so many other cool things). According to his insight, a framework is something that calls your code. A library is something your code calls. Frameworks are more rigid things that force structure on your functionality. If the structure it imposes is good, then your code will be good.
Their scope is also tailored to the languages they support. As you pointed out, different languages will have different needs.
I'm not saying that I gave the perfect definition of a framework. But if anything the original definition is even worse or less meaningfull.
Also, it is certainly possible to have a mix of a library and a framework where parts use IOC and others don't. Maybe that's try for Rails (never used it) and that's where your confusion comes from?
I don't agree with this simplistic distinction between framework and library. There are plenty of libraries that call back into user code. A better definition might be that a framework imposes an entire 'application model' on you, and trying to step outside that predefined model is at your own risk, while a library is a much smaller and flexible building block (also a building block for frameworks).
But there's a large gray zone between these two, and eventually the distinction is also often quite pointless in the real world.
I think the last sentence is really true. And yes, there are libraries that call back into user code, which makes them framework-like in this regards.
> A better definition might be that a framework imposes an entire 'application model' on you, and trying to step outside that predefined model is at your own risk
This is the kind of definition were 50% will call something a framework and the other half will call it a library then. Not sure if that is really helpful.
Yeah, if this is not just an once-off async callback (where you could just use a promise) but somthing more complicated, then this is indeed more framework-like and for me would be a reason to try to avoid it.
> then where does "abstracting things" and "framework" start and end?
It doesn’t. If you abstract things enough there is your framework.
The only things I’ve seen that were truly without a framework were raw php files that did everything contained within that single file. And even these had headers that combined some common functionality.
> Not all software has an implied framework within it.
The definitions of "framework" are always a sticky issue. If you take "framework" at face value, it's minimally a set of idioms. "an essential supporting structure which other things are built on top of" - which necessarily includes a mental model of execution. This relates closely to why naming, in software development, is considered so difficult.
All software has an inherent framework. First is the mental model and then the implementation. Implementation middleware to simplify utilizing these idioms or enforce them, are incidental. If you're lucky, you can derive some of the underlying design from documentation.
Ironically, those who claim that they never use a framework are largely making implicit claims about what they consider a framework to be or have.
> The definitions of "framework" are always a sticky issue.
Hence why the article defines what it means by framework, and by the definition in the article, software rarely has any implied frameworks within as one of the definition points is that there is code in the framework the user is not free to change.
There certainly can be frameworks emerging within large projects, but by the definition in the article they're not problematic because they don't lock you in: You can change those pieces. You in particular ultimately remain in charge of the flow of control in the code. Those "frameworks" don't take away control and put you in a straightjacket.
The article could perhaps have been framed better as "how to write a framework or framework-like thing which doesn't become a problem". Some thoughts might be:
* Structure it as decoupled components where you can opt in and opt of different elements, including of control flow. E.g. Padrino - a Ruby web framework fits well here. You can pick and choose which ORM to use; you can opt in to a router, controller, admin interface, mailers, logging, caching, and view libraries, or not use them at all. You can start with plain Sinatra and add in bits of Padrino as and when you choose, or supply your own.
* In particular, if possible, externalise the control of flow into replaceable components. Doing this alone can often be enough to get you out of the straight-jacket of "frameworks as defined by the article"
* Allow users to override/replace all components rather by defining clear interfaces and not assuming you can call hard-code calls between the different components. Padrino again fits well there. So did e.g. Qmail treated as a "framework for building a mail server" ("nobody" used pure Qmail, but Qmail defined the interfaces between each individual program which made up the full system, so you could replace every single bit step by step). In particular there should be no "magic" glue which there isn't a well defined way of tearing out.
Well, I don't disagree, and we could almost label that "framework zero", and also hence the reference to Unix utilities and their assumptions regarding stdin/out, but I am also taking a contextual cue from the article linked at the top which is clearly taking aim at large pre-chewed boluses of code such as Rails, Django, Drupal and so forth.
I am just about old enough to have even toggled in a program on the front panel of a PDP-8 that my local university had kept around to occupy valuable floor space in their computing center. I wouldn't say I used a framework, but I was just a kid at the time, so it's possible that I did use a stepladder.
Really? Did my toggling on an 8e that ran as a controller for a COM (Computer Output Microfilm) "printer".
Not saying that I could write code directly in octal... but I was pretty darn close. Of course, it helps when your assembly language consists of just eight instructions.
An important part of being a framework is that it is made for reusability, similar to a library. Just because your code has some thought out structure/architecture doesn't mean that it has an inherent framework.
> An important part of being a framework is that it is made for reusability
I might have agreed with this at one time. A dedicated "framework" has documentation and additional software to shortcut assumptions, but a coherent design isn't different enough from the rules that guide any given framework to be a distinction. The biggest differences are how mature the frameworks are in breadth of documentation, guidance in how to achieve constrained goals (there is no "everything" framework), and supporting software to shortcut boilerplate.
> Whether that informally-specified framework might be considered worthy of extraction into a unit of software for itself is another matter, and largely a case of programmer hubris.
The interesting thing to me is that this is how Django, one of the canonical big backend frameworks, came into being. It was based on what a newspaper's website's staff were actually using in practice.
But this is fine. The framework that the organisation develops for itself is designed to solve the problems that the organisation has.
As TFA says, one of the main problems with frameworks is that the maintainers of the framework don't share your organisation's goals, and therefore will have different problems to solve.
While one can think of every problem as a snowflake situation never encountered by anyone before, outside of its core business domain an organization (particularly a non-technical one) rarely faces truly unique challenges. Most of the time one can also decompose the solution into a number of well-known problems that had been solved before.
For example, in an overall solution for some snowflake business challenge you may see components such as an order taking system, a customer support center, a CRM, an ERP—and on another level patterns like a statically rendered site, an SPA, a “classic” content-driven site, and so on. In my opinion, being blind to these opportunities and intent on putting the entire solution together without any delegation of control flow smells of lazy architectural thinking and/or job security. The exact decomposition would depend on business specifics, foreseeable future evolution of the business, team capabilities and other factors, but as a result you’d be able to radically lighten the implementation and indeed maintenance burden with a strategic use of frameworks or even lightly customized CMS.
This simply isn't true for, well, every project I've been on. There is always some unique wrinkle in the requirements that means this project needs a different approach.
SAP is the classic example of this: SAP implements vanilla business processes (with lots of flexibility built in). Yet every single business implementing SAP needs extensive customisation and modification to make it fit their business processes. Some have spent millions or tens of millions trying to make SAP fit their business and failed.
In your terms; every business is a snowflake. You cannot create (for example) an order taking system that will fit all businesses. Or even "all businesses for whom order taking is not part of their core business domain". Only "those businesses who are willing and able to make their order-taking process fit your system".
You identify common aspects and snowflake aspects, and in the end the separation as to which parts are snowflake (contain business specifics). That’s your job as software architect. Again, the locations of snowflake parts tend to be similar across businesses, and this is where good frameworks and CMS tend to offer extension points.
It’s a spectrum: a CMS may be more fiddly as to customization but more reliable if your needs and extension points fit, framework offers more freedom, and a bespoke combination of libraries generally forces you to implement and integration test more of control flow and imposes higher costs of maintaining proper documentation as to how everything fits together (to avoid the next engineer accidentally killing performance due to a misunderstanding of how it’s supposed to work).
On the other hand, CMS and frameworks can actually inform your decisions, as their engineers had faced tasks similar to yours time and time again.
I work in startups mostly, where requirements are not defined and the business learns as it goes; it's simply not possible to identify all the areas that are "snowflake" ahead of time.
It is sometimes possible to persuade the business that if they create the process in a way that matches the framework it will make life easier for everyone. But often that isn't possible, and often there are good reasons for that.
I see. When writing my comment I also had in mind all the businesses that are not primarily technical (shops and such).
I think it’s often possible to identify the truly inflexible/snowflake aspects the business and still make use of frameworks/CMS. For a tech-focused company there are possibly more cases in which building your own is a viable decision, but with other companies that don’t have strong technical brains so to speak “this will cost you more to develop and more difficult to hire for later” is something they would understand…
<quote>Some have spent millions or tens of millions trying to make SAP fit their business and failed.</quote>
Any business that tries to make SAP fit their needs will fail to some degree (usually to a large degree, and expensively).
SAP will tell you in a heavy German accent that you bought the perfect business practices from them, and if you want to be successful, you VILL make your business fit SAP, not the other way around. In reality, they're right - All the really successful SAP installations I've ever seen had the company tossing all of their existing processes and replacing them wholesale with the ones built into SAP. Trying to make SAP fit foreign practices is a losing deal.
Yeah, I've heard the same. And this echoes what I think happens with frameworks. You cannot make the framework fit your process. You might be able to make your process fit the framework. But the further your ideal process diverges from the framework's process, the more painful it is and the more the benefits of getting started faster are lost.
> Not all software has an implied framework within it. Most Unix command-line utilities do not, for example, with only a few exceptions, and discounting the C standard library as something worthy of the label “framework”.
The C standard library is exactly that though, a framework for writing UNIX command line tools :)
A library is not a framework. You can write framework-free apps while using libraries (in fact, most do - not wanting to be burdened with a framework doesn't mean you have to write all functionality yourself).
A framework is either about inversion of control (it calls your code, e.g. you write web request controller logic, and it sets up the infrastructure for calling your controllers), and/or a set of ways to structure your code, like classes to extend, folder structure, a set of patterns you must follow to work with it, like a specific MVC-like organization of code, and so on.
Well to be pedantic, the CRT invokes a callback called 'main' with preprocessed (command line) parameters, in the 'main callback' you're expected to do something with the parameters that have been passed to you (for instance read data from stdin, process it and write back to stdout), and then return from the 'main callback' with a success or failure code.
Ok, I'm throwing together the CRT and standard lib here, but in the end both are parts of the "UNIX command line tools framework" which is supposed to provide a programming environment to easily extend the UNIX shell with your own commands.
By this definition everything is a framework. You're never the one calling code, it's always the BIOS, the bootloader, the kernel program loader, etc. I don't want to go all ad-reductio, but this is one of the points I have against the anti-framework people: the code you write is actually a pretty small percentage of the total code that makes up your system/application. Good engineering is working to make sure that code is differentiating code, not irrelevant code like garbage collection, HTTP header parsing, etc.
> You're never the one calling code, it's always the BIOS, the bootloader, the kernel program loader, etc. I don't want to go all ad-reductio
I don't think you're even being reductive; it's just irrelevant. The saying is to do with the software you're writing right now - do you include a framework (e.g. Django, Ruby on Rails, Spring) or do you include libraries that you could swap out (e.g. Flask - which terms itself a "micro framework", but is a library for this definition, ReactJS, SQLAlchemy) and your code is in control. You're right that the code will run on one or more operating systems, but abstracting out that far elides the useful conversation application developers can have about eggs and baskets.
> the code you write is actually a pretty small percentage of the total code that makes up your system/application
This is almost always true, but seems again irrelevant. How I write my application is worthy of discussion in and of itself, if for no other reason than, with a few exceptions, I'll spend a lot more time and money on making my application than I will thinking about how the Linux kernel works.
> I don't think you're even being reductive; it's just irrelevant.
The arguments here are:
"With libraries you call the code; with frameworks they call your code"
"This isn't a good distinction because there are lots of things we wouldn't consider frameworks that call your code"
That seems relevant to me.
> I'll spend a lot more time and money on making my application than I will thinking about how the Linux kernel works.
That means the kernel is doing its job, and if you swap out "Linux kernel" with "Django", that would also mean Django is doing its job. Without the kernel, you'd have to do a lot more work talking to hardware and scheduling other processes to run. Without Django, you'd have to do a lot more work wrangling HTTP and SQL.
It feels like peoples' issue with frameworks are that they force a way of thinking on you. But everything in software does that, the semantics of processes, pages, threads and so on are entirely made up, just like model view controller is.
> The saying is to do with the software you're writing right now - do you include a framework (e.g. Django, Ruby on Rails, Spring) or do you include libraries that you could swap out (e.g. Flask - which terms itself a "micro framework", but is a library for this definition, ReactJS, SQLAlchemy) and your code is in control.
I'd say by this definition (your code calls a library, a framework calls your code), Flask is every bit as much a framework as Django; I write functions that are called by the router just like I do for Django views. Sure, I can swap out the ORM and the templating library; I might even be able to swap out the routing library, but here be dragons. But a standard Flask application and a standard Django application are very similar. And if I wrote an application using Flask, it would be more or less a rewrite to swap in something else for Flask, because I'd be depending on Flask's request and response objects, at minimum.
This is partly why I don't think this definition is very useful, too. Clearly Django and Flask are different, but this isn't why.
>I don't want to go all ad-reductio, but this is one of the points I have against the anti-framework people: the code you write is actually a pretty small percentage of the total code that makes up your system/application
Which is neither here, nor there.
We're talking about a specific kind of inversion of control and forced structure within the codebase.
Else we could just go down an irrelevant rabbit hole, and it would like being a lawyer in a criminal case and arguing that your client is innocent, because "ultimately everything, including the murder, is just deterministic after-effects caused by the Big Bang".
Well, my point is that because this applies to more or less everything, it's not a great determinant of library vs. framework.
Like, the way you use Django is by wiring up URLs to functions [0]. This is pretty similar to setting up a vector table for interrupt handlers. Is that a framework? What makes Django a framework and vector tables not a framework?
I'm not trying to be pedantic here, I just really couldn't tell you the difference, and as a result, I'm not sure the distinction is useful. It sounds more like a post-hoc rationalization of why you like or don't like something.
Except none of these steps are dictated by the C standard library (some may be dictated by some libc's)
EDIT: To expand on this: You can call the code from stuff other than a shell; I'm assuming you mean "C runtime" by CRT, and some libc's may have issues without them, though usually only access to argc/argv and atexit(), and you can certainly write C without linking with the initialisation code; and while you'll of course usually enter via main() you don't have to. You decide the control flow.
The kernel loads your program, and schedules its execution. This is basically the same as using an async framework and sending the entry point to your application.
If you're willing to extend a little, there are also signal handlers, or setting up callbacks in pthreads.
Again this isn't to be reductive, but to say this is a super common method of encapsulating irrelevant stuff. It doesn't seem to be a significant differentiation between "I'm a library" and "I'm a framework".
CRT also does stuff like floating point emulation, loading dynamic libraries on demand instead of at load time (e.g on AIX and Windows), handling threads post C11, or runtime checks in hardened code.
The point is all of that is optional. You can - and I have - write C to be executed on bare hardware with no initialisation code, and depending on your choice of libc you can still use it (though some functionality may not be available).
Of course it is still C. You've just opted not to use some of the functionality.
Nothing stops you from e.g. providing your own startup code which then calls the appropriate initialisation code either.
The point being that there's no enforced inversion of control in the sense used by the article, and so calling it a framework in the sense described by the article is meaningless.
Even if we postulated the inversion of control was there, the fact you can replace all parts of it still means it does not fit the article definition.
If you were to write a program that relies on those aspects of the abstract C machine and don't provide those aspects, then you might have an argument, in that in that case the observable behaviour would be different, but if you choose not to make use of that functionality, its presence is entirely irrelevant.
This is also massively shifting goal posts. You first wrote "At which point it is no longer C". By your argument here, e.g. the Linux kernel is not written predominantly in C. But nobody uses the term that way. If you were to speak specifically about ISO C, maybe, but the person I replied to initially did not limit it to ISO C.
As such this is also entirely irrelevant to the original argument.
Everyone knows Linux is actually written in GCC C, and Google has burned lots of dollars making it work with clang, if it was proper C, that wouldn't never been an issue.
Yeah, that is why plenty people then show up on Stack Overflow with questions that prove how much they know C, versus "whatever my compiler did when I tried it out".
I actually have written software without a framework, so by this standard I feel qualified to comment.
Not all software has an implied framework within it. Most Unix command-line utilities do not, for example, with only a few exceptions, and discounting the C standard library as something worthy of the label “framework”. Nevertheless even they exist within an overall architecture that starts to look like one, if you squint, and realise the enormous power of piping stdout around.
However, many line-of-business applications do develop sufficient complexity, as the owner/operator adds new features to support their expanding operations, that the subsequent edifice either accretes random code into a horrifying fatberg of unmaintainability, or some wiser developer refactors substantial parts of the interface, business logic, persistence, and runtime configuration, effectively creating a framework within that application on which the logic and interface and so forth subsequently hang, and with a pinch of skill and luck, in a fashion that is more readily reasoned about and amended.
Whether that informally-specified framework might be considered worthy of extraction into a unit of software for itself is another matter, and largely a case of programmer hubris.