The Economic Benefit of Refactoring

javaeeeee3 pts0 comments

The Economic Benefit of Refactoring

The Economic Benefit of Refactoring

Giles Edwards-Alexander

Giles is CTO for Europe, Middle East and India at<br>Thoughtworks. He has over 25 years experience in engineering and<br>technology leadership across technologies from mobile to AI and<br>industries including retail, fintech and<br>healthcare.

This article is part of “Exploring Gen<br>AI”. A series capturing Thoughtworks technologists' explorations of using gen ai technology for<br>software development.

30 July 2026

As part of getting to grips with the new world of agentic engineering,<br>I built an application to support my work. It’s a sophisticated app:<br>high-quality web UI with dynamic refresh and look-up, modals and<br>auto-save, integrations to external systems, machine learning and text<br>analysis, background jobs, and a proper environment setup with fully<br>automated deployment. It’s approximately 150,000 lines of code,<br>primarily in Rust (~120 kLoC) with the remainder in TypeScript and<br>Terraform.

This was entirely written by agents. Mostly Claude Code, and some use<br>of Cursor. I didn’t read or review any of the code, except<br>occasionally, out of interest.

While building the application, I could see some things going<br>awry. After watching an edit to line 4,000 of a file scroll by in the<br>terminal, I had a closer look. The data access layer had grown to over<br>6,000 lines. As more features landed, this continued to<br>grow. Every query, read or write, repeated the same HTTP request<br>setup, the same JSON encoding and decoding. Eventually, it reached 17,155<br>lines. In a single Rust file.

An experiment in refactoring

The 17,155 line file was the entire data access layer. A single,<br>self-contained module. Reviewing the code, there was no<br>de-duplication, no internal language, limited extraction of functions,<br>and very little extraction of classes. It did have a clear boundary<br>with an interface to preserve. It was a great target for refactoring.

The goal of refactoring an agentic code base is to spend tokens now in<br>refactoring to make token consumption for future work lower. An<br>experiment should be able to show that as this file was refactored the<br>token cost of making separate feature implementations in this code<br>base would decrease.

Precisely because agents never learn this was now possible to run as<br>an experiment. I could prompt a fresh agent to make exactly the same<br>change after every refactoring stage. Unlike a human engineer, the<br>experiment would not be tainted by learning from previous steps.

Create an overall refactoring plan, following strict refactoring<br>discipline.

Craft a representative change, described in a single prompt.

Establish a baseline cost of change: in a sub-agent, execute that<br>prompt, including asking the sub-agent to report token consumption.

Throw away the change.

In a loop:

Apply a single step of the overall refactoring.

In a sub-agent, execute exactly the same change receiving the<br>token cost of the change.

Throw away the change.

Record all token costs, time to execute the change, and lines of<br>code after each step of the refactoring, including the baseline.

The prompt used for the representative change and the refactoring<br>steps applied are shown in the appendices, below.

One caveat: Claude doesn’t provide reliable methods for counting<br>tokens live despite showing token counts, reporting tokens consumed<br>per session, and billing for tokens. I’m assuming this is a<br>temporary issue that will improve over time. Instead, the sub-agent<br>reported the number of characters received and sent and used<br>tiktoken to approximate tokens, by dividing character count by<br>four.

Results

Step<br>Data Access Layer LoC<br>Largest file LoC<br>Total Rust LoC<br>Input tokens per change<br>Output tokens per change<br>Time per change (s)

Baseline<br>17,155<br>17,155<br>50,359<br>159,564<br>1,705<br>342

Step 1 (FirestoreClient)<br>16,706<br>16,706<br>49,910<br>155,205<br>1,723<br>530

Step 2 (extract_doc_id, new_link)<br>16,562<br>16,562<br>49,766<br>159,227<br>2,105<br>574

Step 3 (link-query helpers)<br>16,567<br>16,567<br>49,771<br>154,054<br>2,105<br>524

Step 4 (FakeStore predicates)<br>16,577<br>16,577<br>49,781<br>154,146<br>2,060<br>654

Step 5 (value ctors)<br>16,469<br>16,469<br>49,673<br>171,251<br>2,036<br>1,353

Step 6 (FieldsBuilder)<br>16,469<br>16,469<br>49,673<br>171,251<br>2,036<br>1,353

Step 7 (queries.rs)<br>16,474<br>15,670<br>49,678<br>151,850<br>1,800<br>587

Step 8 (traits.rs)<br>16,508<br>13,845<br>49,712<br>132,558<br>1,723<br>446

Step 9 (traits/ split)<br>16,508<br>13,845<br>49,712<br>132,558<br>1,723<br>446

Step 10 (codec.rs)<br>16,521<br>12,846<br>49,725<br>131,871<br>1,750<br>540

Step 11 (fake_store.rs)<br>16,535<br>11,122<br>49,739<br>133,016<br>2,460<br>600

Step 12 (store/ split)<br>16,550<br>9,269<br>49,754<br>104,080<br>2,050<br>490

Step 13 (co-locate tests)<br>16,550<br>9,269<br>49,754<br>104,080<br>2,050<br>490

Step 14 (complete fake_store.rs)<br>16,553<br>7,225<br>49,757<br>107,205<br>2,453<br>523

Step 15 (store/ split)<br>16,608<br>3,695<br>49,812<br>27,360<br>2,113<br>454

The interesting metrics here are the total lines of code in the data<br>access layer, the total lines of code in the largest single file in<br>the data access layer and the input tokens consumed while producing<br>the...

step refactoring change code tokens lines

Related Articles