How LLM Helped Me Refactor 28-Year-Old Code

TL;DR

ChatGPT/Codex converted old Java applet code to JavaScript surprisingly well. But when I asked it to do what sounded like a simpler task – reformat and unify a set of old HTML tutorial pages – it struggled badly. The main lesson was simple: LLMs are excellent at well-defined transformations, but much less reliable when the task depends on many unstated assumptions.

Why This Project Existed in the First Place

This project started in 1998, when I was a computer science student. At that time I was interested in optimization algorithms. My bachelor thesis was on applying Travelling Salesman Problem algorithms to scheduling in a book distribution company, and one semester project was to illustrate something, preferably an algorithm, using a Java applet.

Given that overlap, I decided to build a small applet demonstrating a genetic algorithm. Soon after that, I had about a month during a summer stay at HTW Dresden to extend it into several applets and add explanatory texts. When the pages were published, the response was much bigger than I expected. They were used for teaching at many universities, and I received e-mails with questions and requests for help.

For a while, the small website was surprisingly popular.

Back When Java Applets Were Exciting

It is hard to explain today how attractive Java applets were at the time. I liked, and still like, C++, but Java made development much faster. It also made it possible to create interactive animations and applications directly in the browser.

JavaScript existed, of course, but at that time it was much more limited. A lot of frontend work was about making pages behave at least roughly consistently across browsers. Java applets were not perfect either. Every page containing an applet would freeze the browser for a while during loading – sometimes for one second, sometimes for tens of seconds, depending on the computer.

Still, they were powerful enough that they felt worth it.

Why I Never Rewrote It Earlier

After some years, Java applets stopped being supported in browsers. That effectively ended the useful life of the site.

I did not mind too much, but every few years someone would ask me whether I wanted to rewrite those pages in JavaScript. I never really wanted to. At that time I did not particularly like JavaScript, and although I occasionally played with technologies like WebAssembly and later Blazor in C#, a full rewrite still felt like several days of work at minimum. I never had enough motivation to do it just for fun.

Trying Codex on the Java-to-JavaScript Conversion

A week ago, I was using Codex in Visual Studio Code for something else, and then I thought: why not try it on this old project?

First, I decompiled the .class files into .java source code. I still have a backup with better documented source code somewhere, but apparently that did not matter much to the LLM.

I gave it a prompt asking it to convert the Java applets in the ga/java directory to JavaScript for modern browsers, and mentioning that there were HTML files showing how the applets had originally been embedded.

in the ga/java directory there are java files with several applets. Convert these applets to javascript, so that I can run them in modern browsers. There are html files showing how the java applets were embedded. Can you do this at once or do you want to break the task into smaller tasks?

The answer was encouraging. It immediately recognized that this was not one repeated applet, but a small family of different demos: simple 2D genetic algorithm applets, a TSP visualizer, a 3D surface visualizer, and a walking simulation. It suggested splitting the work into phases, but also said it could execute the whole task end to end.

Better to break it into smaller tasks, but I can still handle the full directory end-to-end.
After inspecting ga/java, this is not one applet repeated six times. It's a mix of:
- simple 2D GA demos: BasicGA, BasicGASlow, ParamsBasicGA
- a more complex parser + 3D surface visualizer: GA3D
- a TSP visualizer/editor: TSPGAAll
- a creature/walking simulation: WalkGA
Those share some GA logic, but the UI and rendering models are different enough that doing all of them as one undifferentiated rewrite would be higher risk.
Recommended split:
1. Convert the common GA/core classes to JavaScript modules.
2. Port the simple 2D applets and replace their HTML embeddings.
3. Port TSPGAAll.
4. Port GA3D.
5. Port WalkGA.
That said, I don't need you to manually slice it up first. I can take the whole task and execute it in those phases myself. If you want, I'll start now by building the shared JS runtime and converting the simplest applets first.

I told it to proceed, except for WalkGA, which I had never finished to a publishable level anyway.

yes go ahead. You don't have to convert WalkGA, this one won't be used.

Why the Conversion Worked So Well

This part worked almost unbelievably well.

After about 20-25 minutes, I had browser-based replacements for the main Java applets. The conversion covered the simple GA demos, the TSP applet, and the 3D GA visualizer, including a browser-side expression parser. The HTML entry pages had been updated as well, and the unused walk.html was explicitly marked as not ported.

Converted the Java applet hosts in java to browser-based pages. The main implementation is in ga-modern.js with shared styles in ga-modern.css. I replaced the HTML entry points for default.html, color.html, all.html, tsp.html, ga3d.html, and index.html. walk.html now explicitly says it was not ported.
The rewrite covers:
- BasicGA, BasicGASlow, and ParamsBasicGA
- TSPGAAll
- GA3D, including a browser-side expression parser for the original function syntax
...

When I looked at the result, the new “applets” felt almost exactly like I remembered them.

I think this worked so well because the task was highly structured. The source code was there, the target platform was clear, and the expected behavior was concrete. Even though the code itself was not trivial, the transformation was well defined.

Porting the Neural Network Applet

I then did the same with the neural network applet, and again the result was surprisingly good. No real fix was necessary. It went a bit too far in restructuring the layout, but I could live with that.

The only correction I remember asking for was essentially cosmetic: in the HTML UI the borders were rounded, which looked odd because they were barely visible. I asked for plain rectangular borders instead, and that was enough.

in the HTML UI the borders are round and it looks strange that they are not visible. Remove the rounding, leave just rectangles

So after roughly 30 minutes for the GA applets and another 30 minutes for the neural network applet, the main porting work was done. I spent about one extra hour preparing the original source code.

Where Things Started Going Wrong: Reformatting the HTML

At that point it seemed obvious that I should also ask Codex to reformat and unify the HTML pages.

The site had grown over time in a messy way. It started with the original genetic algorithms tutorial in English. A year later I added neural networks. Later, people liked the material enough to translate it, so I ended up with Brazilian Portuguese, Japanese, Bulgarian, and partly Czech translations. A few years later I added a tutorial about ontologies and the semantic web. In parallel, I had also experimented with PHP and with slightly more dynamic layout ideas.

The result was exactly what you would expect from a technical side project that had evolved over many years: duplicated assets, inconsistent structure, mixed layout approaches, and a lot of technical debt. It worked, but it was not clean.

Why the “Simpler” Task Was Actually Harder

I started with small, concrete tasks, such as fixing the encoding and replacing Java applet embeddings with the new JavaScript versions. That part went well.

Then I moved on to the broader idea: unify the tutorials, share styles and assets where possible, and make the site more consistent overall. That was where things became difficult.

Several hours later, late at night, I was still prompting Codex and still not done. I had to repeat requests that I thought were already clear. A change in one place would reintroduce an older problem somewhere else. Parts of CSS would come back. Encoding issues would return. Whenever I made a manual fix directly in HTML, PHP, or CSS, the next prompt often made things worse again.

Overall, this was the key contrast of the whole experience. Converting Java code to JavaScript was technically harder, but the goal was precise. Cleaning up and reformatting the tutorials sounded simpler, but the work depended on many preferences that were only partly documented and partly still evolving in my own head.

Recovering from the Failed Cleanup

The worst moment came after a seemingly simple request to localize labels in both neural network tutorials, English and Czech.

Yes, localize labels. Also for both neural network tutorials (English and Czech).

After that prompt, the text content was gone. The HTML snippets still contained tags like <h2>, but the article text itself had disappeared. When I asked where the text had gone, the answer was blunt: it admitted that it had made a destructive mistake and that much of the article text was no longer recoverable from what remained in the workspace.

I made a destructive mistake there.
I checked the current genetic-algorithms tree, and a lot of the article text is no longer recoverable from what remains in the workspace:
...

About an hour later, I gave up on that approach.

After a few days I looked at CMS options, thinking maybe it was finally time to move the whole thing to something like WordPress or ProcessWire. But none of those felt like a magic solution either, because they would still require time and customization. So I went back to the original idea: keep the custom mini-framework, clear the technical debt manually (meaning: very exact simple prompts and being happy with changes that I didn’t intend to be done), and make it work.

That is what I eventually did. I also updated parts of the text itself, not only to remove mentions of Java applets, but also to improve the English in places.

What This Taught Me About Working with LLMs

It was about task shape.

If the work is well defined, LLMs can be extraordinarily effective. A migration from one technology to another, where the source exists, the target exists, and success is measurable, is a very good fit.

If the work is underspecified, depends on style judgments, or involves a large number of hidden assumptions, the picture changes. Even when the individual edits are technically simple, the process can become slow, repetitive, and fragile.

The Real Difference: Well-Defined Tasks vs. Vague Cleanup

For me, this was the real takeaway.

Converting code from Java to JavaScript used to be a task that required meaningful knowledge of both technologies. Yet in this case it was the easy part.

By contrast, “just” reformatting HTML, unifying layouts, localizing labels, and making old content consistent turned out to be the much harder part, because those tasks were not truly simple. They were full of implicit decisions.

So the distinction is not really complex versus easy. It is well-defined versus vaguely defined.

The Site Is Running Again

The happy ending is that the pages are running again after all these years, and perhaps they can still be useful to someone.

That alone makes the effort worthwhile.

You can see the result here: https://www.obitko.com/tutorials/

Fun Quotes from the Original Version

The original site contained some nice reminders of what web development looked like in the late 1990s.

One note said:

For best viewing of these pages you need a browser with support for frames, JavaScript and Java from version 1.1.

If you had looked at the pages a month ago, you would mostly have seen this:

Here is applet, but your browser does not support Java. If you want to see applets, please check browser requirements.

That message was visible for modern browsers in exactly the same way that it had been visible 28 years ago for browsers without Java installed.

In addition, none of the links to other resources worked anymore either. The most useful one pointed to a description in PostScript, another reminder of how much the web has changed.

Final Takeaway

I came away from this project more optimistic about LLM-assisted refactoring than I expected to be.

For bounded technical migration work, the results were excellent. For editorial cleanup and structural unification of a messy legacy site, the process was much less reliable.

That seems like a useful rule of thumb: use LLMs confidently for well-bounded transformations, but be much more careful when the task depends on many unstated expectations.

One comment

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses cookies for analytics (Google Analytics) and advertising (Google AdSense). You can accept all, reject optional cookies, or choose below. Privacy Policy

Privacy Policy