Join the discussion

Write your take first — we'll ask for email only when you're ready to publish.

  • Hacker News
  • I use 3 AI's (Claude, GPT and Gemini) to review each other's design plans and implementation on the same code base. Each often catches problems the others miss.

    I try to make sure the architecture docs of the code base are refreshed regularly based on recent changes, so it's easier for humans and AI agents to make sense of the code.

    I also regularly stop all other developments and just focus on auditing the code base with these AI's to make sure they are secure, robust, clean, and well structured and well tested -- some refactoring would be needed most of the time, and it's well worth it.

    With this approach, nowadays I often merge code from AI without completely understanding what it's doing, but seems the code has been working so far. :)

  • This is the way. I use gh copilot and have opus interrogate me and write the plan, then gpt review the plan and provide feedback; repeat this multiple times until gpt is either satisfied or starts to nitpick on unimportant stuff. Then sanity check the plan myself and have gpt implement it.

    Each implementation is also reviewed by me before merging to master. I complete PRs only when I'm satisfied with the implementation, my feedback is addressed, and I fully understand what is going on. Agents are the replacement for typing and productivity multipliers.

    I have big picture view of the product, each plan implements only a part of it, scoped to avoid merging unreviwed slop. Probably slower, but result is much better.

  • I'm always curious when I see these stories. How long have you been doing this, for what sort of work, and was the codebase mature before you began working like this?
  • You’ve transitioned from “individual contributor” to “manager”! (;->
  • "The reality is that code that runs and makes the CI green can still be a bad solution, and engineering has always been about implementing adequate, scalable, and extensible solutions."

    Adequate often means done and cheap

  • Disagree, adequate means adequate. Done and cheap is what you call it when a solution is adequate. If the solution isn't adequate, it doesn't matter if it's cheap, because it isn't done.
  • As long as safe and stable are assumed to be base-level requirements… maybe?
  • > Adequate often means done and cheap

    It really, REALLY depends what you're working on. If you're throwing together an internal tool or simple dashboard, it doesn't really matter what the code looks like. But if you're writing software that other programs will depend on, bad design choices ripple out and affect another generation of software. Imagine slop in the linux kernel, in google chrome, or in your compiler or runtime. Its not acceptable.

    I know a lot of people spend their careers writing end user software and web UIs. AI is increasingly a good choice for this sort of code. But that's not all of us. And its not all of the software being written.

  • I was just watching a video about system engineering and the following stucks:

    Stakeholder needs: What people wants to get done with the product

    Management needs: How to manage the spending of resources (time, money,…) to create the product

    Engineering needs: What is the product

    You have to balance the three. Sometimes it’s simple and easy to get right. Sometimes it’s complex enough, you’re never truly sure until the product is out in the wild.

    Software is malleable and we can do easily do iterations which is not possible with hardware. But today, we have a skew towards engineering, where the whole focus is to create a solution, whatever that is. No understanding of the problem, no proper allocation of resources, just do something. Even if it is plastering over the crack for the eleventh time.

  • Its hard to find a middle ground between fully understanding everything in a PR vs a vibe coding type approach. Can you understand "just a little bit" of a PR and merge it into a code base you really care about? Is it maybe fine to "mostly understand it" on the other hand? Its definitely a tough call and its impossible to argue that no trade off is being made.

    LLMs are perfect for quick prototypes, speed runs, learning, etc., but if the code really matters its still not clear cut. I think the definition of what "really matters" is very project dependent of course As an extreme example you would want to understand every line of the code for the control system runs an MRI machine or a jet engine since bugs might mean life or death. Depositing money into the wrong account might not kill anyone but could lead to severe economic losses. But, then again, even problems in far less consequential software may be drastically sub-economic (i.e. saving $1000 on the implementation might cost $10000 if customers aren't happy and fails to re new). Pick your scenario I guess.

    The problem is, this isn't going to change regardless of how well a new model scores on a benchmark. It seems actually AGI is needed.

  • > Before coding agents, when given a task, I would explore the codebase, think of different solutions, experiment, and only then implement. That could take days of consolidating all that context. When I finally submitted that PR, confidence was higher, and explaining each of my changes to my coworkers was easier.

    Now we are getting to the point where we are speed-running the deskilling of engineers into comprehension debt and they themselves rapidly losing confidence in reviewing code they did not write.

    I think this blog post [0] is the best example of what could go entirely wrong and even worse when you do not know the technology.

    If you cannot explain a change even when "the CI is green" or "all tests passing", I will immediately reject it.

    Maybe great for vibe coding prototypes, but it all changes when that code is deployed onto mission critical systems. Just ask Amazon with Kiro. [1]

    [0] https://sketch.dev/blog/our-first-outage-from-llm-written-co...

    [1] https://www.reuters.com/business/retail-consumer/amazons-clo...

    by rvz
  • The bottleneck when using a "faster keyboard" is understanding. We have a tool for this in compsci. Not having to fully understand something in order to successfully exploit it is a staple of computer science; we use abstractions to help us reason at a higher level. You don't necessarily always have to understand the nuance involved in selecting a hash function just to put and get some items in a hash map. Specifically, when are these cases where you don't need to go that deep? Are there similar scenarios for ai written code?

    I'm more interested right now in what does that abstraction look like for AI generated code. Is there some reasonable solution wherein a sandboxed component in the enterprise architecture has various attributes (e.g. the bytes i stuff into this file store component are always the exact bytes i get back from it) confirmed by methods other than a human reading its code? Those methods, are they cheaper, faster, safer than just having a human do it?

    If your enterprise architects have to read every line of code in your system today then i'd claim your architecture practices have room to mature. What can derived from that, and in which scenarios, for the purposes of safely leveraging immutable write-only code? I'm not interested in evolving the code (lines of code spent to solve a business problem was never an asset, it was always a cost) if it wasn't hand crafted by a human, i still have the requirements so i can just regenerate the entire thing with the revised requirement.

  • Visualisation tooling IMO is the way to reason with this.

    You don't look at the code, but use tooling to create a chart of the calls, data models etc. Then you can look at that and see the complexity.

    ...and we already had these tools in the early 2000s, when (can't remember which) no-code fad was running about. You know the ones where you just draw the boxes and lines and poof the code is generated =) There were also tools that did the reverse.

  • And again this makes me wonder, is AI really helping if this much review and rework is needed for all the code it writes?
  • I mean, the reality is a ton of folks in the industry, myself included, are writing glorified CRUD apps in their day jobs. We're building into existing an codebase with established infrastructure and ways of working. What we're building isn't inherently complex or very interesting.

    Meanwhile, those codebases often require a ton of boilerplate and drudgery to get anything done.

    In these spaces it's very easy to read and comprehend AI generated output and review it fairly quickly. So the time savings from dealing with all that boilerplate and conforming with all that existing infrastructure are potentially substantial.

  • Most code they write is obviously fine. Much of the rest isn't obviously fine, but is in fact fine once you've gone through understanding it. But yes, there's some that still benefits from a human eye.

    (For as long as that's true, "software developer" is still a job. It's not clear for how long it will be true.)

  • Depends on what it’s writing. There are times an LLM saves me a lot of time researching library functionality. Especially with testing frameworks. So many strange and arcane features out there beyond the basics, but not hard to understand what they do once you see the code. On that topic I should say I am careful when reviewing the actual test cases.

    However if you’re highly familiar with a domain then LLMs are much less useful.

  • Titles like these make me always point out the obvious: A working state is the absolute minimum requirement for any code to be merged, isn't it? ...imagine to merge something even though you know that's not working.

    Besides, this post has nothing specific to code produced by an LLM, and placing AI in the stated reasons feels completely arbitrary, or is rather a fallacy of our times:

    - I reject [AI] code when I can’t explain the approach in my own words.

    - I reject [AI] code when the diff is bigger than the problem.

    - I reject [AI] code when it introduces abstractions before proving they’re needed.

    - I reject [AI] code when it works locally but makes the system harder to reason about.

    - I reject [AI] code when I’m trusting the output more than my understanding.

  • Fallacy or scapegoat. If management ask for revised KPIs where PRs must be 10x and AI is the "excuse" for this (unrealistic) new demand.
  • Well said. Replace [AI] with "junior dev" or "consultancy contractor" and these assertions have always been thus.
  • I’ve had multiple people say “you don’t work on code anymore, that’s for the AI. You work a level of abstraction above that. As long as you prove it works through testing, the code doesn’t matter anymore. It’s like looking at the assembly the compiler spits out now - who cares?”

    These are the people who spit out an incredible volume of code with AI, to the point reviews simply can’t keep up.

    The last person who said this to me works in embedded, where we look at the assembly all the time. Scary.

  • Not that I disagree with anything here, but...

    I wish it were clearer in these kinds of posts how "I use AI code I don't understand" is so different from "I use libraries written by other people I don't understand", or "I work in a large codebase which was 99% written by other people, and I haven't seen all of it", or even "I use software written by other people I don't understand".

  • My personal rule of thumb: I am usually okay with agents driving e2e implementations if this won't make life noticeably worse when it does not work. Some analytical code? Perfectly fine. Hobby projects? Fine, though I prefer doing a fun part myself. Refactoring production code generating 10x more revenue than my salary? You'd better be at least understanding what it does.
  • Yes this is the thing with these new tools. You have to know when to use them and when not to.

    Good ol' software architecture tricks can also help you slot "vibe coded" components into a larger system safely.

  • Coding with AI eventually comes down to two paths, I've realized. One is using AI exclusively for everything. The other is not using it at all. There is almost no middle ground. The reason is that as the complexity and depth of the problem increase, the code AI generates increasingly follows enterprise level patterns. The deeper the meaning of what I input, the more AI tends to produce code that goes beyond my own area of expertise. For example, a human expert's code is very powerful and deep within their own domain, but when you look at the entire codebase, it's often shallow and uneven outside that domain. But the moment you write code with AI, once you go deep in one part, AI tries to standardize the rest accordingly. This means the entire codebase converges toward enterprise level standard code, which essentially reflects the average patterns of senior programmers who built large scale systems.

    The problem is this. Human cognitive resources are finite, so we inevitably become shallow outside our own expertise. There is no programmer who can do everything well. And as systems grow in scale, they become more modularized and fragmented, making it impossible to understand the whole system. So what should we do about this? That's always the question.

    In the end, do I choose not to use AI, finish the project with uneven code outside my domain, and deliver it? Or do I use AI and deliver a program that is uniform and consistent, but not in my own style? I still don't know. I haven't found the answer yet.

  • Own the design and let AI write the code. Spend the extra free time on becoming a better/broader architect.
  • > There is almost no middle ground.

    I use it rarely. I did have it rewrite some code, mainly from one language to another. That works really well. I also had it rewrite a database interface, which also seems to work (no time to test it thoroughly, yet, so it's not in production). But I'll be damned if I let it write new features. I've debugged other people's code, and it ain't fun. Debugging 10kLOC AI code sounds like hell to me.

    by tgv
  • I feel like my current approach is a decent middle ground.

    In the past, I wrote code by first writing English pseudo-code as a series of self-documenting comments. These would be declarative assertions of what the code will do. (For example, "Method returns true if array values are within 0.5% of spherical.") I then wrote the real code next to each comment.

    My current workflow is mostly the same as before, but as soon as I think there's nothing creative left to do, I allow AI to take a pass at it, insisting it include verbose comments. Next I read everything; its comments are often redundant but allow me to internalise the logic/intent more quickly. I make any corrections myself. And I strip any pointless AI comments.

    In short, I stay in full control of the architecture while tasking AI with the grunt work, the implementation details, and the superficial correctness.

  • I'm part of the middle ground. Not able to do full agent code, but I'm fine using it to generate snippets that i fully read. I find it great to use apis with little documentation. For me AI is similar to a google search when im not able to find meaningful doc or i want the code snipped and refine over it
  • The middle ground is to use it as a power tool: give me an example of this, fix my types, do this fussy bit, find this in the docs, without ever letting go of control.

    When using power tools you make all the measurements and decisions, you just hammer screw drill and cut faster. You cannot power tool your way to building a things that you don’t know how to build.

    The other interesting thing about this is it works with smaller models and uses a fraction of the compute.