Hacker News new | ask | show | jobs
by matsemann 20 days ago
What's the point of the rewrite if it doesn't fix the underlying issues, though?

A rewrite being a good idea often hinges on the ability to simplify. After a decade or more, it's now apparent what the application should and shouldn't do, so one can build it with those learnings and shed all tech debt from how it grew organically.

Aka preserving all behavior is not what I would want from a rewrite. The point would be to make decisions on what behavior should be kept and what complexity can be removed. An AI can't do that. It can help with execution if the decisions are made, but they're made by being very intimate with the codebase and floating all cases and then talking with stakeholders.

8 comments

I work on a codebase from the early 2000s, a lot of it using webforms, a long abandoned .NET technology. A rewrite preserving all behavior and making no observable changes whatsoever would be amazing. But it’s also tested exactly as well as you’d expect from something like that so I’d rather not let AI go wild.
Good example. Transitioning from an outdated framework to a modern (or sometimes "slightly less outdated") one is probably one of the few situations where you do not want to change semantics at all.

And in my experience, these are _dangerous_. People go into "while we're at it..." mode, and it quickly turns into a big 2.0 kind of thing that takes forever.

I would argue that LLMs can speed this kind of thing up, but not by an order of magnitude or anything, just a bit. Unless there's high risk appetite.

It still kind of blows me away that almost any LLM usage for coding isn't viewed as "high risk appetite"

Building products that no one really knows the internals of is crazy to me, and the methods people have of trying to mitigate that problem seem half assed at best

As someone who currently automates the payroll flow generated by someone who doesn’t actually know what it does, I can confirm I am going crazy. My boss will do nothing about it because her boss can’t get finance to let us hire more people. I plan a strongly written resignation letter whenever I find something else.
Sounds like you might work on a team with some agency to say no to management.

We have some and sometimes marketing comes back with some extra revenue from a partner if we build out feature X Y or Z for their new product launch. The contracts are signed so engineering has to do it or we’re blamed for lost revenue.

A few of those a year and you eventually end up in a similar situation.

> Sounds like you might work on a team with some agency to say no to management.

If I didn't work on such a team, I would last exactly as long as it took me to find such a team.

That sounds nice. I hope once I have secured my legal status in my new country (few more years to go) that I can take such a risk. Not everyone is in the same position to take that sort of risk.
I think everyone is right on this question :) I have certainly worked in places where there were enormous code bases written in dead languages going back to the 1970s and I was part of the collective belief that nothing could be done about it and our job in the 2000s was to put lipstick on the pig by burying it behind a web portal, if you remember that short-lived fad. In that kind of environment I would have _loved_ an exact port to a modern tech stack from which we could begin the very slow and careful evolution. Speaking to people who work there, AI has indeed changed at least their perception of what is possible and they have traction on porting it that was considered impossible for decades. Whether it works for some definition of “works” remains to be seen, but it might be self-fulfilling because the belief that it can be done will mean it is tried more often and some of those tries will probably succeed.

With that said, I’ve also recently done a rewrite in a completely different sense, taking what used to be a web app and rebuilding from the ground up as a desktop app instead. Having the original code base for core concept reference, but rethinking the whole UI more than a decade on was IMHO a much better approach in that case.

LLMs/agents are a great way to create a test harness for something like that.
This was my approach to a large rewrite I'm working on. First create the multiple layers of test suite to map out existing behavior at the unit, API, and integration level (something that should have been done incrementally over the 20 years this software has existed), then predicate the new code on the tests. It's been remarkably effective.
I plan to eventually get there, just need to find the time. It’s a lot of code, and a lot of it is not set up for testability.
To start the transition you can build your own tooling, in this case maybe start with the whole app stack including browser in an emulator, emulator controlled over a socket (write a harness that exposes all the inner debuggers, framebuffer, snapshotting, etc). Then generate a component inventory and likely failures for each, and generate pixel-perfection + internal state checks for each. Then migrate one component out (this may be quite a large project due to all the glue you'll need to make this possible). Then do the rest one at a time.

The big problem with doing it this way is you end up with something structurally the same as what you started with, but potentially more code if you e.g. end up carrying your own reimplementation of Web Forms.

Tell the agent to work on it and then give you summaries of code coverage, progress, and so on. It doesn't need to take up much of your time.
Rewriting while changing features is the worst idea ever, which almost always leads to failure, and is the reason why "don't do rewrites" is a widespread rule.

Whether it is humans or AI, the correct way to do it is always a feature exact rewrite, so you can do comparative testing on both systems, and progressive rollout, and then you start adapting features.

Not sure I agree. Having a complete rewrite like you propose is a huge project, and a very scary flip. And I honestly don't see the value in doing it like that. So now you have the same mess as before, just re-written?

Best I've seen it done is to move module by module. So if you want to do "X", you now have to do it in the new system. And the big part of the rewrite of X is figuring out the specs and making it better along the way. Then people also actually want to move.

Moving module by module is definitely the safer way to do it, but at the module level you do the same thing. You have to have it feature exact so that you can replay test against the same interface and do progressive roll out. The difference with AI is that the module size you can one-shot goes way up compared to traditional human rewrite.

> same mess as before, just re-written

The likely path here is probably rewriting from node.js/ruby/python/etc to go/rust/c#/etc so a feature exact rewrite that passes all tests and can return identical responses for replayed production requests is not the same mess at all. You can do all sorts of refactoring, bug fixing, etc, while maintaining exact feature compatibility. The other major thing is back-filling exhaustive test coverage with AI, which then makes agentic coding much more accurate, because the feedback loop from failing tests provides the context for AI to self correct.

A test suite and code are two complimentary representations of the same logic, so using AI to grind test coverage to really high levels (90-95+) gives you two independent inference paths through a model, then the feedback signal from test failures gives you the mechanism to drive these two distinct generation paths to convergence.

A rewrite is like moving house. In the new house, it doesn't have things the way you had everything set up "just right" is the old house. But you now have an extra bedroom and bathroom and no longer have a black mold problem, and most importantly, the opportunity to do things in a new way with hindsight learned from the old house.

The move period has a lot of work ahead to get it back to livable, but also the opportunity to do better than just "livable".

The introduction of AI for rewrites is the equivalent of zero interest loans to housing, reducing the cost of a move. It doesn't mean "keep moving home", it means there is one less factor to worry about if you need to.

Using a better tech stack also provides opportunities to simplify.
One obvious target might be rewriting from an unsupported, broken, and/or obsolete target to something that still works. Or moving a project from a platform that no other system in the company uses to the same setup that all the others use.

Of course it won't quite work, but I can definitely see why some people would want that.

> What's the point of the rewrite if it doesn't fix the underlying issues, though?

Depends on what you mean by underlying issues. If you're in a regulated environment, it may be such a mountain of red tape to change behavior that it's not worth it, even if you know it's not ideal.

But if the underlying issues are tech debt, bad design, and other things invisible to the outside world, that's different.

Say I rewrite a large codebase from python to C++, preserving all behavior. That's up to a 50x speed up.
Not a good example i'd say given Python's position as pretty much the ultimate glue language :) You'd more likely keep the python shell (and faster developer iteration speed) and push measured hotspots down into c++/rust/c/whatever.

Incidentally, Whenever i've done this in the past it's had a pleasant side effect of improving architecture. You end up forcing something akin to "push for's down and pull if's up" because crossing the ffi boundary is not free. It can be quite magical, as in leading to comically unbelievably speed ups when you also take advantage of vector intrinsics.

On the other hand: you don't need glue when you 3d print the whole thing. Keep it simple with a single language.
Make the fix easy. Then, make the easy fix.