I think this is more about us all being on platforms that value engagement and simply don't care if that "engagement" is people fighting with each other. The Internet always had whackjobs... in fact on a per capita basis I'd bet that in the early days we're praising as "we all got along" the whackjob ratio was higher than it is today and it has since regressed to the norm... but the systems structurally tended to discourage the nastiness. There was still plenty of it, but on Usenet, you could add the guy who enraged you to the point of blinding rage to your ignore file... and you could add the two guys who refuse to ignore each other to your own ignore file. In the Weblog space you could just, you know, not read that other blog that infuriates you. On custom forums the community was small and tended to evict people.
It was not paradise. But it was more workable, when the platforms weren't designed by PhDs to seek out and exploit your outrage for their ad clicks.
ejecting jerks is something forums did better than social media, even if the definition of jerk varied widely and was forum-specific. I can't imagine a forum doing something like promoting the user with the most interacted with posts; they'd probably lock the thread and consider banning
That's not the problem. Wave a magic wand and have all cities walkable and bikeable and you'd still have school busses.
I suppose we could wave more magic wands and say "ok, everybody with kids has to live in a city whether they like it or not" and wave some more magic wands and eliminate all concerns about crime or other dangers, but if we're going to wave this many magic wands maybe we should just wave one that makes it so children don't need to go to school at all because they are all magically educated already.
The people who hand write code for a game engine will beat the people who try to vibe code a game engine.
But they'll both be beaten by people using AI intelligently to generate code, but not letting it drive everything. Who look at every line and apply their experience to fixing what the AI generates until it outputs more or less what you would have, only more quickly.
The false dichotomy that some of you are trying to push between "just taking whatever the AI slops out" and "pristine hand-crafted code by dedicated, loving experts" doesn't exist.
I'd put my estimates at 3x speed improvements. The amount of infra required upfront? 5x one time cost. These are estimates from Godot mobile app work. We have been trying out: no reviews under specific file sizes, except at design bottlenecks or large refactors. Number of PRs is probably up 3x with maybe 20% increase in regressions? Number of tests in our CI is up 500% (again, approximate), but this is absolutely required or we'd be awash in uncaught regressions with the velocity of code changes.
We have PR auditing skills, PR writing skills, testing conventions, etc that all need to be self-monitored for bullsh*t Claude ignorance (e.g. you apply them many times, then review your own PRs manually before merge). None of that is free, but we have shipped significantly more code as a result.
Hearing about a Godot mobile app is hilarious to me. If there was ever a signal that Godot is not a serious tool to create releasable games, but rather a toy for beginners to mess around with, spending a bunch of resources on porting the engine to phones is it. Wowza
I am struggling to understand the exact content of your message. I believe it's that Godot is unserious. Okay? Game engines serve a niche much smaller than broad consumer apps or SaaS platforms. Seems like a dunk I don't quite understand.
It's a game built in Godot that runs on mobile (a mobile game). Godot is C++, there is no porting of engine to run on mobile? Slay the Spire 2 is built in Godot and has 500k concurrent users.
I interpreted your comment "Godot mobile app work" to mean you worked on porting Godot itself to mobile, which I then checked and found that it did actually happen https://godotengine.org/article/gabe-stable-release/
If Godot for Android is unrelated to you then I misread. But I still find it hilarious conceptually, unrelated to you, that Godot is spending resources on porting itself to phones while it has so many serious outstanding issues. As though game devs are going to be coding on their phones in any meaningful way.
Thank you for clarifying! That totally changed my interpretation.
There is a surprising number of projects dedicated to making Godot work on mobile, and I am equally confused by that focus. I guess it's more possible with AI coding though, but couch game dev doesn't feel like a real thing.
"(It’s famously not well capable of sounding human)"
Rather than a binary, I prefer to measure the question of "how much text does it take to be reasonably sure that it's an AI?"
By that metric, it is getting better at a reasonable pace. People are also getting better at prompting their AIs to write in something other than the default LLM style. If you think you're good at picking up that style, you probably are. But it's a lot harder to pick up AIs when they're fed a style sample. You wrote in the default AI style, and yeah, most of us have twigged to that by the end of your couple of short sentences. But feed the AI a style sample and it can definitely make it two sentences without every one realizing it's AI.
I've been using Kimi K2.6 lately (don't have 2.7 available through blessed work channels yet) for tasks where I already know what it is I want to do and I want to just step through the process in pieces, and it's fine. Do I have to correct it maybe a bit more than Opus? Yeah, but the real cutoff would be between "I have to read every line" and "I can just trust it without reading every line" and for me neither model hits that mark, and I expect it to be a while yet for that. Is it as good as Opus if I want to spit ball about architecture and then convert that to code? No, but I don't have that problem all the time, and it's there if I do need it.
And now in a heavy coding week rather than bumping up against my spend limit by late Wednesday or Thursday I'm comfortably below it all week.
That said if anything I feel like I have to reign in K2.6 much more than Opus, actually. If I want to just ask it a question without it inferring some coding task to immediately start doing, it takes a lot more care to prevent it from just running off half-cocked off of an only 3/4s-cocked idea of my own. I use "plan" mode with both but it's somewhat more defensive with K2.6 than Opus.
Now that I have an nvme SSD in all my computers and boot times are roughly 10-15 seconds or so unless something has gone wrong, the advantage of sleeping is somewhat mitigated.
Back in the spinning rust era, though, a good unsuspend could be something like 50 times faster to get to a running computer. Possibly more, depending on what your OS needed to start up.
It is still more convenient to have my previous environment most of the time, and still faster to unsuspend than boot, but it isn't as much of an advantage as it used to be, no.
I haven't done a lot of Typescript, but I've done at least a couple of month's worth now, and every time I have to type "as" my inner Haskell programmer screams.
If I could add one feature to Typescript it would be something like "as" that actually validates the result against the type system and can fail. Unfortunately, that's way, way easier said than done. It's the bad type of keyword that has unbounded runtime cost because it would have to be a runtime comparison, and there are a lot of design questions about how to write it. However, I still petulantly want it even though I can hardly define it. "zod" is pretty good but you can see how trying to add that as a "keyword" is nightmare fuel for a language-level change.
"every time I have to type "as" my inner Haskell programmer screams." - most of the times you don't have to. You choose to.
"If I could add one feature to Typescript it would be something like "as" that actually validates the result against the type system and can fail." - I don't think it's fair to expect that since most of the statically typed languages will not guarantee things in runtime unless you specifically run a validation code in runtime.
There's also type guards and good old self-written validation functions you can use.
"I don't think it's fair to expect that since most of the statically typed languages will not guarantee things in runtime unless you specifically run a validation code in runtime."
If I have a value of type X in a static language, then I know that it absolutely conforms to the layout of type X. It isn't even that we have to provide a "validation function", it is that it is quite literally physically impossible for my value to not conform to the definition of type X, in the languages like C or Go or Rust where the type layout is actually a specification of a layout of data in memory. If I have JSON '{"a": 1}', there is no way whatsoever to stick that in a "struct { A string }", because it physically doesn't fit. By "physically", I mean, in RAM, in the physical cells and voltages. There's no way to validate that a "struct { A int }" 'really contains an int' because there is no way for it to be anything else.
Typescript specifically has these issues because all of its objects boil down to a Javascript object with certain keys, and all of the values are ultimately of type "any" no matter what Typescript tries to lay on top of it. If I have this sort of data come in to a static language, I have to have a step where it very deliberately converts it down to the static representation. There isn't an equivalent of "as". Modulo unsafe, but we don't count unsafe in these sorts of discussions.
I am absolutely guaranteed in a static language that if my struct says field "A" is an int, it absolutely, positively is, always has been, and always will be.
The main problem I encounter with "as" is when I have external data coming in. For that I have zod and validation functions. What prompted my post is my experience yesterday where I corrected an AI using "as" (which it used because a lot of its training data does this) and had it call an actual validation function that I happened to already have before it cast it into the type. But the reason my Haskell programmer screams inside is that a validation function can still be wrong, because the compiler isn't helping me. In a static language, I can guarantee that if I have "I dunno, some JSON value" on one side and a struct comes out the other end with some value derived from it, I have absolutely had some bit of code check that and pack it into the static value in a way that the compiler has helped check. I can further reliably compose these promises quite reliably through further type specification in my static type.
A validation function can still have bugs in it that a static language compiler would have strictly, compile-time validated. It's better, but it's still the manifestation of the quite accurate criticism that dynamic languages end up trading away all their convenience with not specifying types with having to have vast swathes of validation, and testing of that validation, in the testing backend. In Typescript, I can mostly sorta kinda compose them together, but it takes a lot more features and grease and effort. I appreciate Typescript in its capacity as taming Javascript and prefer it substantially over Javascript alone, it's probably the best thing of its type that we could hope for, but if I consider it as a language that stands alone, I really really dislike it.
The "satisfies" keyword may be what you are missing. Most of the cases I used to need "as" (usually weirdly permissive types from some lib) can be nudged in line with a "satisfies"
In addition to exploring `satisfies` as a better `as` (compile checks, that don't assert), you may also be looking for `is` aka Type Guards (runtime checks that assert types).
If you have a validator function `function isSomeSpecificType(obj: unknown): boolean` you make it a Type Guard by changing the return type to be the type assertion you need: `function isSomeSpecificType(obj: unknown): obj is SomeSpecificType`. Typescript's narrowing is pretty good about using Type Guards to good advantage.
"This is just validation that is using the type system to indicate the validation has already occurred. I think the real point of “parse, don’t validate” is to make the type system give you structural guarantees that couldn’t exist otherwise (e.g. always having a first/last element in the NonEmpty example from the original article)."
It's the same thing. In the latter case, something has validated that your NonEmpty has a first and a last element. It's all validation before you stick it in a type that asserts that the validation is guaranteed to have occurred so every function receiving it doesn't need to do it itself.
Any non-trivial use of a type system will involve making guarantees the type system itself can not actually express [1]. There's nothing wrong with saying "this is a valid email in accordance with my standards" in a type. Merely using the type system to assert "I have some sort of value in the name and host fields" is valid but a degenerate use. "struct Email { name: Name, host: Hostname }" is an even stronger use of the type system, where Name and Hostname are themselves values you can only get by passing some incoming string through a validation process. Asserting that these things exist is just the most basic check possible, but your type still permits {name: "\0\0\0\0\0\0", host: "!"}, whereas under my definition, assuming that Name and Hostname are reasonably defined, that value will not be ever be something that can be witnessed.
In fact in general, while I don't absolutely rigidly apply this, especially in smaller script-like programs, when a "string" appears in my strong types that specifically means "this has unbounded contents". It's an appropriate type for "stuff I got off a network" or "stuff a user typed". What stuff? Don't know. Haven't checked it yet. When I do it'll get a more specific type like a Username or DecodedUTF8String or something else. Thanks to people using way too many "strings" and "ints" in the world I have to constantly explain to my LLM that I want stronger types. I'm yet to find the invocation to put into my CLAUDE.md or equivalent to get it to do it right the first time consistently.
[1]: With a wistful stare into the distance acknowledging the theoretical utopia of dependent types... but it doesn't seem to be coming down from "theoretical" any time soon.
> It's the same thing. In the latter case, something has validated that your NonEmpty has a first and a last element.
No, it has parsed it into a structure that structurally has at least one element, not just the promise that there ought to be one. From the original “Parse, don’t validate” article:
data NonEmpty a = a :| [a]
> your type still permits {name: "\0\0\0\0\0\0", host: "!"}
I actually originally wrote it with an array of EmailNameCharacters, etc but didn’t want to overcomplicate the example.
I don't understand the naming scheme, or the apparent lack of it. I half expected it to be some sort of UUID which would at least makes sense. At one per person for 7 billion people that's a little under 33 bits. Make it a nice round 40 for a bit of future proofing (the scheme doesn't need to live forever) and to make a bit of space internally and that's 5 words from a 256-word list. That would seem to make a lot more sense then first-come, first-serve on something as easy to abuse as .self.
However, perhaps more relevantly, it isn't clear why this needs a TLD and all the hassle associated with a tld when it could just as easily be attached to any convenient domain name lying around that you have access to, such as, oh, say, onmy.cloud.
Then again I have this objection to almost all TLDs. But I'm not sure I'm wrong.
At the very least if you want to show ICANN that you mean business I would strongly suggest just doing it on onmy.cloud, and tell people that if you get the .self you'll transparently migrate their onmy.cloud domain on to .self when you get it. Nothing says "I can do this" like actually doing it.
Controlling the TLD has its own benefits and drawbacks (managing email reputation, for example) but as a regular person I have more reason to trust `.cloud` than `.self` purely on the basis of proven continuity. My `.com` domain will almost certainly live as long as the internet does provided that I keep paying to renew.
Regardless, a UUID is probably the right call. It doesn't help with memorability but it's at least more stable than an IPv4/IPv6 address and can be hard-coded. I wonder if you would get a full zone or if it's just an A/AAAA record given their broader goals of email and VPN tunneling.
If your UI is not fully controllable with a keyboard, the same forces that made that happen will eventually make a mouse mandatory for this hypothetical tech stack too.
The terminal has no Platonic quality of being keyboard only. It is an accident of history and the limitations it has had. Remove the limitations and remove the accident of history and you will just end up drawn into the strange attractor of GUIs, warts and all.
There could be a brief honeymoon where the tech stack looks like some of you are imagining in your heads, but it would only last as long as it wasn't used by very many people. Google "gemini protocol" for a similar situation. That protocol has basically a cap on how popular it could possibly get before it just turned into HTTP B as the rest of the world forcibly upgraded it regardless of what the core project thinks. They exist in the shadow of HTTP, as the terminal exists in the shadow of GUIs. This is not a bad thing. It is what lets them be what they are. The shadows of GUIs or HTTP is large and there is plenty of space to be. Trying to give the terminal more GUI capabilities is like trying to give Gemini more web capabilities; you'll just end up in the same place, only with less refinement.
It was not paradise. But it was more workable, when the platforms weren't designed by PhDs to seek out and exploit your outrage for their ad clicks.
reply