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
44 lines
2.3 KiB
Markdown
44 lines
2.3 KiB
Markdown
# Slice with Lambda — C# demo examples
|
|
|
|
Three C# demo examples for the **Slice with Lambda** refactoring.
|
|
Condensed mechanics: https://www.sammancoaching.org/refactorings/slice.html
|
|
(where that page says mock, we use a lambda instead).
|
|
Full Java walkthrough: `../../storyboard/storyboard.md`.
|
|
Slides: `~/qwan/slides-rjs/decks/refactoring/slice-with-lambda/slides.md`, served at http://localhost:9001/#/refactoring/slice-with-lambda.
|
|
|
|
## The three examples
|
|
|
|
| file | guard (client state) | unwanted dependency | lambda | tail |
|
|
|---|---|---|---|---|
|
|
| `MetaphorFree.cs` | `if (a < 0) return 0;` | `_someDependency.mightThrowWhenPreconditionNotSatisfied(a)` | `Func<int, int> readB = a => ...` | `int c = a + b; return c * 2;` |
|
|
| `WeatherStation.cs` | `if (_wateredToday)` | `_lightSensor.Read()` (byte) | `Func<byte> readLight = () => ...` | sunny -> `WateringDuration.Medium`, shady -> `Short` (reading > 128 => `SunExposure.Sunny`) |
|
|
| `IceCreamShop.cs` | `if (_thawedToday)` | `_thermometer.Read()` (byte) | `Func<byte> readTemperature = () => ...` | warm -> `ThawAmount.Medium`, cold -> `Low` (temperature > 25 => `Warmth.Warm`) |
|
|
|
|
In all three, the guard reads client state (a parameter or a flag the client
|
|
owns), so it stays in the extracted method. Only the dependency call moves
|
|
into the lambda.
|
|
|
|
## The ramp
|
|
|
|
`MetaphorFree.cs` is the smallest possible shape: no loop, one dependency
|
|
call, a tail of one arithmetic step. It carries the capture-to-parameter
|
|
lesson: the lambda takes `a` as its parameter (`readB(a)`) because a lambda
|
|
moved up into the function head cannot capture method parameters. Its
|
|
step-4 stub tests include a throwing stub.
|
|
|
|
`WeatherStation.cs` and `IceCreamShop.cs` are same-shape domain
|
|
repetitions — guard, one dependency call, map to enum, constant tail — so
|
|
participants can practice extracting the lambda twice. The C# delegate
|
|
syntax (`Func<byte>`) is worth the repetition.
|
|
|
|
## Same three regions every time
|
|
|
|
Each example deliberately has the same three regions:
|
|
|
|
- **before**: guard clauses
|
|
- **middle**: one dependency call
|
|
- **after**: tail that depends on the value the dependency produced
|
|
|
|
Matching the pattern: extract the dependency-using code into a lambda,
|
|
slide the definition to the top, extract the method below it, pass the
|
|
lambda as parameter, test with pure lambda stubs. |