Enough AI copilots, we need AI HUDs (geoffreylitt.com)
568 points by walterbell 14h ago 188 comments
Multiplex: Command-Line Process Mutliplexer (github.com)
26 points by todsacerdoti 8h ago 6 comments
How to make websites that will require lots of your time and energy
131 OuterVale 128 7/28/2025, 7:41:41 AM blog.jim-nielsen.com ↗
Migrations randomly fail, schema changes are a nightmare, and your team forgets how SQL works.
ORMs promise to abstract the database but end up being just another layer you have to fight when things go wrong.
But as someone who writes both raw SQL and uses ORMs regularly, I treat a business project that doesn’t use an ORM as a bit of a red flag.
Here’s what I often see in those setups (sometimes just one or two, but usually at least one):
- SQL queries strung together with user-controllable variables — wide open to SQL injection. (Not even surprised anymore when form fields go straight into the query.)
- No clear separation of concerns — data access logic scattered everywhere like confetti.
- Some homegrown “SQL helper” that saves you from writing SELECT *, but now makes it a puzzle to reconstruct a basic query in a database
- Bonus points if the half-baked data access layer is buried under layers of “magic” and is next to impossible to find.
In short: I’m not anti-SQL, but I am vary of people who think they need hand-write everything in every application including small ones with a 5 - 50 simultaneous users.
Personally, from the database-ops side, I know how to read quite a few ORMs by now and what queries they result in. I'd rather point out a missing annotation in some Spring Data Repository or suggest a better access pattern (because I've seen a lot of those, and how those are fixed) than dig through what you describe.
I know exactly what's going on, while getting some level of idiocy protection (talking about wrong column names, etc).
On the other hand, I agree that mapping SQL results to instances of shared models is not always desirable. Why do you need to load a whole user object when you want to display someone's initials and/or profile picture? And if you're not loading the whole thing, then why should this limited data be an instance of a class with methods that let you send a password reset email or request a GDPR deletion?
It's hard to find similarly mature and complete solutions. In the JS/TS world, I like where Drizzle is going, but there is an unavoidable baseline complexity level from the runtime and the type system (not to criticize type systems, but TS was not initially built with this level of sophistication in mind, and it shows in complexity, even if it is capable).
Here's the thing. In five of six companies I have worked at, this story is the exact same. Python, Ruby, Elixir. Passing around ORM objects and getting boundaries mixed leading to more interdependencies and slower velocities and poor performance until a huge push is required to fix it all.
Querysets within a domain seems fine, but when you grow, domains get redefined. Defining good boundaries is important. And requires effort to maintain.
For greenfield projects, you have a chance of splitting the codebase into packages with each one having its own model, migrations and repository, and if you want to cross these boundaries, make it an API, not a Django model. For existing projects this is hard to do most of the time though.
First thing I noticed was that I couldn't roll an SQL statement by hand even though I had a distinct memory of being able to do so in the past.
I went with an ORM and eventually regretted it because it caused insurmountable performance issues.
And that, to me, is the definition of a senior engineer: someone who realised that they've already forgotten some things and that their pool of knowledge is limited.
What they are not for is crafting high performance query code.
It literally cannot result in insurmountable performance issues if you use it for CRUD. It's impossible because the resulting SQL is virtually identical to what you'd write natively.
If you try to create complex queries with ORMs then yes, you're in for a world of hurt and only have yourself to blame.
I don't really understand people who still write basic INSERT statements. To me, it's a complete waste of time and money. And why would you write such basic, fiddly, code yourself? It's a nightmare to maintain that sort of code too whenever you add more properties.
At my day job everyone gave up on attempting to use the awkward ORM dsl to do migrations and just writes the sql. It’s easier, and faster, and about a dozen times clearer.
> I don't really understand people who still write basic INSERT statements
Because it’s literally 1 minute, and it’s refreshingly simple. It’s like a little treat! An after dinner mint!
I jest, I’m not out here hand rolling all my stuff. I do often have semi-involved table designs that uphold quite a few constraints and “plain inserts” aren’t super common. Doing it in sql is only marginally more complex than the plain-inserts, but doing them with the ORM was nightmarish.
Sql does not really needs fixing. And something like sqlc provides a good middle ground between orms and pure sql.
I've worked with devs who hated on ORMs for performance issues and opted for custom queries that in time became just as much a maintenance and performance burden as the ORM code they replaced. My suspicion is the issues, like with most tools, are a case of devs not taking the time to understand the limits and inner workings of what they're using.
More specifically a GraphQL-native columnar database such as Dgraph, which can leverage the query to optimize fetching and joining.
Or, you could simply use a CRUD model 1:1 with your database schema and optimize top-level resolvers yourself where actually needed.
Prisma can also work, but is more susceptible to N+1 if the db adapter layer does separate queries instead of joining.
And schema changes and migrations? With ORMs those are a breeze, what are you're on about. It's like 80% of the reason why we want to use ORMs. A data type change or a typo would be immediately caught during compilation making refactoring super easy. It's like a free test of all queries in the entire system. I assume that we're talking about decent ORMs where schema is also managed in code and a statically typed language, otherwise what's the point.
We're on .NET 8+ and using EF Core.
(when it is not lower, then it is because there are sec framework and other fields that might not be mapped directly do the prisma schema)
people forget how sql works??? people literally try to forget on how to program
more and more programmer use markdown to "write" code
My personal opinion is that ORMs are absolutely fine for read provided you periodically check query performance, which you need to do anyway. For write it's a lot murkier.
It helps that EF+LINQ works so very well for me. You can even write something very close to SQL directly in C#, but I prefer the function syntax.
I have my personal website running on svelte. When I decided to have a blog, I quickly came up with a solution to use markdown to html converter and just added a couple of routes to existing setup and voila, the blog is up and running. I don't care that it depends on several packages. Publishing a post takes just a push to my repo.
They said at the start they were going on personal experience. I relate deeply to what they're saying: it's most definitely not a rant/beef against another project/client, it's most definitely the learnings of someone who's been producing personal websites for decades, has kicked themselves a few times in the process and can sarcastically poke fun at their journey in front of others.
Yes; a lot of people don't code because they need to make something work, they code for the joy of it. When the software they need to write is boring or solved - like another CRUD app, front- or back-end - instead of picking the boring and easy to build and comprehend languages and frameworks, they will make it interesting for themselves. Learn a new language, framework, or design paradigm; follow whatever is trending at the moment, etc.
A lot of new software is over-engineered from the start. A lot of that is cargo cult as well, e.g. big companies use microservices in their custom k8s cluster, therefore we should use microservices in our custom k8s cluster too.
Things like Wordpress sound super simple - you don’t even need to code!
But you do need to worry about managing an entire Apache server, managing a crappy database, hardcoding bullshit in PHP, cronjobs, cloud deployment and the fact that almost all “features” of it like plugins and themes etc are massive security vulnerabilities
I think the pitfall to avoid ITT is that there’s a single source of maintenance effort - there are likely many!
I was mainly providing an alternate example to “over-engineering is the only source of complexity” train of thought this thread largely has
If you can "make a website" by using a third-party provider but instead you opt into running wordpress on your own, you are still over-engineering.
I have no problem with sql but an ORM makes what I know about sql very ugly.
I grab a framework to also keep my skills relevant, especially if I'm not practicing them in my day job. If I didn't have that impulse, I'd keep it simple all the time. I'm really good at it, because I really dislike complexity as it requires me to remember more things and I don't really like that feeling.
I'll optimize if I absolutely have to.
Not that businesses ever cared about this attitude. I mean, I've seen it work. The work that I do with LLMs is quick and pragmatic. No need to put stuff into production when it's just a prototype. No need to use a framework if gluing an LLM with some Python code and a well crafted prompt produces the result we need. It allows me to ship in days, not weeks. Obviously, if one then wants it productionized, additional work needs to be put into it and possibly the code needs to be refactored. But, in my opinion, that's the time and place where that type of stuff should happen.
As a rationalization, sure, but never as the reason.
They do offer more than coding standards.
It's like asking "I'm new to driving, what brand of nitros should I be using"
Nah dude, get your sea legs first
What about your simple Go server or FastAPI server. Probably yes.
You can:
Use Next.js (frequently changing lots of transitive deps, suffers from Node ecosystem churn too)
Roll your own framework
OR (FANFARE....)
Use simpler arguably more professional tools. That 10 year old .NET MVC site. Guess what. Still works. Still secure.
The big frontend frameworks have great backward compatibility and usually provide codemods that automatically update your project.
If you install UI components and other libraries that might get abandoned or have breaking changes in major version updates you might have to put in more effort, that's not different in Go or Python.
Patient: Doctor, it hurts when I do this.
Doctor: Don't do this than.
Compare that to something like jQuery where all the edge cases have already been accounted for 10 years ago.
It's not like you are always writing better code than the open source projects are. Unless you are one of the best developers in the world, then sure, then that might work, but for the rest of us, we are probably not guaranteed to ever write code that is 100% bug free for five years.
Security vulnerabilities grow in unattended code then?
Or they were there from the second the code was written but with some luck someone noticed them and fixed them?
Old code isn't necessarily insecure just because it's old...
Same, except I skipped Python and went with bash (https://gist.github.com/lelanthran/2634fc2508c93a437ba5ca511... if you're curious).
If I had to do it again, I'd go with Python, but because it started off as a small 5 line shell script I thought "Why bother with Python?".
1. be multiple developers on the same project.
2. for each developer, use your own tools and techniques, insist on only handling those parts of the site that you did with your tools, and insist on never fully understanding those remaining parts of the site the other devs did.
This will allow for all sorts of fun, including:
- A multiple inconsistent implementations of the same thing
- B even better, those multiple inconsistent implementations affecting and breaking each other!
One you have this going, there are some easy bonus pickings: Whenever B happens, "fix" it with weird extra incancations inside your own toolset, cleverly avoiding any attempt at (2) above.
If you succeed at this, several developers can, combining these techniques to sabotage and trigger a veritable pinball game of strange breaking effects.
Note: CSS is a great place to start this game!
Here's some more:
- People only visit your personal website knowing they can personally read, understand, audit and approve every single line of code that ever went into it. This means you don't really have a personal website unless you meticulously wrote every single line and every single change is clearly described and accessible on github (and sourcehut, and forgejo, and the rest. What sort of monster uses only Github nowadays?)
- Remember to explain every single self-doubting existential thought that went into producing (or not producing) your website: people aren't there for objective, intellectual, educational tech content, they're probably more interested in self-deprecating metacognition.
Broad heuristics can be very effective
We make decisions on many more datapoints than can be put into what sometimes amounts to a “for and against” list
not every problem has a technical solution.
most of the time the real trade off is financial.
especially now with AI generated boilerplate and npm commands that shit out 10,000 lines of code at a keystroke.
Frameworks solve these problems efficiently. Sure, some frameworks can be overly complex (I'm personally not a fan of Next.js), but that's a problem with the specific framework, not the idea of using a framework at all. But many frameworks make things much simpler and let you avoid reinventing the wheel. You could write your own scripts (in practice a mini-framework) but eventually you'll hit limitations, especially as your project grows or you start working with others. At that point, you'll probably end up switching to an established framework anyway.
If you're already using something like PHP with server-side rendering and templates, that's fine too—you've just chosen a different kind of framework (it is still some kind of framework. Just not a client-side one). I just don't buy into the idea that avoiding all build steps and frameworks is somehow more "pure." It feels a bit like a hipster take: "I'm going to write everything from scratch and avoid all tools just to show that I can."
And from the linked post on the same website.
> if you write vanilla HTML, CSS, and JS, all you have to do is put that code in a web browser and it runs.
Very (very, very) few large projects use plain JS (instead of TS) these days. Let's stop acting like all these people don't know what they're doing.
This post is probably applicable to selected tiny and small projects. And for some of those, it may be better if there was no JS at all.
There are much better arguments to use TypeScript than "five billion flies can't be wrong". Most other popular tech choices are in fact rather silly.
While there is sometimes good reason to use TS, often you might be better served using JSDoc so you have type safety without the compilation step.
I currently see the direct comparison as my company has one project that uses old-school php backed rendering with a bit of vanilla js sprinkled it and one with modern React and TS. The React team is significantly less productive and the code is much harder to maintain, has more bugs, is less performant and harder ton onboard people to. But when I suggest that a new project does not not need to be a SPA, I always get booed.
They certainly have their reasons and they definitely aren't stupid, but it would be more useful to know what those reasons are and in what scope they are applicable.
More recently, see how there's a strong push towards types in Python. AI/ML is to Python what the internet was for JS. And types are here.
most of it from my observation is people justifying their own roles, where the real value they bring is arguable imo
Then came linters and everyone hates me. But you know the codebase is slightly less buggy/shitty thanks to them.
The funniest thing to me is people thinking they don't need tests, linters, type checkers, because they're so good at it.
Even admitting one wants to go with bare bone web components authoring and maintaining them is expensive, requires lit or something.
Thus, what's the solution? Some sort of templating? Again, you're bringing on dependencies.
A small amount of PHP as a templater for simple raw HTML and JS segments is pretty nice.
I side-stepped that completely, even on actual production web apps for clients, with this: https://github.com/lelanthran/ZjsComponent
Now, you may argue that that is a dependency, but it doesn't have any of its own, you can make a copy of it, serve it from your primary domain, and you're done.
If your "dependency" is yourself because you wrote your own template for your specific needs, is that still a dependency?
I wrote a templating solution for my own repeated sections and I'm so glad. It does exactly what I need, it's simple for me to understand if ever it grows large and I need a refresher, and easily expandable.
A classical example might be https://www.npmjs.com/package/is-odd
Anyway, to include this package as a dependency is indeed overkill. I would most likely opt for vendoring this package into the project (including licenses and acknowledgement), as the code is unlikely to change and is MIT licensed.
honestly ctrl+c, ctrl+v of hand written html. and i'm cool as a cucumber.
But wait, now you want to add an active state to your navigation links, and you're manually changing the `class="active"` in 12 different files...
I could go on, it doesn't scale beyond triviality, albeit LLMs do help speeding up.
Finally we have our web 3.0!
...