There is no way to autogenerate migrations that work in all cases. There are lots of things out there that can generate migrations that work for most simple cases.
They don't need to work in every case. For the past `~15 years 100% of the autogenerated migrations to generating tables, columns or column names I have made just work. and i have made thousands of migrations at this point.
The only thing to manually migrate are data migrations from one schema to the other.
It is blatantly obvious to anyone with just a little bit of experience that the reddit devs barely know what they are doing. This applies to their frontend as well as backend. For some reason, reddit is also the only major social network where downtime is expected. Reddit throwing 500 errors under load happens literally every week.
Reddit also puts the "eventually" in "eventually consistent". Not in the sense of consistency being driven by events, but in the colloquial sense of "someday". The new message indicator will go away ... eventually. Your comment will show up ... eventually.
I, too, am a big fan of prolog and have (at least) yearly binges where I write a lot of it for fun and profit (and some frustration), but I do not consider myself to be an expert. But even I can see that the author has what I would consider a pretty basic understanding of prolog. Which makes it even more surprising they are writing a book that uses prolog.
More than anything, this reveals your lack of understanding of modern languages and type systems.
TypeScript, for example, is one of the most widely used languages in the world. It has an incredibly powerful type system which you can use to model a lot of your invariants. By leaning on patterns such as correct-by-construction and branding, you can carry around type-level evidence that e.g. a number is within a certain range, or that the string you are carrying around is in fact a `UserId` and not just any other random string.
Can you intentionally break these guarantees if you go out of your way? Of course. But that's irrelevant, in the same way it is irrelevant that `any` can be used to break the type system guarantees. In practice, types are validated at the boundaries and everything inside can lean on those guarantees. The fact that someone can reach in and destroy those guarantees intentionally doesn't matter in practice.
But now try defining a type that enforces a RFC-compliant email address...
There are languages with proper type systems that can define full contracts, but Typescript is not among them. Without that, you haven't really defined a usable contract as it pertains to the discussion here. You have to rely on testing to define the contract (e.g. assert the result of the 'generate email' function is RFC-complaint).
And Typescript most definitely does. Testing is central to a Typescript application. It may have one of the most advanced type systems found in languages actually used, but that type system is still much too incomplete to serve as the contract. Hence why the ecosystem is full of testing frameworks to help with defining the contract in tests.
"Parse, don't validate", while familiar to all HN users (it feels like it gets posted here every week), is orthogonal and does not address what we are talking about. To extrapolate, let's stay with the email address type example.
In Typescript, you can define an EmailAddress type as:
type EmailAddress = string & { __brand: "EmailAddress" }
If you are feeling saucy, you can even define it as:
type EmailAddress = `${string}@${string}` & { __brand: "EmailAddress" }
But nether of these prove to me, the user of your API, that an EmailAddress value is actually a RFC-compliant email address. Your "parse" function, if you want to think in those terms, is quite free to slip in noncompliant characters (even if only by accident) that I, the consumer, am not expecting. The only way for me to have confidence in your promise that EmailAddress is RFC-compliant is to lean on your tests written around EmailAddress production.
That isn't true for languages with better type systems. In those you can define EmailAddress such that it is impossible for you to produce anything that isn't RFC-compliant. But Typescript does not fit into the category of those languages. It has to rely on testing to define the contract.
Let's imagine we are working with some hypothetical language in which what you describe is possible.
At some point, you will have to write a function where you validate/parse some arbitrary string, and it then returns some sort of `Email` type as a result. That function will probably return something like `Option<Email>` because you could feed it an invalid email.
The implementation for that function can also be wrong, in exactly the same way the implementation for the typescript equivalent could be wrong. You would have to test it just the same. The guarantees provided by the typescript function are exactly equivalent, except for the fact that you do technically have an escape hatch where you can "force" the creation of a branded `Email` without using the provided safe constructor, where the other language might completely prevent this - but I've already addressed this. In practice, it doesn't matter. You only make the safe constructor available to the user, so they would have to explicitly go out of their way to construct an invalid branded `Email`, and if they do, well, that's not really your problem.
> Let's imagine we are working with some hypothetical language in which what you describe is possible.
Or even a real one. The hypothetical part is that you'd be able to understand it. The languages with complex type systems are complete bears to work with, as I am sure you can image. It isn't just some historical curiosity as to why we prefer to use testing over types to define the contract. It is way more practical. But, no matter how you feel about that, it remains that we do define the contract in tests in the languages people actually use.
> The implementation for that function can also be wrong, in exactly the same way the implementation for the typescript equivalent could be wrong.
The compiler would give you an error if you got the syntax wrong, and in isolation it's fair that you could, say, get the domain name wrong as long as it is syntactically valid. I suppose what I failed to convey, making some assumptions about your understanding of type systems, is that the types would not just specify RFC-compliance. You would also spec out other dependencies such that you also couldn't even provide the wrong domain name without a compiler error. So, no, the implementation of the function couldn't be wrong.
You could mis-spec the contract, of course. Then the function could be "wrong". Maybe this is the intent behind what you are trying to say here. But the idea has always been here that I would also read and accept the contract, so it wouldn't actually be "wrong". It would be exactly what we both expect. My side will be written to what the contact specifies. If you try to deviate from the contract later, you'll face the wrath of the compiler.
As you point out, that's not the case in Typescript. If you try to change the contract (even if by accident) the compiler/typechecker will never say a word. I won't know until my code starts breaking. Your tests are the only thing you have to keep you in line with what we agreed upon. Tests define the contract in its case.
> Or even a real one. The hypothetical part is that you'd be able to understand it. The languages with complex type systems are complete bears to work with, as I am sure you can image.
I have written Haskell professionally for several years and worked with Idris and other similar languages. I'm perfectly aware of what is possible.
> The compiler would give you an error if you got the syntax wrong, and in isolation it's fair that you could, say, get the domain name wrong as long as it is syntactically valid. I suppose what I failed to convey, making some assumptions about your understanding of type systems, is that the types would not just specify RFC-compliance. You would also spec out other dependencies such that you also couldn't even provide the wrong domain name without a compiler error. So, no, the implementation of the function couldn't be wrong.
Wow, wouldn't that be something. This is hilariously wrong. You can build tiny functions and then compose those into larger functions and then the larger functions are all correct but only as long as their components are correct. It would be lovely if there was some magic construct that prevented you from writing incorrect code. Maybe it could be extended to hacker news comments, and then we could have just skipped this entire discussion.
> You could mis-spec the contract, of course. Then the function could be "wrong". Maybe this is the intent behind what you are trying to say here. But the idea has always been here that I would also read and accept the contract, so it wouldn't actually be "wrong". It would be exactly what we both expect. My side will be written to what the contact specifies. If you try to deviate from the contract later, you'll face the wrath of the compiler.
A truly baffling take. Bravo! Even on Hacker News, that was truly something. I don't even know where to begin. I guess I don't really have to, since when it comes to explaining the ease with which you transfer words straight from your ass to hacker news comments, it does a better job than I could possibly hope to do.
> As you point out, that's not the case in Typescript. If you try to change the contract (even if by accident) the compiler/typechecker will never say a word. I won't know until my code starts breaking. Your tests are the only thing you have to keep you in line with what we agreed upon. Tests define the contract in its case.
At this point, it's fairly clear that you are just thoroughly confused about how any of this works and what is actually possible. If you disagree, I'd love to hear how you would implement some sort of construct that allows you to write a function of the type `String -> Email` that doesn't throw if the email is invalid, can process arbitrary user input (not just string literals in your code), and somehow makes it a compiler error if your code is ever incorrect at all. PS: Explicitly returning and carrying around proof of validity doesn't count.
Why can't it 'throw' if the email is invalid? You can — and would — encode that into the contract, detailing exactly what that means, so no problem for the user. They will write their code expecting that condition and everything will be fine. There is nothing special about failure cases. It is only a state, just like every other state.
> At this point, it's fairly clear that you are just thoroughly confused about how any of this works and what is actually possible.
Ad hominem is a logical fallacy. It is surprising that a comment that claims to understand programming language types in great detail would also commit an obvious logical error, given how important logic is in that context. But, stranger things have happened, I suppose. Unfortunately, there is nothing we can take from a logical error. Assuming it was trying to be written in good faith and free of errors, no doubt we'll get a meaningful explanation of what was actually trying to be expressed with code examples to follow. Looking forward to it.
Thank you for (once again) making it clear to any reader that you are not to be taken seriously. If only we could edit older comments so that the reader didn't have to suffer through all your nonsense to find out.
The reader has no idea who the author is. Nor do they need to as the words on the page already provide sufficient information to determine if the words are worthy of being taken seriously or not. Trying to assign meaning from the author onto the message is not logically sound. Words stand on their own.
Turning to logical fallacies in an attempt to steer the reader away from understanding that Typescript relies on testing to downplay the original misunderstanding that you mention realizing cannot be edited now isn't going to work, I'm afraid. The reader is able to see through such a thin veneer. They could be convinced by a technical exchange directed at the topic at hand, but it is telling that we never saw anything of the sort.
It's extremely convenient for you to become offended at this stage so you can avoid actually addressing my points, since your claims are borderline nonsense. Any person that understands dependent types and is unfortunate enough to read through all the drivel you have posted in this thread will also immediately realize this, so it doesn't really matter. You are right that your words stand on their own in that regard.
In the end, you leave this thread knowing this as well, if you are at all capable of introspection.
How is it painful? You need to bump a minor version? It took me less than 5 minutes 90% of which was waiting for CI. There's even a tool you can run to do it for you.
Your site has waterfalls and flashes of unstyled content. It loads slowly and the whole design is basically exactly what every AI-designed site looks like.
All of the work you described is essentially manual labor. It's not difficult work - just boring, sometimes error prone work that mostly requires you to do obvious things and then tackle errors as they pop up in very obvious ways. Great use case for AI, for sure. This and the fact that the end result is so poor isn't really selling your argument very well, except maybe in the sense that yeah, AI is great for dull work in the same way an excavator is great for digging ditches.
> This and the fact that the end result is so poor isn't really selling your argument very well
If you ever find yourself at the point where you are insulting a guy's passion project in order to prove a point, perhaps have a deep breath, and take a step back from the computer for a moment. And maybe you should look deep inside yourself, because you might have crossed the threshold to being a jerk.
Yes, my site has issues. You know what else it has? Users. Your comments about FOUC and waterfalls are correct, but they don't rank particularly high on what are important to people who used the site. I didn't instruct the AI to fix them, because I was busy fixing a bunch of real problems that my actual users cared about.
As for loading slowly -- it loads in 400ms on my machine.
Look, buddy. You propped yourself up as an Experienced Dev doing cool stuff at Profitable Startup and don't understand Advanced Programming, and your entire argument is that you can keep doing the same sort of high quality(FSOV) work you've been doing the past 10 years with AI, just a lot faster.
I'm just calling spade a spade. If you didn't want people to comment on your side project given your arguments and the topic of discussion, you should just not have posted it in a public forum or have done better work.
If I were to summarize the intent of my comments in a single sentence, it would be something like "I have been an engineer for a while, and I have been able to do fun stuff with AI quickly." You somehow managed to respond to that by disparaging me as an engineer ("Experienced Dev") and saying the fun stuff I did is low quality ("should have [...] done better work"). It's so far away from the point I was making, and so wildly negative - when, again, my only intent was to say that I was doing fun AI stuff - that I can't imagine where it originated from. The fact that it's about a passion project is really the cherry on top. Do you tell your kids that their artwork is awful as well?
I can understand to some degree it would be chafing that I described myself as working at a SF Series C startup etc. The only intent there was to illustrate that I wasn't someone who started coding 2 weeks ago and had my mind blown by typing "GPT build me a calculator" into Claude. No intent at all of calling myself a mega-genius, which I don't really think I am. Just someone who likes doing fun stuff with AI.
And, BTW, if you reread my initial comment, you will realize you misread part of it. I said that "Advanced Programming" is the exact opposite of the type of work I am doing.
Look, I'm not trying to dunk on your website for fun. The issue is that you're making a specific argument: you're an experienced developer who uses AI to be 5-10x more productive without downsides, and you properly audit all the code it generates. You then offered your project as evidence of this workflow in action.
The problem is that your project has basic performance issues - FOUC, render waterfalls - that are central concerns in modern React development. These aren't arbitrary standards I invented to be mean. They're fundamental enough that React's recent development has specifically focused on solving them.
So when you say I'm inventing quality standards (in your now-deleted comment), or that this is just a passion project so quality doesn't matter, you're missing the point. You can't argue from professional authority that AI makes you more productive without compromise, use your work as proof, and then retreat to "it's just for fun" when someone points out the quality issues. Either it demonstrates your workflow's effectiveness or it doesn't. You can't have it both ways.
The kids' artwork comparison doesn't work either. You're not a child showing me a crayon drawing - you're a professional developer using your work as evidence in a technical argument about AI productivity. If you want to be treated as an experienced developer making authoritative claims, your evidence needs to support those claims.
I'm genuinely not trying to be cruel here, but if this represents what your AI workflow produces when you're auditing the output, it raises serious questions about whether you can actually catch the problems the AI introduces - which is the entire crux of your argument. Either you just aren't equipped to audit it (because you don't know better), or you are becoming passive in the face of the walls of code that the AI is generating for you.
I will accept for the moment that you are not just being willfully cruel.
Let's talk a little about FOUC and the waterfall. I am aware of both issues. In fact, they're both on my personal TODO list (along with some other fun stuff, like SSR). I have no doubt I could vibe code them both away, and at some point, I will. I've done plenty harder things. I haven't yet, because I was focusing on stuff that my moderators and users wanted me to do. They wanted features to ban users, a forgot password feature, email notifications, mobile support, dark mode, and a couple of other moderation tools. I added those. No one complained about FOUC or the waterfall, and no one said that the site loaded slowly, so I didn't prioritize those issues.
I understand you think your cited issues are important. To be honest, they irk me, too. But no one who actually uses the site mentioned them. So, when forced to prioritize, I added stuff they cared about instead.
> You can't argue from professional authority that AI makes you more productive without compromise, use your work as proof, and then retreat to "it's just for fun" when someone points out the quality issues
You seem to have missed the point of saying "it's just for fun". My point was this: You are holding a week-long project done with AI to professional standards. Nothing ever done in a week is going to be professional level! That is an absurd standard! You are pointing at the rough edges, that of course exist because it was done on the side, as some insane gotcha that proves the whole thing is a house of cards. "This is "dull work"! You should "have done better work" if you wanted to talk with us"! For FOUC?!? C'mon.
I'm wondering: do you genuinely not understand how compilers work at all or is there some deeper point to your AI/compiler comparison that I'm just not getting?
My understanding is that compilers work just like originally described. I type out what I want. I feed that into a compiler. It takes that input of what I want and generates code.
Is that not your understanding of how compilers work? If a compiler does not work like that, what do you think a complier does instead?
A compiler can be deterministic in some cases, but not necessarily so. A compiler for natural language cannot be deterministic, for example. It seems you're confusing what a compiler is with implementation details.
Let's get this topic back on track. What is it that you think a compiler does if not take in what you typed out for what you want and use that to generate code?
I've written more than one compiler, so I definitely understand how compilers work.
It seems you're trying to call anything that transforms one thing into another a compiler. We all know what a compiler is and what it does (except maybe you? It's not clear to me) so I genuinely don't understand why you're trying to overload this terminology further so that you can call LLMs compilers. They are obviously and fundamentally different things even if an LLM can do its best to pretend to be one. Is a natural language translation program a compiler?
> Is a natural language translation program a compiler?
We have always agreed that a natural language compiler is theoretically possible. Is a natural language translation program the same as a natural language compiler, or do you see some kind of difference? If so, what is the difference?
This doesn't feel like good-faith. There are leagues of difference between "what you typed out" when that's in a highly structured compiler-specific codified syntax *expressly designed* as the input to a compiler that produces computer programs, and "what you typed out" when that's an English-language prompt, sometimes vague and extremely high-level
That difference - and the assumed delta in difficulty, training and therefore cost involved - is why the latter case is newsworthy.
When has a semantic "argument" ever felt like good faith? All it can ever be is someone choosing what a term means to them and try to beat down others until they adopt the same meaning. Which will never happen because nobody really cares.
They are hilarious, but pointless. You know that going into it.