die kunst der kleinen schritte...* aus transformation priority premise , uncle bob . arten von...
TRANSCRIPT
Die Kunst der
kleinen SchritteDavid Völkel XP Days Germany 09.11.2018
David Völkel XP Days Germany 09.11.2018
@davidvoelkelcodecentric
Software Craft Meetup Munich
#TDD
Disclaimer!
"It's the small steps part that distinguishes the TDD amateurs from the TDD experts ...
Experts are able to take smaller Steps.“*
*James Shore
Leap*
* Leap Pattern aus Kent Becks "Responsive Design" https://www.infoq.com/presentations/responsive-design
Image by Thor
Hohes Risiko
Initial State Target State Step 1 State 1 Step 2 State 2 State n-1 Step n Steps …
Leap
Initial State Target State Step 1 State 1 Step 2 State 2 State n-1 Step n Steps …
Fehler?
Wer
teac
hse
0,00
0,25
0,50
0,75
1,00
1 4 7 10 13 16 19 22 25 28 31 34 37 40 43
Erfolgswahrscheinlichkeit pro Schritt 0,95
Erfo
lgsw
ahrs
chei
nlic
hkei
t
Anzahl Mikroschritte
Initial State Target State Step 1 State 1 Step 2 State 2 State n-1 Step n Steps …
Kosten bei Fehler
zeitaufwändige Suche nach Ursache{
Stepping Stone*
* Stepping Stone Pattern aus Kent Becks "Responsive Design" https://www.infoq.com/presentations/responsive-design
Image by Seattle Municipal Archives
Stepping Stone*
Initial State Target State Step 1 State 1 Step 2 State 2 State n-1 Step n Steps …
Undo is your friend Fehler schnell finden
Aber auch Tests häufig ausführen!
"Test 3 Problem"String methodToImplement(String argument) { if (conditionOn(argument)) { return "Test 3 fake result"; } if (otherConditionOn(argument)) { return "Test 2 fake result"; } return "Test 1 fake result"; }
Refactoring?
Refactoring Von außen beobachtbares
Verhalten
bleibt gleich
Refactoring
Transformation*
Von außen beobachtbares
Verhalten
bleibt gleich
wird erweitert
* aus Transformation Priority Premise , Uncle Bob
Arten von Changes
RED GREEN
REFACTOR
Transformation
Refactoring
Triangulation
TDDRED GREEN
REFACTORGreen Bar Patterns*
* aus "Test -Drivene Development by Example“, Kent Beck
TDDRED GREEN
REFACTORGreen Bar Patterns
Triangulation
Fake it
Obvious Implementation
Fake Response
Fake Response Test 2 Test 2 Generisch gemacht
„Refactoring" macht generisch
Alles implementieren Test 1 Test 1
Test 1
Test 1
Test 1
Test 1
Triangulation
Fake it
Obvious Implementation
„Refactoring" macht generisch Fake Response
Fake Response Test 2 Test 2 Generisch gemacht
Alles implementieren Test 1 Test 1
Test 1
Test 1
Test 1
Test 1
Aufwand
Triangulation
Fake it
Obvious Implementation
„Refactoring" macht generisch Fake Response
Fake Response Test 2 Test 2 Generisch gemacht
Alles implementieren Test 1 Test 1
Test 1
Test 1
Test 1
Test 1
Aufwand vs
Risiko
Green Bar PatternsSweetspot
Triangulation
Fake it
Obvious Implementation
Logik
Struktur
Trivial
RED GREEN
„Klassisches Refactoring“
REFACTOR
Cleanup Remove Duplication
Express Intent
Ziel Wartbarkeit
RED GREEN
REFACTOR
Preparatory Refactoring*
"An example of preparatory refactoring",Martin Fowler
"Green Phase"
Implementation Test grün
„Grün Phase“ beim Triangulieren
"Green Phase"
TransformationPreparatory Refactoring
Ziel: Rot verkürzen
Test grün
Test grün
Implementation
"Green Phase"
Preparatory Refactoring
Test auskommentieren
Test
Test grün
Test grün
Implementation
TransformationTest
Transformation Priority Premise*
Kontext
Versprechen
Auswahl nächster Testcase
Kleinere Schritte Weniger „Steckenbleiben“
* "The Transformation Priority Premise", Uncle Bob
Prio 1 Trafo Prio 2 Trafo
…
Prio n Trafo
Simpel
Komplex
Transformation Priority Premise
Transformation in nächstem Test
Transformationen1.({}–>nil) 2.(nil->constant) 3.(constant->constant+) WTF? 4.(constant->scalar) 5.(statement->statements) 6.(unconditional->if) 7.(scalar->array) 8.(array->container) 9.(statement->recursion) 10.(if->while) 11.(expression->function) 12.(variable->assignment)
* "The Transformation Priority Premise", Uncle Bob
*
Hypothese1.({}–>nil) 2.(nil->constant) 3.(constant->constant+) 4.(constant->scalar) 5.(statement->statements) 6.(unconditional->if) 7.(scalar->array) 8.(array->container) 9.(statement->recursion) 10.(if->while) 11.(expression->function) 12.(variable->assignment)
0.Refactorings
WahrscheinlichkeitEr
folg
swah
rsch
einl
ichk
eit
Anzahl Mikroschritte
0
0,25
0,5
0,75
1
1 4 7 10 13 16 19 22 25 28 31 34 37 40 43
0,990,950,90,8
1.({}–>nil) 2.(nil->constant) 3.(constant->constant+) 4.(constant->scalar) 5.(statement->statements) 6.(unconditional->if) 7.(scalar->array) 8.(array->container) 9.(statement->recursion) 10.(if->while) 11.(expression->function) 12.(variable->assignment)
0.RefactoringsErfolgswahrscheinlichkeit
pro Schritt
Vorbereitende Refactorings Trivialtestcases
Fake it "Refactoring"
Triangulation
Obvious Implementation Mutual State
Green Bar & TPP?1.({}–>nil) 2.(nil->constant) 3.(constant->constant+) 4.(constant->scalar) 5.(statement->statements) 6.(unconditional->if) 7.(scalar->array) 8.(array->container) 9.(statement->recursion) 10.(if->while) 11.(expression->function) 12.(variable->assignment)
magnifier by Artem Yurov from the Noun Project
Kategorien-SpielGreen Bar Patterns Obvious Implementation Fake it Triangulation
Transformationen
Fake it Outside-In
„Test 3“ Fake 3 result
Logik
Struktur & DekompositionFake it
Triangulation
*Fake it Outside-In
*
Fake it Outside-In
Fake it "Refactoring“„Test 3“
TrafoFake 3 result
Preparatory Refactoring
Logik
Struktur & DekompositionFake it
Triangulation
Fake it Outside-In
Fake it "Refactoring“„Test 3“
TrafoFake 3 result
Preparatory Refactoring
Logik
Struktur & DekompositionFake it
TriangulationGgf. nachtriangulieren
Dekomposition durch
Refactoring
Aufgabe Dekomposition
1.„Test 3“ („Normalfall“, nicht „Trivialfall“) 2.Fake Ergebnis 3.dekomponiere durch Refactoring 4.Fake it generisch machen 5.trianguliere „null-safe“
expect(renderName('David', ‚Voelkel')) .toBe('Firstname: David\nLastname: Voelkel');
expect(renderName(null, null)) .toBe('Firstname: -\nLastname: -');
Rückwärts rechnen
„Virtuelle Fake Daten“
1.„Test 3“ 2.Fake Ergebnis 3.dekomponiere durch Refactoring 4.rechne Stück für Stück zurück mit virtuellen Fake Daten in jedem Schritt
5.join() zum konkatenieren
assertThat(renderMethods(asList("a", "b", "b"))) .isEqualTo(„a(), b(), c()");
Aufgabe rückwärts rechnen
Triangulation mit Fakedaten„Virtuelle Fake Daten“
Aufgabe
Constraints Trianguliere mit TPP Verwende vorbereitendes Refactoring Implementierung mit Collection Pipeline* (oder For Loop)
expect(concatenate(['a', 'b', 'c'])).toBe('abc');
In JS: array.join() In Java: stream.collect(Collectors.joining())
* "Collection Pipeline", Martin Fowler
Aufgabe
Constraints Trianguliere sauber mit TPP Verwende vorbereitendes Refactoring Implementierung mit Rekursion
expect(splitByComma(['a,b,c'])) .toBe(['a', 'b', 'c']);
ohne "split()" aus Lib sonstige wie „indexOf()“ … erlaubt
Stärken?Triangulation Fake it
Stärken?Fake it
Struktur Templating Mapping Dekomposition Berechnungen Collections/Iterationen
Triangulation
Logik Conditionals Rekursionen Algorithmen
Neuer Test nötig?
Sicherheit Scope zu groß
Aufwand
Einsparen Trivialtestfälle Verwendung von Libs implizit in Testdaten Triangulation mit Daten
Daumenregel: neuer Ausführungszweig?
Zu große SchritteRisiken Steckenbleiben beim TDD Lange Fehlersuche
Gegenmittel Hochpriore Changes zuerst => „Zeit im Rot“ minimieren
Kleine SchritteTriangulation Vorbereitende Refactorings
Fake it Rückwärts rechnen / Problem Dekomposition Iterationen
RetroWas hat Dich überascht?
Was glaubst Du ist praxistauglich?
1.„Test 3“ 2.Fake Ergebnis 3.Alles was wir heute gelernt haben!
assertThat(renderMethods(asList("C"))) .isEqualTo(asList(“__A__“, “_B_B_“, “C___C“));
Fallback Aufgabe
LicenseCreative Commons Attribution-ShareAlike 3.0