line

Code Quality Improvement Techniques Part (opens in new tab)

Effective refactoring often fails when developers focus on the physical structure of code rather than its conceptual meaning. When nested loops for paged data are extracted into separate functions based solely on their technical boundaries, the resulting code can remain difficult to read and maintain. The article argues that true code quality is achieved by aligning function boundaries with logical units, such as abstracting data retrieval into sequences to flatten complex structures.

Limitations of Naive Extraction

  • Traditional paged data processing often results in nested loops, where an outer while loop manages page indices and an inner for loop iterates through items in a chunk.
  • Simply extracting the inner loop into a private method like saveMetadataInPage(page) frequently fails to improve readability because it splits the conceptual task of "fetching all items" into two disconnected locations.
  • This "mechanical extraction" preserves the underlying implementation complexity, forcing the reader to track the state of pagination and loop conditions across multiple function calls.

Refactoring Based on Conceptual Boundaries

  • A more effective approach identifies the high-level semantic units: "retrieving all items" and "processing each item."
  • In Kotlin, the pagination logic can be encapsulated within a Sequence<Item> using the sequence builder and yieldAll keywords.
  • By transforming the data source into a sequence, the consumer function can replace a nested loop with a single, clean for loop.
  • This abstraction allows the main business logic to focus on "what" is being done (saving metadata) while hiding the "how" (managing page indices and hasNext flags).

Forest over Trees

  • When refactoring, developers should prioritize the "forest" (the relationship between operations) over the "trees" (individual functions).
  • This methodology is not limited to loops; it applies equally to nested conditional branches and complex data structures.
  • The goal should always be to ensure that the code reflects the meaning of the task, which often requires restructuring the data flow rather than just splitting existing blocks of code.