Files
learning-hour-maker/ideas/slice-with-lambda/zeroth-draft-of-refactoring-pattern.md
Your Name 77ae05c28c Rename split-loop-with-lambda to slice-with-lambda
The refactoring is now published as Slice on sammancoaching.org:
https://sammancoaching.org/refactorings/slice.html

- git mv ideas/split-loop-with-lambda -> ideas/slice-with-lambda
- rename learning-hour file and update frontmatter name
- update paths in tools/rehearse scripts and report title
- update prose: 'Split Loop with Lambda' -> 'Slice with Lambda'
  in learning hour, exercise READMEs, storyboard, solution comments
- link the published Slice refactoring from the pattern draft
2026-09-29 15:47:30 +00:00

7.2 KiB
Raw Permalink Blame History

Authors: Emily Bache, Willem van den Ende

Introduction

This is a zeroth draft of the Slice with Lambda refactoring pattern (published as Slice, formerly called "Split Loop with Lambda"). Our meta-goals are being more explicit in naming the refactorings and patterns we used to ourselves, and enable others to name the patterns, so they can reproduce the mechanics reliably on their own.

Initial literature survey (see related patterns below) has not yet revealed an existing Refactoring Pattern description. In order to fit some or all of this refactoring in a learning hour, it is worth writing down what we mean, with examples (so, in case the resulting exercise does not fit in a learning hour, we have a blog post to refer to for more details and/or recapturing the mechanics).

context / motivation

you have a long method. Somewhere in the mindle of the method, a collection of values is being transformed. the transformation depends on an object with multiple dependencies, and/or you do not want that particular collection in the composed method (it stands in the way of composing the method).You want to move this method call) to another class, but do not want the dependencies there.
you can not " extract parameter" ,because multiple values are transformed,and if the transformation needs to be done depends on the decisions inside the method. (A lambda introduces an explicit form of laziness. Instead of a value, we inject a function that can get the value, when needed. Instead of calculating the value beforehand, and then discard it when not needed).

Mechanics

We use some of the mechanics from the Split Loop refactoring, even though the immediate motivation is not Divergent Change. The inside loop may conceptually do one thing, but depend on something outside of the current method that we do not want (side-effects, or concerns that are not properly separated yet).

Split loop suggests “‘introduce variable’ refactorings and ‘slide statement’ “. These may be necessary, but the introduced variable is of type function, not value.

  1. Extract the code that uses the unwanted dependency into a lambda
  2. Use slide statement on the definition of the lambda to the top of the method. Leave the invocation in place
  3. Extract the method below the slides statement. You now have a new method, that takes the lambda as a parameter
  4. Move the method to another class where the unwanted dependency is not present
  5. Move and/or create tests, using the lambda as a stub instead of a concrete invocation of the unwanted dependency.
  6. Check that "everything that could possibly break" is tested - the extracted lambda allows more combinations to be easily tested.

The no-loop minimal shape

The mechanics above are usually applied inside a loop, but the pattern does not require one. The minimal shape is a method consisting of guard clauses, then ONE call on an unwanted dependency in the middle, then a tail that depends on the value the call produced:

public int Calculate(int a)
{
    if (a < 0) return 0;
    int b = _someDependency.mightThrowWhenPreconditionNotSatisfied(a);
    int c = a + b;
    return c * 2;
}

The same mechanics apply: extract the call into a lambda, slide the lambda definition to the top, extract the method below the slide statement with the lambda as a parameter. There is simply no loop to split — hence "Slice".

Capture-to-parameter: the lambda cannot capture the method's parameters

When the lambda is moved up into the function head (as a parameter via the overload seam), it cannot capture the method's parameters — they are not in scope there — so the lambda must take them explicitly:

Func<int, int> readB = a => _someDependency.mightThrowWhenPreconditionNotSatisfied(a);

and every invocation becomes

int b = readB(a);

Note that the Java storyboard lambda already took daysForward as its parameter, so the Java walkthrough does not hit this; the C# metaphor-free demo (exercise/csharp/MetaphorFree.cs) does.

Consequences / resulting context.

focused part of a method that can be
extracted to form a composed method, or moved.

the Lambda may still have side-effects in production code, it is not purely functional..
the code, method, is now testable. the "implementation"in the tests is a pure function, or a list ofpure functions.
Be mindful of a bunch of lambdas lying around. New design emerge from there. this might lead to extracting ports. Alambda function like this is a tiny adapter.

Aha moment for exercise

the new tests are actually glanceable and pure.
A pure function has no side-effents (e-g. state or IO)

Related patterns
extract function pointer
extract method object- not sue if this exists
method obic is in case a sunde amount ofState is needed.
Adapter - we adapt on interface that does notfit, to what we need. I
Osterhout: small interface that hides complexitygood power-to-weight ratio 1 1 11

https://www.sammancoaching.org/learning_hours/testable_design/slice.html slice learning hour that has a graphic of the movement, but doesn't describe the exact mechanics we use here.
![][image1]

Not for public consumption: There is a video of Emily Bache demoing the Icecream Slice Refactoring where she performs this exact refactoring - extracting a lambda, using the function as a parameter to an extracted method, and using a pure lambda implementation of the function to create/fix an approval test. Kata: https://github.com/emilybache/IceCreamForecasting-Refactoring-Kata . the video focuses on the LongRangeForecast method in java.

Extracting a lambda, and using its’ type can be seen as a tiny implementation of https://martinfowler.com/bliki/RoleInterface.html for a micro-adapter. We have one function signature (the Role Interface) and one small implementation. It is, in a way, the smallest Port (function signature) and Adapter (the extracted code with the unwanted dependency) that could possibly work. Later on, we might discover that some state and behaviour of the unwanted dependency can be grouped together in a larger Adapter, hidden behind a number of smaller RoleInterfaces (e.g. the read side and the write side of a Repository implementing the CQRS pattern by exposing separate interfaces for the Command and Query side, used by different clients).

Aside

Motivating quote from "refactoring to patterns" by Joshua Kerievsky, page 123, "compose method":
"Do you write a lot of Composed Methods? I like to think I do, but I often find that I don't, at first. So I have to go back and refactor to this pattern. When my code has many Composed Methods, it tends to be easy to use, read and extend "

JK also quotes Kent Beck, he wrote Composed Method in "Smalltalk Best Practice Patterns" and thought it was too simple to write down, but was appreciated by many afterwards.