The suggestion in TFA is to ensure that you consume your dependencies in a decoupled fashion, a move toward utilizing libraries rather than following a framework.
I've spent lots of development time in highly-constrained environments that often feel more like a framework than a true platform. When given the opportunity, I'm inclined to follow the author's suggestion to keep dependencies decoupled. Even supposedly fundamental dependencies will eventually need to be swapped out, even if just for a v2. But your domain core should be making monotonic progress towards the distillation of your key concepts and relationships.
Django does not dictate the flow of your code. It provides some libraries and there are common patterns, but Django is more or less just a set of Python modules you can import and use as you want (A bit of configuration is done for you if you follow common layouts, but you don't have to and can manually do the configuration).
What dictates program flow is when you use HTTP with Django (What its primary use case is) but that is dictated by the request/response nature of HTTP not by Django.
You can use as little or as much of Django as you want. Naturally, the more of it you use, the more it does for you.
As the lead developer on three Django based commercial saas products, there is a trade off. Spend your time reinventing the same basic things or spend your time building your product. Even the maintenance argument is really a trade off. When you are small, frameworks help by outsourcing a huge amount of labor. When you can afford more developers, you gain control and maintainability by ditching the framework.
Let’s take it for granted you’re using it with HTTP since it’s a web framework (this would all apply with WS).
You routes call your views. Your views load your models. These feed into your templates, which go into a response. You can tweak what’s going on at each step (DRF) but there’s definitely a way it’s all supposed to work together. It’s classic IOC.
All a Django View is is a function (or in the case of a class-based view, a method of the class) that takes a request object and returns a response object... this is pretty fundamental to HTTP, so any HTTP app will do this. Its not Django dictating it, its the nature of HTTP.
You don't have to use any of those parts of Django if you don't want to.
I often opt to use Jinja2 instead of the Django Template Engine. I happen to like the Django ORM, so I usually do use it, but you certainly don't have to, I have certainly used Django without models before. Your views don't do anything with models unless you tell them to.
Using Django for this is of course completely overkill, but using a known framework, especially considering that Django is what's used in other applications here, did have some benefits. All our devs having to fix something in this app, will immediately be familiar with it as it looks exactly like the other Django apps we have. No new way to do migrations, talk to the db, open a shell, log- and reliability setup is identical with other apps, etc. etc.
And just cuz it’s optional doesn’t mean it’s not frameworky. A solid platform just wouldn’t offer any frameworky elements.
If that is not dictating how you write your code, I don’t know what is.
Its not just Django that locks you in, it's all the third party apps people end up adding. All these integrate tightly with Django.
They often block upgrades as they have different python and Django version requirements.
I use Django and Rails as examples. Both are, indeed, "just a bunch of libraries". But many of those libraries, and especially their bundled collection, enforce certain behaviour, shape and architecture.
When you inherit from base-classes offered by a library, you are tightly coupling against that: i'd then stop calling it a library and call it a framework instead. The alternative would be a library that you inject, or compose.
There's a big difference between (Rails)
`class Project < ActiveRecord::Base; end`
and
class Project
def initialize(project_repo) # Ruby has no interfaces, but this would be something that has at least an `.add(project)`
@project_repo = project_repo
end
endThe first inherits, couples tightly to a bunch of libraries (ActiveRecord::Base really is just a bunch of modules that you could pick and choose) the former injects behaviour which might come from libraries, or might come from your own code.
(Genuinely curious as someone who's working on a similar idea in a different language)
On the opposite, I'm in love with pydantic. Like any other package, it has issues, but it tries to solve a single problem, it's concise, validators are explicit and readable.
Obviously I don't mean any disrespect towards DRF maintainers, they're doing an impressive job, a lot of people use and love their work (and I still use it everyday)
Libraries over frameworks.
If you chose not to use an existing framework and end up building your own instead, you just live long enough to become the villain of your own story, as it were. But it's really, really tempting to write frameworks.
That was uncalled for.
This is simply false.
On the other hand, every sufficiently complex framework-dependant application is way too complex for what it does, and would be a lot simpler if it was not using said framework.
> My last and--to me the most significant--observation is this: You want to pay the majority of your attention to the code that has the greatest impact on your desired outcomes.
One of your greatest desires should be to have strong propietry technology that you control. Otherwise you are not different from anyone, and anyone can duplicate your work in two months by just using the same framework.
Most businesses are not successful by virtue of the technologies they choose. Facebook is probably the foremost example here; they started with PHP and moved over time to leverage additional technologies (some homegrown like hack and react, others just additional languages like C++).
There are plenty of facebook clones in plenty of languages. The technology isn't the reason Facebook hasn't been supplanted by a competitor with the exact same product.
One of your greatest desires should be to have strong propietry technology that you control
Yes – and you should be investing your time in making that "strong proprietary technology" more effective, and spending as little time as possible doing all the bits that your competitors didn't have to do because they picked an off-the-shelf solution that did most of it to a "good enough" level.
What often ends up happening is you have to do a lot of useless work to get around the limitation of the framework you decided to use at the start.
Since most people on HN are in the web space, framework often refers to things like "Django" or "Redux". These beats always cost way more than they provide.
For a web server, a library like the standard "net/http" in Go is way more useful than a "framework".
Now-a-days there are less security vulnerabilities and more buggy messes powered by Express.JS. API's with shitty query string parsers than crash the server.
The average developer should just be using a framework.
Yes, and the non-average shouldn't.
Web app security is a genuinely tricky area with lots of edge cases. Good frameworks provide abstractions that mean you don't have to deal with a lot of those problems for most mainstream cases.
If the average developer is so incompetent maybe they should undergo further training before being allowed to touch production systems? I suppose this is what code reviews are for, but I don't see how it helps when incompetent developers review each other's code.
Generally when a company's tech needs aren't very unique, and they seek to compete on time to market, then a shelf framework makes sense. Companies whose needs stretch the boundaries of shelf frameworks too much may be better served by building on a lower level platform like from a standard library--entirely or in part.
Yet building from scratch is costly. Depending on the stack / language chosen it may cost an "innovation token" or three. Small companies can't afford a lot of these tokens. And lots of eager engineers want to believe their problems are unique, dragons never before defeated. IME most problems aren't like that. They're boring, such as a codebase that's lost its fit as the market or company has grown, pivoted, or contracted.
... Have you ever written a simple web app? Pull values from a db and present them somehow? Having something that just gives me places to plug in the business logic makes this pretty trivial.
Yes I have. A lot.
* HTML forms * and admin * a plug-and-play security framework that's already worked out all the kinks of crypto libraries * an ORM and DB libraries for a half dozen production-ready DBs, with their kinks in transaction and connection management already sorted out
I have a bridge in Crimea to sell you.
Yes, it appears that companies won't budget that at all. Many seem to ship fast, fix later. It is also on the customer, really.
Some people expecting software developers to deliver high quality software (with near 100 % code coverage and exceptional performance), but paying them less and less, is not fair. No wonder, some devs are incentivized to skip unit tests or error handling. Because some employer or some customer won't pay for it.
This is the status quo that makes me pessimistic. It appears that software development is gluing things together and make it somehow work.
This ain't fun for me.
Note this is a feature, not a bug, of "agile" development - you learn and adjust on the fly
However, this would not work for many outfits. It’s just the way that I work.
WFM. YMMV.
[0] https://littlegreenviper.com/miscellany/forensic-design-docu...
[1] https://littlegreenviper.com/miscellany/evolutionary-design-...
I seem to have upset people. I’d certainly be interested in knowing why, as my comment directly addresses the parent, and does not coarsen the discourse.
Don't dwell on it - save your sanity and move on
6. Frameworks often handle the last 20% of a project that no one wants to do, such as handling compatibility or accessibility issues.
7. There’s a good chance that the framework has already had to deal with edge cases that you would otherwise learn the hard way
Frameworks have a very narrow compatibility and accessibility range, and to get the other (often more than) 20% requires extra hackery which has to be bolted onto the framework in ways that were not foreseen by the framework writers.
Those who have problems with frameworks are solving problems that are to some extent novel. Maybe only 10% novel, but that's still enough to feel like the framework is a straitjacket - because everything else is a solved problem and that 10% is the hard bit and the framework just makes it even harder.
Perhaps some of those people could re-examine their problem and achieve it in a different way using the framework, but others couldn't. But to say "if you're not using a framework you're doing it wrong" perhaps exposes a lack of experience with unusual problems, and "all software ends up containing a custom framework" is confusing frameworks with architecture.
If you wanted to work with Scala 3 and Play 2.7, you couldn't. You needed to stick with Scala 2.13 to be able to use Play 2.7.
This was more than a year ago. Now we have Play 2.8. Is it compatible with Scala 3 now?
Edit:
I am not entirely sure whether it was possible to make Scala 3 and Play 2.7 work. So my statement above might be partially wrong.
However, I had other dependencies too, which required me to use Scala 2.13.
Consider to downvote this, if you think I made a false statement. I should have looked up the documentation beforehand and not rely on my (past) personal experience/impression at all.
Bad mistake!
Things that you (can) put away behind abstractions, layers or wrappers.
I'm the author and tried to convey clearly the difference between libraries and frameworks. Both allow code-reuse, both allow "standing on shoulders". But one allows you to do so with freedom of movement, independence and domain constraints (libraries) whereas the other locks you in, enforces architectures and designs and requires workarounds when your domain-requirements differ from what the framework dictates.
Adopting frameworks is a variation on the the Build vs Buy question, even when there's no money involved. Does the framework provide some features that are necessary for the technology but not core to what your business does? It's probably OK to use. A company that adopts a framework for its core business is essentially giving up any competitive edge, because any company that uses that same framework with the at least the same skill as your team will end up being a viable competitor.
Frameworks actually add to a deplorable side of the software industry. They encapsulate truly great efforts and wisdom into a package which cannot be unwrapped and used partially. They are like smartest CPUs soldered into shitty boards (or simply incompatible with your requirements) without a chance to unsolder the functionality and use it elsewhere. You can’t make your own and you can’t take one off the shelf.
Consider this imaginary example: someone figured out all of the nuances of dom events across all browsers ever and made a clear api to it. Library way is to provide (Context, DomEvent) => MyEvent. Framework way is to create a complex rendering idiom in which MyEvent appears naturally and is an implementation detail. In the latter case you buy two for the price of two, and only so.
Or, they want to test a new idea/paradigm in some area. Without composable libraries, they are doomed to repeat all the mistakes you pointed out because to compete with already existing solutions they have to go all the way through issues unrelated to the idea itself. All that only to battle test it. For most library makers, the desired outcome is a sum of all parts, not just one.
Do you have a concrete non-hypothetical example? Because I don't think I've seen this.
You don't need to use everything just because it is available. Even basic web services are not enabled by default, and is something you need to explicitly add as a dependency. If you don't want to use Hibernate, just import a different dependency instead.
It lets me focus on business logic, while handling the interface outside the "garden" for me. In my experience, the use of annotations is confined outside the business logic. If that's not the case, the code is organized badly and will cause issues regardless of framework.
Example (could be improved of course)
@RestController
@RequestMapping("/dogs")
public class DogController {
private final DogRegister dogRegister;
public DogController(DogRegister dogRegister) {
this.dogRegister = dogRegister;
}
@PostMapping
public void registerDog(@RequestBody Dog dog) {
dogRegister.registerDog(dog);
}
}
If I decided to change it to a message based approach, I could do that without changing any business logic, by replacing the controller with a queue listener. Also note how IOC will automatically inject the business logic component. @Service
public class DogListener {
private final DogRegister dogRegister;
public DogListener(DogRegister dogRegister) {
this.dogRegister = dogRegister;
}
@JmsListener("dogs")
public void registerDog(Dog dog) {
dogRegister.registerDog(dog);
}
}
In my view this is a framework that gets out of your way. I did not have to change the business logic (dog service). Spring takes care of the interface outside the program. If I wanted to switch to a different standard than JMS, I would most likely in many cases just need to change to a different annotation.If the code is organized badly, the business logic would have been included in the controller and be harder to change. But isn't that the case of bad structure in general?
But I'm inclined to agree on the case of Spring Boot... It's meant to be a "convention over configuration" kind of thing, so I guess by nature it ties you in pretty hard.
After 25 years of experience writing software I can honestly say I have encountered many people that agree with this, and perhaps all of them (every single one) have not actually experienced writing an application without a framework. This sentiment sounds correct in theory, but it isn't based on any experience from any one of the people making such a claim.
The reason why that is comes down to selection bias and cognitive conservatism. Once you become dependent upon a framework everything looks like a framework, even when it isn't. Therefore everything works as expected (like a framework) or it doesn't, which isn't buggy. So really this isn't a question of the software, but of the developer's capability to perceive (or not) that software.
This is why I refer to frameworks as an insane asylum as I described here to 27 up votes: https://news.ycombinator.com/item?id=32914694
All a framework means is that there is a coherent, repeatable model for implementing the building blocks out of which the application is built.
Even a simple command line program with hardly any functionality soon runs into the issue of having more than one command-line argument or environment-variable based configs. And a sensible, maintainable approach to this involves someone spotting ‘hey! We can abstract the bits that all our command-line parameters have in common so processing them all is consistent’. And then you have a framework. Because now ‘adding a new command line parameter’ has to be done in the standard way - you register a validator here and you add a help string there.
Building something without a framework is a rejection of patterns, or of the value of establishing repeatable structure.
Software that facilitates encapsulating chunks of functionality as standard building blocks is more maintainable over time. It’s much easier to work on a system where you can take a user story and interpret it as ‘okay, so we can implement that as a new Task type and then add a Tool to the Tool Library that lets users who have the right Role create a Schedule to run the task’. any time a system is sufficiently structured that you can think that way, it’s essentially become a framework.
Frameworks can be lightweight or heavyweight, sure, and they can be open to being overstepped or closed - and choosing when to prefer to structure your framework to make it easier or harder for someone to step outside the lines is just an engineering choice like any other.
With that definition all programming languages are frameworks.
The first part of the article defines what the author means by a framework, which is different from libraries, and programming languages in general.
It's similar to the difference between function and algorithm. The former is literally code, and the latter is conceptual.
Many programming languages are distributed with a cohesive framework. For example, Rust is distributed not only with rustc to compile binaries, but also with cargo to manage library dependencies. That doesn't prevent you from using rustc without cargo, though, or even making another rust compiler for GCC, and using GCC's framework.
What is a class definition in an OO language but a way for you to implement some state and some functions in a particular pattern that, when plugged in the framework of the compiled application runtime, will take care of the lifecycle and marshalling of calls to your code?
That meets all the definitions of framework provided by the author.
Which is exactly what I am talking about.
If adding a new commandline parameter to your application involves adding a piece of validation logic that gets called on startup, putting an extra line of code into the help text initializer, and writing a handler to be called when the parameter is supplied... then the flow of control is already dictated by the application, and you are adding new functionality over the top of an abstraction. You are using a framework, not a 'function'.
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.
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.
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.
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.
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.
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.
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".
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.
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?
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?
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.
But there's a large gray zone between these two, and eventually the distinction is also often quite pointless in the real world.
> 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.
Callback hell however, is not something I'd associate with a framwork
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.
The C standard library is exactly that though, a framework for writing UNIX command line tools :)
(for anything else it's much less useful)
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.
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.
Similarly, "libc is the same as a framework" is not an abstraction/assumption at any meaningful level, or really pertinent to the discussion.
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'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.
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.
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".
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.
[0]: https://docs.djangoproject.com/en/4.1/intro/tutorial01/#writ...
It doesn't fit the term as used in the article at all, though, in that it doesn't dictate the overall program's flow of control.
shell => CRT => main(argc, argv) => exit code => shell
(to me, the CRT and C standard lib are not strictly separate, although that's debatable of course)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.
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.
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.
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".
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.
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.
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".
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.
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 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…
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.
:s/framework/SAP/g
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.
It is quite telling of HN's audience if they honestly think that "every sufficiently complex framework-free application contains a [buggy] half-framework." The precise definition of a framework may be a bit hard to pin down, but most any experienced practitioner knows it when they see it. Things I look for:
* coupling of a blessed architecture, libraries, and patterns. Some choice of libraries may be allowed, but they must conform to a framework-prescribed interface.
* difficulty of isolating behavior for fast unit testing when using framework as prescribed (not always, but this is right more often than I want still)
* inversion of control as a core building block instead of straightforward composition. (This point gets fuzzier in callback-centric langs.)
* main() (or its moral equivalent) ends up being a framework bootstrap call, or is hidden entirely.
* related to last points: emphasis on hiding as many execution details as possible to present a simplified view of what the framework author believes is important.
* reliance on extension points to customize behavior (via subclassing/hooks) rather than simply exposing primitive operations that users can call alongside custom code.
* documentation beyond API docs and tutorials, usually necessitated by the number of novel concepts introduced by the framework
* heavier-than-normal emphasis on marketing, often leading with social proof from a megacorp, sometimes with big promises on how this framework is not like the others
The main takeaway should be this: a framework is not something that wants to blend into the background of your application. It is extremely visible and it is something that you program to, and often must take what it wants into account when designing. Without a framework, you can literally do whatever you want, including making a huge mess, or something small, functional and minimal.
I believe that should disqualify most of the rather absurd claims that all libraries/patterns/libc are "frameworks."
Programming language is a framework over machine language. Java garbage collector is a wrapper around manual memory management. Java Servlets is a pretty thin wrapper over HTTP request/response, is this a framework already? How about Java JAX-RS, it is built on top of Java Servlets and built to handle mostly REST type requests.
Same with database connectivity. Where framework starts? On JDBC/ODBC driver layer? ORM mapper like iBatis? JPA/Hibernate "true" ORM with automatic dirty checking?
An abstraction layer over a database is not necessarily a framework, it can be just a library. I'm not familiar enough with specific ORMs to comment on those.
A programming language is interesting to look at from this point of view. While sure, you need to use the programming language's features to implement control flow, it typically doesn't actually dictate a high-level control flow itself. There are probably languages where this is not completely true.
For that matter, it seems to me that CGI would be a framework in this sense - the high level control flow is that you are called by the web server, run, take input from environment variables, output an HTTP response, and exit. Not fundamentally different from "Django views take a request object as an argument, and return a response object, and are called by the framework". Just a matter of degree.
It appears bias, and possibly even neurological limitations, largely account for framework dependence. Typically this is self evident when you step back and examine the opinions qualifying that dependency as most such arguments are fallacies from ignorance. Decision avoidance is the primary indicator of ASD.
For example many of the arguments in favor of frameworks will sound something like: ”I tried without a framework once and produced a framework anyways, so therefore you must use a framework”.
Another example: ”The code must broken and slow if not using a framework.” Without evidence (numbers) this is a bias (or a lie). Before making that claim there is likely no performance measure or comparative defect count. In my experience doing this for 25 years rarely measure anything and instead invent assumptions to qualify whatever opinion they want. Example (look at the parent and peer comments for comparison): https://news.ycombinator.com/item?id=33004060
No. It's also to make the work easier and do the heavy lifting, too. Conventions alone are useless if the work becomes more difficult.
It's a vague term but it is pretty darn obvious what the desired intent is behind frameworks and why the endless discussions on their costs and benefits exist. Frankly, most developers couldn't care less about the semantics, they only care if the outcome is beneficial.
In my experience, the correct way of saying this is: I tried without a framework once, and I found myself rebuilding everything that the framework previously gave me. Therefore, I must use a framework (for things that are remotely similar to the thing I built a framework for).
A framework is something that provides an ecosystem for you to develop in. Rather that using your own style/glue/etc a framework provides all of this for you. Another key aspect of a framework is how much it hides. It's not uncommon that a framework (like rails) hides almost everything from you down to exactly how it's launched. I suppose you could say the hallmark of a framework is it's closer to writing a giant configuration in a bespoke DSL than actual programming.
I regularly end up having to
1. Either write my own code to query the db and build Ruby objects from the response and viceversa OR use ActiveRecord.
2. Same thing about managing the database schema. Either my own code or someone else's. So why not Rails' well tested one?
3. Organize the code base in some way that makes sense.
4. Write my own code to manage tests OR use rspec / capibara (OK, they are not part of a framework but they are a large dependency)
In the end I always regret I didn't use Rails from the beginning because I end up spending a lot of time doing useless takes. Keep in mind that I do that for my own projects in my free time. 99% of the times my customers decide what to use (Rails, Django, Phoenix.)
* It lets me pick and choose an ORM. I usually prefer Sequel over ActiveRecord. Pretty much nobody suggests you should use Sinatra without an ORM unless you genuinely don't need a database.
* Nobody suggests you should build your own schema management. Pick an ORM which provides it out of the box (e.g. Sequel), or use a component which provides it (e.g. Padrino has a generator component which out-of-the-box supports generating migration helpers for the major Ruby ORM's and some you're unlikely to have heard of)
* Nobody suggests you should write your own code to manage tests. Just use rspec / capybara, or whatever else you prefer. And again, consider using Padrino's generator if you want something to generate scaffolding for it for you.
The point of using Sinatra is the freedom to opt-in to your preferred components as and if/when needed. If you always want the ones Rails provide, just use Rails, nobody will think less of you for doing so. Not even those of us who personally don't like using Rails.
For my part I rarely want the ones Rails provide, and so I rarely use Rails. Often I use bare Sinatra. Sometimes I mix in some components from Padrino because they can be easily torn out again.
I'd suggest that if you want something lighter than Rails but have those issues with Sinatra, look at Padrino (Sinatra + a pre-packaged set of components you can opt in or out of separately, or layer in piece by piece on top of Sinatra if/when you need them). But you can also just use Rails.
I've usually used Flask and even when I needed a few db operations you could easily contain that to a small part of the code and stepping up to django would have felt like a huge step up in complexity. But I guess it really depends on what you're actually writing - your use case sounds a bit like "something like wordpress" from a "customer uses this" point, and mine were mostly "small REST API endpoint for something".
The whole here is no more literally true than the original lisp quote, but (just like the original) that doesn't stop it from being true in spirit.
No, this definition doesn't describe what people understand as frameworks.
A framework is a library that is so pervasive that you cannot reasonably do so - your shim would just be a copy of the framework's API, and it would be exceptionally difficult to take a different framework and make it fit the shim.
E.g. if you need to work with time zones, you can easily write out the function signatures you need, then look up any number of date-time libraries and make any one of them fit your shim.
But if you need to 'manage data flow between backend and UI', and try to write out the function signatures you need, you're either going to be copying a particular framework's API or you're going to have a hell of a time implementing the same signatures for two different frameworks if one is one-way and the other is two-way.
The old archetype of a framework might be one which expects to control an overall event loop for your application.
In practice many things we would still recognise as frameworks allows you to undo that, but I still think it's a useful rule of thumb in that even many frameworks which technically allows you to remain in control of the overall flow tend to assume the framework will mostly dictate structure and flow.
I've written a number of frameworks, plugins, and extensions, and refactored existing ones. I've used a number of them. I tend to customize stuff, which isn't always conducive to using "heavy" frameworks. I've enjoyed "bald" ones. Done some big stuff.
Some came out great ... some ... not so great.
The "not so great" stuff tended to be early in my career. Refactoring existing ones, helped me to learn how to do it right.
I think the first one that I refactored, was PHP Nuke. It emitted terrible HTML, and my refactoring made sure the output would validate (and WAG the dog, so to speak). I ended up binning it, when they did their first upgrade. Learned a harsh lesson, there.
I wrote a framework in Perl. That was ... challenging.
These days, I tend to use a lot of modules and connectors, and use whatever framework is built into the OS (I write native Swift). I've heard great things about Laravel, but I have never used it.
Do you really think that there isn't a single person who claims that frameworks are good who has never written an application without one?
Well, now you know me. I've tried writing a website without React, and I ended up writing a buggy half-implementation of React. (In my defense, I didn't really know of React at the time.) You only really have to do that sort of thing once before you learn that frameworks have some advantages.
There are a lot of different types of organizations, and their needs for development vary. Using well known tools reduces onboarding time, and in a large organization with turnover, that's not an insignificant cost. You really think the documentation you wrote for your app is better than those of a popular open source framework?
Frameworks also bring community defined best practices and standards. There is support from tooling like test frameworks that make functional / unit testing easy, linting and code formatting tools, IDE support, autocomplete snippets, debugging tools, browser extensions. These things might not be important in a small team, but with 100 devs, they bring real benefits.
> I just put all my state data in one object, save it on each user interaction
The saying is any "sufficiently complex app", and your approach to state management speaks volumes about the scale and type of front end apps that you work on. If you've never had bugs in your state using this strategy, it's wonderful. But if there were 100 of you constantly adding to and changing this global object, do really think that would be manageable?
How much state are you dumping in this object? If you only reference it on page refresh, your app must not be very reactive. One UI component could have quite a bit of state associated with it. One complex dashboard SPA could have hundreds of different pieces of state that are being tracked. Modern frameworks are tackling that problem, and the fact that you don't have it doesn't mean nobody else does.
You can use frameworks where they fit, and not where they don't. Knowing when to do which takes time and experience, but it is definitely do-able, and better.
Frameworks allow you to update, and maintain your app for free, since others will do it for you. If you do it yourself, you have to do all the work and that's keeping you from adding value elsewhere.
To not use frameworks these days would be objectively stupid unless you're working on extremely low-level things.
I instead prefer test automation to frameworks for automation. They are both tech debt, but only one of those provides a layer of risk mitigation (regression detection or changes to business requirements). The other provides a substitute for training, experience, and soft skills which suppresses risk realization. Just because the danger is hidden to lower layers does not indicate the danger is gone or avoided. If this were true frameworks would eliminate the need for testing and quality assurance.
The cold hard truth is that most developers are not the genius hackers they fancy themselves to be.
That's the big caveat. Loads of frameworks leave clear issues dead in the water. Your team/predecessors weren't the most clean. Now have fun fixing that one issue working out a framework you can't easily modify or switch out.
Of course that problem isn't unique to frameworks nor inherent to framework rather than social and legal problems.
Usually not for free. Sooner or later there's an API breaking change and you end up spending time reading changelogs trying to figure out how to get your code working again...
Not "CAN you run with crutches?" (as anyone who can run without crutches can run with them) but DO you run with crutches, as though running without crutches might signify a lack of ability. Fine time to unask the question.
Another team member has developed frameworks for both infrastructure management and creating services exposed over http. Here there is a large value in using the same internal tooling over 20+ projects. But once again, being an internal-only tool means that the documentation is severely lacking, and often we need new features in the frameworks. All of that is essentially blocking on the single team member. In this case we're keeping the frameworks, but it definitely has its caveats.
Where I currently work they primarily rely on nontechnical qualities for candidate selection because they are more interested in choosing the right people than a tool user. Either way they will be investing time in training in some form and would rather that training focus on the business objectives than the technical objectives. Counter-intuitively I was entering the code earlier here than at previous employers even though I am writing in a language I have never touched before. This is likely because I entered this employment drowning in deliberate one-on-one training.
I also have 25 years of experience and started my career writing C and FORTRAN on mainframes without any real library let alone a framework and then wrote my own libraries in C for my next job where I had to write cross platform code that ran on x86 based PCs and mainframes.
My next job, involved maintaining a proprietary compiler/IDE/VM for ruggedized Windows CE devices. So I think I have experience working without frameworks. Not to mention by the time I graduated from college in 1996 , I was a hobbyist assembly language programmer on 4 processors for 10 years (65C02, 68030, PPC 601, x86)
I can say that it’s the fifth level of hell coming behind an “architect’s” half ass framework who thought their problem was so special that they didn’t want to use a mainstream framework to handle non business specific concerns.
There have been a few times that I have ripped out my own code in favor of a popular library when I discovered it.
I'm much more likely to rip out the one function I need out of a framework or library and put it in my code, with a comment "// stolen from <source>". I've spent lots of time untangling the crux of someone's implementation away from the problematic abstractions they built up around it to make it universally adaptable.
In the context of web applications, frameworks mean that your devs don't have to be experts in SQL Injection, XSS, SSRF, Session management etc etc etc.
My experience over several hundred tests was that without a framework there weren't many apps that could get that right first time. If they were lucky the pentesters found the issues, if they were unlucky, it was attackers.
I’ve inherited non framework projects many times. They take way more time to get up to speed on.
Now I’ve seen framework projects where they clearly didn’t try and work with it. Those ones just make me sad.
Twice, I made the mistake of programming my own data frameworks so that I wouldn't have to rely on pre-existing databases. Total mistake both times. I have learned my lesson. (Most people wouldn't even think of doing that now; but I've been a pro since the 80's. The situation with web frameworks now is analogous in many ways to the situation with databases long ago.)
Which is not so difficult, because that busy person is in the same organisation as you, and therefor working towards the same goal.
Fixing that bug is much more difficult if that person is in an outside organisation, serving many other customers on the same code base (with possible conflicting needs), and/or is not actually in any way accountable for it (open source).
Hopefully. But not necessarily. This argument is spinning in circles. In house projects can be abandoned just as oppen-source ones can. For me that was Powermock for example.
{evil laugh.mp3}…
Ideally yes but in reality: all teams have bottlenecks, and nearly all teams have assholes. Is fixing your problem on their OKR or whatever.
Free / open source code can be fixed by anyone: the volunteer owner (who you could even bribe to fix it), any contractor with experience, or someone in the org. This is the beauty with free software. It enables people to fix their printer drivers even if they didn’t write it originally.
To have a fix accepted on an OSS project means fixing it not just for your use case but also for every other user of the project, on every target platform, while aligning with the goals of that project. If you can get anyone to look at the PR in the first place. Assuming you've used the framework to save time, you probably don't have time to go through all that and your deadline will not wait a month or six for your code to make it into a release. Depending on your employer you may well need internal permission and legal sign-off to contribute to an OSS project in company time which is yet another hoop to jump through; though that goes for forking too.
Not to mention, the frameworks tend to be hard to use "correctly". Rails devs will have heard the term "the Rails way". In fact this article has an awesome example. There's a snippet of code of a controller checking to see if a User exists with the given email. Any Rails veteran would know that you can just call `User.create` in the controller and rely on validations for that kind of check. But that's another problem with frameworks - you have to know the whole thing in order to use it well.
#1 is definitely true. I had my own halfassed 'framework', and have dug into enough older web apps to know that everyone else had one too. (Or at least the smart ones did.)
The difference is I have plenty of resources at my disposal to learn how to use a popular framework. I only have hopefully the one “architect” who thought their problem was a special snowflake to ask about their framework - if they are still at the company.
This applies to whatever in-house monstrosities get built too, except that without docs or a million eyeballs to judge whether a workflow makes some sense to an outsider.
It is no fun when an open-source framework pushes a new major version, then deprecates the version you were on, or dependencies fail to find matching version, and you beg github developers to fix the bug and your issue sits open for months and is then closed with no warning.
There are at least two things wrong. One is those things is missing standard functionality (eg, leftpad), and the other is a failure to maintain appropriate hubris (eg, is_even).
Or three or twelve of them.
Frameworks force you into a paradigm. Yes, to spin up quicker, get new engineers onboarded quicker, etc a framework will do the job. But it's not a free lunch. In exchange for this you are hopelessly intertwined in the author's idea of what makes something good. You're bound to their bugs, you're bound to the nuance, and most importantly you're developing knowledge of a framework, and not what the framework does. Some major frameworks, for example React, might pass the smell test as "just use it". This is the exception and not the rule mostly guided by the fact that Javascript is the absolute hottest garbage to ever grace our unfortunate field.
For some people this exchange is worth it. I'd generally recommend a company use pieces of a framework where they can. But to use a whole framework? Let's put it this way, early in my career I was involved in more old rails projects than I care to admit that were FILLED with kludges because no one could justify actually doing it right and in-housing most of it. I've been involved in projects that were hopeless dependent on the ORM-du-jour that were completely hamstrung because the ORM didn't take full advantage of the query planner, or lacked the necessary constructs for complicated queries, etc. ORMs are the worst, in my opinion, because the only other option is to then _force_ the ORM to do what you would've done originally (defeating it's purpose). General purpose web frameworks are close runners up (and related).
Your 5 points are nice sounding, and you probably get a lot of CTOs and engineering directors to agree with you. However, as a man in the trenches I can't say anything but you're fortunate to never have been on something complicated enough that a framework hamstrings you. Rescuing a project from a decision made by some framework-first shortsighted genius is the reason we get paid as much as we do.
I've had fairly good success with what I like to call "framework libraries". That is, all or most of the functionality of a framework, but composed more as a library (or rather, a set of libraries) than a framework, giving you the best of both, mostly. ORMs are often given as an example, but I rarely found them as issue as most I've used have an "escape" to allow you to just use SQL if need be. The bigger problems with frameworks are when you want to compose some application in a way the framework doesn't really like (this can be a problem in Rails, for example).
I aggressively push things to libraries whenever I work on something; sometimes they can be made public, sometimes not, but even when private it helps a lot in mentality of people, especially with certain kind of devs.
If you do it yourself, you're bound to your own bugs. When they have bugs, it's fixed by a team of highly skilled contributors.
Not using frameworks is just an ego problem, or a lack of skills.
Three months later we find a few game breaking bugs. Do the right thing and send a report and hope the author's fix things. Things didn't get fixed in time. Now over budget and over the time limit I have VPs of engineering breathing down my neck (as the lead at the time) for why things aren't getting done.
This is not an isolated case. You might not run into this problem using a mature framework (the problem then is being bound by the author's idea of a good architecture), but if you're needing something better and venture into other languages for your needs you will run into this at some point. "Highly skilled contributors" often work for free. Perhaps I'd agree with you if you meant some professional, paid, framework. But I have never had an experience where these "high skill open sourced contributors" fix bugs inside my sprint cadence. The implication that I have an ego and skill problem for not using a framework, but these so-called contributors are "high skilled" is insulting to not only me but the entire profession.
I'd imagine the nuance is in what kind of language you use. Lowest common denominator languages like Ruby, Javascript, etc (things that can be learned quickly in a code camp) tend to be dominated by framework-first-and-always people since frameworks can be parsed easily by seat warmers. Engineering management loves frameworks because it takes the thinking out of writing code. The maligned view of engineers as people who will "screw things up when they're left to their own devices" is so pervasive they've even got other engineers parroting it.
If you believe it's a "lack of skill" or "ego" problem to honestly not use a framework in some cases you should probably stop hiring idiots. An actual "high skill" engineer will evaluate the cost and probability of needing to break out of a framework.
Using a framework you're not familiar with to build a project on a deadline is absolutely stupid.
Using a new framework without wide community support for, that you're not familiar with, and for a project is mind-blowingly stupid.
I'm hoping that you were a junior engineer at the time that didn't know better and that you learned from it.
If you use a really good framework, no framework is vastly worse.
From one day to the next there will probably be one or two frameworks which dominate your work. If it's really good you'll have an overall positive impression of them and vice versa.
Some brilliant folks are just bored by usual rather generic work, and their idea of 'fun' is to keep reinventing the wheel that specifically fits current problem. Actual benefits to business be damned, intellectual fun is more important. Once those folks leave (and they always leave eventually), its mayhem for the remainder of the team/company.
For me, this kind of 'autistic' brilliance is overall just professional incompetency that shows over long time period and I avoid hiring such folks. One can babysit them and steer them but its rarely worth it within usual teams.
I could write a dissertation on this statement alone. But let's use two examples. Python and Node. Both are very "never do anything yourself" languages. Lots of libraries, even more frameworks. What's the result?
1. CVEs all over that place that effect nearly anything people touch.
2. Library creep. Pulling in one library or framework pulls in the entire planet.
3. Libraries and frameworks exist for absolute trivia. Node is famous for this, including stupid packages that literally just color text (and not in a meaningful way like a logger).
So in exchange for avoiding your alleged "autistic brilliance" you increase your attack surface 10 fold. I use libraries all the time, I am absolutely sure to limit their scope as much as possible. I won't use libraries for trivia, and I evaluate frameworks extremely carefully. It's kind of funny how often your opinion is parroted in startup forums but for some reason I keep making more money every year despite every signal pointing to me somehow being in the class of engineer that are, according to you, better off without a job.
Companies are run by idiots. The hubris you show is the same hubris a VP of engineering shows having last programmed 10 years ago. It shows a complete lack of nuance and understanding of the engineer.
> 3. If you have a small team that hires slowly, it's relatively straightforward to bring new devs up to speed on "the way we do things." if you are hiring rapidly and/or have a large team, the more bespoke things you have, the harder it is to maintain them.
I disagree that framework or no-framework is the distinguishing characteristic. I do think that the quality of the code base, documentation, and onboarding plays a role in how fast devs get onboarded. Anecdotally, the only framework-based projects I've signed on to ended up incurring more onboarding time because I had to learn the framework, how the framework does things, and then how the team does things in the framework. All of this "how" is a step before "why", of which, every step eventually needs to be repeated over the course of my tenure in order to be successful.
> 4. Over time, everything degrades. In the long run, many framework-free applications either get walled off as "legacy" apps with new work done in separate services, or replaced outright. If it makes you money before that happens, you win. It is not necessary to try to design architecture that will last for centuries.
I've personally never seen this in any language except Java. Spring might as well be Java at many companies. The bespoke applications stay around, in my experience, because:
- They exactly match the business requirement and that requirement doesn't change much
- People don't know how to work on them or the product has little funding, probably because of the above reason
- The company has hired a team to maintain the product that have not moved
I've also seen where companies try to replace something bespoke with something written in a framework where the budget expands multiple years in a row and the project never completes because it's impossible to make the framework do what the bespoke product did completely.
> 5. My last and--to me the most significant--observation is this: You want to pay the majority of your attention to the code that has the greatest impact on your desired outcomes.
To me, this reads as, "we should spend the majority of the time focusing on our core competencies". I've heard this time and time again in this industry and no matter what way I've heard it explained I've never liked it. Businesses that only stay in their core competency, or narrowly define their competency, often stagnate with time. There's a lot less opportunity for organic business growth with that mindset. They'll also have little expertise to solve problems as they scale, other than through purchasing, because they only have knowledge that serves their core competency. The businesses I've seen become most successful alongside strong technical success were businesses that encouraged employees to innovate and experiment in new ways on a rhythm, allowing that innovation to inspire and percolate when it finds a strong usecase.
This is one of the most interesting replies, thank you.
The pitch for a lot of tools—be they frameworks, libraries, languages, &c.—is that if they’re popular, you get to hire people who arrive already knowing the basics of how things are done.
The reality is that popularity waxes and wanes, so when people are evaluating a tool’s fitness for purpose, they sometimes have to read tea leaves to decide if it’ll pay off or not.
A company making several such wrong bets in a row often has a trail of poorly supported ancient technologies lurking around. They still work—Joel Spolsky famously said that code doesn’t rust—but it’s aggravating to onboard, there are few productivity advantages, and sometimes the same thing is done three different ways because the company made two “wrong” bets before making the bet they currently think is “right.”
Would things be better had they just done their own thing and stuck to it? Possibly, I tried above NOT to make a claim that a popular framework is either the right thing to do or the wrong thing to do.
But it is good to read your comment pointing out that sometimes, a popular framework isn’t popular enough to harvest the benefits for people onboarding.
Not really true. Sure they add some, but the alternative (libraries) also add weight. So the question should be: do FWs add more weight than using libs directly.
There are some FWs in Rust where the weight is very minimal. That said the FWs are also very minimal.
not sure what framework-free has to do with. I'd remove the word "framework-free" and it would still be just as true
Yet a nicely designed, simple, custom half-framework is cheaper to maintain than a bloated popular framework.
Of which you are the creator and expert, and have complete control and insight, and can change it in any way you want any time. It is in 100% alignment with your goals at all time.
If you use a framework your organisation becomes incredibly complex, because you are now actually competing against the needs of other companies, your competitors, which are also influencing the framework.
Your software is custom made for your organisation, it's not mass producing identical systems on an assembly line, so it doesn't make sense to share a common platform like you do with cars. And even if you did, this platform would be a joint venture, and absolutely not made by a subcontractor, and no way in hell some random unpredictable volunteering hobby organisation.
And then you change a job and you take 80% knowledge with you and your now-past project is in deep trouble.
Not to mention that the interesting parts of your app should be the domain logic and workarounds and solutions used in it for business issues and historical layers of bussiness logic choices. And that a single person can take with them whether there's a framework or not.
> Not to mention that the interesting parts of your app should be the domain logic and workarounds and solutions used in it for business issues and historical layers of bussiness logic choices.
In my experience this has been a point in favor of OTS frameworks--the code you don't care about is handled by the framework, and you bring the business logic. But also, reading through this, I guess I don't understand your comment. Isn't the business logic in the code? How can a person take it with them?
Its not guaranteed. I've seen many developers spend lots of time trying to get the framework they're working in to cooperate or dig through bad documentation. Framework authors are fallible too and general-purpose software is really hard to get right.
I wonder if some of the disagreements in this thread are just like, people in favor of frameworks used Rails/Django, people against them used Spring/Struts.
> Framework authors are fallible too and general-purpose software is really hard to get right.
Yeah, I think that's solved by the "market". There was a big explosion of Python frameworks in the aughts: TurboGears, CherryPy, Pyramid/Pylons, Zope, web.py, etc. etc. Lots of stuff. The ecosystem now is Django/FastAPI (Flask/Tornado legacy apps are either stuck or moving to FastAPI IME). Django got it right.
But more broadly, what are the odds a bespoke framework will do it right? Will you think up a new way to organize controllers, or to abstract auth, or to manage database sessions, etc. etc. etc. That sounds like a nightmare to me; just let me focus on the business logic please, haha.
The market will settle on "good enough for the average usecase".
> But more broadly, what are the odds a bespoke framework will do it right? Will you think up a new way to organize controllers, or to abstract auth, or to manage database sessions, etc. etc. etc.
Some of this is a nightmare indeed (e.g. dealing with any web security stuff). Other things are very straightforward, especially when you don't have to deal with 1000 other people's use cases but only your own.
> just let me focus on the business logic please
We all want this. The question we should be asking is do we spend more time fighting a 3rd party framework or implementing our own. The answer may well be we'd spend more time implementing our own - but its still important to be aware if things start to go south.
> ... fighting a 3rd party framework ...
Can you give some examples of this? I'm personally finding it hard to come up with examples where this is a significant problem. The closest I can get is I worked on a Django REST Framework project where we went all-in on serializers, but then ripped it out because performance wasn't where we wanted it to be. But it's pretty easy to not use serializers in DRF, so it wasn't actually significant.
- Angular v1. Scope, transclusion, watchers, directives, DI and things randomly breaking.
- Almost all of the modern devops configuration tools. Would be easily replaced by some very basic typescript functions / libraries and Deno. In fact, cdk8s (which is typescript) comes with a mandatory jsii layer included, adding about 150MB of node_modules. This layer translates between the TS API and other languages you might use (Python etc). You get it even if you don't use the other languages and it has measurable impact on e.g. CI run times
- Bazel (another "build framework"). You just wanted some basic build caching, but get to do all the work for perfect hermeticity instead, which includes things like different directories, dealing with symlinks and dealing with tools that handle those symlinks poorly.
Its really, really easy to pick the wrong tool(s).
But is it a reasonable alternative to build an alternative to webpack yourself? Or Angular? I would bet some people have tried/done this, and also have some frustrating experiences.
My point is I think you have to be _very_ careful when deciding to take on a big engineering project, like making your own JS build tool. Will the improvements in devex really outweigh the engineering hour investment? IME the answer is almost always no, what usually happens is you get a half-baked, non-documented/tested system, and reading through this thread, I'm not sure any of the anti-framework people have shown convincing examples where they did better than an OTS framework.
Or if they did, they released it! Django is famously one such instance, or your Bazel example. It seems like they bet right, or did a lot of off-hours work (pretty sure that's the case w/ Django haha) to get it going.
Before code-splitting, yes, it was quite easy (not much harder than building a makefile). Webpack is difficult and complex because it has to cater to literally thousands of tools (https://www.npmjs.com/search?q=webpack%20plugin). An individual project can choose to use a simple js-only bundler and a copy command for static assets.
There was nothing to release there, however - we just wrote the equivalent of a makefile. It was not a big engineering project at all.
Would I do the same thing today? No, because of code splitting and because there are simpler, faster bundlers out there already (esbuild).
> Will the improvements in devex really outweigh the engineering hour investment? IME the answer is almost always no, what usually happens is you get a half-baked, non-documented/tested system, and reading through this thread, I'm not sure any of the anti-framework people have shown convincing examples where they did better than an OTS framework.
This is, where I think we differ. I think much more often than not, we already have half-baked, poorly documented systems which we insist on trying to use, even if the team is quite capable of building something better. This is also one of the reasons we have JS fatigue - its not because the language or even the browser somehow prevents something better from being built, its because we keep insisting on using poorly designed tools or tools designed to solve problems that large companies have but we don't really have.
If it's a matter of training up other people, we're just as well becoming experts in a framework
You are both right and also describing every single company I've seen. I haven't worked in a straight up software company, though. Maybe they have things better.
But I described the reality.
Yes you still have to know how it's glued together but at least there is still standardisation whilst still being flexible enough to swap individual libraries
Not a perfect solution but a good compromise in my experience
Use frameworks, use libraries. They will save you time, make your code less buggy, make it easier to hire other people.
Writing your own ball of mud is great for a hobby but not for business.
And even worse when these frameworks are open source and don't even have any accountable people at all, and god knows how many people working professionally are suddenly held hostage by some dude who just felt like going backpacking in south america for 6 months without giving any notice to anyone.
It'd be like saying I always make my own food from scratch — have you seen the state of the burger van down on the corner? You can't trust food made by others.
All frameworks aren't created equal — as with any tooling, you choose something based on the features of the framework but also the longevity, reputation and ecosystem built around it.
Thinking about this case more, this is exactly what you want from frameworks: compatibility guarantees. Frameworks break compatibility, but deliberately and slowly. Will your in-house framework do that? Will it announce and well document its intent to deprecate functionality in favor of new features? Will it find all the users of it across your enterprise and work with them on migration strategies? Will it build in deprecation notices for literally years? Will it build in tests for the bridging changes? Django does all of this, for you, for free.
No, I'm not. The guy who quit 2 years ago was. I've worked with custom frameworks, and while they where both clever and powerful with some quite cool features which would have been tricky to do in a more generic framework, they where also virtually undocumented, fragile, difficult to extend and slow to get people up to speed on.
I see this more often when the project is open source. For some reason we feel like when its not, we don't need to pay attention to the documentation. Nothing could be further from the truth.
To commoditize a critical (and formerly well compensated) skill for the purpose of outsourcing it to the country with the cheapest possible labor?
I broadly agree with GP here, but to round out some of their points:
- Frameworks take care of the parts of your application that aren't special. In the same way garbage collection isn't the value your company provides to customers, HTTP header parsing (or whatever) isn't either.
- Frameworks prevent your team from diving down architecture rabbit holes, or having to read a bunch of books on DDD, or what have you. This sounds like a small point, but if you tracked the number of expensive engineering hours spent disagreeing about where code should go, look like, and work, you would realize it's a pretty big one.
- Frameworks are tested way better than you ever could by thousands of users, actually documented, contain compatibility guarantees, and have security policies. To match this quality, your company would probably spend millions of dollars on eng hours. That's why company-specific frameworks don't match this quality.
- Frameworks make onboarding way easier. Most Python engineers know Django; most Ruby engineers know Rails. By definition, you can't hire engineers that already know your framework (even if you use something like Hexagonal, because no two implementations of this are alike). And again, because your in-house framework will be poorly tested/documented/etc., new hires will struggle. They'll also wonder if this is a career cul-de-sac: "I have 4 years of irrelevant experience in [bespoke framework X]" is not an enticing resume bullet.
> Your software is custom made for your organisation, it's not mass producing identical systems on an assembly line
This returns us to the palace vs. suburbs framing. The software you write is a super small percentage of the code that runs your app, all the way from firmware to CSS libraries. Good engineering is carefully deciding what code you will write yourself, because code isn't just implementation, it's design, buy-in, maintenance, documentation, and liability. Some enterprises are replacing a big chunk of that stack (Oxide or Cloudflare come to mind), but I bet 95% of companies are just building REST/GraphQL servers. That's not special enough to require a custom, in-house framework. You should just build the house the regular way.
Every sufficiently complex built-on-top-of-a-framework application contains an ad hoc, informally-specified, bug-ridden, slow implementation of workarounds to the framework's limitations, the overhead of parts it doesn't need, a nightmarish dependency situation, and as a cherry on top, it ends up based on a previous version, of the framework (as the latter's creators rewrite with different APIs every couple of years for no good reason).
Often you end up with an external framework, and an internal framework, and workarounds for both of them.... that are trying to evolve into their own framework
I’ve been using static site generators for my product site and app documentation and every time I set up a new dev machine e (or just update the generator) I’m in dependency hell because some plugins had breaking changes etc. that’s why I switched to my own bug ridden php implementation of the site/docs. At least I don’t get to spend the day googling for change logs, etc when I type ‘make’.
/rant over
And I would add to the title, that using a overly _hyped_ framework will harm the maintenance. Using some framework, simply because it is new or hyped, that will get teams and companies in trouble.
I observed many Rails developers and many apps (purely anecdotal, I wish I could run a real study), but the problems are the usual, the ones on top of my mind right now:
- database changes affect directly UI code, so a change in the DB requires changing code in a million places
- Rails devs don't know SQL as much as they should (often just don't know it), for a framework that so SQL-centered, it's weird
- hidden logic (callbacks)
These are very common problems with this framework and are well known to hinder company growth and ability to iterate.Would a home-grown framework be better? I cannot tell, but surely if the list of downsides when choosing a framework was written in the splash page, I would be way more scared. "If you use this framework, your db will 100% be coupled with your frontend" is a terrifying statement.
Given that, framework should be evaluated for their downsides too, but there isn't even a list of known issues.
Choice of a framework both attracts a certain type/subculture, and repels another.
Example: You have an old app that uses Backbone+CoffeeScript for the front end. If you stick with that, it will absolutely impact your hiring. But what about switching?
If you pick React, that will have one impact. If you pick Ember, that will have a different impact. And so forth…
The default "Rails Way" has a particular dynamic around REST and CRUD that makes it very easy to "Extrude the implementation into the interface," and, "Extrude the implementation into the API." It's what accelerates building a thing the first time, but later on it can work against you.
JM2C about this, but it's what I have observed and have lived through refactoring on multiple occasions...
2. If you have a talented team, that half of a framework can be much better than using a one-size-fits-all framework that is popular because it used to be lean and mean with a small surface area, but has grown over time to do everything for everyone, becoming a complex monster.
3. If you have a small team that hires slowly, it's relatively straightforward to bring new devs up to speed on "the way we do things." if you are hiring rapidly and/or have a large team, the more bespoke things you have, the harder it is to maintain them.
4. Over time, everything degrades. In the long run, many framework-free applications either get walled off as "legacy" apps with new work done in separate services, or replaced outright. If it makes you money before that happens, you win. It is not necessary to try to design architecture that will last for centuries.
5. My last and--to me the most significant--observation is this: You want to pay the majority of your attention to the code that has the greatest impact on your desired outcomes.
Using libraries and frameworks is like a business outsourcing things that aren't its core competency and also aren't competitive differentiators. Most software shops do not win by having their own framework or by not having a framework, they win by using something bog-standard and saving their attention for the part of their code that "moves the needle."
But that's only "most," and your business may be one of the few.