Author here. I'm surprised to see this surfacing now. I just wanted to clarify, since apparently the post doesn't do a good job at it, that what I discussed there is not a methodology I advocate for. The point of the post was: ok, since there are organizations mandating to maximize speed by reducing time spent on typing code (or even mandating to maximize agents usage), is there a way we can meet that requirement while still preserving the rigor somewhere else?
This was a follow up to a previous article[1] and the pair tried to express what I still think today (using AI daily at work): every time I use AI for coding, to some capacity I'm sacrificing system understanding and stability in favor of programming speed. This is not necessarily always a bad tradeoff, but I think it's important to constantly remind ourselves we are making it.
For sure every time you use ai you’re sacrificing understanding if you don’t plan out and understand how exactly the ai is going to do the work you asked it to do.
The same output that is such a bad thing in this article can also be used to gain context, by making a thorough plan with your ai first, reading through the plan and proposing changes just like you would with a real developer.
You can also use this output to have the ai write a journal as well. The journal can be as detailed as possible and essentially a ledger of all of the changes your ai has made to the code. This allows not only for your teammates reviewing your pr to gain greater context, but also can be used by yourself, or even the ai itself to figure the why behind a particular implementation was done the way it was, far into the future even.
Lastly how many of us ever deploy code without actually checking the feature works e2e? I would gather not many of us do, I don’t, because even though we may have a greater understanding of the code, we can make mistakes in the code or in our logic. And I keep coming back to why would we treat llms any differently? I believe we should be spending our energy thoroughly manually testing a feature to make sure when we brainstormed we actually did get every edge case, and it works well.
I think most people test at least a happy path of their code end to end. I think we can all agree that your last sentence is far more aspirational than bare minimum standard practice. (“I believe we should be spending our energy thoroughly manually testing a feature to make sure when we brainstormed we actually did get every edge case, and it works well.”)
I did one small side web project by only writing spec tests and prompts and testing the results in a browser, never reading nor editing a single line of generated code. It was something for home and so low stakes, but it worked remarkably well and was much better tested than the typical 2022-era home project of mine.
> every time I use AI for coding, to some capacity I'm sacrificing system understanding and stability in favor of programming speed.
Sure, but couldn't you say the same for letting other people contribute code too? In either case, you make the choice of how deeply you want to review it. You can ask the AI or the human to explain things that aren't clear.
For me it's case by case in either scenario. Sometimes it's not that important to look closely at a specific subsystem that's self-contained or just simple, other times I need to carefully audit whatever touches a different system. You need a good sense of the existing codebase/architecture in the first place to make these determinations.
I always wondered why people don't also ask the AI to generate code comments/documentation, summaries of those documentation, overview of the system, and re-review them all for correctness for the changes they asked the AI to do.
What I've noticed reviewing all my colleagues' AI generated code PRs is: it really is just code, and the rare comment here and there is still added by the human.
We're already trying to light tokens on fire as fast as possible to stay on acceptable required use leaderboards, why not light some more for system understanding and housekeeping.
Don’t you think that the provider of the LLM is also a dimension on these discussions about responsibility? We often talk about the tech itself (LLM driven development) but how we access it is just as important imo. It’s either locked behind a non trivial amount of hardware (for open models) or some monopolistic driven provider entity like OpenAI or anthropic. In the provider case, it’s not really the LLM that will “own” the code, it’s the provider itself and we’ll be at the mercy of whatever pricing model they shove down our throats.
You are missing another dimension how easy it would be to migrate if adding new feature hits a ceiling and LLM keeps breaking the system.
Imagine all tests are passing and code is confirming the spec, but everything is denormalized because LLM thought this was a nice idea at the beginning since no one mentioned that requirement in the spec. After a while you want to add a feature which requires normalized table and LLM keeps failing, but you also have no idea how this complex system works.
Don't forget that very very detailed spec is actually the code
> Don't forget that very very detailed spec is actually the code
Came here to say this, but you said it for me. If the problem were merely one of insufficient rigour or detail in specs, it would have been solved long before LLMs.
> Don't forget that very very detailed spec is actually the code
The tests, sure. But certainly not the code itself, as that sits far too close to the implementation (i.e. it is the implementation). An almost infinite number of implantations can fulfill “does foo when bar”, so how can we prove that ours is the spec itself?
It’s kind of like a scientist coming up with a hypothesis post-hoc to fit the results of the experiment.
I know you were simplifying, but "does foo then bar" is so far away from what an actual specification is that it defeats the point.
A more complete spec will capture performance requirements, input preconditions and output postconditions, error handling and recovery behaviors, threading behaviours, hardware assumptions, etc. It's hard to do these things without leaning at least somewhat on the specific language runtime you are using, otherwise you'd end up regurgitating the C standard each time you design a software system.
It's this sort of stuff that is meant when people say "sufficiently detailed".
If you're actually testing all these things, then I might agree with you that you can do it in the tests, but almost no one actually is. I'd struggle to write a test suite that tests all the specification-level assumptions I draw from my language and target platforms.
> Don't forget that very very detailed spec is actually the code
In the age of AI this is more true than you know. Given a detailed enough spec and test suite you can effectively rewrite any application with any language in a fully automated way.
I've coined that as "Duck coding" :D If it quacks like a duck, walks like a duck and looks like a duck - it's duck enough for as far as the spec is concerned. Does it matter what is inside the duck?
Yes. It would be like buying a car that you have no idea about the engine and gearbox and kind of fuel it is using or if at all. It have four wheels and and it can drive you from point A to B. Sure but sometimes it happens that some particular brands and they particular model requires engine renovation after 100k km because it is so shitty design.
Right now we are just starting vibe coded software, nobody knows how it will behave in 2 years or 5 or 10. My guess it won't. So we will enter age of scratch software. You build it, ship it. And after few months you will ship entirely new one. And then again. And again. And again. Because maintenance is hard and costly and writing from scratch will cost like 1k$ in tokens.
And users will have problem of migrating the data if possible at all. But if migration is hard and everything changes all the time does it even matter if you are using X o Y software? Does it even matter since you can write your own software and migrate your data there?
I think we saw how this ends with Chinese manufacturing. You buy some stuff from AliExpress for 2$ and throw it away in two weeks and buy a new one. So quality does not matter anymore.
> just like we don’t read assembly, or bytecode, or transpiled JavaScript
This makes sense since certain higher-level code produces certain lower-level code, while LLM cannot. If the transpired JS code doesn't work we could just find out the bug in minifiers, etc. but one cannot figure out why LLM fails at one task, especially considering LLMs, even SOTA ones, could be strongly affected by even small prompt changes. Taking this into consideration, I don't think this is a sound reasoning why we don't need to review ai-generated code.
> The LLMs produce non-deterministic output and generate code much faster than we can read it, so we can’t seriously expect to effectively review, understand, and approve every diff anymore.
Exactly. However, this could also indicate a weaker review standard instead of just dropping review. We could also suggest an idea where devs mainly review code design or interfaces, leveraging one's *taste*, while leaving strict logic reasoning, validating and testing to other tools or approaches. It cannot pursuade me that the nature of LLM's code generation must lead to a complete cancel of the code review.
Anyway, I'm not opposing this article and its thought of shift in the future is really good.
Couldn't we slowly add guardrails that eventually lead to code generation becoming more and more deterministic over time?
I'm seeing in my experience that Claude has become better with every version at producing uniformity in its code output. Especially where the architecture is clear and documented. And even more so in languages with built in uniformity (Go, HTMX, SQL) where there is intentionally only one or two ways of doing things. In such environments, the output is nearly deterministic.
Software engineering has always worked this way, just not to ICs.
“The LLMs produce non-deterministic output and generate code much faster than we can read it, so we can’t seriously expect to effectively review, understand, and approve every diff anymore. But that doesn’t necessarily mean we stop being rigorous, it could mean we should move rigor elsewhere.“
Direct reports, when delegated tasks by managers, product non-deterministic outputs much faster than team leads/managers can review, understand or approve every diff. Being a manager of software developers has always been a non-deterministic form of software engineering.
“The thing that really helps me is thinking back to when I’ve worked at larger organizations where I’ve been an engineering manager. Other teams are building software that my team depends on.
If another team hands over something and says, “hey, this is the image resize service, here’s how to use it to resize your images”... I’m not going to go and read every line of code that they wrote.
I’m going to look at their documentation and I’m going to use it to resize some images. And then I’m going to start shipping my own features. And if I start running into problems where the image resizer thing appears to have bugs or the performance isn’t good, that’s when I might dig into their Git repositories and see what’s going on. But for the most part I treat that as a semi-black box that I don’t look at until I need to.”
Suppose the image resize service has some caching, and due to a bug in the caching, under certain circumstances it will respond with an already-cached resized version of a different source image.
Let's say for example it caches on something stupid like the CRC32 of the input image -- good enough that the couple dozen images in your test dataset don't collide, you don't see it in smoke testing your app, but real world data has collisions on a daily basis.
This gets into production and customer A sees a resized version of customer B's document for a thumbnail. Now customer A is wondering how many other customers are seeing resized versions of their private documents in thumbnail images. They are very very mad.
If the image resize service was built by "another team" then that other team is responsible for the bug and will take most of the heat for it. If it was built by an "agent swarm" or "gas town" or whatever under my direction then I'm 100% responsible for it and rightly deserve the heat.
That is why I cannot understand any approach that doesn't involve reading the code at all. Testing alone is not sufficient. MTTR is not sufficient because you can't make a customer less mad about a data privacy bug by fixing it.
But then, the ownership is clear. And no team would be like to be pointed that their 5th iteration is also broken and can’t be relied for production usage. That’s the difference with AI code. LLM are not aligned with your goals. Any trust in them doing the right thing is very misguided.
Simon Willison’s analogy does not apply unless that other team was immediately fired after they delivered the image resize service, or (more commonly) was done by a one off contractor. The difference is the trust model. We trust that our company has hired a competent team which maintains knowledge of the image resizing service, that they respond to bug reports and feature requests and that they know how to fix and implement those.
Now I have been on HN long enough to know that we used to despise code written by contractors which we now depend on.
No, because those direct reports can use tools to build deterministic software. LLMs can't, because they themselves are non-deterministic. They will say they did, and they will be wrong. And the LLM you have check will also say it did, and it will be wrong. Etc etc.
These things just can't be in the critical path. They are ridiculously unreliable.
> Being a manager of software developers has always been a non-deterministic form of software engineering.
I disagree. Being a manager of programmers requires that you trust your programmers and have some way of occasionally verifying the correctness and efficacy of what they build to make sure that that trust is still properly placed.
But on top of that, the user of an LLM isn't really akin to a manager of programmers. Human programmers are responsible for what they write [0], and even the ones that only cost ~50% of a senior's total comp [1] are still going to be able to fairly reliably explain to you why they made the decisions they did, and fairly reliably be able to follow instruction. LLMs just aren't there yet, and the major LLM providers may never care to get them there.
A programmer who's using LLMs is a programmer who's using LLMs... not a manager of other programmers. I'm not going to say that the tech will never advance to that point, but it's simply not there yet.
[0] Unless management decides otherwise, of course.
[1] Nvidia's CEO recently mentioned that he'd be "deeply alarmed" if senior staff aren't spending at least half of their total compensation [2] on LLM providers, so I'm going to use that as my benchmark for "expected annual LLM spend".
[2] ...meaning that each senior programmer costs their employer at least 50% more than their total compensation....
> If I had to roll out such a development process today, I’d make a standardized Markdown specification the new unit of knowledge for the software project. Product owners and engineers could initially collaborate on this spec and on test cases to enforce business rules. Those should be checked into the project repositories along with the implementing code. There would need to be automated pull-request checks verifying not only that tests pass but that code conforms to the spec. This specification, and not the code that materializes it, is what the team would need to understand, review, and be held accountable for.
The constant urge I have today is for some sort of spec or simpler facts to be continuously verified at any point in the development process; Something agents would need to be aware of. I agree with the blog and think it's going to become a team sport to manage these requirements. I'm going to try this out by evolving my open source tool [1] (used to review specs and code) into a bit more of a collaborative & integrated plane for product specs/facts - https://plannotator.ai/workspaces/
What we really we need is some kind of more detailed spec language that doesn't have edge cases, where we describe exactly what we expect the generated code to do, and then formally verify that the now generated code matches the input spec requirement. It'd be super helpful to have something more formal with no ambiguity, especially because the english language tends to be pretty ambiguous in general which can result in spec problems
I also tend to find especially that there's a lot of cruft in human written spec languages - which makes them overly verbose once you really get into the details of how all of this works, so you could chop a lot of that out with a good spec language
I nominate that we call this completely novel, evolving discipline: 'programming'
There are languages like Dafny that permit you to declare pre- and post-conditions for functions. Dafny in particular tries to automatically verify or disprove these claims with an SMT solver. It would be neat if LLMs could read a human-written contract and iterate on the implementation until it's provably correct. I imagine you'd have much higher confidence in the results using this technique, but I doubt that available models are trained appropriately for this use case.
> What we really we need is some kind of more detailed spec language that doesn't have edge cases, where we describe exactly what we expect the generated code to do, and then formally verify that the now generated code matches the input spec requirement.
That's theorem provers and they're awful for anything of any reasonable complexity.
Shame us all for moving away from something so perfect, precise, and that "doesn't have edge cases."
Hey - if you invent a programming language that can be used in such a way and create guaranteed deterministic behavior based on expressed desires as simple as natural language - ill pay a $200/m subscription for it.
> where we describe exactly what we expect the generated code to do, and then formally verify that the now generated code matches the input spec requirement.
In ancient times we had tech to do exactly that: Programming languages and tests.
I called it gates on mine. I loved Beads but it closed tasks without any validation steps. Beads also had other weird issues, so I made my own alternative. I think "Gates" is also used by others projects that took on the same challenge I did in mine weirdly enough.
We've been through that so many times. When UML arrived (and ALM tools suites, IBM was trying to sell it, Borland was trying to sell it, all those fancy and expensive StarTeam, Caliber and Together soft), then BPML and its friends arrived, Business Rule Management System (BRMS), Drools in Java world, etc.
It all failed. For a simple reason, popularized by Joel Spolsky: if you want to create specification that describes precisely what software is doing and how it is doing its job, then, well, you need to write that damn program using MS Word or Markdown, which is neither practical nor easy.
The new buzzword is "spec driven development", maybe it will work this time, but I would not bet on that right now.
BTW: when we will be at this point, it does not make sense anymore to generate code in programming languages we have today, LLM can simply generate binaries or at least some AST that will be directly translated to binary. In this way LISP would, eventually, take over the world!.
I’ve been considering this as well, and trying to get my colleagues to understand and start doing it. I use it to pretty decent effect in my vibe coded slop side projects.
In the new world of mostly-AI code that is mostly not going to be properly reviewed or understood by humans, having a more and more robust manifestation and enforcement, and regeneration of the specs via the coding harness configuration combined with good old fashioned deterministic checks is one potential answer.
Taken to an extreme, the code doesn’t matter, it’s just another artifact generated by the specs, made manifest through the coding harness configuration and CI. If cost didn’t matter, you could re-generate code from scratch every time the specs/config change, and treat the specs/config as the new thing that you need to understand and maintain.
> If cost didn’t matter, you could re-generate code from scratch every time the specs/config change, and treat the specs/config as the new thing that you need to understand and maintain.
The critical insight is that this is not true. When people depend on your software, replacing it with an entirely different program satisfying all of your specs and configurations is a large, months-long project requiring substantial effort and coordination even after new program is written. It seems to work in vibe coded side projects because you don't have those dependencies; if you got an angry email from a CEO saying that moving a critical button ruined their monthly review cycle, and demanding 7 days notice before you move any buttons going forwards, you'd just tell them no.
I prefer "the bottleneck is understanding" framing.
The author is nibbling at the same problem ultimately, but i don't think "hey one strategy is we could just let cognitive debt accumulate so we can go faster!" is a particularly insightful tool in the toolbox. Don't misread me, i'm not denying it can be a valid strategy.
Instead i want to read about insightful strategies for optimising that system-wide bottleneck we have: understanding.
Tell me about how you managed to shift to a higher level of abstraction, tell me about how and when that abstraction leaks. Tell me how you reduced the amount of information that has to flow through the system bottleneck.
>... my first bet would be specifications ... and tests ... If I had to roll out such a development process today, I’d make a standardized Markdown specification the new unit of knowledge for the software project.
I've found that adopting RFC Keywords (e.g. RFC 2119 [1]; MUST, SHOULD, MAY) at least makes the LLM report satisfaction. I'd love to see a proper study on the usage of RFC keywords and their effect on compliance and effectiveness.
That's literally what OpenSpec does (https://openspec.dev/). It's quite nice. I've only exceptionally rarely seen claude do something wrong based on spec docs when it's fully spec'd out. More often it's because something wasn't nailed down and claude was forced to make assumptions.
The downside is the ospx markdown specs sometimes end up too granular, focusing on the wrong or less important details, so reading the specs feels like a slog.
Also at times aspects of the english language spec end up way more verbose than just giving a code example would be.
> We can stop reading LLM-generated code just like we don’t read assembly, or bytecode, or transpiled JavaScript; our high-level language source would now be another form of machine code
This is too weird for me. At least with programming languages I can consult the documentation and if the programming language isn’t behaving as documented, it’s obviously a defect and if you’re savvy enough you often have open channels that accept contributions. Can we say the same for Claude or other AI solutions?
The underlying mechanism is still the same: humans type and products come out.
So something which must be true if this author is right is that whatever the new language is—the thing people are typing into markdown—must be able to express the same rigor in less words than existing source code.
Otherwise the result is just legacy coding in a new programming language.
> Otherwise the result is just legacy coding in a new programming language.
And this is why starting with COBOL and through various implementations of CASE tools, "software through pictures" or flowcharts or UML, etc, which were supposed to let business SMEs write software without needing programmers, have all failed to achieve that goal.
While they failed to achieve the goal outright, I'd argue that each is a concrete step towards it. The languages we have today are more productive than the languages we had decades ago.
I think it's an open question of whether we achieve the holy grail language as the submission describes. My guess is that we inch towards the submission's direction, even if we never achieve it. It won't surprise me if new languages take LLMs into account just like some languages now take the IDE experience into account.
> must be able to express the same rigor in less words than existing source code
Yes but also no. Writing source means rigorously specifying the implementation itself in deep detail. Most of the time, the implementation does not need to be specified with this sort of rigor. Instead the observable behavior needs to be specified rigorously.
That doesn't sound right. For example, there's plenty of software with the correct observable behavior which leaks credentials. So what needs to be captured goes beyond observable behavior.
Is it? All the electricity and capital investment in computing hardware costs real money. Is this properly reflected in the fees that AI companies charge or is venture capital propping each one up in the hope that they will kill off the competition before they run out of (usually other people's) money?
Even ignoring the AI costs, 'rework' is going to be more expensive as soon as you have customers. For example any sort of data migration. Or UX expectations. Or public API interface. None of these can change without some thought, so one would be leaning on these specs quite a lot.
The lesson I've learned from our new AI age is how little a large number of people who've worked in software development their entire careers understand software development.
I suppose all the money floating around AI helps dummify everything, as people glom on to narratives, regardless of merit, that might position them to partake.
What we actually have now is the ability to bang out decent quality code really fast and cheaply.
This is massive, a huge change, one which upends numerous assumptions about the business of software development.
...and it only leaves us to work through every other aspect of software development.
The approach this article advocates is to essentially pretend none of this exists. Simple, but will rarely produce anything of value.
This paragraph from the post gives you the gist of it:
> ...we need to remove humans-in-the-loop, reduce coordination, friction, bureaucracy, and gate-keeping. We need a virtually infinite supply of requirements, engineers acting as pseudo-product designers, owning entire streams of work, with the purview to make autonomous decisions. Rework is almost free so we shouldn’t make an effort to prevent incorrect work from happening.
As if the only reason we ever had POs or designers or business teams, or built consensus between multiple people, or communicated with others, or reviewed designs and code, or tested software, was because it took individual engineers too long to bang out decent code.
AI has just gotten people completely lost. Or I guess just made it apparent they were lost the whole time?
All the talking points and techniques are those which were used when pushing outsourcing: give better specs, write detailed tests, accept bad code because it works so who cares, we can just rewrite from scratch later, and my favorite "they will get better with more exposure to your code base". None of these takes is wrong, but what they neglect is doing all that work is way more effort than if I wrote the original code myself.
Using an LLM to one shot a small function (something i would do with a very specific search on Google or SO) is handy. Giving it a harness and free access to a code base leads to some terrible code, and doubling down with more instructions and agents in the loop means more time writing the rube Goldberg orchestration rather than just opening up an editor and writing code.
Yeah this article is in a real uncanny valley for me where it has some insight, but it also throws out some wild ideas that don't pass the sniff test for me.
To me what AI is doing is changing the economics of human thought, but the change is happening way faster than individuals, let along organizations can absorb the implications. What I've seen is that AI magnifies the judgment of individuals who know how to use it, and so far it's mostly software engineers who have learned to use it most effectively because they are the ones able to develop an intuition about its limitations.
The idea of removing the human from the loop is nonsense. The question is more what loops matter, and how can AI speed them up. For instance, building more prototypes and one-off hacky tools is a great use of vibe coding, changing the core architecture of your critical business apps is not. AI has simultaneously increased my ability to call bullshit, while amplifying the amount of bullshit I have to sift through.
When the dust settles I don't really see that the value or importance of reading code has changed much. The whole reason agentic coding is successful is because code provides a precise specification that is both human and machine readable. The idea that we'll move from code to some new magical form of specification is just recycling the promise of COBOL, visual programming, Microsoft Access, ColdFusion, no-code tools, etc, to simplify programming. But actually the innovations that have moved the state of the art of professional programming forward, are the same ones that make agentic coding successful.
I appreciate your insights in a sea of psychosis comments. I find it strange how many people think we have achieved the likes of Y2K flying cars 20 years ago, or the dream of having every car on the road be an electric fully self driving car by now (a promise made at least over a decade ago by several of these types).
The point I’m making is that we give the spotlight to people who are making absurd claims. We have not achieved the ability to remove the human from the loop and continually produce value-able outputs. Until we do, I don’t see how any of the claims made in this article are even close to anything more than simply gate-keeping slop.
And if we do remove the human from the loop? What then, what are humans for? Do we get Keynes' idea that we only need to work a few hours a week or do we get a continuation and intensification of what we already have: a few high 'earners' and a sea of people struggling to make ends meet?
> Product owners and engineers could initially collaborate on this spec and on test cases to enforce business rules. Those should be checked into the project repositories along with the implementing code. There would need to be automated pull-request checks verifying not only that tests pass but that code conforms to the spec. This specification, and not the code that materializes it, is what the team would need to understand, review, and be held accountable for.
This just sounds like typical requirements management software (IBM DOORS for example, which has been around since the 90s).
It's kind of funny how AI evangelists keep re-discovering the need for work methods and systems that have existed for decades.
When I worked as a software developer at a big telecom company and I had no say in what the software was supposed to do, that was up to the software design people--they were the ones responsible for designing the software and defining all the requirements--I was just responsible for implementing that behavior in code.
One of my first tasks at my first job out of college required me to learn dxl (doors extension language) and implement some really intricate requirements management features.
It was gratifying to build the confidence of learning a new language quickly that I had never even heard of before. DXL was also pretty awful.
Opened a lot of doors for me though, no pun intended.
Spec-driven development is basically PRIDE, the first proven commercial software methodology dating back to 1971. In fact it may be the culmination of PRIDE because PRIDE's creators realized coding wasn't the hard part; the hard part was systems analysis, determining what problem needed to be solved and what to build. Coding comes last and when you did it right, was simply a translation step.
And now that step can be 100% automated.
Information systems design was a solved problem in the 1970s. PRIDE turned it from an art into a proven, repeatable science. Programmers, afraid of losing their perceived importance, resisted the discipline it imposes as the mustang resists the bit, but now that they're going the way of buggy-whip makers, maybe systems design as a science will make a comeback after 50 years.
My amazon orgs leadership has been obsessed with spec driven development while individual engineers tell me the only use they have is to placate leadership. I'm tired
TDD is done in a tight loop (minutes) while coding. For every little micro-feature/fix, you write a test for the new behavior you want, implement the minimal ugly fix to get the test to pass, then rely on the tests so you don't regress as you clean up.
LLMs struggle with TDD. They want to generate a bunch of code and tests in large passes. You can instruct them to do red/green TDD, but the results aren't great.
SDD starts before implementation, and formalizes intent and high-level design. LLMs eat it up. The humans can easily reinvent the worst parts of waterfall if they're not careful.
I wonder if with the speed of iteration with AI the industry will switch back to waterfall. Clear documentation first so the LLM can easily produce what's being asked with a round of testing before going back to the documentation stage and running it again. History does repeat itself.
> We can stop reading LLM-generated code just like we don’t read assembly, or bytecode, or transpiled JavaScript; our high-level language source would now be another form of machine code.
My opinion is very close to this. Currently the reason that it's bad to not reviewing/testing the code LLMs generated is because the LLMs can sometime generate bad codes. But it's a bug that can be improved. One day you'll have LLMs generating code consistently better than what a human could write. And then you just stop needing to review them. (And that's probably also the time where most programmers/developers got fired too)
Don't get surprised if anyday the LLMs starts to generate binaries directly. THAT will be impossible to read and costs more time to analyze.
> Currently the reason that it's bad to not reviewing/testing the code LLMs generated is that the LLMs can sometime generate bad codes.
Sometimes?
I am heavily into vibe coding and I think they almost always generate bad code. At least as soon as you're distant enough from the code to call it vibe coding.
When you're still in touch with the code, have at least been recently talking to it about code rather than 100% about features, and its context is filled with good code, it can generate good code.
> "I'd make a standardized Markdown specification the new unit of knowledge for the software project. ... There would need to be automated pull-request checks verifying not only that tests pass but that code conforms to the spec."
Agree, this is how you make the development loop more deterministic and ultimately autonomous. It's how I've been using coding agents myself for the past few months (by building my own to support this natively [1]).
If you have a spec you approve/agree on, have an agent code against it, and then have a review phase verify the implementation didn't drift from the spec (either by adding or removing features), you get to a position where you can trust the outcome.
There's still a lot to be said about spec definition and what if during implementation gaps are discovered, and that's where HITL comes into play.
This could very well be a pattern that some teams evolve into. Specs are the new source -- they describe the architectural approach, as well as the business rules and user experience details. End to end tests are described here too. This all is what goes through PRs and review process, and the code becomes a build artifact.
It just doesn’t work though. Anthropic couldn’t even get Claude to build a working C compiler which has a way better specification than any team can write and multiple reference implementations.
"A sufficiently precise spec is code". I've read somewhere here before.
So guardrails, i.e. sufficiently precise spec and tests, will need to be as strict as the LLM is bad at getting the right context and asking back the right questions. I suppose at that point not much difference between a human engineer and it.
I might even start my own blog to write about things I've found.
1. Always get the agent to create a plan file (spec). Whatever prompt you were going to yolo into the agent, do it in Plan Mode first so it creates a plan file.
2. Get agents to iterate on the plan file until it's complete and thorough. You want some sort of "/review-plan <file>" skill. You extend it over time so that the review output is better and better. For example, every finding should come with a recommended fix.
3. Once the plan is final, have an agent implement it.
4. Check the plan in with the impl commit.
The plan is the unit of work really since it encodes intent. Impl derives from it, and bugs then become a desync from intent or intent that was omitted. It's a nicer plane to work at.
From this extends more things: PRs should be plan files, not code. Impl is trivial. The hard part is the plan. The old way of deriving intent from code sucked. Why even PR code when we haven't agreed on a plan/intent?
This process also makes me think about how code implementation is just a more specific specification about what the computer should do. A plan is a higher level specification. A one-line prompt into an LLM is the highest level specification. It's kinda weird to think about.
Finally, this is why I don't have to read code anymore. Over time, my human review of the code unearthed fewer and fewer issues and corrections to the point where it felt unnecessary. I only read code these days so I can impose my preferences on it and get a feel for the system, but one day you realize that you can accumulate your preferences (like, use TDD and sum types) in your static prompt/instructions. And you're back to watching this thing write amazing code, often better than what you would have written unless you have maximum time + attention + energy + focus no matter how uninteresting the task, which you don't.
React team seems to really have set a precedent with their "dangerouslySetInnerHTML" idea.
Or did they borrow it somewhere?
I'm just curious about that etymology, of course the idea is not universally helpful: for example, for dd CLI parameters, it would only make a mess.
But when there's a flag/option that really requires you to be vigilant and undesired the input and output and all edge cases, calling it "dangerous" is quite a feat!
You're probably thinking of Rice's theorem (a sort of generalised halting problem), but this task is actually way easier than that, since we're not trying to study arbitrary algorithms: we're trying to study the subset of human-comprehensible algorithms. Most of the things we want computers to do are things that, given enough time, someone can write a program to solve: and generally, those programs are not tricksy or meta, and don't involve unsolved mathematics problems found by studying busy-beaver candidates. If it's possible for a human to understand how a program works (which is a necessary component of writing such a program), it's possible to write a mathematical proof about the program's behaviour, and that means it's in principle possible to automate the construction of that mathematical proof, which is equivalent to the "determine whether code conforms to the spec" task.
"Somewhat easier than an impossible task" is not a particularly strong claim about when (or whether) this problem will be solved, though.
That's what formal verification is about. I did some (using PSL for hardware verification); writing the formal spec is way harder than the actual code. It will find a lot of subtle issues, and you spend a most of the time deciding if it's the spec or the code that's wrong.
Having the code-writing part automated would have a negligible impact on the total project time.
This is a task that humans are exceptionally bad at, because we are not computers. If something uses the right words in the right order such that it communicates the correct algorithm to a human, then a human is likely to say "yup, that's correct", even if an hour's study of these 15 lines reveals that a subtle punctuation choice, or a subtle mismatch between a function's name and its semantics, would reveal that it implements a different algorithm to the expected one.
LLMs do not understand prose or code in the same way humans do (such that "understand" is misleading terminology), but they understand them in a way that's way closer to fuzzy natural language interpretation than pedantic programming language interpretation. (An LLM will be confused if you rename all the variables: a compiler won't even notice.)
So we've built a machine that makes the kinds of mistakes that humans struggle to spot, used RLHF to optimise it for persuasiveness, and now we're expecting humans to do a good job reviewing its output. And, per Kernighan's law:
> Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?
And that's the ideal situation where you're the one who's written it: reading other people's code is generally harder than reading your own. So how do you expect to fare when you're reading nobody's code at all?
I feel like people who program in JavaScript or whose projects pull megabytes of dependencies, don’t get a moral right to complain about this. You guys just sit and calm down this time, you already said what you could.
Your app takes 20 seconds to load, pulling 50 megabytes of minified JS. Your backend is a mess of 20 Rust microservices, 300 megabytes docker image each.
Nobody has actually been reading and understanding code in your org for the past 15 years. And nobody has ever been responsible, everybody has just been job hopping for a 15% total comp bump.
I found that adding "philosophy" descriptions help guide the tooling. No specs, just general vibes what's the point, because we can't make everyone happy and it's not a goal of a good tool (I believe).
Technology, implementation may change, but general point of "why!?" stays.
> Then where does the rigor go? Similar to the Thoughtworks report, my first bet would be specifications (which is not the same as prompts) and tests (which is not the same as TDD).
This is what we're building for at Saldor (https://saldor.com). It's a hard problem, to get a team in the habit of writing good specs. Probably because it's a hard thing to do: thinking of the behavior of your program, especially at the edges. But I agree (biased) that this is probably the way forward for writing code in the near future. I'm excited to see other people thinking about it.
I have team do this using CLAUDE.md telling Claude to do it in a set of interconnected steps, but in brief: they are to make it write every aspect of transcript somewhere: PRD, research notes, spec, dev log and debate log, break/fix/retro notes, commit log, PR, release notes, README, docs .mds... heavy emphasis on the edges in our thinking, and just as important, the edges in its ability to provide good leverage.
It needs a core set of guidance on the ordering and how to write "as of" a given phase or release so context stays current, trusting the old info is in git history it can navigate for the story of how we got here.
CC's /insights claims I have 10:1 md edits to code edits, and we both note this way of working is resulting in far fewer error loops per higher quality outcome.
// So yes, interested in your product. Baking something more broadly battle tested in so we don't have to reinvent it makes sense.
the irony is that AI is making this exact problem worse. ppl are generating entire codebases now without reading any of it -- the flag might as well be the default. the skill thats actually becoming scarce isnt writing code, its reading code you didnt write and knowing if its correct.
markdown became the language I hate the most thank to LLMs and specs-driven approach. everything feels so dumb right now in agentic coding.
looping blindlessly and aimlessly until it compiles then until the playwright server or whatever devtools shows that it somehow works. push the code, have a llm autoreview/autofix,push to prod, run a mythos (perfect name) to identify the bug that opus 4.7 create. loops on loops on loops of some kind of zombie processes running to a "goal" that everyone seems to mystify in talks to just hide the fact that we do nothing anymore. the bottleneck never was code. it was the gate that was keeping away the Elizabeth Holmes and SBF from software engineering and it just opened.
A colleague and I have taken to use of the verb "meatspin", from another era in Internet shock humour, to describe what it is that coding agents actually do 99% of the time.
it's the most honest framing I've seen, but specs as the new source of truth is exactly what we promised ourselves with UML, then WSDL, then OpenAPI. the graveyard of just make the artifact above the code authoritative is long
very true. and we already know and agree with this.
user experience/what the app actually does >>> actually implementing it.
elon musk said this a looong time ago. we move from layer 1 (coding, how do we implement this?) to layer 2 thinking (what should the code do? what do we code? should we implement this? (what to code to get the most money?))
I left a similar comment elsewhere in this thread. I still remember when so many people hallucinated that we would suddenly have flying cars by 2002 at the latest. If we achieve several more major improvements on current technology, these thoughts are interesting to consider. But not before that occurs.
Instead of accepting 20,000 lines of slop per PR (and never-ending combinatorial complexity), maybe we should aim to think about abstractions and how to steer LLMs to generate code similar to that of a skilled human developer. Then it could actually be a maintainable artifact by humans and LLMs alike.
I don't get why every AI article is so hyper-focused on coding speed. If the coding is so fast doesn't it make sense to invest more time into quality, learning, documentation, testing refactoring, making a better product? I'm beginning to think that the slopcoders are evaluated by kLOCs of lines written in addition to LLM token usage and they're just maximising the measured metrics. Whether that actually ends up in production or is used by any real person is seemingly irrelevant. Likely the more bugs that are produced the more agents can be spun in parallel to simulate busywork.
Author here. I'm surprised to see this surfacing now. I just wanted to clarify, since apparently the post doesn't do a good job at it, that what I discussed there is not a methodology I advocate for. The point of the post was: ok, since there are organizations mandating to maximize speed by reducing time spent on typing code (or even mandating to maximize agents usage), is there a way we can meet that requirement while still preserving the rigor somewhere else?
This was a follow up to a previous article[1] and the pair tried to express what I still think today (using AI daily at work): every time I use AI for coding, to some capacity I'm sacrificing system understanding and stability in favor of programming speed. This is not necessarily always a bad tradeoff, but I think it's important to constantly remind ourselves we are making it.
[1] https://olano.dev/blog/tactical-tornado/
For sure every time you use ai you’re sacrificing understanding if you don’t plan out and understand how exactly the ai is going to do the work you asked it to do.
The same output that is such a bad thing in this article can also be used to gain context, by making a thorough plan with your ai first, reading through the plan and proposing changes just like you would with a real developer.
You can also use this output to have the ai write a journal as well. The journal can be as detailed as possible and essentially a ledger of all of the changes your ai has made to the code. This allows not only for your teammates reviewing your pr to gain greater context, but also can be used by yourself, or even the ai itself to figure the why behind a particular implementation was done the way it was, far into the future even.
Lastly how many of us ever deploy code without actually checking the feature works e2e? I would gather not many of us do, I don’t, because even though we may have a greater understanding of the code, we can make mistakes in the code or in our logic. And I keep coming back to why would we treat llms any differently? I believe we should be spending our energy thoroughly manually testing a feature to make sure when we brainstormed we actually did get every edge case, and it works well.
I think most people test at least a happy path of their code end to end. I think we can all agree that your last sentence is far more aspirational than bare minimum standard practice. (“I believe we should be spending our energy thoroughly manually testing a feature to make sure when we brainstormed we actually did get every edge case, and it works well.”)
I did one small side web project by only writing spec tests and prompts and testing the results in a browser, never reading nor editing a single line of generated code. It was something for home and so low stakes, but it worked remarkably well and was much better tested than the typical 2022-era home project of mine.
2 replies →
It gets better:
(NOT a lawyer)
Previously, liability and indemnification could be bureaucratically laundered to "engineers", because it was a huge diffuse set of people.
Now the bag is left with top of the chain for authorizing LLMs. Gia Tan went the hard way with xz. LLM-trolling is the new social engineering.
> every time I use AI for coding, to some capacity I'm sacrificing system understanding and stability in favor of programming speed.
Sure, but couldn't you say the same for letting other people contribute code too? In either case, you make the choice of how deeply you want to review it. You can ask the AI or the human to explain things that aren't clear.
For me it's case by case in either scenario. Sometimes it's not that important to look closely at a specific subsystem that's self-contained or just simple, other times I need to carefully audit whatever touches a different system. You need a good sense of the existing codebase/architecture in the first place to make these determinations.
I always wondered why people don't also ask the AI to generate code comments/documentation, summaries of those documentation, overview of the system, and re-review them all for correctness for the changes they asked the AI to do.
What I've noticed reviewing all my colleagues' AI generated code PRs is: it really is just code, and the rare comment here and there is still added by the human.
We're already trying to light tokens on fire as fast as possible to stay on acceptable required use leaderboards, why not light some more for system understanding and housekeeping.
10 replies →
The people can meaningfully collaborate and produce something of high quality.
Don’t you think that the provider of the LLM is also a dimension on these discussions about responsibility? We often talk about the tech itself (LLM driven development) but how we access it is just as important imo. It’s either locked behind a non trivial amount of hardware (for open models) or some monopolistic driven provider entity like OpenAI or anthropic. In the provider case, it’s not really the LLM that will “own” the code, it’s the provider itself and we’ll be at the mercy of whatever pricing model they shove down our throats.
I don't like the premise of the article, but I agree that if you accept the premise, the contents of the articles are a good way to do it.
[flagged]
He was establishing the context of The current blog post. Very unlikely that he was doing it for Google juice.
> my first bet would be specifications and tests
You are missing another dimension how easy it would be to migrate if adding new feature hits a ceiling and LLM keeps breaking the system.
Imagine all tests are passing and code is confirming the spec, but everything is denormalized because LLM thought this was a nice idea at the beginning since no one mentioned that requirement in the spec. After a while you want to add a feature which requires normalized table and LLM keeps failing, but you also have no idea how this complex system works.
Don't forget that very very detailed spec is actually the code
> Don't forget that very very detailed spec is actually the code
Came here to say this, but you said it for me. If the problem were merely one of insufficient rigour or detail in specs, it would have been solved long before LLMs.
> Don't forget that very very detailed spec is actually the code
The tests, sure. But certainly not the code itself, as that sits far too close to the implementation (i.e. it is the implementation). An almost infinite number of implantations can fulfill “does foo when bar”, so how can we prove that ours is the spec itself?
It’s kind of like a scientist coming up with a hypothesis post-hoc to fit the results of the experiment.
I know you were simplifying, but "does foo then bar" is so far away from what an actual specification is that it defeats the point.
A more complete spec will capture performance requirements, input preconditions and output postconditions, error handling and recovery behaviors, threading behaviours, hardware assumptions, etc. It's hard to do these things without leaning at least somewhat on the specific language runtime you are using, otherwise you'd end up regurgitating the C standard each time you design a software system.
It's this sort of stuff that is meant when people say "sufficiently detailed".
If you're actually testing all these things, then I might agree with you that you can do it in the tests, but almost no one actually is. I'd struggle to write a test suite that tests all the specification-level assumptions I draw from my language and target platforms.
I've found LLM written unit tests to be fairly low quality which makes sense as writing good tests takes understanding that writing good code.
Also the quality of tests in general in projects is often so so and that's reflected in the output of LLMs even more so.
It'd be insane to come up with theories before doing any sort of observation.
> Don't forget that very very detailed spec is actually the code
In the age of AI this is more true than you know. Given a detailed enough spec and test suite you can effectively rewrite any application with any language in a fully automated way.
I've coined that as "Duck coding" :D If it quacks like a duck, walks like a duck and looks like a duck - it's duck enough for as far as the spec is concerned. Does it matter what is inside the duck?
Yes. It would be like buying a car that you have no idea about the engine and gearbox and kind of fuel it is using or if at all. It have four wheels and and it can drive you from point A to B. Sure but sometimes it happens that some particular brands and they particular model requires engine renovation after 100k km because it is so shitty design.
Right now we are just starting vibe coded software, nobody knows how it will behave in 2 years or 5 or 10. My guess it won't. So we will enter age of scratch software. You build it, ship it. And after few months you will ship entirely new one. And then again. And again. And again. Because maintenance is hard and costly and writing from scratch will cost like 1k$ in tokens.
And users will have problem of migrating the data if possible at all. But if migration is hard and everything changes all the time does it even matter if you are using X o Y software? Does it even matter since you can write your own software and migrate your data there?
I think we saw how this ends with Chinese manufacturing. You buy some stuff from AliExpress for 2$ and throw it away in two weeks and buy a new one. So quality does not matter anymore.
2 replies →
> just like we don’t read assembly, or bytecode, or transpiled JavaScript
This makes sense since certain higher-level code produces certain lower-level code, while LLM cannot. If the transpired JS code doesn't work we could just find out the bug in minifiers, etc. but one cannot figure out why LLM fails at one task, especially considering LLMs, even SOTA ones, could be strongly affected by even small prompt changes. Taking this into consideration, I don't think this is a sound reasoning why we don't need to review ai-generated code.
> The LLMs produce non-deterministic output and generate code much faster than we can read it, so we can’t seriously expect to effectively review, understand, and approve every diff anymore.
Exactly. However, this could also indicate a weaker review standard instead of just dropping review. We could also suggest an idea where devs mainly review code design or interfaces, leveraging one's *taste*, while leaving strict logic reasoning, validating and testing to other tools or approaches. It cannot pursuade me that the nature of LLM's code generation must lead to a complete cancel of the code review.
Anyway, I'm not opposing this article and its thought of shift in the future is really good.
Couldn't we slowly add guardrails that eventually lead to code generation becoming more and more deterministic over time?
I'm seeing in my experience that Claude has become better with every version at producing uniformity in its code output. Especially where the architecture is clear and documented. And even more so in languages with built in uniformity (Go, HTMX, SQL) where there is intentionally only one or two ways of doing things. In such environments, the output is nearly deterministic.
Software engineering has always worked this way, just not to ICs.
“The LLMs produce non-deterministic output and generate code much faster than we can read it, so we can’t seriously expect to effectively review, understand, and approve every diff anymore. But that doesn’t necessarily mean we stop being rigorous, it could mean we should move rigor elsewhere.“
Direct reports, when delegated tasks by managers, product non-deterministic outputs much faster than team leads/managers can review, understand or approve every diff. Being a manager of software developers has always been a non-deterministic form of software engineering.
Simon Willison made a similar parallel recently:
https://simonwillison.net/2026/May/6/vibe-coding-and-agentic...
Suppose the image resize service has some caching, and due to a bug in the caching, under certain circumstances it will respond with an already-cached resized version of a different source image.
Let's say for example it caches on something stupid like the CRC32 of the input image -- good enough that the couple dozen images in your test dataset don't collide, you don't see it in smoke testing your app, but real world data has collisions on a daily basis.
This gets into production and customer A sees a resized version of customer B's document for a thumbnail. Now customer A is wondering how many other customers are seeing resized versions of their private documents in thumbnail images. They are very very mad.
If the image resize service was built by "another team" then that other team is responsible for the bug and will take most of the heat for it. If it was built by an "agent swarm" or "gas town" or whatever under my direction then I'm 100% responsible for it and rightly deserve the heat.
That is why I cannot understand any approach that doesn't involve reading the code at all. Testing alone is not sufficient. MTTR is not sufficient because you can't make a customer less mad about a data privacy bug by fixing it.
1 reply →
This leaves out the part where you ask the original developer: "Why does this thing do that?"
But then, the ownership is clear. And no team would be like to be pointed that their 5th iteration is also broken and can’t be relied for production usage. That’s the difference with AI code. LLM are not aligned with your goals. Any trust in them doing the right thing is very misguided.
2 replies →
Simon Willison’s analogy does not apply unless that other team was immediately fired after they delivered the image resize service, or (more commonly) was done by a one off contractor. The difference is the trust model. We trust that our company has hired a competent team which maintains knowledge of the image resizing service, that they respond to bug reports and feature requests and that they know how to fix and implement those.
Now I have been on HN long enough to know that we used to despise code written by contractors which we now depend on.
3 replies →
No, because those direct reports can use tools to build deterministic software. LLMs can't, because they themselves are non-deterministic. They will say they did, and they will be wrong. And the LLM you have check will also say it did, and it will be wrong. Etc etc.
These things just can't be in the critical path. They are ridiculously unreliable.
> Being a manager of software developers has always been a non-deterministic form of software engineering.
I disagree. Being a manager of programmers requires that you trust your programmers and have some way of occasionally verifying the correctness and efficacy of what they build to make sure that that trust is still properly placed.
But on top of that, the user of an LLM isn't really akin to a manager of programmers. Human programmers are responsible for what they write [0], and even the ones that only cost ~50% of a senior's total comp [1] are still going to be able to fairly reliably explain to you why they made the decisions they did, and fairly reliably be able to follow instruction. LLMs just aren't there yet, and the major LLM providers may never care to get them there.
A programmer who's using LLMs is a programmer who's using LLMs... not a manager of other programmers. I'm not going to say that the tech will never advance to that point, but it's simply not there yet.
[0] Unless management decides otherwise, of course.
[1] Nvidia's CEO recently mentioned that he'd be "deeply alarmed" if senior staff aren't spending at least half of their total compensation [2] on LLM providers, so I'm going to use that as my benchmark for "expected annual LLM spend".
[2] ...meaning that each senior programmer costs their employer at least 50% more than their total compensation....
> Being a manager of software developers has always been a non-deterministic form of software engineering.
Unless the manager is also a principal/architect, I don’t find this to be agreeable.
It’s similar to saying that you are a non-deterministic chef when you order food from a restaurant.
Well yes but if no humans at the company understand the code then no one is truly responsible for it.
what about the artifacts that were supposed to test the correctness of the code? are they passing willy nilly?
4 replies →
> If I had to roll out such a development process today, I’d make a standardized Markdown specification the new unit of knowledge for the software project. Product owners and engineers could initially collaborate on this spec and on test cases to enforce business rules. Those should be checked into the project repositories along with the implementing code. There would need to be automated pull-request checks verifying not only that tests pass but that code conforms to the spec. This specification, and not the code that materializes it, is what the team would need to understand, review, and be held accountable for.
The constant urge I have today is for some sort of spec or simpler facts to be continuously verified at any point in the development process; Something agents would need to be aware of. I agree with the blog and think it's going to become a team sport to manage these requirements. I'm going to try this out by evolving my open source tool [1] (used to review specs and code) into a bit more of a collaborative & integrated plane for product specs/facts - https://plannotator.ai/workspaces/
[1] https://github.com/backnotprop/plannotator
What we really we need is some kind of more detailed spec language that doesn't have edge cases, where we describe exactly what we expect the generated code to do, and then formally verify that the now generated code matches the input spec requirement. It'd be super helpful to have something more formal with no ambiguity, especially because the english language tends to be pretty ambiguous in general which can result in spec problems
I also tend to find especially that there's a lot of cruft in human written spec languages - which makes them overly verbose once you really get into the details of how all of this works, so you could chop a lot of that out with a good spec language
I nominate that we call this completely novel, evolving discipline: 'programming'
There are languages like Dafny that permit you to declare pre- and post-conditions for functions. Dafny in particular tries to automatically verify or disprove these claims with an SMT solver. It would be neat if LLMs could read a human-written contract and iterate on the implementation until it's provably correct. I imagine you'd have much higher confidence in the results using this technique, but I doubt that available models are trained appropriately for this use case.
1 reply →
> What we really we need is some kind of more detailed spec language that doesn't have edge cases, where we describe exactly what we expect the generated code to do, and then formally verify that the now generated code matches the input spec requirement.
That's theorem provers and they're awful for anything of any reasonable complexity.
1 reply →
Check out Allium, posted here recently.
https://juxt.github.io/allium/
Hate it all you want, but XML is genuinely a good fit there, and Claude is apparently insanely good at working with XML prompts.
7 replies →
yes, am familiar with the "code is spec" trope.
Shame us all for moving away from something so perfect, precise, and that "doesn't have edge cases."
Hey - if you invent a programming language that can be used in such a way and create guaranteed deterministic behavior based on expressed desires as simple as natural language - ill pay a $200/m subscription for it.
4 replies →
> where we describe exactly what we expect the generated code to do, and then formally verify that the now generated code matches the input spec requirement.
In ancient times we had tech to do exactly that: Programming languages and tests.
like declarative vs imperative?
I called it gates on mine. I loved Beads but it closed tasks without any validation steps. Beads also had other weird issues, so I made my own alternative. I think "Gates" is also used by others projects that took on the same challenge I did in mine weirdly enough.
https://github.com/Giancarlos/guardrails
We've been through that so many times. When UML arrived (and ALM tools suites, IBM was trying to sell it, Borland was trying to sell it, all those fancy and expensive StarTeam, Caliber and Together soft), then BPML and its friends arrived, Business Rule Management System (BRMS), Drools in Java world, etc.
It all failed. For a simple reason, popularized by Joel Spolsky: if you want to create specification that describes precisely what software is doing and how it is doing its job, then, well, you need to write that damn program using MS Word or Markdown, which is neither practical nor easy.
The new buzzword is "spec driven development", maybe it will work this time, but I would not bet on that right now.
BTW: when we will be at this point, it does not make sense anymore to generate code in programming languages we have today, LLM can simply generate binaries or at least some AST that will be directly translated to binary. In this way LISP would, eventually, take over the world!.
I’ve been considering this as well, and trying to get my colleagues to understand and start doing it. I use it to pretty decent effect in my vibe coded slop side projects.
In the new world of mostly-AI code that is mostly not going to be properly reviewed or understood by humans, having a more and more robust manifestation and enforcement, and regeneration of the specs via the coding harness configuration combined with good old fashioned deterministic checks is one potential answer.
Taken to an extreme, the code doesn’t matter, it’s just another artifact generated by the specs, made manifest through the coding harness configuration and CI. If cost didn’t matter, you could re-generate code from scratch every time the specs/config change, and treat the specs/config as the new thing that you need to understand and maintain.
“Clean room code generation-compiler-thing.”
> If cost didn’t matter, you could re-generate code from scratch every time the specs/config change, and treat the specs/config as the new thing that you need to understand and maintain.
The critical insight is that this is not true. When people depend on your software, replacing it with an entirely different program satisfying all of your specs and configurations is a large, months-long project requiring substantial effort and coordination even after new program is written. It seems to work in vibe coded side projects because you don't have those dependencies; if you got an angry email from a CEO saying that moving a critical button ruined their monthly review cycle, and demanding 7 days notice before you move any buttons going forwards, you'd just tell them no.
[flagged]
[dead]
I prefer "the bottleneck is understanding" framing.
The author is nibbling at the same problem ultimately, but i don't think "hey one strategy is we could just let cognitive debt accumulate so we can go faster!" is a particularly insightful tool in the toolbox. Don't misread me, i'm not denying it can be a valid strategy.
Instead i want to read about insightful strategies for optimising that system-wide bottleneck we have: understanding.
Tell me about how you managed to shift to a higher level of abstraction, tell me about how and when that abstraction leaks. Tell me how you reduced the amount of information that has to flow through the system bottleneck.
> We can’t leverage agents if our unit of work is still “add a new endpoint to the RESTful API”
Why not? You just make every task faster. Not everything has to be an uncontrollable rocket launch.
> We need a virtually infinite supply of requirements, engineers acting as pseudo-product designers, owning entire streams of work
Why? To build what? You can only build as fast as you understand the business and your users.
>You can only build as fast as you understand the business and your users.
It should be possible to go faster by having AI understand the business and users.
It doesn't do that though. Understand. That's not how LLMs work.
2 replies →
>... my first bet would be specifications ... and tests ... If I had to roll out such a development process today, I’d make a standardized Markdown specification the new unit of knowledge for the software project.
I've found that adopting RFC Keywords (e.g. RFC 2119 [1]; MUST, SHOULD, MAY) at least makes the LLM report satisfaction. I'd love to see a proper study on the usage of RFC keywords and their effect on compliance and effectiveness.
1. https://www.rfc-editor.org/info/rfc2119/
That's literally what OpenSpec does (https://openspec.dev/). It's quite nice. I've only exceptionally rarely seen claude do something wrong based on spec docs when it's fully spec'd out. More often it's because something wasn't nailed down and claude was forced to make assumptions.
The downside is the ospx markdown specs sometimes end up too granular, focusing on the wrong or less important details, so reading the specs feels like a slog.
Also at times aspects of the english language spec end up way more verbose than just giving a code example would be.
Is it time for the literate programming renaissance?
> We can stop reading LLM-generated code just like we don’t read assembly, or bytecode, or transpiled JavaScript; our high-level language source would now be another form of machine code
This is too weird for me. At least with programming languages I can consult the documentation and if the programming language isn’t behaving as documented, it’s obviously a defect and if you’re savvy enough you often have open channels that accept contributions. Can we say the same for Claude or other AI solutions?
If you run a local LLM and an open source agent harness you are pretty close to that.
can you explain how? with a compiler you can rely on the adage "it's never a compiler bug" (until it is! and then you can fix it)
how can a local LLM with an open source agent harness provide the same trustworthiness?
2 replies →
The underlying mechanism is still the same: humans type and products come out.
So something which must be true if this author is right is that whatever the new language is—the thing people are typing into markdown—must be able to express the same rigor in less words than existing source code.
Otherwise the result is just legacy coding in a new programming language.
> Otherwise the result is just legacy coding in a new programming language.
And this is why starting with COBOL and through various implementations of CASE tools, "software through pictures" or flowcharts or UML, etc, which were supposed to let business SMEs write software without needing programmers, have all failed to achieve that goal.
While they failed to achieve the goal outright, I'd argue that each is a concrete step towards it. The languages we have today are more productive than the languages we had decades ago.
I think it's an open question of whether we achieve the holy grail language as the submission describes. My guess is that we inch towards the submission's direction, even if we never achieve it. It won't surprise me if new languages take LLMs into account just like some languages now take the IDE experience into account.
> must be able to express the same rigor in less words than existing source code
Yes but also no. Writing source means rigorously specifying the implementation itself in deep detail. Most of the time, the implementation does not need to be specified with this sort of rigor. Instead the observable behavior needs to be specified rigorously.
That doesn't sound right. For example, there's plenty of software with the correct observable behavior which leaks credentials. So what needs to be captured goes beyond observable behavior.
9 replies →
> Rework is almost free
Is it? All the electricity and capital investment in computing hardware costs real money. Is this properly reflected in the fees that AI companies charge or is venture capital propping each one up in the hope that they will kill off the competition before they run out of (usually other people's) money?
Even ignoring the AI costs, 'rework' is going to be more expensive as soon as you have customers. For example any sort of data migration. Or UX expectations. Or public API interface. None of these can change without some thought, so one would be leaning on these specs quite a lot.
Yeah, a lot of Claude Code users(me included) found in March if rework is free or not.
The lesson I've learned from our new AI age is how little a large number of people who've worked in software development their entire careers understand software development.
I suppose all the money floating around AI helps dummify everything, as people glom on to narratives, regardless of merit, that might position them to partake.
What we actually have now is the ability to bang out decent quality code really fast and cheaply.
This is massive, a huge change, one which upends numerous assumptions about the business of software development.
...and it only leaves us to work through every other aspect of software development.
The approach this article advocates is to essentially pretend none of this exists. Simple, but will rarely produce anything of value.
This paragraph from the post gives you the gist of it:
> ...we need to remove humans-in-the-loop, reduce coordination, friction, bureaucracy, and gate-keeping. We need a virtually infinite supply of requirements, engineers acting as pseudo-product designers, owning entire streams of work, with the purview to make autonomous decisions. Rework is almost free so we shouldn’t make an effort to prevent incorrect work from happening.
As if the only reason we ever had POs or designers or business teams, or built consensus between multiple people, or communicated with others, or reviewed designs and code, or tested software, was because it took individual engineers too long to bang out decent code.
AI has just gotten people completely lost. Or I guess just made it apparent they were lost the whole time?
All the talking points and techniques are those which were used when pushing outsourcing: give better specs, write detailed tests, accept bad code because it works so who cares, we can just rewrite from scratch later, and my favorite "they will get better with more exposure to your code base". None of these takes is wrong, but what they neglect is doing all that work is way more effort than if I wrote the original code myself.
Using an LLM to one shot a small function (something i would do with a very specific search on Google or SO) is handy. Giving it a harness and free access to a code base leads to some terrible code, and doubling down with more instructions and agents in the loop means more time writing the rube Goldberg orchestration rather than just opening up an editor and writing code.
Yeah this article is in a real uncanny valley for me where it has some insight, but it also throws out some wild ideas that don't pass the sniff test for me.
To me what AI is doing is changing the economics of human thought, but the change is happening way faster than individuals, let along organizations can absorb the implications. What I've seen is that AI magnifies the judgment of individuals who know how to use it, and so far it's mostly software engineers who have learned to use it most effectively because they are the ones able to develop an intuition about its limitations.
The idea of removing the human from the loop is nonsense. The question is more what loops matter, and how can AI speed them up. For instance, building more prototypes and one-off hacky tools is a great use of vibe coding, changing the core architecture of your critical business apps is not. AI has simultaneously increased my ability to call bullshit, while amplifying the amount of bullshit I have to sift through.
When the dust settles I don't really see that the value or importance of reading code has changed much. The whole reason agentic coding is successful is because code provides a precise specification that is both human and machine readable. The idea that we'll move from code to some new magical form of specification is just recycling the promise of COBOL, visual programming, Microsoft Access, ColdFusion, no-code tools, etc, to simplify programming. But actually the innovations that have moved the state of the art of professional programming forward, are the same ones that make agentic coding successful.
I appreciate your insights in a sea of psychosis comments. I find it strange how many people think we have achieved the likes of Y2K flying cars 20 years ago, or the dream of having every car on the road be an electric fully self driving car by now (a promise made at least over a decade ago by several of these types).
The point I’m making is that we give the spotlight to people who are making absurd claims. We have not achieved the ability to remove the human from the loop and continually produce value-able outputs. Until we do, I don’t see how any of the claims made in this article are even close to anything more than simply gate-keeping slop.
And if we do remove the human from the loop? What then, what are humans for? Do we get Keynes' idea that we only need to work a few hours a week or do we get a continuation and intensification of what we already have: a few high 'earners' and a sea of people struggling to make ends meet?
1 reply →
> Product owners and engineers could initially collaborate on this spec and on test cases to enforce business rules. Those should be checked into the project repositories along with the implementing code. There would need to be automated pull-request checks verifying not only that tests pass but that code conforms to the spec. This specification, and not the code that materializes it, is what the team would need to understand, review, and be held accountable for.
This just sounds like typical requirements management software (IBM DOORS for example, which has been around since the 90s).
It's kind of funny how AI evangelists keep re-discovering the need for work methods and systems that have existed for decades.
When I worked as a software developer at a big telecom company and I had no say in what the software was supposed to do, that was up to the software design people--they were the ones responsible for designing the software and defining all the requirements--I was just responsible for implementing that behavior in code.
One of my first tasks at my first job out of college required me to learn dxl (doors extension language) and implement some really intricate requirements management features.
It was gratifying to build the confidence of learning a new language quickly that I had never even heard of before. DXL was also pretty awful.
Opened a lot of doors for me though, no pun intended.
Spec-driven development is basically PRIDE, the first proven commercial software methodology dating back to 1971. In fact it may be the culmination of PRIDE because PRIDE's creators realized coding wasn't the hard part; the hard part was systems analysis, determining what problem needed to be solved and what to build. Coding comes last and when you did it right, was simply a translation step.
And now that step can be 100% automated.
Information systems design was a solved problem in the 1970s. PRIDE turned it from an art into a proven, repeatable science. Programmers, afraid of losing their perceived importance, resisted the discipline it imposes as the mustang resists the bit, but now that they're going the way of buggy-whip makers, maybe systems design as a science will make a comeback after 50 years.
My amazon orgs leadership has been obsessed with spec driven development while individual engineers tell me the only use they have is to placate leadership. I'm tired
How does spec driven development differ from test driven development?
TDD is done in a tight loop (minutes) while coding. For every little micro-feature/fix, you write a test for the new behavior you want, implement the minimal ugly fix to get the test to pass, then rely on the tests so you don't regress as you clean up.
LLMs struggle with TDD. They want to generate a bunch of code and tests in large passes. You can instruct them to do red/green TDD, but the results aren't great.
SDD starts before implementation, and formalizes intent and high-level design. LLMs eat it up. The humans can easily reinvent the worst parts of waterfall if they're not careful.
They're not mutually exclusive.
1 reply →
[dead]
I wonder if with the speed of iteration with AI the industry will switch back to waterfall. Clear documentation first so the LLM can easily produce what's being asked with a round of testing before going back to the documentation stage and running it again. History does repeat itself.
We already switched
> We can stop reading LLM-generated code just like we don’t read assembly, or bytecode, or transpiled JavaScript; our high-level language source would now be another form of machine code.
My opinion is very close to this. Currently the reason that it's bad to not reviewing/testing the code LLMs generated is because the LLMs can sometime generate bad codes. But it's a bug that can be improved. One day you'll have LLMs generating code consistently better than what a human could write. And then you just stop needing to review them. (And that's probably also the time where most programmers/developers got fired too)
Don't get surprised if anyday the LLMs starts to generate binaries directly. THAT will be impossible to read and costs more time to analyze.
> Currently the reason that it's bad to not reviewing/testing the code LLMs generated is that the LLMs can sometime generate bad codes.
Sometimes?
I am heavily into vibe coding and I think they almost always generate bad code. At least as soon as you're distant enough from the code to call it vibe coding.
When you're still in touch with the code, have at least been recently talking to it about code rather than 100% about features, and its context is filled with good code, it can generate good code.
Is it possible to reason or prove the correctness of an LLM?
> "I'd make a standardized Markdown specification the new unit of knowledge for the software project. ... There would need to be automated pull-request checks verifying not only that tests pass but that code conforms to the spec."
Agree, this is how you make the development loop more deterministic and ultimately autonomous. It's how I've been using coding agents myself for the past few months (by building my own to support this natively [1]).
If you have a spec you approve/agree on, have an agent code against it, and then have a review phase verify the implementation didn't drift from the spec (either by adding or removing features), you get to a position where you can trust the outcome.
There's still a lot to be said about spec definition and what if during implementation gaps are discovered, and that's where HITL comes into play.
[1] https://github.com/jelmersnoeck/forge
This could very well be a pattern that some teams evolve into. Specs are the new source -- they describe the architectural approach, as well as the business rules and user experience details. End to end tests are described here too. This all is what goes through PRs and review process, and the code becomes a build artifact.
It just doesn’t work though. Anthropic couldn’t even get Claude to build a working C compiler which has a way better specification than any team can write and multiple reference implementations.
"A sufficiently precise spec is code". I've read somewhere here before.
So guardrails, i.e. sufficiently precise spec and tests, will need to be as strict as the LLM is bad at getting the right context and asking back the right questions. I suppose at that point not much difference between a human engineer and it.
In short:
We will have code full of unknown bugs, that is unfixable.
The solution is to replace it with more of the same but with some new specification (fix some bug add some new feature).
And this will be done by using astounding amounts of compute in massive new data centres.
Yeah, this has been my process for months now.
I might even start my own blog to write about things I've found.
1. Always get the agent to create a plan file (spec). Whatever prompt you were going to yolo into the agent, do it in Plan Mode first so it creates a plan file.
2. Get agents to iterate on the plan file until it's complete and thorough. You want some sort of "/review-plan <file>" skill. You extend it over time so that the review output is better and better. For example, every finding should come with a recommended fix.
3. Once the plan is final, have an agent implement it.
4. Check the plan in with the impl commit.
The plan is the unit of work really since it encodes intent. Impl derives from it, and bugs then become a desync from intent or intent that was omitted. It's a nicer plane to work at.
From this extends more things: PRs should be plan files, not code. Impl is trivial. The hard part is the plan. The old way of deriving intent from code sucked. Why even PR code when we haven't agreed on a plan/intent?
This process also makes me think about how code implementation is just a more specific specification about what the computer should do. A plan is a higher level specification. A one-line prompt into an LLM is the highest level specification. It's kinda weird to think about.
Finally, this is why I don't have to read code anymore. Over time, my human review of the code unearthed fewer and fewer issues and corrections to the point where it felt unnecessary. I only read code these days so I can impose my preferences on it and get a feel for the system, but one day you realize that you can accumulate your preferences (like, use TDD and sum types) in your static prompt/instructions. And you're back to watching this thing write amazing code, often better than what you would have written unless you have maximum time + attention + energy + focus no matter how uninteresting the task, which you don't.
> PRs should be plan files, not code. Impl is trivial.
Doesn’t it bother you that the outcome each PR is different every time you/CI “run it”?
Entertaining flag name!
React team seems to really have set a precedent with their "dangerouslySetInnerHTML" idea.
Or did they borrow it somewhere?
I'm just curious about that etymology, of course the idea is not universally helpful: for example, for dd CLI parameters, it would only make a mess.
But when there's a flag/option that really requires you to be vigilant and undesired the input and output and all edge cases, calling it "dangerous" is quite a feat!
I’m pretty sure this comes from Claude code’s --dangerously-skip-permissions
which sounds like it came from React's "dangerouslySetInnerHTML", per the comment you replied to.
4 replies →
> There would need to be automated pull-request checks verifying not only that tests pass but that code conforms to the spec.
As I understand, this is an unsolved problem.
Step 1: solve the halting problem.
Yep, calling it an "unsolved" problem is a misnomer. We already have mathematical proof that it's impossible.
But that aside, it's such a shame that many drinking the AI Kool-Aid aren't even aware of the theoretical limits of a computer's capabilities.
4 replies →
You're probably thinking of Rice's theorem (a sort of generalised halting problem), but this task is actually way easier than that, since we're not trying to study arbitrary algorithms: we're trying to study the subset of human-comprehensible algorithms. Most of the things we want computers to do are things that, given enough time, someone can write a program to solve: and generally, those programs are not tricksy or meta, and don't involve unsolved mathematics problems found by studying busy-beaver candidates. If it's possible for a human to understand how a program works (which is a necessary component of writing such a program), it's possible to write a mathematical proof about the program's behaviour, and that means it's in principle possible to automate the construction of that mathematical proof, which is equivalent to the "determine whether code conforms to the spec" task.
"Somewhat easier than an impossible task" is not a particularly strong claim about when (or whether) this problem will be solved, though.
5 replies →
this is actually precisely what humans' roles will be.
"is this implementation/code actually aligned with what i want to do?"
humanic responsibility's focus will move entirely from implementing code to deciding whether it should be implemented or not.
u probably mean unsolved as in "not yet able to be automated", and that's true.
if pull-request checks verifying that tests are conforming to the spec are automated, then we'd have AGI.
That's what formal verification is about. I did some (using PSL for hardware verification); writing the formal spec is way harder than the actual code. It will find a lot of subtle issues, and you spend a most of the time deciding if it's the spec or the code that's wrong.
Having the code-writing part automated would have a negligible impact on the total project time.
> humanic
No, thank you
This is a task that humans are exceptionally bad at, because we are not computers. If something uses the right words in the right order such that it communicates the correct algorithm to a human, then a human is likely to say "yup, that's correct", even if an hour's study of these 15 lines reveals that a subtle punctuation choice, or a subtle mismatch between a function's name and its semantics, would reveal that it implements a different algorithm to the expected one.
LLMs do not understand prose or code in the same way humans do (such that "understand" is misleading terminology), but they understand them in a way that's way closer to fuzzy natural language interpretation than pedantic programming language interpretation. (An LLM will be confused if you rename all the variables: a compiler won't even notice.)
So we've built a machine that makes the kinds of mistakes that humans struggle to spot, used RLHF to optimise it for persuasiveness, and now we're expecting humans to do a good job reviewing its output. And, per Kernighan's law:
> Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?
And that's the ideal situation where you're the one who's written it: reading other people's code is generally harder than reading your own. So how do you expect to fare when you're reading nobody's code at all?
2 replies →
I feel like people who program in JavaScript or whose projects pull megabytes of dependencies, don’t get a moral right to complain about this. You guys just sit and calm down this time, you already said what you could.
Your app takes 20 seconds to load, pulling 50 megabytes of minified JS. Your backend is a mess of 20 Rust microservices, 300 megabytes docker image each.
Nobody has actually been reading and understanding code in your org for the past 15 years. And nobody has ever been responsible, everybody has just been job hopping for a 15% total comp bump.
Now the secret is out.
I found that adding "philosophy" descriptions help guide the tooling. No specs, just general vibes what's the point, because we can't make everyone happy and it's not a goal of a good tool (I believe).
Technology, implementation may change, but general point of "why!?" stays.
> Then where does the rigor go? Similar to the Thoughtworks report, my first bet would be specifications (which is not the same as prompts) and tests (which is not the same as TDD).
This is what we're building for at Saldor (https://saldor.com). It's a hard problem, to get a team in the habit of writing good specs. Probably because it's a hard thing to do: thinking of the behavior of your program, especially at the edges. But I agree (biased) that this is probably the way forward for writing code in the near future. I'm excited to see other people thinking about it.
Saldor pitch is on point.
I have team do this using CLAUDE.md telling Claude to do it in a set of interconnected steps, but in brief: they are to make it write every aspect of transcript somewhere: PRD, research notes, spec, dev log and debate log, break/fix/retro notes, commit log, PR, release notes, README, docs .mds... heavy emphasis on the edges in our thinking, and just as important, the edges in its ability to provide good leverage.
It needs a core set of guidance on the ordering and how to write "as of" a given phase or release so context stays current, trusting the old info is in git history it can navigate for the story of how we got here.
CC's /insights claims I have 10:1 md edits to code edits, and we both note this way of working is resulting in far fewer error loops per higher quality outcome.
// So yes, interested in your product. Baking something more broadly battle tested in so we don't have to reinvent it makes sense.
the irony is that AI is making this exact problem worse. ppl are generating entire codebases now without reading any of it -- the flag might as well be the default. the skill thats actually becoming scarce isnt writing code, its reading code you didnt write and knowing if its correct.
markdown became the language I hate the most thank to LLMs and specs-driven approach. everything feels so dumb right now in agentic coding. looping blindlessly and aimlessly until it compiles then until the playwright server or whatever devtools shows that it somehow works. push the code, have a llm autoreview/autofix,push to prod, run a mythos (perfect name) to identify the bug that opus 4.7 create. loops on loops on loops of some kind of zombie processes running to a "goal" that everyone seems to mystify in talks to just hide the fact that we do nothing anymore. the bottleneck never was code. it was the gate that was keeping away the Elizabeth Holmes and SBF from software engineering and it just opened.
A colleague and I have taken to use of the verb "meatspin", from another era in Internet shock humour, to describe what it is that coding agents actually do 99% of the time.
making the review artifact explicit feels like the part teams skip
> Product owners and engineers could initially collaborate on this spec and on test cases to enforce business rules.
LOL. I had to check if this was published on April 1st.
it's the most honest framing I've seen, but specs as the new source of truth is exactly what we promised ourselves with UML, then WSDL, then OpenAPI. the graveyard of just make the artifact above the code authoritative is long
I legit can't tell if this article is satire, or not.
very true. and we already know and agree with this.
user experience/what the app actually does >>> actually implementing it.
elon musk said this a looong time ago. we move from layer 1 (coding, how do we implement this?) to layer 2 thinking (what should the code do? what do we code? should we implement this? (what to code to get the most money?))
this is basic knowledge
Elon Musk has been saying Teslas would have fully autonomous self-driving within 1-3 years since 2013
I left a similar comment elsewhere in this thread. I still remember when so many people hallucinated that we would suddenly have flying cars by 2002 at the latest. If we achieve several more major improvements on current technology, these thoughts are interesting to consider. But not before that occurs.
We need the pragmatic engineer more than ever.
Instead of accepting 20,000 lines of slop per PR (and never-ending combinatorial complexity), maybe we should aim to think about abstractions and how to steer LLMs to generate code similar to that of a skilled human developer. Then it could actually be a maintainable artifact by humans and LLMs alike.
I don't get why every AI article is so hyper-focused on coding speed. If the coding is so fast doesn't it make sense to invest more time into quality, learning, documentation, testing refactoring, making a better product? I'm beginning to think that the slopcoders are evaluated by kLOCs of lines written in addition to LLM token usage and they're just maximising the measured metrics. Whether that actually ends up in production or is used by any real person is seemingly irrelevant. Likely the more bugs that are produced the more agents can be spun in parallel to simulate busywork.
Does this post mark the top of the hype train or is there still more to come?
Still more to come I think. Until all the major AI companies IPO starting this year.
[flagged]
[flagged]
[flagged]
[flagged]