Fundamentals 8 min read

Boost Readability by Reordering Code Lines — Data-Flow Order Beats Method Extraction

The article shows how interleaving multiple data-flow chains in a method forces readers to context-switch, and demonstrates that simply reordering lines to follow each chain sequentially — without changing logic or extracting methods — dramatically improves readability, while explaining why method extraction can backfire when variables are shared across chains.

samdeepthink
samdeepthink
samdeepthink
Boost Readability by Reordering Code Lines — Data-Flow Order Beats Method Extraction

The author examines a common readability problem: a method where individual lines are correct and well-named, yet the overall flow is hard to follow because adjacent lines belong to different data chains. The example comes from a production inventory module that queries three related data paths — material → recipe item → recipe → product, material → material info, and a final assembly step.

A Hard-to-Read Method

The original code interleaves the two primary data chains:

var recipeItems = recipeItemRepository.findByMaterialIds(materialIds);
var bomIds = recipeItems.stream().map(RecipeItem::getRecipeId).toList();
var materials = materialRepository.findByIds(materialIds);
var recipes = recipeRepository.findByIds(bomIds);
var materialMap = materials.stream().collect(Collectors.toMap(Material::getId, Function.identity()));
var productIds = recipes.stream().map(Recipe::getProductId).toList();

The first two lines follow the recipe-item chain, the third jumps to material lookup, the fourth returns to recipes, the fifth builds a material map, and the sixth jumps back to the recipe chain for product IDs. The reader's attention must constantly switch between chains, increasing cognitive load even though the logic is correct.

Reordering by Data Flow

By grouping each chain contiguously and separating groups with blank lines, the same code becomes far easier to read:

var recipeItems = recipeItemRepository.findByMaterialIds(materialIds);
var bomIds = recipeItems.stream().map(RecipeItem::getRecipeId).toList();
var recipes = recipeRepository.findByIds(bomIds);
var productIds = recipes.stream().map(Recipe::getProductId).toList();

var materials = materialRepository.findByIds(materialIds);

var materialMap = materials.stream().collect(Collectors.toMap(Material::getId, Function.identity()));
var recipeItemMap = recipeItems.stream().collect(Collectors.groupingBy(RecipeItem::getRecipeId));

Now the first four lines form an unbroken chain from material to product. A blank line visually isolates the independent material chain. The final two lines concentrate map construction. Each variable is declared right where its context lives, eliminating the need to scroll back and forth. The author emphasizes that blank lines serve as structural delimiters, letting the reader see data blocks at a glance.

Method Extraction Isn't a Silver Bullet

A typical refactoring instinct is to extract each chain into a separate method. However, the materialMap variable is used both in logging inside the recipe chain and in the final result assembly. Extracting the recipe chain would force materialMap to be passed as a parameter or returned, bloating method signatures. When data is referenced in multiple places, the overhead of parameter passing can outweigh the clarity gained from extraction, and the split methods may become harder to understand because the caller and callee contexts must be held simultaneously. In such cases, reordering lines is a simpler, more direct improvement.

Handling Intersecting Data Flows

Real-world data flows often intersect, preventing perfect grouping. The guiding principle: declare variables as close as possible to their first use. The article illustrates this with a snippet where materialMap is needed for logging and later assembly:

// materialMap used in both logging and result assembly
var materialMap = materials.stream().collect(Collectors.toMap(Material::getId, Function.identity()));
auditLogger.log(materialMap);

// Main data chain stays coherent, materialMap declared near its first use
var recipeItems = recipeItemRepository.findByMaterialIds(materialIds);

The farther a declaration is from its use, the more mental effort is required to track the variable. The author advises organizing code around the primary data chain, keeping it coherent, and tolerating minor interference from secondary variables as long as they don't disrupt the main flow.

Summary

Code ordering falls outside typical linting rules, yet it materially affects the reading experience. Writing with the reader in mind — minimizing eye and brain travel — distinguishes merely functional code from truly maintainable code. The author also notes that AI-generated code quality depends on the constraints provided; embedding readability rules such as data-flow ordering into engineering guidelines can steer AI toward producing cleaner code.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

data flowvariable declarationclean codecode readabilitycode organizationsoftware craftsmanshipmethod extraction
samdeepthink
Written by

samdeepthink

Knowledge Planet: Old Dock's Tech Chronicles Zhihu: SamDeepThinking A technical manager who still codes heavily on the front line. From junior developer to tech lead, then tech manager, now leading the whole front‑ and back‑end development team—leveling up along the way. I have some insights on programming, career development, and tech management.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.