Monday, 2 November 2026

What extraction cannot slim: a study registered before the data

Some long methods can't be fixed by extracting methods. Early returns, values that change on every branch, and results that need more than one return value all get in the way. I believe a framework that injects functions and sequences them can take apart many of those methods. I created that framework, OfficeFloor, so my belief counts for nothing until it's measured. This post describes a study that measures it on 580 open-source Java repositories, as they stood before AI coding assistants. The hypotheses and the rules for reading them were committed before any repository was scanned.

The question

In What reviewers call a Long Method is a length, a method reads as a Long Method from 26 code lines. The usual fix is Extract Method: lift pieces out until every piece, and what's left, fits under 25 lines. SinewSlim searches for the cheapest way to do that, pricing each cut by what crosses it (how SinewSlim prices a split).

For some methods there's no such way at all. A return can't leave an extracted piece. A piece can return only one value, and a record to carry more is a cost of its own. Some methods are knotted together so tightly that every cut is blocked. This study calls those methods stuck.

Function injection cuts differently. Each piece becomes a function the framework calls. The framework supplies its arguments, so nothing is passed in by hand. A function can hand on any number of values. An early return becomes the end of a function, followed by a flow. An if can become a decision with a flow per branch. OfficeFloorSlim searches for the cheapest split of that kind, with costs set before this study and described in its design.

So the question is: of the long methods extraction can't slim, how many can function injection take apart?

What a developer would actually do

Nobody would rewire a method into functions when extracting one method would do. Nobody would insist on functions too short to need it either. The study prices the realistic mix, which I call the combined split: functions where the flow divides, with extracted methods inside a function where its body is still long.

cost(combined) = injection cost of the functions        (values carried + 1 per function + 1 per flow)
               + SinewSlim's cost of the methods extracted inside them

the plan       = the lowest sum;  on a tie, fewer extracted methods;  then fewer functions

The whole method as one function, slimmed by extraction alone, is always one of the candidates. So wherever extraction works, the combined split works too, and it never costs more than extraction plus 1. That holds by construction, so the study doesn't report it as a finding.

The hypotheses

Each stuck method is put in one category, tested conventional first, so function injection only gets a method nothing simpler could fix:

CategoryThe stuck method…
2slims by extraction if records may carry several values back
1otherwise, slims by extraction if its jumps (return, break, continue) are ignored
3otherwise, has a plan under the combined split: only function injection takes it apart
4has no plan from either
  • H1 (rescue), confirmatory. Category 3 is at least a quarter of the stuck methods, and at least 30 of them. The bar was fixed on 31 October 2026, before any scan. Read from the 95% interval of the population estimate: supported if the whole interval is at or above 25%, refuted if it's all below, inconclusive otherwise.
  • H2 (improvement), an estimate. Of the long methods extraction can slim, how often does the combined split choose function injection and cost less? It's reported with its interval and no threshold. Ties are counted apart, because the tie-break favours injection.

What I'd already seen

A plan registered before the data has to say what was seen before it was written. I'd run the combined split on one repository: OfficeFloor's own. There it rescued 12 of 119 stuck methods, about 10%, well under H1's quarter. Of the 327 long methods extraction slims, it chose injection and cost less for 95 (29%). That 29% is why H2 has no threshold: any share I set after seeing it would test nothing.

So the one repository I've seen points against H1. I still expect code written by many hands, before AI assistants, to show more methods that only injection can take apart than my own framework's code does. That's my expectation, and the study can refute it. It's in the plan, dated, before the sample was drawn.

The sample

  • Drawn by an independent tool. open-source-repository-sampler draws a seeded, stratified random sample of GitHub repositories. The seed, 20261101, was fixed in the plan, and the study's scripts refuse any other.
  • Before AI coding assistants. Each repository is pinned to the newest commit on its default branch before 1 December 2020. That's six months before 1 June 2021, which was itself before GitHub Copilot's technical preview opened.
  • Three popularity tiers, drawn equally: over 5,000 stars, 1,000 to 5,000, and 200 to 999.
  • Large enough to have methods worth reading: at least 50 functions in at least 15 files. Repositories owned by me or by OfficeFloor are excluded.
  • Production code only: every .java file, leaving out tests, build output and generated code.

The draw finished on 2 November 2026. Of 757 repositories drawn, 580 were usable and 177 were excluded by the criteria, with none lost to errors. The sample is committed in the study's repository, so anyone can see that nothing was hand-picked.

Guarding against myself

I created OfficeFloor, SinewSlim and OfficeFloorSlim. A study like this can be tilted in many quiet ways, so the design closes off the ones I could think of:

  • The study computes no cost of its own. Every figure comes from the released tools, pinned by version and checksum: OfficeFloorSlim 0.3.0, built on SinewSlim 0.2.0. The costs were settled in those tools before the study could tune them.
  • The two totals are never compared. Extraction and injection count different things, and the weight that would turn one into the other is exactly what a sceptical reader would say I picked to flatter OfficeFloor. The study compares what both measure: the worst seam, the number of parts and the largest part.
  • Every figure is reported, whichever way it points: every reason the split fails, every method where injection's worst seam is larger than extraction's, and every excluded repository.
  • The unit is the repository. Intervals come from a bootstrap over repositories within tiers. Per-repository medians are reported beside the pooled figures, so a few huge projects can't quietly carry the result.

The threats that remain are in the plan. It's a projection: nobody wrote this code for function injection, so the split is what it would cost, and the migration isn't counted. Loops and lambda bodies are never cut into separate functions. Adding the two costs to choose a combined plan weighs them 1 to 1. Stars measure attention, not craft.

Run it yourself

Every step is a script, run by hand, in the study's repository, long-method-slim-study.

No comments:

Post a Comment