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
1.9 KiB
1.9 KiB
Exercise folder — Slice with Lambda (learning hour)
Contents:
java/— pre-factored exercise repo (prefactored-longrange; runs withmvn test)solution/— reference end state after step 3 (extracted method taking the lambda)rehearse-with-agent.md— how Willem rehearses this with qwen-code + java-refactoring-mcp
Reference solution
See solution/. End state of the production code (simplified):
public Map<IceCream, Integer> longRangeForecast() {
return longRangeForecast(daysForward -> {
scorer.updateSelection();
return scorer.lookupWeather(daysForward);
});
}
public Map<IceCream, Integer> longRangeForecast(
LongFunction<Boolean> dayOffsetToWeather) {
var expectedWeather = collectExpectedWeather(dayOffsetToWeather);
// ... reset loop + scoring loop, unchanged ...
}
private static List<Boolean> collectExpectedWeather(
LongFunction<Boolean> dayOffsetToWeather) {
var expectedWeather = new ArrayList<Boolean>();
for (Instant interestingDate : DATES) {
long daysForward = ChronoUnit.DAYS.between(ANCHOR_DATE, interestingDate);
expectedWeather.add(dayOffsetToWeather.apply(daysForward));
}
return expectedWeather;
}
Notes on the end state:
- Key move:
scoreris used only inside the lambda; the extracted methodcollectExpectedWeatherhas no dependency onScorerat all — all its inputs are parameters. - The public no-arg overload keeps callers unchanged; it injects the
"real" weather lambda. The test calls the overload with a pure
daysForward -> trueinstead. - The test is pure and glanceable:
alwaysSunnyweather gives{Strawberry:12, Chocolate:12, Vanilla:17, }(approved file included). scorer.updateSelection()turned out to be deletable (it only mutates staticScorer.flavourstate that this method never reads). Leaving it in the lambda is fine for step 3; deleting it is a debrief aha.