If there is such a thing as “web framework hopping” I did it in the past few months.
I was writing this very simple application part of a bigger project. All it did was compile information from a whole bunch of APIs.
First, I tried really hard to make WSGI, more specifically Flask, to work. Now, if you install flask[async], it allows you to use co-routines in routes, which is awesome. The best way to make a whole bunch API calls through HTTP is to make them concurrently. But the response times were high (even with concurrency), sometimes ugly Jo’s API would take 20s to answer. So that made it really hard for WSGI. Well, I suppose, If using WSGI was REALLY important, maybe for backwards compatibility, I could go with something like gevent or eventlet. But I just wanted something simple and clean.
Naturally, as I really liked Flask, I went for Quart. Well… AFAIK Phil Jones (author of Quart) is doing magic, and the future for Flask (when it finally supports ASGI properly) looks promising. But, for now things just look extra-hacky. E.g.: to access a the ‘name’ field in a form in Flask you do: request.form["name"]; In Quart (one-liner) is (await request.form)["name"]. Quart is trying really hard to push things forward, but it has too much baggage.
Then I tried Sanic. It promised to be unopinionated and flexible. Well, I spent three days just trying to make it work. Most of that time spent modifying the default behavior. Really, everything in it is all but unopinionated. It just feels like a “brand” web framework, if there is such a thing. It does all whole bunch of stuff that you don’t need and all that you need it doesn’t do. Also, weird things were happening with the built-in server.
Now at that point, I had just spent a week picking a web framework. I was frustrated. So, I decided to look what ASGI meant specifically and why was it so hard to write a proper framework based on it. So, naturally, I read this. My mind was just blown. WTF is it really that simple?! After two hours, the first iteration of µHTTP came to life. And I used it on our project. And for a while there, the air smelled nicer. But, it was a company project, so there was always another shitty feature to implement. And thonny (first name of µHTTP) wasn’t cutting it anymore.
So came Uvicorn, Starlette and FastAPI. Wow, I mean, wow. All other frameworks look like toys compared to Starlette. Starlette is unopinionated and flexible. But, is not simple. FastAPI seemed to solve that, making it “easy to learn, fast to code”. And it did. After rewriting part of the code base to play well with typing notations, things worked really well.
But, I just couldn’t forget thonny. I wanted to KISS him so bad. So, in a two-day haze I turned thonny into µHTTP.
Why µHTTP?
Stupid simple, seriously there are maybe 15 lines of “real” code in it. No external dependencies.
Extremely modular, as I mentioned in the docs, entire extensions can just follow the simple App pattern.
Very opinionated, to the point where it has no opinions.
Fast, because it doesn’t really do much.
Not about types.
I think it solved, cleanly, all the imaginary problems I had in web development.
Great response, OP. Definitely save this and publish it somewhere.
You might be intrigued to learn that the original author of Flask released it as an April Fools project that wired together his two other popular Python libraries — werkzeug and jinja2 — into a single “microframework,” which he called deny.py. The reason it was a joke is because all he did was concatenate the two other libraries together and then write a thin wrapper which was the kernel of the modern Flask API. But this was over a decade ago (source). I mention this because when someone asks the question “why not flask?” today, it’s worth remembering that most people asked the question, to the author of flask, “why not django or bottle or web2py?” a decade ago. Sometimes to release something fresh and new, you need to ignore what’s already out there, and have a little fun. Good luck with µHTTP, OP, it seems cool!
I went to the github and after reading the README, was still left wondering the same thing as OP. Your response here was excellent, I recommend putting it somewhere that visitors to the repo can find it.
For commercial applications, straying away from the more popular options might not be wise.
For personal projects, however, this might be appreciated due to its simplicity and flexibility.
I’m not sure how this will go for Beeper, but I do think the fact that this iMessage implementation exists and that it works means that Apple will finally be forced to (a) take RCS seriously, which was already starting to happen; and (b) consider making the iMessage app x-platform (with functional Android and browser implementations, even if it requires an Apple ID to use). If they don’t do this, given that a high school student reversed their protocol and a startup launched a working x-platform commercial implementation (probably on a shoestring budget), it will be very hard for the governments of the world to believe iMessage’s insistence on being Apple-hardware-only is anything but an anti-competitive move.
Yes, in response to regulatory pressure, especially in the EU, they capitulated and announced RCS support would be coming to iMessage eventually. That is good. But there is always a background concern that they will seek to satisfy the letter of regulation but not the spirit.
For example: how much of the RCS standard to implement, whether to drag feet on roll out, whether to track the standard as it changes, and whether to diverge iMessage farther from RCS are still open questions inside Apple.
I think the ethical move would be for Apple to fully support RCS in iMessage, and also to make an x-platform opt-in iMessage app available across platforms, even if that x-platform app is tied to an Apple ID. Heck, there’d even be a benefit for those Apple users who aren’t all-in on using Apple on every single device. I think this release of Beeper / pypush / etc. will create some natural pressure for this outcome, which would make the iMessage network more akin to Telegram, Signal, LINE, etc. just with built-in support on Apple hardware.
Ironically, iMessage is (just barely) not popular enough in the EU for their monopoly regulation to kick in. But, iMessage is popular enough in the US for the same regulation to apply, but… the US doesn’t have the same regulatory framework. So, I’d say, this reversing work is even more important now.
Kinda like Steph Ango’s “don’t delegate understanding”. In the python ecosystem we’re blessed with the double edged sword of rich packaging. My default action is usually to search for a package to solve the issue. But you’re right! We should make space for creativity and let loose our curiosity. Reminds me of this quote from Paul Graham’s How to Do Great Work:
Curiosity is the key to all four steps in doing great work: it will choose the field for you, get you to the frontier, cause you to notice the gaps in it, and drive you to explore them. The whole process is a kind of dance with curiosity.
Staying curious about what lies behind the abstraction curtain spurs that creativity. Plus, who doesn’t enjoy spending less time reading CHANGELOG.md.
Sorry OP, everybody is fixating on your hot take on dependency injection and the actual message of your post about rejecting distractions got lost in the clever title and the snarkiness.
I heard you. To create novel insights and get those creative juices running it’s good to reject dependencies, travel light, and focus hard on solving a problem.
It’s unfortunate, but in my experience, this is what happens to most blog posts. You write about foo with an offhand example of how bar is analogous to foo, and then all the comment are about bar. Or worse, you write about how foo is good/bad/nuanced, but no one reads the piece at all and they just go off on their own preexisting opinions about foo with no engagement on why you think foo is good/bad/nuanced. Such is the life of a programming blogger.
In “programming articles”, some “authors” like to “quote” things a “whole bunch”, which is “annoying”.
But the main issues with this article is that it uses a lot of words to say almost nothing. TLDR - The author doesn’t like dependency injection, or dependencies. And sure, that’s fine. I don’t like dependencies, either. Nobody wakes up in the morning and says, “Hey, today would be a great day to go drag in a bunch of unnecessary software packages into our project!” (Although admittedly, more than a few js-based projects sure do seem to operate this way.)
But some developers work in the real world, where building Doom, creating Redis, or starting Monty Python isn’t on the menu. And in the real world, in which we’re not all John Carmack, sometimes you end up interfacing with other people’s code. Come to think of it, Carmack had to deal with other people’s code, too … back when he wrote Doom, he was supporting at least 3 different graphics APIs that I can remember (OpenGL IIRC, something from 3dfx that I can’t remember the name of – maybe the predecessor of Glide? – and the third one might have been some Microsoft API that became DirectSomethingOrOther). Regardless, those are dependencies.
This article just wasn’t particularly helpful in any way, in terms of dealing with the complexities in the real world of software development, or in terms of conveying information or knowledge. In situations where a tool like DI isn’t helpful, just don’t use it; it really is that simple. And just because you think that you’ve experienced one or more such situations, doesn’t mean either (a) that those are the only situations in existence, or (b) that a tool that was not applicable to your situation(s) should be discarded out of everyone else’s tool box.
The concept of DI is simple, easy to understand, and valuable for avoiding tight coupling. It’s not a silver bullet; it’s just a useful tool.
I appreciate your comment. I edited out the snark in the opening, which was a mistake, and not the point of the post in the slightest. And I also edited out the scare quotes wherever they were, because that was a stylistic mistake.
I also appreciate your point about how, sometimes, getting shit done means dealing with dependencies.
I also want to correct one thing you said. You said I don’t like dependencies. Far from it. I do like dependencies! I use them all the time. And my main programming languages are Python and JavaScript, which use them all the time.
My point is that vs the state you need for creativity, dependencies/tools can be like a siren song. They can make you think you’re making progress when you’re really not. Same for things like frameworks and code generators (more prevalent now with generative AI).
So, the point of the post (and I agree with you that I could have said it better, or with fewer words, or with better words), is that human ingenuity counts for something and to tap into that ingenuity, we might need to reject all our dependencies (for awhile).
I hope I didn’t come across too snarky. It wasn’t so much directed at you; I was really just irritated at the younger me, who stubbornly took so long to learn some of these simple things.
I’ve lived through many dependency hells, DLL hells, JAR hells, CLASSPATH hells, framework hells, etc. I’m not denying the existence of hell; I just want to balance the desire for “avoid all dependencies” with the “I’ll just randomly grab a library that does that already”. Those extremes are both painful, from experience.
100%. I hear you. I’ve lived through those hells, too. I’ve also gotten quite a lot of mileage from amazing dependencies – the cited example of Redis, included! And countless wonderful Python and JavaScript libraries over the years – more mileage from the Python ones than the JavaScript ones, naturally 😉 … So, it cuts both ways. My post came from a place of realizing that, sometimes, you just gotta sit down and code it out! Which reminds me, Advent of Code is coming up…
Designing classes to have all their dependencies injectable by default is creating features when none are called for. If a class I am building has to use specific dependencies, and is not currently intended for re-use with other dependent objects, it should not be built to be flexible. Doing so results in code that is harder to trace its behavior since there is more indirection. It also means that the code reflects reality - it’s only being used with a single set of dependent classes.
In terms of it making code “more testable”, this highly depends on the language and what can easily be done when testing. In Java, as far as I know, you cannot mock the new operator so you do need to inject dependencies you wish to mock in a test. In Ruby, there is no need for this, since new is a method call you can mock.
In terms of “more modular”, this is a subjective notion and it’s not clear to me that “more modular”—by any definition—is always desired. Highly abstracted codebases can be extremely hard to debug or understand, so there are times when less module, more explicit, more verbose, more concrete code can be a benefit.
That all said, if a class does need to be flexible, DI is great, and far better than e.g. boolean flags or any other way of making the class flexible.
In my experience, code benefits from being as concrete as possible (but not moreso).
Indeed! One of my favorite (oldie but goodie – and somewhat spicy) talks on this topic of “module overdesign” is “Stop Writing Classes” (on YouTube) by Jake Diederich, a core developer in the Python community.
In it, he lays out a few examples where a simple “plain old function” might have been the simplest solution vs a class, and suggests ways to use and design classes responsibly.
The article discusses dependency injection (DI) and dependency management (DM). DI is essential for modular code design. While Java DI frameworks like Spring are complex, Python and JS can implement DI easily without frameworks due to their dynamic nature. It’s unclear why the article relates DI and DM. While languages like C++ lack robust DM, Python has added tools like Poetry and Pipenv to improve it. Overall, the connection between DI and DM is unclear.
I think this is an astute comment. FWIW, I didn’t mean to draw any connection between DI frameworks and DM frameworks except insofar as they are both ways that programmers spend a lot of time not coding on their core problem and instead researching/adopting/integrating external tools/dependencies. Since that is what the article is about: sealing oneself off to focus creatively on your core problem, using the playful term “dependency rejection.”
You’re also right that lightweight DI in isolation is just a code organization technique and nothing harmful about that, especially in dynamic languages where it is supported a bit more “natively.”
dependency injection isn’t about some future benefit, it’s a benefit to the programmer today. it allows testablity, it allows modularity, and it’s not tied to any sort of complex framework like spring boot. many languages and ecosystems use it to great effect. go and zig are two conceptually simple languages that use dependency injection (when you’re using net/http/httptest you’re using dependency injection, and every zig allocator is an exercise in dependency injection).
as for the Build or Buy question, that’s a tale as old time, but the C language has caused far more harm than good here. dependencies are such a pain in the ass to use in C that people don’t use them, but that doesn’t automatically make them go read the latest academic papers and use a novel data structure, most of the time it just means they use a shitty, inefficient linked list when any other sort of container would be better
On DI, I think you’re right, if defined so narrowly as “take an instance as an argument to your functions,” then, sure, it is not a particularly harmful! But this is the lightest weight approach to DI out there, a lot of “DI frameworks” take much heavier approaches, such as requiring objects implement “service/injector” protocols and run inside a “container,” especially in more static languages like Java (Spring/Guice/etc.). But also, that opening discussion was just meant to lay out a contrast between “thinking up front really hard about your dependencies” vs “rejecting your dependencies.” I regret making the opening take so snarky, though – point noted. 😁
On DI, I think you’re right, if defined so narrowly as “take an instance as an argument to your functions,” then, sure, it is not a particularly harmful!
What else should it mean? You can’t just go and redefine an existing term. Heck, you even quoted Wikipedia which specifically uses that definition.
If you cannot get your definitions straight, then I can only doubt the rest…
What else should it mean? You can’t just go and redefine an existing term.
I’ll defend the author on this one. I basically only hear about dependency injection in the context of heavyweight frameworks that demand you hand over the entire program to them. To the point where the term basically means spring. They aren’t redefining usage here, they’re reflecting a real definition that is used out in the world (assuming you’re a descriptivist rather than a prescriptivist, you just kinda have to roll with these).
Yes, exactly. This is what I had in mind. I am actually quite pleased to learn, on this thread, that the term “dependency injection” has been reclaimed away from the “Inversion of Control framework” use cases and toward the more lightweight use cases.
I never worked with one of those frameworks and don’t know why they exist or the pains they inflict. I had to come to the comments to find out that’s what you’re arguing against versus DI, which I use extensively for testing and love with Rust and Ruby alike.
Fair enough! The essay is not meant to argue against DI, so much as to argue for “dependency rejection,” a creativity-spurring thing of programming – as much as possible – directly in your problem domain instead of constantly hunting around for dependencies, tools, and frameworks that might help. The “c” tag was only because a C project and its author (Redis / antirez) is used to illustrate.
In my personal idiolect, passing in your dependencies as arguments is “inversion of control”, which is a very useful technique that I think developers naturally gravitate towards even if they don’t know that specific name. Using a massive XML file to configure which dependencies get passed in where is “dependency injection”, which I’m much more unsure about.
In programming, there is a technique that is almost the opposite of this, called “dependency injection.” It’s a way of worrying, up front, about how to split the modules in your program from other code. You aim to give the “future you” a vague “future benefit” of being able to swap out a module dependency later.
When writing code, I don’t use dependency injection to convey a “vague future benefit” to my “future self,” rather I’m almost always helping current me make my code testable as an isolated module so that current me doesn’t need to worry about my APIs being built on top of shifting sands.
To me, dependency injection is largely about the initialization problem with a complex object graph. Can you program without it? Sure. But it is a good and useful solution to a not uncommon problem. The author’s misunderstanding of what DI is undermines whatever useful point they are trying to make, and doesn’t give me a lot of interest in digging for it.
I am of two minds here, split on how the DI works. When this is “automatic” that is not written out in your codebase somewhere, it’s the single most detrimental practice in code readability that I see in products I’ve worked on. The issue is that very few systems have perfect names and what you are led to believe is the object graph is never what it actually is. The defense against this argument is usually something along the lines of “get gud”, which is not very pragmatic in collaborative environments.
However, when the graph is explicitly built and all the units uses DI you instead get a very compact overview of the system as well as excellent test ability, at the cost of writing maybe a few hundred lines of factory methods. If this is hard, your design is probably bad and should just “get gud”.
In case it’s helpful, my original quick description for DI in this post was “a way to formally split up modules in your code and let you initialize and swap them at runtime.” I revised it to the perhaps snarkier current version only because the post is not at all about dependency injection, and I was describing some of the worst forms of DI (e.g. DI frameworks and “Inversion of Control,” mentioned in the footnotes) to draw a stronger contrast for “dependency rejection,” which is what the article is actually about. The article is also not (entirely) about programming.
p.s. I’ve used DI plenty, too. In fact, I once worked on a project for 3 years where the bulk of code was running inside the Spring Framework. (Yes, shudder … This was years ago and Java/Spring were the rage where I worked.) So that colors my experience. I appreciate your feedback though and now regret, a little, not toning down the snark here, as commenting on modern lightweight uses of DI was not the point of this post.
(Update: I edited the snark out of the submitted post a little bit by getting rid of the scare quotes, without changing the basic gist of the opening. I also explicitly mentioned “dependency injection frameworks” in the next para, since that was my real target.)
I revised it to the perhaps snarkier current version only because the post is not at all about dependency injection, and I was describing some of the worst forms of DI (e.g. DI frameworks and “Inversion of Control,” mentioned in the footnotes) to draw a stronger contrast for “dependency rejection,” which is what the article is actually about. The article is also not (entirely) about programming.
So I agreed with the article’s spirit, but was also confused by the snarky take on DI. Not because I haven’t seen bloated over-abstract versions of it, but because the good version of DI, as I see it, is precisely in line with what you are arguing for. One of its main benefits is forcing you to reckon explicitly with every dependency you take on, so you can’t lie to yourself about them, and this creates beneficial pressure to use fewer dependencies.
I’m with you. It was simply a mistake in my writing in the original published draft to be snarky on that topic. I was thinking of the “overwrought DI frameworks” while the writing only referenced “dependency injection.” Thus the cleanup. 😁
So the problem here is mainly rhetorical, by which I mean, the art of rhetoric, of persuasive writing. A technical metaphor for a non-technical issue will often get you mired in a technical discussion (like this) that misses the point. A non-technical metaphor for a technical point usually doesn’t have this problem. If you want to make a subtle point, you might want to turn down the bombast/clickbait. People, especially lobste.rs readers, will still read and enjoy your piece, but if you start from a strong black-white position you invite the “well, actually” crowd to come and undermine it.
I agree. Lesson learned. In a lot of ways, it was an honest mistake – the opening had no snark at all in my original (private) draft, and, for who knows what reason, I added it in during my last round of edits. Sometimes your writer brain just doesn’t get it right. I appreciate the comment – and I revised the post, accordingly! I only regret inflicting this writing error on the lobste.rs community, y’all deserve better!
For a first-person account, Eich and Wirfs-Brock wrote an extended narrative of JavaScript’s development in “JavaScript: The First 20 Years” (2020). Can be found via Internet Archive Scholar PDF here. I wrote a review for GoodReads which you can read here.
WordPress makes it easy to create a website or blog and pretty quickly switch away from thinking about web servers, web requests, JavaScript, HTML, and CSS, and instead focus immediately on content (at least, once installation/setup is done). That has always been its big UX win.
Similarly, Excel lets you focus on content (the numbers/figures/data) rather than on a programming language or analysis framework.
But, both WordPress and Excel offer escape hatches to full-blown programming environments (themes/plugins and PHP for WordPress, formulas/add-ons and VBA for Excel). This model has problems but certainly lets users focus on what they want to get done, while still having lots of customizability/extensibility options open to them.
I would say that WordPress is well positioned for a big design upfront website. You hire a contractor. They charge you $X0,000. You get a website and you have your semi-technical but not real web developer staff people manage it for N years until the design becomes too dated to bear and then you go back to step 1. It works really well in that niche. If you actually can afford to keep a web developer on staff, you could get a better product, but most people don’t want to pay that much money when their website is not a differentiator.
That option works well only if you also outsource the hosting. It’s very easy to create an insecure WordPress site. I believe the rise of static site generators was driven in a large part by this: WordPress convinced a lot of people that running scripts in response to requests was insecure. A number of WordPress sites I saw were faking this with a reverse proxy that had an allow list of pages so that WordPress effectively worked as a static site generator for the caching proxy layer.
WordPress also aggressively optimises for adding content through the web UI. I’m honestly surprised at how popular this is. I’ve used two flows when preparing blog content. The first is to write it in some markup language (DocBook XML if I’m unlucky, Markdown with some blog-specific extensions for semantic info if I’m more lucky), editing these in a git repo, and then pushing them. The second is editing in a Word document with track changes on and incorporating feedback until reviewers are all happy. Neither of these flows works well with WordPress. As far as I can tell, the only flow that does is to write the contents directly into their editor and post as a draft for internal sharing. That, in turn, doesn’t work well for a corporate site where the people with access to the site are not the ones producing contents.
Neither of these flows works well with WordPress. As far as I can tell, the only flow that does is to write the contents directly into their editor and post as a draft for internal sharing.
I have it on reliable sources that what works remarkably well is copy-pasting from Google Docs or even Microsoft Office. So what usually ends up happening is that posts get drafted on Google Docs, email chains with Microsoft Word documents and so on, and when it finally gets approved, someone copy-pastes it. There’s a little post-factum cleanup (e.g. <strong> tags) but that kind of hurdle seems to be considered acceptable. It sounds horrible but if I’m being honest it sounds less horrible than any “let’s get people who aren’t nerds to write Markdown” story I’ve heard.
WordPress is one of the things that comes closest to the “it’s like Word but for web” workflow, which adequately serves an uncanny proportion of web users. It certainly doesn’t work for large corporate deployments where, by necessity, whoever writes the content can’t get within six feet of the web server. But, much like small personal websites of tech-minded users, that’s a small enough niche that’s adequately served by other platforms.
I’m a big fan of static deployments just because it’s cheaper and generates a lot fewer security-related headaches. But even static website generators that are touted as easy to use, like Hugo or Jekyll, are still so contrived that they’re nowhere nearly adequate for people who don’t enjoy tinkering with technology.
(At the risk of having my lobste.rs membership unilaterally withdrawn, I want to say that I’m an unashamed FrontPage apologist :-D).
I have it on reliable sources that what works remarkably well is copy-pasting from Google Docs or even Microsoft Office.
That wasn’t my experience. All of the formatting got horribly mangled and required careful side-by-side comparison of the two to reproduce the original.
If that flow actually worked reliably then I can see WordPress working well for non geeks.
It’s probably specific to formatting requirements. In my experience, copy-pasting stuff from Google Docs is fairly reliable as long as you stick to paragraphs, headings (minus some <strong> tags), lists and default-formatted tables. If you need more advanced formatting, you are, indeed, quite screwed.
However, paragraphs, headings and lists adequately encompass the needs of a large percentage of Internet users. Furthermore, advanced formatting features (in-page excerpts, extended quotes) are theme- and design-specific enough that markup languages tend to handle them rather poorly anyway; more advanced systems will take you 90% of the way, but still leave you dealing with the extra 10% by hand, at a significant, and often non-transferrable learning cost.
Google Docs works much better for this - given it has more limited formatting. Word formatting doesn’t even work reliably between versions of Word (a while back I tried opening a resume created in Word on Windows in Word on macOS to less than impressive results) so there’s little surprise it doesn’t play well outside of Word.
I briefly worked for a company recently that was all-Microsoft all the time. After years of using Google Docs for collaborative editing I was absolutely shocked how bad Word (desktop and online) are for this. I have no real love for Google or proprietary solutions in general, but they have gotten online collaborative editing about as right as I’ve ever seen it implemented.
Most people don’t pay for good hosting and if you follow a defunct WordPress blog in RSS long enough, it will eventually become a spam site, with the original owners blissfully unaware.
WordPress definitely falls short when it comes to multi-user workflows where content needs more than a cursory review by more than one person. I’m also not aware of any open source tooling / CMS that does this well.
I have heard tell of proprietary systems that handle it well, but neither WordPress nor Drupal nor static-site generators are good at a real editorial workflow. Static site CMS quickly lose their charm for me when having to deal with a bunch of images and the Markdown workflow is awful for any real editorial workflow that requires tracked changes and input from multiple stakeholders…
The closest for me is editing in Google Docs and then pasting into WordPress. It handles copy/paste from Google Docs passably well, though Google Docs falls short in not handling custom styles and AFAICT still suffers a lack of code styling.
What I really want is a fully open source start-to-finish publishing tool chain / CMS that starts with composition and allows for a real editorial workflow with approvals and scheduling.
Is the way to interpret this table that: “C is the programming language most amenable to LLM based completion, and TypeScript the least?” (Of the considered set, of course?)
Oh nah, the sort is alphabetical. I’m drawing my conclusions from the median score, lower is better. But I’m also not sure of my interpretation. I’m just some guy.
Ah, I see. It’s an interesting question, which programming languages are more amenable to this sort of completion. I always assumed that it would be, “Whatever language has the most code examples that the model can use as a training data set.” (Thus maybe HTML, CSS, Python & JavaScript would be winners, based on open source popularity.) But then I thought about it a bit more and I suspect your hunch is right that languages that are more regular / static might have an advantage. One thing that was a bit humbling for me to realize was that LLMs, in some way, have an easier time completing code than natural language since code follows very strict syntax and parser rules, at least compared to fluent English language. Combined with the eventual (inevitable) step that they can train the code generation models on the basis of actual compiler/linter output, and I imagine LLMs will be even better at generating working and fluent code than they are at generating fluent natural language.
I did a deep dive and it has a lot of things I’d want from a Google Groups replacement.
OP wrote this, though:
It’s also tempting to use GitHub Discussions since all these projects are developed on GitHub anyway, but I think this tendency should be resisted. GitHub is wonderful now but fundamentally proprietary, same as Google Groups.
I’m glad this was posted, because John Gruber has such different software values than I do. He seems to think of app development as being akin to making films (he even has a Kubrick quote), where meticulousness, look-and-feel, and polish matter much more than utility. He judges other pieces of software the way a filmmaker judges other films – he’s looking for artistry. But I view software as a utility first, and artwork second. And especially so for software running daily on my pocket computer (smartphone).
Meanwhile, many of my core software values don’t get a mention from him. Like the fact that there is way more open source software for Android than for iOS, and this goes down to every layer. Or, the fact that Android’s developer toolchain is entirely x-platform, allowing developers to tweak and modify software regardless of what desktop operating system they use.
I love Apple’s design values. When I have my design cap on, there’s a flow of admiration in the direction of macOS and iOS. And I even participate in the Apple ecosystem a little, with a Mac Mini & iPad. But my daily developer workstation is Linux, and my daily phone is Android. Thinkpad X1C and Pixel 7, because I do care about well-designed utility.
And both have f/oss software, programmability, and utility as their core values, aligned with mine. Thus, for me, and for many like me, that’s the show.
Now… when I’m recommending unfussy hardware/software for my non-techie friends & family? Sure, it’s the Macbook Air and iPhone, then. But I’m really glad a choice exists on the market for people like me, and I’m not sure what value there is in bashing the other side just because it doesn’t share your values.
The conclusion you don’t state, and perhaps don’t draw, is “the iphone apps that focus on look-and-feel are less functional than the android apps that don’t”. I certainly don’t draw that conclusion.
Look and feel matters for functionality. Those of you who haven’t read Jef Raskin’s book should read it, particularly chapters 2-4. One example: How many per cent of the touches/gestures hit and act on an item that wasn’t there yet when the user’s brain decided to act? This is easily measured with user testing, videos and questions, and one of the chief ways to reduce the number is to add slick little animations and transitions, so that touch targets don’t appear suddently, but rather slide in, grow, shrink in ways that the brain use.
Yes, I don’t draw that conclusion either. I think iOS and macOS apps are perfectly functional – and sometimes moreso than Android or Linux counterparts. But I don’t think John Gruber was treating good design as being in service of function. He was treating good design as a showcase of craft and artistry. (Perhaps even of commercial ambition, as he derides the Android Mastodon projects as “hobby projects”, while praising the iOS “commercial” ones.)
100% agree with you that Jef Raskin has some great thoughts on the utility of good design (many of which could benefit the f/oss world). There was some interesting work in this direction a few years back in the Linux desktop world by the (now defunct) non-profit Yorba.
Gruber is solidly from the background of Mac indie apps like Panic’s stuff, which place a premium on design and functionality but are also vehicles for sustaining small businesses.
That which we do is follow rules of thumb. We don’t reason from first principles, even when those first principles are important to us.
Our real goal is to build applications and services that serve the users well, which includes being low on frustration. Being low on errors and frustration is… being pleasant to use, which ends up being some rules of thumbs about animations and general slickness.
You may be interested in the work of Richard Sapper. He was the original designer of the first black Thinkpad 700c. He kind of embodies an alternative to the Deiter Rams school of design (which Apple follows closely) where every device is very solutions-oriented.
The numbers can’t really be compared to prior years, as others have pointed out, due to a change in the survey design.
But, why are so many developers encountering Linux in their day to day lives even if they aren’t running Linux as their main workstation OS?
For Windows developers, it’s the rise of WSL. Windows was always missing a great UNIX shell and now WSL provides it in spades.
For macOS developers, it’s native support for Linux VMs & containers as well as the rise of M1/arm. These two trends make it so that macOS’s BSD heritage and local terminal is a less comparatively useful proxy for local development (vs just running a local VM or container running Linux, which is now easy enough, and fast), whereas perhaps in past years the BSD heritage was good enough to e.g. run Python, Ruby, or Node.
For all developers, Linux is the standard deployment environment in the cloud, whether you are using Amazon EC2 or Google GCE or something else like DigitalOcean. Even developers running Linux workstations find a need to virtualize and containerize Linux environments.
For all developers, IDEs have gotten better at working with remote Linux machines, or local containers. See VSCode “Remote” extension, and private networking tools like Wireguard, Tailscale, ZeroTier.
Finally, Linux has showed up in a lot of “long tail” hardware use cases, such as Raspberry Pi, Android, NAS devices, Steam Deck, etc.
So I wouldn’t really call 2022 the year of the Linux “desktop”, but I wouldn’t be surprised if Linux is the “#1 #2 operating system”. That is, it’s not the OS everyone runs on their workstation, but it is the OS everyone runs in their workstation, from their workstation, or around their workstation. It’s the closest thing developers have to a “standard development & deployment OS” even while their workstations and desktop environments fracture on Windows/Mac/LinuxDistro lines. And if a developer has a homelab server or a favorite remote development VM, it is almost certainly running Linux and accessed via ssh.
Doing my first-ever Advent of Code. I completed day 9 of 9 yesterday evening. Have to tackle day 10 and 11 this weekend. I’m writing all the programs in Python first, and then, if I have spare time, writing a Zig version, as well. I did the Zig version for about 5 days so far. I’m also tracking some of my progress via Mastodon here.
I think every generation of programmers feels nostalgic for the “good old days” when they felt like they understood their whole stack and were working directly at a super low level. But I’m not at all convinced that it’s actually true that we once did.
For example, I got into web dev in the early 2000s with PHP and Perl on the backend and HTML/CSS/JS (“DHTML”) on the frontend. And at the time I felt like I understood the stack, but really I understood only down to about the point of the HTTP daemon, with a little bit of knowledge of what was going on over the wire. The internals of, say, Apache and then the underlying TCP/IP stack, operating system, etc., were all just opaque to me. They were commodity pieces taken off the shelf to do what they did and I didn’t have to worry much about them.
Today, we have a lot more commodity pieces to take off the shelf – that part, at least, is true. But I’m not convinced that it’s necessarily a bad thing, or necessarily separates us from the problems we’re working on. First of all, we have all those pieces because people ran into problems, figured out solutions that worked well enough for them, and then made those solutions available, often for free and with the ability to modify/improve. That’s a great thing and has absolutely advanced the state of our art by leaps and bounds.
More importantly: I feel like I am closer, today, to the actual problems I’m trying to solve than ever before.
Once upon a time, there were a lot more intermediate problems that I had to solve and that got in the way of whatever I actually wanted to do. I can think and reason about web applications and their constituent parts in ways that early-2000s me could not have conceived of. Back then I had to invent my own half-assed MVC-ish architecture because the big wave of modern backend frameworks was still just over the horizon. Back then I had to manually set up servers and install all the packages – HTTP daemon, database, cache, etc. – and wire them all together. Once upon a time I even was on a team that had to literally wire up and rack-mount our own hardware! Back then I had to do a ton of extra work that put distance between me and the actual problems I was hoping to solve, which tended to be things like features or bugfixes in a web app.
Today, I feel like there are fewer layers interposing themselves between me and the problems I’m trying to solve, precisely because so much of that stuff has been replaced by commodified solutions/components. Which does mean I’m working at a higher level of abstraction, much of the time. And does mean I’ve had to learn new patterns and ways of talking about them and how to work with the interfaces of the commodified pieces. But it doesn’t mean that I feel I’ve lost something or that it’s no longer fun or challenging to me.
(though I also am a long-standing believer in the idea that most people in most teams at most companies shouldn’t be trying to invent new tech from scratch in the first place – it’s usually a sign that things have gone badly wrong)
I liked this comment because it describes my own background, all the way down to the timing and anecdotal illustrations. (I, too, came up with Perl, PHP, and “DHTML”; I, too, racked my own servers.) And though I think you are right that every generation of programmers is delusionally nostalgic for the prior era’s “simplicity”, I also think you might be missing some of the traps in today’s programmer culture. Specifically, I came up in a culture of open: open web & open protocols & open source & open architecture.
It’s not a question of whether I knew my whole stack. That depended on my willingness and free time. It was a question of whether I could know the whole stack. And also whether I could contribute at any layer. And that’s what the web and LAMP and then Python & f/oss databases and so forth gave me. Since we’re of the same era, you know exactly what “closed” used to mean in that late 90s & early 00s era: Microsoft’s closed source development ecosystem. ASP and C# developers deploying to IIS and SQL Server certainly got things done for businesses, they didn’t struggle with much accidental complexity. But their stack was so damn proprietary, so damn unknowable. From the web server to the framework/language to the OS and so on.
Today, we have open source everywhere in the development environment, but there has been a precipitous and worrying rise of proprietary in the production environment, due especially to “serverless” style public cloud APIs. This should be seen for what it is: much closer to the Microsoft model of the 90s/00s than the alternative. And all the same concerns for developers apply.
(This is one of the reasons why, even though I am expert in AWS/GCP and a fan of each, my main use case for them is commodity compute, memory, and storage. I don’t want to rack physical servers anymore, but I still want it to feel as though I have a rack of servers sitting in a data center, running open source software I can comprehend. That I can destroy the rack and recreate it programmatically is all to the good, but I don’t want it hidden from me entirely for when my code has to run on it. For the compute & memory side, give me SSH access & full-blown Linux userland, or give me death!)
It was a question of whether I could know the whole stack.
Most people couldn’t, and definitely wouldn’t. At least if we’re using a full definition of “the stack”. From the web down to silicon. Any other definition of “the stack” is just stopping a little bit before we get uncomfortable. Why not include file system implementation? Or layer 1 & 2 network protocols? Or processor microarchitecture?
The beef with serverless, though, I agree. Back when I first started dealing with cloud, it felt like we could (and maybe would, in time) arrive at some sort of abstraction, even if just conceptual, of cloud, that would make which cloud you’re using more of an implementation detail. We never quite got there, and now it looks like we’re as further from it as we’ve ever been. And this forces you to bet not on technology, but on companies, which kinda rubs me the wrong way, sometimes.
I do love chatGPT but what I guess I’ve not seen yet is people pointing out it “plagiarizes” in the same sense as those art generation bots that caught a similar hype wave a month or two ago. Ask it how you would use Z3 to check two firewalls for equivalence, for example, and it spits out a slightly (although competently!) modified version of the blog post that I wrote on the topic: https://ahelwer.ca/post/2018-02-13-z3-firewall/
I guess since my blog is licensed under CC-BY-SA this is a violation of that license (and all the material it obviously read from Wikipedia) but I find it difficult to be too mad about it. I’ll probably start being mad when they use all this appropriated human endeavor to get it to convince you to buy certain products or hold certain political views.
I suspect that language models are very good plagiarists because every word, sentence, paragraph travels through the following high level translation: words => concepts, concepts => words. All the words that map to the same concepts across a large scale internet / wikipedia / stackoverflow / etc crawl act as votes, of a kind, for those concepts and their tangled web of relationships to other concepts. Then these very, very good natural language generation algorithms can take the concepts back down to words again, in fluent sentences and paragraphs. But the words generated by chatGPT won’t be the exact words read/plagiarized by chatGPT.
Think of it this way. Let’s say you read 3 essays describing the themes of The Great Gatsby. Then, two hours later, someone asked you, “write an essay describing the themes of the Great Gatsby”, but you no longer had access to those 3 essays you read. You’d probably write a plausible essay describing the themes of The Great Gatsby, even if you yourself had never read The Great Gatsby. Were you plagiarizing the 3 essays you read a few hours ago when you did it? Now imagine the same thing, but where it is not 3 essays but millions, and it’s not relying on human memory/brain, but on a very purpose-built set of content indexing algorithms and a very sophisticated natural language generator.
One way I’ve been thinking about it is that the algo has, in a sense, turned plagiarism into an art form. The algorithm’s goal is to not get caught merely returning a source document that has the answer. It also knows how to synthesize information from many different source documents. As neat a trick as this is, it is hard for me to see this not creating a long-term seed vs leech problem for internet content.
One way I’ve been thinking about it is that the algo has, in a sense, turned plagiarism into an art form.
It has always been an art form: On Bullshit. Skimming source material and quickly coming up with an intelligent-sounding essay that you didn’t believe – this was the skill in college, and you had to be smart to do it well. It is the skill of mimicing a way of talking, a way of thinking… at bottom, the skill of understanding the markers and heuristics that others will use to judge your fluency.
I feel this is the skill GPTChat possesses in abundance. Importantly, it is a different skill than true fluency (as the parent article attests).
I do love chatGPT but what I guess I’ve not seen yet is people pointing out it “plagiarizes” in the same sense as those art generation bots that caught a similar hype wave a month or two ago.
Woah, I haven’t heard of this. Do you mean like the training set is plagiarized, or that it actually outputs plagiarized works?
Yes the training set clearly includes modern artists who did not license their art for inclusion in the dataset, and you can ask it to imitate their style.
Getting an exact reproduction is unlikely because of the way the information is compressed.
Is imitation the same as plagiarism? I do not think it is.
Can you name specific artists whose work was included in those training datasets without appropriate license? I know Greg Rutkowski is one of the more imitated artists, but much of his work is uploaded to ArtStation which has a rather broad reuse license. Greg is also very good about adding alt-text which helps train the models.
Your Content may be shared with third parties, for example, on social media sites to promote your content on the Site, and may be available for purchase through the Marketplace. Accordingly, you hereby grant royalty-free, perpetual, world-wide, licences (the “Licences”) to Epic and our service providers to copy, modify, reformat and distribute Your Content
Although Emad claims that artist style imitation has more to do with the CLIP language model than the LAION image dataset.
I do wonder if something like chatGPT would develop a coherent political agenda, or if it would just regurgitate whatever was in its training data. Probably the latter.
As ever with things like this, why would anyone use this instead of flask, bottle, cherry.py and other micro frameworks?
Well, I don’t know about anyone.
If there is such a thing as “web framework hopping” I did it in the past few months.
I was writing this very simple application part of a bigger project. All it did was compile information from a whole bunch of APIs.
First, I tried really hard to make WSGI, more specifically Flask, to work. Now, if you install
flask[async]
, it allows you to use co-routines in routes, which is awesome. The best way to make a whole bunch API calls through HTTP is to make them concurrently. But the response times were high (even with concurrency), sometimes ugly Jo’s API would take 20s to answer. So that made it really hard for WSGI. Well, I suppose, If using WSGI was REALLY important, maybe for backwards compatibility, I could go with something like gevent or eventlet. But I just wanted something simple and clean.Naturally, as I really liked Flask, I went for Quart. Well… AFAIK Phil Jones (author of Quart) is doing magic, and the future for Flask (when it finally supports ASGI properly) looks promising. But, for now things just look extra-hacky. E.g.: to access a the ‘name’ field in a form in Flask you do:
request.form["name"]
; In Quart (one-liner) is(await request.form)["name"]
. Quart is trying really hard to push things forward, but it has too much baggage.Then I tried Sanic. It promised to be unopinionated and flexible. Well, I spent three days just trying to make it work. Most of that time spent modifying the default behavior. Really, everything in it is all but unopinionated. It just feels like a “brand” web framework, if there is such a thing. It does all whole bunch of stuff that you don’t need and all that you need it doesn’t do. Also, weird things were happening with the built-in server.
Now at that point, I had just spent a week picking a web framework. I was frustrated. So, I decided to look what ASGI meant specifically and why was it so hard to write a proper framework based on it. So, naturally, I read this. My mind was just blown. WTF is it really that simple?! After two hours, the first iteration of µHTTP came to life. And I used it on our project. And for a while there, the air smelled nicer. But, it was a company project, so there was always another shitty feature to implement. And thonny (first name of µHTTP) wasn’t cutting it anymore.
So came Uvicorn, Starlette and FastAPI. Wow, I mean, wow. All other frameworks look like toys compared to Starlette. Starlette is unopinionated and flexible. But, is not simple. FastAPI seemed to solve that, making it “easy to learn, fast to code”. And it did. After rewriting part of the code base to play well with typing notations, things worked really well.
But, I just couldn’t forget thonny. I wanted to KISS him so bad. So, in a two-day haze I turned thonny into µHTTP.
Why µHTTP?
I think it solved, cleanly, all the imaginary problems I had in web development.
Great response, OP. Definitely save this and publish it somewhere.
You might be intrigued to learn that the original author of Flask released it as an April Fools project that wired together his two other popular Python libraries — werkzeug and jinja2 — into a single “microframework,” which he called deny.py. The reason it was a joke is because all he did was concatenate the two other libraries together and then write a thin wrapper which was the kernel of the modern Flask API. But this was over a decade ago (source). I mention this because when someone asks the question “why not flask?” today, it’s worth remembering that most people asked the question, to the author of flask, “why not django or bottle or web2py?” a decade ago. Sometimes to release something fresh and new, you need to ignore what’s already out there, and have a little fun. Good luck with µHTTP, OP, it seems cool!
I went to the github and after reading the README, was still left wondering the same thing as OP. Your response here was excellent, I recommend putting it somewhere that visitors to the repo can find it.
Very cool. If you are wondering how far the modularity aspect can go, you might want to check out (my) Storage Combinators [pdf] [acm]
I’ll definitely see what I can learn from what you’ve done.
For commercial applications, straying away from the more popular options might not be wise. For personal projects, however, this might be appreciated due to its simplicity and flexibility.
I’m not sure how this will go for Beeper, but I do think the fact that this iMessage implementation exists and that it works means that Apple will finally be forced to (a) take RCS seriously, which was already starting to happen; and (b) consider making the iMessage app x-platform (with functional Android and browser implementations, even if it requires an Apple ID to use). If they don’t do this, given that a high school student reversed their protocol and a startup launched a working x-platform commercial implementation (probably on a shoestring budget), it will be very hard for the governments of the world to believe iMessage’s insistence on being Apple-hardware-only is anything but an anti-competitive move.
There was news a few weeks ago that Apple announced they’ll adopt RCS. Not sure what came first, but it’s already happening.
Yes, in response to regulatory pressure, especially in the EU, they capitulated and announced RCS support would be coming to iMessage eventually. That is good. But there is always a background concern that they will seek to satisfy the letter of regulation but not the spirit.
For example: how much of the RCS standard to implement, whether to drag feet on roll out, whether to track the standard as it changes, and whether to diverge iMessage farther from RCS are still open questions inside Apple.
I think the ethical move would be for Apple to fully support RCS in iMessage, and also to make an x-platform opt-in iMessage app available across platforms, even if that x-platform app is tied to an Apple ID. Heck, there’d even be a benefit for those Apple users who aren’t all-in on using Apple on every single device. I think this release of Beeper / pypush / etc. will create some natural pressure for this outcome, which would make the iMessage network more akin to Telegram, Signal, LINE, etc. just with built-in support on Apple hardware.
Hmm. A negative development today on the point of EU regulation:
iMessage will reportedly dodge EU regulations, won’t have to open up
Ironically, iMessage is (just barely) not popular enough in the EU for their monopoly regulation to kick in. But, iMessage is popular enough in the US for the same regulation to apply, but… the US doesn’t have the same regulatory framework. So, I’d say, this reversing work is even more important now.
Kinda like Steph Ango’s “don’t delegate understanding”. In the python ecosystem we’re blessed with the double edged sword of rich packaging. My default action is usually to search for a package to solve the issue. But you’re right! We should make space for creativity and let loose our curiosity. Reminds me of this quote from Paul Graham’s How to Do Great Work:
Staying curious about what lies behind the abstraction curtain spurs that creativity. Plus, who doesn’t enjoy spending less time reading CHANGELOG.md.
Exactly. I also really enjoyed that pg essay, thanks for reminding me about it! Also, hi, former colleague! 👋
Sorry OP, everybody is fixating on your hot take on dependency injection and the actual message of your post about rejecting distractions got lost in the clever title and the snarkiness.
I heard you. To create novel insights and get those creative juices running it’s good to reject dependencies, travel light, and focus hard on solving a problem.
It’s unfortunate, but in my experience, this is what happens to most blog posts. You write about foo with an offhand example of how bar is analogous to foo, and then all the comment are about bar. Or worse, you write about how foo is good/bad/nuanced, but no one reads the piece at all and they just go off on their own preexisting opinions about foo with no engagement on why you think foo is good/bad/nuanced. Such is the life of a programming blogger.
Yea, it was a good lesson for me, though! I appreciate your comment.
In “programming articles”, some “authors” like to “quote” things a “whole bunch”, which is “annoying”.
But the main issues with this article is that it uses a lot of words to say almost nothing. TLDR - The author doesn’t like dependency injection, or dependencies. And sure, that’s fine. I don’t like dependencies, either. Nobody wakes up in the morning and says, “Hey, today would be a great day to go drag in a bunch of unnecessary software packages into our project!” (Although admittedly, more than a few js-based projects sure do seem to operate this way.)
But some developers work in the real world, where building Doom, creating Redis, or starting Monty Python isn’t on the menu. And in the real world, in which we’re not all John Carmack, sometimes you end up interfacing with other people’s code. Come to think of it, Carmack had to deal with other people’s code, too … back when he wrote Doom, he was supporting at least 3 different graphics APIs that I can remember (OpenGL IIRC, something from 3dfx that I can’t remember the name of – maybe the predecessor of Glide? – and the third one might have been some Microsoft API that became DirectSomethingOrOther). Regardless, those are dependencies.
This article just wasn’t particularly helpful in any way, in terms of dealing with the complexities in the real world of software development, or in terms of conveying information or knowledge. In situations where a tool like DI isn’t helpful, just don’t use it; it really is that simple. And just because you think that you’ve experienced one or more such situations, doesn’t mean either (a) that those are the only situations in existence, or (b) that a tool that was not applicable to your situation(s) should be discarded out of everyone else’s tool box.
The concept of DI is simple, easy to understand, and valuable for avoiding tight coupling. It’s not a silver bullet; it’s just a useful tool.
I appreciate your comment. I edited out the snark in the opening, which was a mistake, and not the point of the post in the slightest. And I also edited out the scare quotes wherever they were, because that was a stylistic mistake.
I also appreciate your point about how, sometimes, getting shit done means dealing with dependencies.
I also want to correct one thing you said. You said I don’t like dependencies. Far from it. I do like dependencies! I use them all the time. And my main programming languages are Python and JavaScript, which use them all the time.
My point is that vs the state you need for creativity, dependencies/tools can be like a siren song. They can make you think you’re making progress when you’re really not. Same for things like frameworks and code generators (more prevalent now with generative AI).
So, the point of the post (and I agree with you that I could have said it better, or with fewer words, or with better words), is that human ingenuity counts for something and to tap into that ingenuity, we might need to reject all our dependencies (for awhile).
Thank you for the thoughtful response!
I hope I didn’t come across too snarky. It wasn’t so much directed at you; I was really just irritated at the younger me, who stubbornly took so long to learn some of these simple things.
I’ve lived through many dependency hells, DLL hells, JAR hells, CLASSPATH hells, framework hells, etc. I’m not denying the existence of hell; I just want to balance the desire for “avoid all dependencies” with the “I’ll just randomly grab a library that does that already”. Those extremes are both painful, from experience.
100%. I hear you. I’ve lived through those hells, too. I’ve also gotten quite a lot of mileage from amazing dependencies – the cited example of Redis, included! And countless wonderful Python and JavaScript libraries over the years – more mileage from the Python ones than the JavaScript ones, naturally 😉 … So, it cuts both ways. My post came from a place of realizing that, sometimes, you just gotta sit down and code it out! Which reminds me, Advent of Code is coming up…
Designing classes to have all their dependencies injectable by default is creating features when none are called for. If a class I am building has to use specific dependencies, and is not currently intended for re-use with other dependent objects, it should not be built to be flexible. Doing so results in code that is harder to trace its behavior since there is more indirection. It also means that the code reflects reality - it’s only being used with a single set of dependent classes.
In terms of it making code “more testable”, this highly depends on the language and what can easily be done when testing. In Java, as far as I know, you cannot mock the
new
operator so you do need to inject dependencies you wish to mock in a test. In Ruby, there is no need for this, sincenew
is a method call you can mock.In terms of “more modular”, this is a subjective notion and it’s not clear to me that “more modular”—by any definition—is always desired. Highly abstracted codebases can be extremely hard to debug or understand, so there are times when less module, more explicit, more verbose, more concrete code can be a benefit.
That all said, if a class does need to be flexible, DI is great, and far better than e.g. boolean flags or any other way of making the class flexible.
In my experience, code benefits from being as concrete as possible (but not moreso).
Indeed! One of my favorite (oldie but goodie – and somewhat spicy) talks on this topic of “module overdesign” is “Stop Writing Classes” (on YouTube) by Jake Diederich, a core developer in the Python community.
In it, he lays out a few examples where a simple “plain old function” might have been the simplest solution vs a class, and suggests ways to use and design classes responsibly.
The article discusses dependency injection (DI) and dependency management (DM). DI is essential for modular code design. While Java DI frameworks like Spring are complex, Python and JS can implement DI easily without frameworks due to their dynamic nature. It’s unclear why the article relates DI and DM. While languages like C++ lack robust DM, Python has added tools like Poetry and Pipenv to improve it. Overall, the connection between DI and DM is unclear.
I think this is an astute comment. FWIW, I didn’t mean to draw any connection between DI frameworks and DM frameworks except insofar as they are both ways that programmers spend a lot of time not coding on their core problem and instead researching/adopting/integrating external tools/dependencies. Since that is what the article is about: sealing oneself off to focus creatively on your core problem, using the playful term “dependency rejection.”
You’re also right that lightweight DI in isolation is just a code organization technique and nothing harmful about that, especially in dynamic languages where it is supported a bit more “natively.”
dependency injection isn’t about some future benefit, it’s a benefit to the programmer today. it allows testablity, it allows modularity, and it’s not tied to any sort of complex framework like spring boot. many languages and ecosystems use it to great effect. go and zig are two conceptually simple languages that use dependency injection (when you’re using
net/http/httptest
you’re using dependency injection, and every zig allocator is an exercise in dependency injection).as for the Build or Buy question, that’s a tale as old time, but the C language has caused far more harm than good here. dependencies are such a pain in the ass to use in C that people don’t use them, but that doesn’t automatically make them go read the latest academic papers and use a novel data structure, most of the time it just means they use a shitty, inefficient linked list when any other sort of container would be better
On DI, I think you’re right, if defined so narrowly as “take an instance as an argument to your functions,” then, sure, it is not a particularly harmful! But this is the lightest weight approach to DI out there, a lot of “DI frameworks” take much heavier approaches, such as requiring objects implement “service/injector” protocols and run inside a “container,” especially in more static languages like Java (Spring/Guice/etc.). But also, that opening discussion was just meant to lay out a contrast between “thinking up front really hard about your dependencies” vs “rejecting your dependencies.” I regret making the opening take so snarky, though – point noted. 😁
What else should it mean? You can’t just go and redefine an existing term. Heck, you even quoted Wikipedia which specifically uses that definition.
If you cannot get your definitions straight, then I can only doubt the rest…
I’ll defend the author on this one. I basically only hear about dependency injection in the context of heavyweight frameworks that demand you hand over the entire program to them. To the point where the term basically means spring. They aren’t redefining usage here, they’re reflecting a real definition that is used out in the world (assuming you’re a descriptivist rather than a prescriptivist, you just kinda have to roll with these).
Yes, exactly. This is what I had in mind. I am actually quite pleased to learn, on this thread, that the term “dependency injection” has been reclaimed away from the “Inversion of Control framework” use cases and toward the more lightweight use cases.
You would help us all if you clarify it in the beginning of your post, so that juniour developers understand that as well. :-)
I never worked with one of those frameworks and don’t know why they exist or the pains they inflict. I had to come to the comments to find out that’s what you’re arguing against versus DI, which I use extensively for testing and love with Rust and Ruby alike.
The post is tagged with “c” which doesn’t help.
Fair enough! The essay is not meant to argue against DI, so much as to argue for “dependency rejection,” a creativity-spurring thing of programming – as much as possible – directly in your problem domain instead of constantly hunting around for dependencies, tools, and frameworks that might help. The “c” tag was only because a C project and its author (Redis / antirez) is used to illustrate.
In my personal idiolect, passing in your dependencies as arguments is “inversion of control”, which is a very useful technique that I think developers naturally gravitate towards even if they don’t know that specific name. Using a massive XML file to configure which dependencies get passed in where is “dependency injection”, which I’m much more unsure about.
When writing code, I don’t use dependency injection to convey a “vague future benefit” to my “future self,” rather I’m almost always helping current me make my code testable as an isolated module so that current me doesn’t need to worry about my APIs being built on top of shifting sands.
To me, dependency injection is largely about the initialization problem with a complex object graph. Can you program without it? Sure. But it is a good and useful solution to a not uncommon problem. The author’s misunderstanding of what DI is undermines whatever useful point they are trying to make, and doesn’t give me a lot of interest in digging for it.
I am of two minds here, split on how the DI works. When this is “automatic” that is not written out in your codebase somewhere, it’s the single most detrimental practice in code readability that I see in products I’ve worked on. The issue is that very few systems have perfect names and what you are led to believe is the object graph is never what it actually is. The defense against this argument is usually something along the lines of “get gud”, which is not very pragmatic in collaborative environments.
However, when the graph is explicitly built and all the units uses DI you instead get a very compact overview of the system as well as excellent test ability, at the cost of writing maybe a few hundred lines of factory methods. If this is hard, your design is probably bad and should just “get gud”.
This matches my experience with DI as well.
In case it’s helpful, my original quick description for DI in this post was “a way to formally split up modules in your code and let you initialize and swap them at runtime.” I revised it to the perhaps snarkier current version only because the post is not at all about dependency injection, and I was describing some of the worst forms of DI (e.g. DI frameworks and “Inversion of Control,” mentioned in the footnotes) to draw a stronger contrast for “dependency rejection,” which is what the article is actually about. The article is also not (entirely) about programming.
p.s. I’ve used DI plenty, too. In fact, I once worked on a project for 3 years where the bulk of code was running inside the Spring Framework. (Yes, shudder … This was years ago and Java/Spring were the rage where I worked.) So that colors my experience. I appreciate your feedback though and now regret, a little, not toning down the snark here, as commenting on modern lightweight uses of DI was not the point of this post.
(Update: I edited the snark out of the submitted post a little bit by getting rid of the scare quotes, without changing the basic gist of the opening. I also explicitly mentioned “dependency injection frameworks” in the next para, since that was my real target.)
So I agreed with the article’s spirit, but was also confused by the snarky take on DI. Not because I haven’t seen bloated over-abstract versions of it, but because the good version of DI, as I see it, is precisely in line with what you are arguing for. One of its main benefits is forcing you to reckon explicitly with every dependency you take on, so you can’t lie to yourself about them, and this creates beneficial pressure to use fewer dependencies.
I’m with you. It was simply a mistake in my writing in the original published draft to be snarky on that topic. I was thinking of the “overwrought DI frameworks” while the writing only referenced “dependency injection.” Thus the cleanup. 😁
So the problem here is mainly rhetorical, by which I mean, the art of rhetoric, of persuasive writing. A technical metaphor for a non-technical issue will often get you mired in a technical discussion (like this) that misses the point. A non-technical metaphor for a technical point usually doesn’t have this problem. If you want to make a subtle point, you might want to turn down the bombast/clickbait. People, especially lobste.rs readers, will still read and enjoy your piece, but if you start from a strong black-white position you invite the “well, actually” crowd to come and undermine it.
I agree. Lesson learned. In a lot of ways, it was an honest mistake – the opening had no snark at all in my original (private) draft, and, for who knows what reason, I added it in during my last round of edits. Sometimes your writer brain just doesn’t get it right. I appreciate the comment – and I revised the post, accordingly! I only regret inflicting this writing error on the lobste.rs community, y’all deserve better!
On Linux on my developer workstation and personal server(s):
apt
and the whole Debian + Ubuntu ecosystem around itpython
ssh
bash
zsh
gnome-terminal
(mainly, for not changing much over the years)vim
(same)git
htop
nginx
redis
sqlite
In my personal web hosting:
apach2
mysql
wordpress
memcached
Mainly because this simple LAMP stack has lasted for more than a decade (see archive) of continuous operation.
For a first-person account, Eich and Wirfs-Brock wrote an extended narrative of JavaScript’s development in “JavaScript: The First 20 Years” (2020). Can be found via Internet Archive Scholar PDF here. I wrote a review for GoodReads which you can read here.
Release notes are a bit more interesting and detailed than the announcement blog post:
https://release.gnome.org/45/
Or the developer release notes.
“Modern dev practices” have a lot to learn from things like wordpress & excel.
Why do so many people pick these things as the basis of their operations? How they seem to work so well despite perceived “obvious” flaws?
We all know the flaws of these systems, but what are the benefits we miss due to focusing on the flaws?
WordPress makes it easy to create a website or blog and pretty quickly switch away from thinking about web servers, web requests, JavaScript, HTML, and CSS, and instead focus immediately on content (at least, once installation/setup is done). That has always been its big UX win.
Similarly, Excel lets you focus on content (the numbers/figures/data) rather than on a programming language or analysis framework.
But, both WordPress and Excel offer escape hatches to full-blown programming environments (themes/plugins and PHP for WordPress, formulas/add-ons and VBA for Excel). This model has problems but certainly lets users focus on what they want to get done, while still having lots of customizability/extensibility options open to them.
I would say that WordPress is well positioned for a big design upfront website. You hire a contractor. They charge you $X0,000. You get a website and you have your semi-technical but not real web developer staff people manage it for N years until the design becomes too dated to bear and then you go back to step 1. It works really well in that niche. If you actually can afford to keep a web developer on staff, you could get a better product, but most people don’t want to pay that much money when their website is not a differentiator.
That option works well only if you also outsource the hosting. It’s very easy to create an insecure WordPress site. I believe the rise of static site generators was driven in a large part by this: WordPress convinced a lot of people that running scripts in response to requests was insecure. A number of WordPress sites I saw were faking this with a reverse proxy that had an allow list of pages so that WordPress effectively worked as a static site generator for the caching proxy layer.
WordPress also aggressively optimises for adding content through the web UI. I’m honestly surprised at how popular this is. I’ve used two flows when preparing blog content. The first is to write it in some markup language (DocBook XML if I’m unlucky, Markdown with some blog-specific extensions for semantic info if I’m more lucky), editing these in a git repo, and then pushing them. The second is editing in a Word document with track changes on and incorporating feedback until reviewers are all happy. Neither of these flows works well with WordPress. As far as I can tell, the only flow that does is to write the contents directly into their editor and post as a draft for internal sharing. That, in turn, doesn’t work well for a corporate site where the people with access to the site are not the ones producing contents.
I have it on reliable sources that what works remarkably well is copy-pasting from Google Docs or even Microsoft Office. So what usually ends up happening is that posts get drafted on Google Docs, email chains with Microsoft Word documents and so on, and when it finally gets approved, someone copy-pastes it. There’s a little post-factum cleanup (e.g.
<strong>
tags) but that kind of hurdle seems to be considered acceptable. It sounds horrible but if I’m being honest it sounds less horrible than any “let’s get people who aren’t nerds to write Markdown” story I’ve heard.WordPress is one of the things that comes closest to the “it’s like Word but for web” workflow, which adequately serves an uncanny proportion of web users. It certainly doesn’t work for large corporate deployments where, by necessity, whoever writes the content can’t get within six feet of the web server. But, much like small personal websites of tech-minded users, that’s a small enough niche that’s adequately served by other platforms.
I’m a big fan of static deployments just because it’s cheaper and generates a lot fewer security-related headaches. But even static website generators that are touted as easy to use, like Hugo or Jekyll, are still so contrived that they’re nowhere nearly adequate for people who don’t enjoy tinkering with technology.
(At the risk of having my lobste.rs membership unilaterally withdrawn, I want to say that I’m an unashamed FrontPage apologist :-D).
That wasn’t my experience. All of the formatting got horribly mangled and required careful side-by-side comparison of the two to reproduce the original.
If that flow actually worked reliably then I can see WordPress working well for non geeks.
It’s probably specific to formatting requirements. In my experience, copy-pasting stuff from Google Docs is fairly reliable as long as you stick to paragraphs, headings (minus some
<strong>
tags), lists and default-formatted tables. If you need more advanced formatting, you are, indeed, quite screwed.However, paragraphs, headings and lists adequately encompass the needs of a large percentage of Internet users. Furthermore, advanced formatting features (in-page excerpts, extended quotes) are theme- and design-specific enough that markup languages tend to handle them rather poorly anyway; more advanced systems will take you 90% of the way, but still leave you dealing with the extra 10% by hand, at a significant, and often non-transferrable learning cost.
Google Docs works much better for this - given it has more limited formatting. Word formatting doesn’t even work reliably between versions of Word (a while back I tried opening a resume created in Word on Windows in Word on macOS to less than impressive results) so there’s little surprise it doesn’t play well outside of Word.
I briefly worked for a company recently that was all-Microsoft all the time. After years of using Google Docs for collaborative editing I was absolutely shocked how bad Word (desktop and online) are for this. I have no real love for Google or proprietary solutions in general, but they have gotten online collaborative editing about as right as I’ve ever seen it implemented.
Most people don’t pay for good hosting and if you follow a defunct WordPress blog in RSS long enough, it will eventually become a spam site, with the original owners blissfully unaware.
WordPress definitely falls short when it comes to multi-user workflows where content needs more than a cursory review by more than one person. I’m also not aware of any open source tooling / CMS that does this well.
I have heard tell of proprietary systems that handle it well, but neither WordPress nor Drupal nor static-site generators are good at a real editorial workflow. Static site CMS quickly lose their charm for me when having to deal with a bunch of images and the Markdown workflow is awful for any real editorial workflow that requires tracked changes and input from multiple stakeholders…
The closest for me is editing in Google Docs and then pasting into WordPress. It handles copy/paste from Google Docs passably well, though Google Docs falls short in not handling custom styles and AFAICT still suffers a lack of code styling.
What I really want is a fully open source start-to-finish publishing tool chain / CMS that starts with composition and allows for a real editorial workflow with approvals and scheduling.
Is the way to interpret this table that: “C is the programming language most amenable to LLM based completion, and TypeScript the least?” (Of the considered set, of course?)
Oh nah, the sort is alphabetical. I’m drawing my conclusions from the median score, lower is better. But I’m also not sure of my interpretation. I’m just some guy.
Ah, I see. It’s an interesting question, which programming languages are more amenable to this sort of completion. I always assumed that it would be, “Whatever language has the most code examples that the model can use as a training data set.” (Thus maybe HTML, CSS, Python & JavaScript would be winners, based on open source popularity.) But then I thought about it a bit more and I suspect your hunch is right that languages that are more regular / static might have an advantage. One thing that was a bit humbling for me to realize was that LLMs, in some way, have an easier time completing code than natural language since code follows very strict syntax and parser rules, at least compared to fluent English language. Combined with the eventual (inevitable) step that they can train the code generation models on the basis of actual compiler/linter output, and I imagine LLMs will be even better at generating working and fluent code than they are at generating fluent natural language.
I’ve been thinking GitHub Discussions might be the 2023 successor to Google Groups, especially for programming teams.
https://github.com/features/discussions
In 2021 they launched a private repo version:
https://github.blog/2021-03-09-github-discussions-now-available-for-private-repositories/
I did a deep dive and it has a lot of things I’d want from a Google Groups replacement.
OP wrote this, though:
… which is a valid concern.
I’m glad this was posted, because John Gruber has such different software values than I do. He seems to think of app development as being akin to making films (he even has a Kubrick quote), where meticulousness, look-and-feel, and polish matter much more than utility. He judges other pieces of software the way a filmmaker judges other films – he’s looking for artistry. But I view software as a utility first, and artwork second. And especially so for software running daily on my pocket computer (smartphone).
Meanwhile, many of my core software values don’t get a mention from him. Like the fact that there is way more open source software for Android than for iOS, and this goes down to every layer. Or, the fact that Android’s developer toolchain is entirely x-platform, allowing developers to tweak and modify software regardless of what desktop operating system they use.
I love Apple’s design values. When I have my design cap on, there’s a flow of admiration in the direction of macOS and iOS. And I even participate in the Apple ecosystem a little, with a Mac Mini & iPad. But my daily developer workstation is Linux, and my daily phone is Android. Thinkpad X1C and Pixel 7, because I do care about well-designed utility.
And both have f/oss software, programmability, and utility as their core values, aligned with mine. Thus, for me, and for many like me, that’s the show.
Now… when I’m recommending unfussy hardware/software for my non-techie friends & family? Sure, it’s the Macbook Air and iPhone, then. But I’m really glad a choice exists on the market for people like me, and I’m not sure what value there is in bashing the other side just because it doesn’t share your values.
The conclusion you don’t state, and perhaps don’t draw, is “the iphone apps that focus on look-and-feel are less functional than the android apps that don’t”. I certainly don’t draw that conclusion.
Look and feel matters for functionality. Those of you who haven’t read Jef Raskin’s book should read it, particularly chapters 2-4. One example: How many per cent of the touches/gestures hit and act on an item that wasn’t there yet when the user’s brain decided to act? This is easily measured with user testing, videos and questions, and one of the chief ways to reduce the number is to add slick little animations and transitions, so that touch targets don’t appear suddently, but rather slide in, grow, shrink in ways that the brain use.
Yes, I don’t draw that conclusion either. I think iOS and macOS apps are perfectly functional – and sometimes moreso than Android or Linux counterparts. But I don’t think John Gruber was treating good design as being in service of function. He was treating good design as a showcase of craft and artistry. (Perhaps even of commercial ambition, as he derides the Android Mastodon projects as “hobby projects”, while praising the iOS “commercial” ones.)
100% agree with you that Jef Raskin has some great thoughts on the utility of good design (many of which could benefit the f/oss world). There was some interesting work in this direction a few years back in the Linux desktop world by the (now defunct) non-profit Yorba.
Gruber is solidly from the background of Mac indie apps like Panic’s stuff, which place a premium on design and functionality but are also vehicles for sustaining small businesses.
Try sending him mail. Ask “is a low error frequency a sign of good craftsmanship?”
I can guess his answer.
I’m going to post my own answer.
That which we do is follow rules of thumb. We don’t reason from first principles, even when those first principles are important to us.
Our real goal is to build applications and services that serve the users well, which includes being low on frustration. Being low on errors and frustration is… being pleasant to use, which ends up being some rules of thumbs about animations and general slickness.
His very first example, Ice Cubes, is open source.
You may be interested in the work of Richard Sapper. He was the original designer of the first black Thinkpad 700c. He kind of embodies an alternative to the Deiter Rams school of design (which Apple follows closely) where every device is very solutions-oriented.
The numbers can’t really be compared to prior years, as others have pointed out, due to a change in the survey design.
But, why are so many developers encountering Linux in their day to day lives even if they aren’t running Linux as their main workstation OS?
For Windows developers, it’s the rise of WSL. Windows was always missing a great UNIX shell and now WSL provides it in spades.
For macOS developers, it’s native support for Linux VMs & containers as well as the rise of M1/arm. These two trends make it so that macOS’s BSD heritage and local terminal is a less comparatively useful proxy for local development (vs just running a local VM or container running Linux, which is now easy enough, and fast), whereas perhaps in past years the BSD heritage was good enough to e.g. run Python, Ruby, or Node.
For all developers, Linux is the standard deployment environment in the cloud, whether you are using Amazon EC2 or Google GCE or something else like DigitalOcean. Even developers running Linux workstations find a need to virtualize and containerize Linux environments.
For all developers, IDEs have gotten better at working with remote Linux machines, or local containers. See VSCode “Remote” extension, and private networking tools like Wireguard, Tailscale, ZeroTier.
Finally, Linux has showed up in a lot of “long tail” hardware use cases, such as Raspberry Pi, Android, NAS devices, Steam Deck, etc.
So I wouldn’t really call 2022 the year of the Linux “desktop”, but I wouldn’t be surprised if Linux is the “#1 #2 operating system”. That is, it’s not the OS everyone runs on their workstation, but it is the OS everyone runs in their workstation, from their workstation, or around their workstation. It’s the closest thing developers have to a “standard development & deployment OS” even while their workstations and desktop environments fracture on Windows/Mac/LinuxDistro lines. And if a developer has a homelab server or a favorite remote development VM, it is almost certainly running Linux and accessed via ssh.
Doing my first-ever Advent of Code. I completed day 9 of 9 yesterday evening. Have to tackle day 10 and 11 this weekend. I’m writing all the programs in Python first, and then, if I have spare time, writing a Zig version, as well. I did the Zig version for about 5 days so far. I’m also tracking some of my progress via Mastodon here.
My zig version for day 7 got stuck on deinit for my nested string hash map. I couldn’t get the iterator() to work. Very strange.
I think every generation of programmers feels nostalgic for the “good old days” when they felt like they understood their whole stack and were working directly at a super low level. But I’m not at all convinced that it’s actually true that we once did.
For example, I got into web dev in the early 2000s with PHP and Perl on the backend and HTML/CSS/JS (“DHTML”) on the frontend. And at the time I felt like I understood the stack, but really I understood only down to about the point of the HTTP daemon, with a little bit of knowledge of what was going on over the wire. The internals of, say, Apache and then the underlying TCP/IP stack, operating system, etc., were all just opaque to me. They were commodity pieces taken off the shelf to do what they did and I didn’t have to worry much about them.
Today, we have a lot more commodity pieces to take off the shelf – that part, at least, is true. But I’m not convinced that it’s necessarily a bad thing, or necessarily separates us from the problems we’re working on. First of all, we have all those pieces because people ran into problems, figured out solutions that worked well enough for them, and then made those solutions available, often for free and with the ability to modify/improve. That’s a great thing and has absolutely advanced the state of our art by leaps and bounds.
More importantly: I feel like I am closer, today, to the actual problems I’m trying to solve than ever before.
Once upon a time, there were a lot more intermediate problems that I had to solve and that got in the way of whatever I actually wanted to do. I can think and reason about web applications and their constituent parts in ways that early-2000s me could not have conceived of. Back then I had to invent my own half-assed MVC-ish architecture because the big wave of modern backend frameworks was still just over the horizon. Back then I had to manually set up servers and install all the packages – HTTP daemon, database, cache, etc. – and wire them all together. Once upon a time I even was on a team that had to literally wire up and rack-mount our own hardware! Back then I had to do a ton of extra work that put distance between me and the actual problems I was hoping to solve, which tended to be things like features or bugfixes in a web app.
Today, I feel like there are fewer layers interposing themselves between me and the problems I’m trying to solve, precisely because so much of that stuff has been replaced by commodified solutions/components. Which does mean I’m working at a higher level of abstraction, much of the time. And does mean I’ve had to learn new patterns and ways of talking about them and how to work with the interfaces of the commodified pieces. But it doesn’t mean that I feel I’ve lost something or that it’s no longer fun or challenging to me.
(though I also am a long-standing believer in the idea that most people in most teams at most companies shouldn’t be trying to invent new tech from scratch in the first place – it’s usually a sign that things have gone badly wrong)
I liked this comment because it describes my own background, all the way down to the timing and anecdotal illustrations. (I, too, came up with Perl, PHP, and “DHTML”; I, too, racked my own servers.) And though I think you are right that every generation of programmers is delusionally nostalgic for the prior era’s “simplicity”, I also think you might be missing some of the traps in today’s programmer culture. Specifically, I came up in a culture of open: open web & open protocols & open source & open architecture.
It’s not a question of whether I knew my whole stack. That depended on my willingness and free time. It was a question of whether I could know the whole stack. And also whether I could contribute at any layer. And that’s what the web and LAMP and then Python & f/oss databases and so forth gave me. Since we’re of the same era, you know exactly what “closed” used to mean in that late 90s & early 00s era: Microsoft’s closed source development ecosystem. ASP and C# developers deploying to IIS and SQL Server certainly got things done for businesses, they didn’t struggle with much accidental complexity. But their stack was so damn proprietary, so damn unknowable. From the web server to the framework/language to the OS and so on.
Today, we have open source everywhere in the development environment, but there has been a precipitous and worrying rise of proprietary in the production environment, due especially to “serverless” style public cloud APIs. This should be seen for what it is: much closer to the Microsoft model of the 90s/00s than the alternative. And all the same concerns for developers apply.
(This is one of the reasons why, even though I am expert in AWS/GCP and a fan of each, my main use case for them is commodity compute, memory, and storage. I don’t want to rack physical servers anymore, but I still want it to feel as though I have a rack of servers sitting in a data center, running open source software I can comprehend. That I can destroy the rack and recreate it programmatically is all to the good, but I don’t want it hidden from me entirely for when my code has to run on it. For the compute & memory side, give me SSH access & full-blown Linux userland, or give me death!)
Most people couldn’t, and definitely wouldn’t. At least if we’re using a full definition of “the stack”. From the web down to silicon. Any other definition of “the stack” is just stopping a little bit before we get uncomfortable. Why not include file system implementation? Or layer 1 & 2 network protocols? Or processor microarchitecture?
The beef with serverless, though, I agree. Back when I first started dealing with cloud, it felt like we could (and maybe would, in time) arrive at some sort of abstraction, even if just conceptual, of cloud, that would make which cloud you’re using more of an implementation detail. We never quite got there, and now it looks like we’re as further from it as we’ve ever been. And this forces you to bet not on technology, but on companies, which kinda rubs me the wrong way, sometimes.
I do love chatGPT but what I guess I’ve not seen yet is people pointing out it “plagiarizes” in the same sense as those art generation bots that caught a similar hype wave a month or two ago. Ask it how you would use Z3 to check two firewalls for equivalence, for example, and it spits out a slightly (although competently!) modified version of the blog post that I wrote on the topic: https://ahelwer.ca/post/2018-02-13-z3-firewall/
I guess since my blog is licensed under CC-BY-SA this is a violation of that license (and all the material it obviously read from Wikipedia) but I find it difficult to be too mad about it. I’ll probably start being mad when they use all this appropriated human endeavor to get it to convince you to buy certain products or hold certain political views.
The same way that Copilot “plagiarizes.”
Cue the anthropomorphising of software by claiming it has “learned” the same way as a human.
I suspect that language models are very good plagiarists because every word, sentence, paragraph travels through the following high level translation: words => concepts, concepts => words. All the words that map to the same concepts across a large scale internet / wikipedia / stackoverflow / etc crawl act as votes, of a kind, for those concepts and their tangled web of relationships to other concepts. Then these very, very good natural language generation algorithms can take the concepts back down to words again, in fluent sentences and paragraphs. But the words generated by chatGPT won’t be the exact words read/plagiarized by chatGPT.
Think of it this way. Let’s say you read 3 essays describing the themes of The Great Gatsby. Then, two hours later, someone asked you, “write an essay describing the themes of the Great Gatsby”, but you no longer had access to those 3 essays you read. You’d probably write a plausible essay describing the themes of The Great Gatsby, even if you yourself had never read The Great Gatsby. Were you plagiarizing the 3 essays you read a few hours ago when you did it? Now imagine the same thing, but where it is not 3 essays but millions, and it’s not relying on human memory/brain, but on a very purpose-built set of content indexing algorithms and a very sophisticated natural language generator.
One way I’ve been thinking about it is that the algo has, in a sense, turned plagiarism into an art form. The algorithm’s goal is to not get caught merely returning a source document that has the answer. It also knows how to synthesize information from many different source documents. As neat a trick as this is, it is hard for me to see this not creating a long-term seed vs leech problem for internet content.
I like your take.
It has always been an art form: On Bullshit. Skimming source material and quickly coming up with an intelligent-sounding essay that you didn’t believe – this was the skill in college, and you had to be smart to do it well. It is the skill of mimicing a way of talking, a way of thinking… at bottom, the skill of understanding the markers and heuristics that others will use to judge your fluency.
I feel this is the skill GPTChat possesses in abundance. Importantly, it is a different skill than true fluency (as the parent article attests).
Woah, I haven’t heard of this. Do you mean like the training set is plagiarized, or that it actually outputs plagiarized works?
EDIT: I mean the art generation bots.
The remainder of that paragraph is an answer to your question
… No it isn’t?
Oh, you were asking about the art.
Yes the training set clearly includes modern artists who did not license their art for inclusion in the dataset, and you can ask it to imitate their style.
Getting an exact reproduction is unlikely because of the way the information is compressed.
Is imitation the same as plagiarism? I do not think it is.
Can you name specific artists whose work was included in those training datasets without appropriate license? I know Greg Rutkowski is one of the more imitated artists, but much of his work is uploaded to ArtStation which has a rather broad reuse license. Greg is also very good about adding alt-text which helps train the models.
Although Emad claims that artist style imitation has more to do with the CLIP language model than the LAION image dataset.
I do wonder if something like chatGPT would develop a coherent political agenda, or if it would just regurgitate whatever was in its training data. Probably the latter.
Developing a coherent political agenda that isn’t a regurgitation of its training data is a very hard task for a human.