Initial commit: Complete TDD workshop materials
- Workshop documentation (WORKSHOP_PLAN, FACILITATOR_GUIDE, etc.) - FizzBuzz kata with demo script (git history to be recreated) - Password Validator kata with demo script and solution - Shopping Cart kata with demo script and solution - Setup guide and TDD reference card for participants
This commit is contained in:
commit
c3355063f2
26 changed files with 4725 additions and 0 deletions
733
docs/fizzbuzz-git-history.patch
Normal file
733
docs/fizzbuzz-git-history.patch
Normal file
|
|
@ -0,0 +1,733 @@
|
|||
From 71fbd5a6f30e2c7f6e5e49807cae18274bc44506 Mon Sep 17 00:00:00 2001
|
||||
From: Dhemas Nurjaya <dhemasnurjaya@outlook.com>
|
||||
Date: Tue, 10 Mar 2026 11:44:55 +0700
|
||||
Subject: [PATCH 01/12] Initial setup: Create FizzBuzz kata structure
|
||||
|
||||
---
|
||||
lib/fizzbuzz.dart | 1 +
|
||||
pubspec.yaml | 9 +++++++++
|
||||
test/fizzbuzz_test.dart | 6 ++++++
|
||||
3 files changed, 16 insertions(+)
|
||||
create mode 100644 lib/fizzbuzz.dart
|
||||
create mode 100644 pubspec.yaml
|
||||
create mode 100644 test/fizzbuzz_test.dart
|
||||
|
||||
diff --git a/lib/fizzbuzz.dart b/lib/fizzbuzz.dart
|
||||
new file mode 100644
|
||||
index 0000000..8c2215b
|
||||
--- /dev/null
|
||||
+++ b/lib/fizzbuzz.dart
|
||||
@@ -0,0 +1 @@
|
||||
+// FizzBuzz kata - empty implementation file
|
||||
diff --git a/pubspec.yaml b/pubspec.yaml
|
||||
new file mode 100644
|
||||
index 0000000..5e6dee3
|
||||
--- /dev/null
|
||||
+++ b/pubspec.yaml
|
||||
@@ -0,0 +1,9 @@
|
||||
+name: fizzbuzz
|
||||
+description: FizzBuzz kata for TDD workshop live demonstration
|
||||
+version: 1.0.0
|
||||
+
|
||||
+environment:
|
||||
+ sdk: ^3.0.0
|
||||
+
|
||||
+dev_dependencies:
|
||||
+ test: ^1.24.0
|
||||
diff --git a/test/fizzbuzz_test.dart b/test/fizzbuzz_test.dart
|
||||
new file mode 100644
|
||||
index 0000000..efeefe0
|
||||
--- /dev/null
|
||||
+++ b/test/fizzbuzz_test.dart
|
||||
@@ -0,0 +1,6 @@
|
||||
+import 'package:test/test.dart';
|
||||
+import '../lib/fizzbuzz.dart';
|
||||
+
|
||||
+void main() {
|
||||
+ // Tests will be added step by step during the demo
|
||||
+}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 39357bebb6432b14ae45942da92de4804e747d02 Mon Sep 17 00:00:00 2001
|
||||
From: Dhemas Nurjaya <dhemasnurjaya@outlook.com>
|
||||
Date: Tue, 10 Mar 2026 11:45:29 +0700
|
||||
Subject: [PATCH 02/12] RED: Add test for input 1 returning "1"
|
||||
|
||||
---
|
||||
test/fizzbuzz_test.dart | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/test/fizzbuzz_test.dart b/test/fizzbuzz_test.dart
|
||||
index efeefe0..27e4266 100644
|
||||
--- a/test/fizzbuzz_test.dart
|
||||
+++ b/test/fizzbuzz_test.dart
|
||||
@@ -2,5 +2,7 @@ import 'package:test/test.dart';
|
||||
import '../lib/fizzbuzz.dart';
|
||||
|
||||
void main() {
|
||||
- // Tests will be added step by step during the demo
|
||||
+ test('returns "1" for 1', () {
|
||||
+ expect(fizzBuzz(1), equals('1'));
|
||||
+ });
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 334c5b510611a36ccd7b5db02b3a7ad1e3ae0863 Mon Sep 17 00:00:00 2001
|
||||
From: Dhemas Nurjaya <dhemasnurjaya@outlook.com>
|
||||
Date: Tue, 10 Mar 2026 11:45:41 +0700
|
||||
Subject: [PATCH 03/12] GREEN: Return "1" (hardcoded minimal solution)
|
||||
|
||||
---
|
||||
lib/fizzbuzz.dart | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/fizzbuzz.dart b/lib/fizzbuzz.dart
|
||||
index 8c2215b..0178355 100644
|
||||
--- a/lib/fizzbuzz.dart
|
||||
+++ b/lib/fizzbuzz.dart
|
||||
@@ -1 +1,5 @@
|
||||
-// FizzBuzz kata - empty implementation file
|
||||
+// FizzBuzz kata - TDD progression
|
||||
+
|
||||
+String fizzBuzz(int n) {
|
||||
+ return '1';
|
||||
+}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From e0ae220dea66522d1726e342820f7e2d61edaafb Mon Sep 17 00:00:00 2001
|
||||
From: Dhemas Nurjaya <dhemasnurjaya@outlook.com>
|
||||
Date: Tue, 10 Mar 2026 11:45:51 +0700
|
||||
Subject: [PATCH 04/12] RED: Add test for input 2 returning "2"
|
||||
|
||||
---
|
||||
test/fizzbuzz_test.dart | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/test/fizzbuzz_test.dart b/test/fizzbuzz_test.dart
|
||||
index 27e4266..7b517ae 100644
|
||||
--- a/test/fizzbuzz_test.dart
|
||||
+++ b/test/fizzbuzz_test.dart
|
||||
@@ -5,4 +5,8 @@ void main() {
|
||||
test('returns "1" for 1', () {
|
||||
expect(fizzBuzz(1), equals('1'));
|
||||
});
|
||||
+
|
||||
+ test('returns "2" for 2', () {
|
||||
+ expect(fizzBuzz(2), equals('2'));
|
||||
+ });
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 4c0471c02ac4bfef56517044519c65478ecd3dbd Mon Sep 17 00:00:00 2001
|
||||
From: Dhemas Nurjaya <dhemasnurjaya@outlook.com>
|
||||
Date: Tue, 10 Mar 2026 11:46:03 +0700
|
||||
Subject: [PATCH 05/12] GREEN: Return string representation of number
|
||||
|
||||
---
|
||||
lib/fizzbuzz.dart | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/fizzbuzz.dart b/lib/fizzbuzz.dart
|
||||
index 0178355..4da1cfa 100644
|
||||
--- a/lib/fizzbuzz.dart
|
||||
+++ b/lib/fizzbuzz.dart
|
||||
@@ -1,5 +1,5 @@
|
||||
// FizzBuzz kata - TDD progression
|
||||
|
||||
String fizzBuzz(int n) {
|
||||
- return '1';
|
||||
+ return n.toString();
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 919e90fd474a2cc4200c9d6d0a0235365f6b718c Mon Sep 17 00:00:00 2001
|
||||
From: Dhemas Nurjaya <dhemasnurjaya@outlook.com>
|
||||
Date: Tue, 10 Mar 2026 11:46:14 +0700
|
||||
Subject: [PATCH 06/12] RED: Add test for input 3 returning "Fizz"
|
||||
|
||||
---
|
||||
test/fizzbuzz_test.dart | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/test/fizzbuzz_test.dart b/test/fizzbuzz_test.dart
|
||||
index 7b517ae..27b1ce6 100644
|
||||
--- a/test/fizzbuzz_test.dart
|
||||
+++ b/test/fizzbuzz_test.dart
|
||||
@@ -9,4 +9,8 @@ void main() {
|
||||
test('returns "2" for 2', () {
|
||||
expect(fizzBuzz(2), equals('2'));
|
||||
});
|
||||
+
|
||||
+ test('returns "Fizz" for 3', () {
|
||||
+ expect(fizzBuzz(3), equals('Fizz'));
|
||||
+ });
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 1db35633b102b359860a7e85361d733038e8655d Mon Sep 17 00:00:00 2001
|
||||
From: Dhemas Nurjaya <dhemasnurjaya@outlook.com>
|
||||
Date: Tue, 10 Mar 2026 11:46:27 +0700
|
||||
Subject: [PATCH 07/12] GREEN: Return "Fizz" for numbers divisible by 3
|
||||
|
||||
---
|
||||
lib/fizzbuzz.dart | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/lib/fizzbuzz.dart b/lib/fizzbuzz.dart
|
||||
index 4da1cfa..21150ec 100644
|
||||
--- a/lib/fizzbuzz.dart
|
||||
+++ b/lib/fizzbuzz.dart
|
||||
@@ -1,5 +1,6 @@
|
||||
// FizzBuzz kata - TDD progression
|
||||
|
||||
String fizzBuzz(int n) {
|
||||
+ if (n % 3 == 0) return 'Fizz';
|
||||
return n.toString();
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 08cc354e1f1798f062e9c947b7d64637870d8964 Mon Sep 17 00:00:00 2001
|
||||
From: Dhemas Nurjaya <dhemasnurjaya@outlook.com>
|
||||
Date: Tue, 10 Mar 2026 11:46:38 +0700
|
||||
Subject: [PATCH 08/12] RED: Add test for input 5 returning "Buzz"
|
||||
|
||||
---
|
||||
test/fizzbuzz_test.dart | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/test/fizzbuzz_test.dart b/test/fizzbuzz_test.dart
|
||||
index 27b1ce6..46f279a 100644
|
||||
--- a/test/fizzbuzz_test.dart
|
||||
+++ b/test/fizzbuzz_test.dart
|
||||
@@ -13,4 +13,8 @@ void main() {
|
||||
test('returns "Fizz" for 3', () {
|
||||
expect(fizzBuzz(3), equals('Fizz'));
|
||||
});
|
||||
+
|
||||
+ test('returns "Buzz" for 5', () {
|
||||
+ expect(fizzBuzz(5), equals('Buzz'));
|
||||
+ });
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From 74d6e23f3faa7c7138178ce00c784c51e97677e4 Mon Sep 17 00:00:00 2001
|
||||
From: Dhemas Nurjaya <dhemasnurjaya@outlook.com>
|
||||
Date: Tue, 10 Mar 2026 11:46:52 +0700
|
||||
Subject: [PATCH 09/12] GREEN: Return "Buzz" for numbers divisible by 5
|
||||
|
||||
---
|
||||
lib/fizzbuzz.dart | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/lib/fizzbuzz.dart b/lib/fizzbuzz.dart
|
||||
index 21150ec..063e7bd 100644
|
||||
--- a/lib/fizzbuzz.dart
|
||||
+++ b/lib/fizzbuzz.dart
|
||||
@@ -2,5 +2,6 @@
|
||||
|
||||
String fizzBuzz(int n) {
|
||||
if (n % 3 == 0) return 'Fizz';
|
||||
+ if (n % 5 == 0) return 'Buzz';
|
||||
return n.toString();
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From ca23fe7f17e7d29d8e375a4a2fc1ac32bf8452c6 Mon Sep 17 00:00:00 2001
|
||||
From: Dhemas Nurjaya <dhemasnurjaya@outlook.com>
|
||||
Date: Tue, 10 Mar 2026 11:47:04 +0700
|
||||
Subject: [PATCH 10/12] RED: Add test for input 15 returning "FizzBuzz"
|
||||
|
||||
---
|
||||
test/fizzbuzz_test.dart | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/test/fizzbuzz_test.dart b/test/fizzbuzz_test.dart
|
||||
index 46f279a..f3203e3 100644
|
||||
--- a/test/fizzbuzz_test.dart
|
||||
+++ b/test/fizzbuzz_test.dart
|
||||
@@ -17,4 +17,8 @@ void main() {
|
||||
test('returns "Buzz" for 5', () {
|
||||
expect(fizzBuzz(5), equals('Buzz'));
|
||||
});
|
||||
+
|
||||
+ test('returns "FizzBuzz" for 15', () {
|
||||
+ expect(fizzBuzz(15), equals('FizzBuzz'));
|
||||
+ });
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From f15c0989635612226d40e28c8507276ecd1c976d Mon Sep 17 00:00:00 2001
|
||||
From: Dhemas Nurjaya <dhemasnurjaya@outlook.com>
|
||||
Date: Tue, 10 Mar 2026 11:47:17 +0700
|
||||
Subject: [PATCH 11/12] GREEN: Return "FizzBuzz" for numbers divisible by both
|
||||
3 and 5 (check 15 first!)
|
||||
|
||||
---
|
||||
lib/fizzbuzz.dart | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/lib/fizzbuzz.dart b/lib/fizzbuzz.dart
|
||||
index 063e7bd..b312695 100644
|
||||
--- a/lib/fizzbuzz.dart
|
||||
+++ b/lib/fizzbuzz.dart
|
||||
@@ -1,6 +1,7 @@
|
||||
// FizzBuzz kata - TDD progression
|
||||
|
||||
String fizzBuzz(int n) {
|
||||
+ if (n % 15 == 0) return 'FizzBuzz';
|
||||
if (n % 3 == 0) return 'Fizz';
|
||||
if (n % 5 == 0) return 'Buzz';
|
||||
return n.toString();
|
||||
--
|
||||
2.53.0
|
||||
|
||||
|
||||
From cd13284513f428908ec0035f0848a12c27636eaa Mon Sep 17 00:00:00 2001
|
||||
From: Dhemas Nurjaya <dhemasnurjaya@outlook.com>
|
||||
Date: Tue, 10 Mar 2026 11:48:30 +0700
|
||||
Subject: [PATCH 12/12] Add documentation for FizzBuzz demo kata
|
||||
|
||||
---
|
||||
DEMO_SCRIPT.md | 346 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
README.md | 56 ++++++++
|
||||
2 files changed, 402 insertions(+)
|
||||
create mode 100644 DEMO_SCRIPT.md
|
||||
create mode 100644 README.md
|
||||
|
||||
diff --git a/DEMO_SCRIPT.md b/DEMO_SCRIPT.md
|
||||
new file mode 100644
|
||||
index 0000000..d0853e0
|
||||
--- /dev/null
|
||||
+++ b/DEMO_SCRIPT.md
|
||||
@@ -0,0 +1,346 @@
|
||||
+# FizzBuzz Live Demo Script
|
||||
+
|
||||
+**Duration:** 15 minutes (0:10–0:25 in workshop schedule)
|
||||
+**Purpose:** Demonstrate RED-GREEN-REFACTOR cycle in real-time
|
||||
+
|
||||
+---
|
||||
+
|
||||
+## Setup (Before Demo Starts)
|
||||
+
|
||||
+- [ ] Open two windows side-by-side: `lib/fizzbuzz.dart` and `test/fizzbuzz_test.dart`
|
||||
+- [ ] Have terminal ready at bottom with `dart test --watch` (optional) or be ready to run `dart test` manually
|
||||
+- [ ] Start with the final completed kata, then `git reset --hard <initial-commit>` to beginning
|
||||
+- [ ] Have git log open in another terminal: `git log --oneline --all`
|
||||
+
|
||||
+---
|
||||
+
|
||||
+## Demo Flow
|
||||
+
|
||||
+### Minutes 0-2: Introduction
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+We're going to build FizzBuzz together using TDD. Everyone knows the rules, right?
|
||||
+[Pause for nods]
|
||||
+
|
||||
+Divisible by 3 → "Fizz"
|
||||
+Divisible by 5 → "Buzz"
|
||||
+Divisible by both → "FizzBuzz"
|
||||
+Otherwise → the number as a string
|
||||
+
|
||||
+Here's the key: I'm NOT going to design this first. I'm going to let the tests tell me what to code.
|
||||
+
|
||||
+Watch the rhythm:
|
||||
+1. RED - Write a test, watch it fail
|
||||
+2. GREEN - Write minimal code to pass
|
||||
+3. REFACTOR - Clean up if needed
|
||||
+
|
||||
+Let's start.
|
||||
+```
|
||||
+
|
||||
+**What to Do:**
|
||||
+- Show the empty files
|
||||
+- Run `dart test` → shows no tests or all passing (from setup)
|
||||
+
|
||||
+---
|
||||
+
|
||||
+### Minutes 2-4: Cycle 1 (Input 1 → "1")
|
||||
+
|
||||
+**RED Phase:**
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+What's the simplest test I could write? Let me start with input 1 returning "1".
|
||||
+```
|
||||
+
|
||||
+**What to Do:**
|
||||
+```dart
|
||||
+// In test/fizzbuzz_test.dart
|
||||
+test('returns "1" for 1', () {
|
||||
+ expect(fizzBuzz(1), equals('1'));
|
||||
+});
|
||||
+```
|
||||
+
|
||||
+Run `dart test` → **FAILS** (function doesn't exist)
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+Good! It's RED. The test is failing for the right reason - the function doesn't exist yet.
|
||||
+```
|
||||
+
|
||||
+**GREEN Phase:**
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+Now, what's the minimum code to make this pass?
|
||||
+[Pause, let them think]
|
||||
+I could return the number... but even simpler: I'll just return "1".
|
||||
+This looks silly, but watch what happens next.
|
||||
+```
|
||||
+
|
||||
+**What to Do:**
|
||||
+```dart
|
||||
+// In lib/fizzbuzz.dart
|
||||
+String fizzBuzz(int n) {
|
||||
+ return '1';
|
||||
+}
|
||||
+```
|
||||
+
|
||||
+Run `dart test` → **PASSES** (GREEN ✅)
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+GREEN! It passes. Now I could refactor, but there's nothing to clean up yet.
|
||||
+Let's add another test.
|
||||
+```
|
||||
+
|
||||
+**Time Check:** You should be at ~4 minutes
|
||||
+
|
||||
+---
|
||||
+
|
||||
+### Minutes 4-6: Cycle 2 (Input 2 → "2")
|
||||
+
|
||||
+**RED Phase:**
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+Next simplest test: input 2 should return "2".
|
||||
+```
|
||||
+
|
||||
+**What to Do:**
|
||||
+```dart
|
||||
+test('returns "2" for 2', () {
|
||||
+ expect(fizzBuzz(2), equals('2'));
|
||||
+});
|
||||
+```
|
||||
+
|
||||
+Run `dart test` → **FAILS** (Expected: '2', Actual: '1')
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+RED again. Now I have duplication in my tests - both expect numbers as strings.
|
||||
+That's okay. Let me make it GREEN.
|
||||
+```
|
||||
+
|
||||
+**GREEN Phase:**
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+Now the hardcoded "1" won't work. What's the simplest solution?
|
||||
+[Pause]
|
||||
+Return the number as a string!
|
||||
+```
|
||||
+
|
||||
+**What to Do:**
|
||||
+```dart
|
||||
+String fizzBuzz(int n) {
|
||||
+ return n.toString();
|
||||
+}
|
||||
+```
|
||||
+
|
||||
+Run `dart test` → **PASSES** (both tests GREEN ✅)
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+Both tests pass! Notice how the second test forced me to generalize.
|
||||
+I didn't plan that - the tests guided me.
|
||||
+```
|
||||
+
|
||||
+**Time Check:** You should be at ~6 minutes
|
||||
+
|
||||
+---
|
||||
+
|
||||
+### Minutes 6-9: Cycle 3 (Input 3 → "Fizz")
|
||||
+
|
||||
+**RED Phase:**
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+Now it gets interesting. Input 3 should return "Fizz".
|
||||
+```
|
||||
+
|
||||
+**What to Do:**
|
||||
+```dart
|
||||
+test('returns "Fizz" for 3', () {
|
||||
+ expect(fizzBuzz(3), equals('Fizz'));
|
||||
+});
|
||||
+```
|
||||
+
|
||||
+Run `dart test` → **FAILS** (Expected: 'Fizz', Actual: '3')
|
||||
+
|
||||
+**GREEN Phase:**
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+Okay, now I need to check divisibility by 3.
|
||||
+```
|
||||
+
|
||||
+**What to Do:**
|
||||
+```dart
|
||||
+String fizzBuzz(int n) {
|
||||
+ if (n % 3 == 0) return 'Fizz';
|
||||
+ return n.toString();
|
||||
+}
|
||||
+```
|
||||
+
|
||||
+Run `dart test` → **PASSES** (all 3 tests GREEN ✅)
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+All three pass! The algorithm is starting to emerge.
|
||||
+```
|
||||
+
|
||||
+**Time Check:** You should be at ~9 minutes
|
||||
+
|
||||
+---
|
||||
+
|
||||
+### Minutes 9-11: Cycle 4 (Input 5 → "Buzz")
|
||||
+
|
||||
+**RED Phase:**
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+Pattern should be clear now. Input 5 returns "Buzz".
|
||||
+```
|
||||
+
|
||||
+**What to Do:**
|
||||
+```dart
|
||||
+test('returns "Buzz" for 5', () {
|
||||
+ expect(fizzBuzz(5), equals('Buzz'));
|
||||
+});
|
||||
+```
|
||||
+
|
||||
+Run `dart test` → **FAILS** (Expected: 'Buzz', Actual: '5')
|
||||
+
|
||||
+**GREEN Phase:**
|
||||
+
|
||||
+**What to Do:**
|
||||
+```dart
|
||||
+String fizzBuzz(int n) {
|
||||
+ if (n % 3 == 0) return 'Fizz';
|
||||
+ if (n % 5 == 0) return 'Buzz';
|
||||
+ return n.toString();
|
||||
+}
|
||||
+```
|
||||
+
|
||||
+Run `dart test` → **PASSES** (all 4 tests GREEN ✅)
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+Four tests passing. But we haven't handled the tricky case yet...
|
||||
+```
|
||||
+
|
||||
+---
|
||||
+
|
||||
+### Minutes 11-14: Cycle 5 (Input 15 → "FizzBuzz")
|
||||
+
|
||||
+**RED Phase:**
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+Here's where it gets fun. What should 15 return?
|
||||
+[Let them answer: "FizzBuzz"]
|
||||
+Right! It's divisible by both 3 AND 5.
|
||||
+```
|
||||
+
|
||||
+**What to Do:**
|
||||
+```dart
|
||||
+test('returns "FizzBuzz" for 15', () {
|
||||
+ expect(fizzBuzz(15), equals('FizzBuzz'));
|
||||
+});
|
||||
+```
|
||||
+
|
||||
+Run `dart test` → **FAILS** (Expected: 'FizzBuzz', Actual: 'Fizz')
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+Uh oh! It returns "Fizz" because 15 is divisible by 3, and we check that first.
|
||||
+We need to check for BOTH before checking for either individually.
|
||||
+```
|
||||
+
|
||||
+**GREEN Phase:**
|
||||
+
|
||||
+**What to Do:**
|
||||
+```dart
|
||||
+String fizzBuzz(int n) {
|
||||
+ if (n % 15 == 0) return 'FizzBuzz'; // Or: if (n % 3 == 0 && n % 5 == 0)
|
||||
+ if (n % 3 == 0) return 'Fizz';
|
||||
+ if (n % 5 == 0) return 'Buzz';
|
||||
+ return n.toString();
|
||||
+}
|
||||
+```
|
||||
+
|
||||
+Run `dart test` → **PASSES** (all 5 tests GREEN ✅)
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+Perfect! All tests pass. ORDER MATTERS. That's a lesson the test taught us.
|
||||
+```
|
||||
+
|
||||
+**Time Check:** You should be at ~14 minutes
|
||||
+
|
||||
+---
|
||||
+
|
||||
+### Minutes 14-15: Wrap Up
|
||||
+
|
||||
+**What to Say:**
|
||||
+```
|
||||
+Let me show you something cool.
|
||||
+[Run: git log --oneline]
|
||||
+
|
||||
+See these commits? Each one is a RED or GREEN step. I can jump back to any point.
|
||||
+
|
||||
+Notice what just happened:
|
||||
+1. I never wrote a "design document" for FizzBuzz
|
||||
+2. The tests told me what code to write
|
||||
+3. The algorithm emerged naturally from simple cases to complex
|
||||
+4. When I made a mistake (checking 3 before 15), the test caught it immediately
|
||||
+
|
||||
+This is TDD. It feels weird at first, but it becomes automatic.
|
||||
+
|
||||
+Now YOU'RE going to try it. Pick your kata and start with the first test.
|
||||
+```
|
||||
+
|
||||
+---
|
||||
+
|
||||
+## Tips for Smooth Delivery
|
||||
+
|
||||
+### DO:
|
||||
+- **Narrate your thinking**: "What's the simplest test?" "What's the minimum code?"
|
||||
+- **Pause before answering**: Let them think for 2-3 seconds
|
||||
+- **Show RED clearly**: Let the test fail, read the error message aloud
|
||||
+- **Type slowly**: They're watching and learning the syntax too
|
||||
+- **Run tests frequently**: After every change
|
||||
+
|
||||
+### DON'T:
|
||||
+- Rush through the cycles - the rhythm is what they're learning
|
||||
+- Skip the RED step - it proves the test can fail
|
||||
+- Write all tests at once - that's not TDD
|
||||
+- Apologize for "simple" code - minimal solutions are the point
|
||||
+- Skip explaining the 15/3/5 order issue - that's a key insight
|
||||
+
|
||||
+### If You Make a Typo:
|
||||
+**Good!** Say: "Oops, typo. See how the test catches it?" Then fix it.
|
||||
+
|
||||
+### If Someone Asks a Question:
|
||||
+Pause the demo, answer briefly, then continue. You have buffer time.
|
||||
+
|
||||
+---
|
||||
+
|
||||
+## Troubleshooting
|
||||
+
|
||||
+| Issue | Fix |
|
||||
+|-------|-----|
|
||||
+| Tests won't run | Check `dart pub get` was run |
|
||||
+| Can't see failure messages clearly | Increase terminal font size |
|
||||
+| Running behind schedule | Skip the "wrap up" or shorten it |
|
||||
+| Running ahead | Add a 6th test (e.g., input 6 → "Fizz") |
|
||||
+
|
||||
+---
|
||||
+
|
||||
+## After the Demo
|
||||
+
|
||||
+Transition to hands-on:
|
||||
+```
|
||||
+"Alright, now you try it. Open one of the katas, uncomment the first test, and make it RED. Then make it GREEN. I'll be walking around - grab me if you get stuck. Go!"
|
||||
+```
|
||||
diff --git a/README.md b/README.md
|
||||
new file mode 100644
|
||||
index 0000000..c4ae816
|
||||
--- /dev/null
|
||||
+++ b/README.md
|
||||
@@ -0,0 +1,56 @@
|
||||
+# FizzBuzz Kata - Live Demo
|
||||
+
|
||||
+## Purpose
|
||||
+
|
||||
+This kata is designed for **live demonstration** during the TDD workshop introduction. It shows the RED-GREEN-REFACTOR cycle in a familiar problem that requires minimal explanation.
|
||||
+
|
||||
+## The Rules
|
||||
+
|
||||
+Write a function that converts numbers to strings according to these rules:
|
||||
+
|
||||
+- Numbers divisible by 3 → `"Fizz"`
|
||||
+- Numbers divisible by 5 → `"Buzz"`
|
||||
+- Numbers divisible by both 3 and 5 → `"FizzBuzz"`
|
||||
+- All other numbers → the number as a string (e.g., `"1"`, `"2"`)
|
||||
+
|
||||
+## Git History as Teaching Tool
|
||||
+
|
||||
+This kata is built with **12 commits** showing each step of the TDD cycle:
|
||||
+
|
||||
+```bash
|
||||
+git log --oneline --all
|
||||
+```
|
||||
+
|
||||
+Each commit shows either:
|
||||
+- **RED**: A failing test
|
||||
+- **GREEN**: Minimal code to pass
|
||||
+- **REFACTOR**: Code cleanup (if needed)
|
||||
+
|
||||
+## Using This for the Demo
|
||||
+
|
||||
+See `DEMO_SCRIPT.md` for detailed talking points and timing guide.
|
||||
+
|
||||
+## Running the Tests
|
||||
+
|
||||
+```bash
|
||||
+dart pub get
|
||||
+dart test
|
||||
+```
|
||||
+
|
||||
+## Checking Out Individual Steps
|
||||
+
|
||||
+To see the code at any point:
|
||||
+
|
||||
+```bash
|
||||
+git log --oneline # See all commits
|
||||
+git checkout <commit-hash> # Jump to that step
|
||||
+git checkout main # Return to final solution
|
||||
+```
|
||||
+
|
||||
+## The "Aha!" Moment
|
||||
+
|
||||
+Notice how the simple tests (1, 2) led to a general solution (n.toString()), and the Fizz/Buzz tests forced the algorithm to emerge naturally. **We never designed the whole solution upfront—the tests revealed it step by step.**
|
||||
+
|
||||
+## For Facilitators
|
||||
+
|
||||
+This is your warm-up kata. Practice it a few times before the workshop so you can live-code it smoothly while talking through your thinking process.
|
||||
--
|
||||
2.53.0
|
||||
|
||||
12
docs/fizzbuzz-git-log.txt
Normal file
12
docs/fizzbuzz-git-log.txt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
cd13284513f428908ec0035f0848a12c27636eaa|Add documentation for FizzBuzz demo kata|Dhemas Nurjaya|dhemasnurjaya@outlook.com|2026-03-10 11:48:30 +0700
|
||||
f15c0989635612226d40e28c8507276ecd1c976d|GREEN: Return "FizzBuzz" for numbers divisible by both 3 and 5 (check 15 first!)|Dhemas Nurjaya|dhemasnurjaya@outlook.com|2026-03-10 11:47:17 +0700
|
||||
ca23fe7f17e7d29d8e375a4a2fc1ac32bf8452c6|RED: Add test for input 15 returning "FizzBuzz"|Dhemas Nurjaya|dhemasnurjaya@outlook.com|2026-03-10 11:47:04 +0700
|
||||
74d6e23f3faa7c7138178ce00c784c51e97677e4|GREEN: Return "Buzz" for numbers divisible by 5|Dhemas Nurjaya|dhemasnurjaya@outlook.com|2026-03-10 11:46:52 +0700
|
||||
08cc354e1f1798f062e9c947b7d64637870d8964|RED: Add test for input 5 returning "Buzz"|Dhemas Nurjaya|dhemasnurjaya@outlook.com|2026-03-10 11:46:38 +0700
|
||||
1db35633b102b359860a7e85361d733038e8655d|GREEN: Return "Fizz" for numbers divisible by 3|Dhemas Nurjaya|dhemasnurjaya@outlook.com|2026-03-10 11:46:27 +0700
|
||||
919e90fd474a2cc4200c9d6d0a0235365f6b718c|RED: Add test for input 3 returning "Fizz"|Dhemas Nurjaya|dhemasnurjaya@outlook.com|2026-03-10 11:46:14 +0700
|
||||
4c0471c02ac4bfef56517044519c65478ecd3dbd|GREEN: Return string representation of number|Dhemas Nurjaya|dhemasnurjaya@outlook.com|2026-03-10 11:46:03 +0700
|
||||
e0ae220dea66522d1726e342820f7e2d61edaafb|RED: Add test for input 2 returning "2"|Dhemas Nurjaya|dhemasnurjaya@outlook.com|2026-03-10 11:45:51 +0700
|
||||
334c5b510611a36ccd7b5db02b3a7ad1e3ae0863|GREEN: Return "1" (hardcoded minimal solution)|Dhemas Nurjaya|dhemasnurjaya@outlook.com|2026-03-10 11:45:41 +0700
|
||||
39357bebb6432b14ae45942da92de4804e747d02|RED: Add test for input 1 returning "1"|Dhemas Nurjaya|dhemasnurjaya@outlook.com|2026-03-10 11:45:29 +0700
|
||||
71fbd5a6f30e2c7f6e5e49807cae18274bc44506|Initial setup: Create FizzBuzz kata structure|Dhemas Nurjaya|dhemasnurjaya@outlook.com|2026-03-10 11:44:55 +0700
|
||||
199
docs/plans/2026-03-10-workshop-improvements-design.md
Normal file
199
docs/plans/2026-03-10-workshop-improvements-design.md
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
# TDD Workshop Improvements - Design Document
|
||||
|
||||
**Date:** 2026-03-10
|
||||
**Author:** Workshop Facilitator
|
||||
**Status:** Approved
|
||||
|
||||
## Overview
|
||||
|
||||
This document outlines the design for enhancing the TDD workshop materials to create a comprehensive, ready-to-deliver 2-hour hands-on session for developers familiar with TDD concepts but lacking practical experience.
|
||||
|
||||
## Goals
|
||||
|
||||
1. Provide a complete live-demo kata (FizzBuzz) with step-by-step progression
|
||||
2. Enhance facilitator guidance with detailed scripts and timing
|
||||
3. Create participant reference materials (TDD cheat sheet)
|
||||
4. Add setup and troubleshooting documentation
|
||||
5. Improve solution files with test-to-code traceability
|
||||
|
||||
## Target Audience
|
||||
|
||||
- **Participants:** Developers who know what TDD is but haven't practiced it regularly
|
||||
- **Facilitators:** Workshop leaders who need clear guidance and scripts
|
||||
- **Format:** 2-hour in-person workshop
|
||||
- **Language:** Dart
|
||||
|
||||
## Design Decisions
|
||||
|
||||
### Approach: Incremental Enhancement
|
||||
|
||||
We'll build improvements in three phases:
|
||||
|
||||
1. **Phase 1:** Live demo foundation (FizzBuzz kata)
|
||||
2. **Phase 2:** Documentation (guides, reference card, setup)
|
||||
3. **Phase 3:** Polish (enhanced solutions, root README)
|
||||
|
||||
This allows for testing each component and ensures core materials are ready first.
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
tdd-workshop/
|
||||
├── README.md # NEW: Workshop overview
|
||||
├── FACILITATOR_GUIDE.md # ENHANCED: Add detailed scripts
|
||||
├── WORKSHOP_PLAN.md # NEW: Complete schedule & checklists
|
||||
├── TDD_REFERENCE_CARD.md # NEW: One-page participant handout
|
||||
├── SETUP_GUIDE.md # NEW: Installation & troubleshooting
|
||||
├── docs/
|
||||
│ └── plans/ # Design documents
|
||||
├── fizzbuzz/ # NEW: Live demo kata
|
||||
│ ├── README.md
|
||||
│ ├── DEMO_SCRIPT.md # Facilitator walkthrough
|
||||
│ ├── pubspec.yaml
|
||||
│ ├── lib/
|
||||
│ │ └── fizzbuzz.dart
|
||||
│ └── test/
|
||||
│ └── fizzbuzz_test.dart
|
||||
├── password_validator/
|
||||
│ └── lib/
|
||||
│ └── password_validator_solution.dart # ENHANCED: Add test references
|
||||
└── shopping_cart/
|
||||
└── lib/
|
||||
└── shopping_cart_solution.dart # ENHANCED: Add test references
|
||||
```
|
||||
|
||||
## Component Designs
|
||||
|
||||
### 1. FizzBuzz Demo Kata
|
||||
|
||||
**Purpose:** Provide a ready-to-demonstrate kata showing RED-GREEN-REFACTOR in real-time.
|
||||
|
||||
**Git Strategy:** Linear commit history showing each TDD cycle:
|
||||
- Commits alternate between RED (failing test) and GREEN (minimal implementation)
|
||||
- Each commit message clearly labeled: "RED: ...", "GREEN: ...", "REFACTOR: ..."
|
||||
- Facilitator can `git checkout` each commit to show progression
|
||||
|
||||
**Key Commits:**
|
||||
1. Initial setup
|
||||
2. RED: Test for 1 → "1"
|
||||
3. GREEN: Return "1" (hardcoded)
|
||||
4. RED: Test for 2 → "2"
|
||||
5. GREEN: Return n.toString()
|
||||
6. RED: Test for 3 → "Fizz"
|
||||
7. GREEN: Check divisibility by 3
|
||||
8. RED: Test for 5 → "Buzz"
|
||||
9. GREEN: Add divisibility by 5
|
||||
10. RED: Test for 15 → "FizzBuzz"
|
||||
11. GREEN: Check both (order matters!)
|
||||
12. REFACTOR: Optional cleanup
|
||||
|
||||
**DEMO_SCRIPT.md Contents:**
|
||||
- Minute-by-minute timing guide (0-5, 5-10, 10-15)
|
||||
- Talking points for each step
|
||||
- Common mistakes to demonstrate intentionally
|
||||
- Key insights participants should notice
|
||||
|
||||
### 2. Enhanced Documentation
|
||||
|
||||
#### TDD_REFERENCE_CARD.md
|
||||
One-page handout covering:
|
||||
- RED-GREEN-REFACTOR cycle diagram
|
||||
- When to refactor (code smells)
|
||||
- Common test patterns (Arrange-Act-Assert)
|
||||
- Dart test assertions quick reference
|
||||
- Tips for staying disciplined
|
||||
- Link to tdd-katas for more practice
|
||||
|
||||
#### SETUP_GUIDE.md
|
||||
Pre-workshop setup with:
|
||||
- Dart SDK prerequisites
|
||||
- Installation steps
|
||||
- Verification procedures
|
||||
- Troubleshooting common issues (pub get fails, PATH issues, etc.)
|
||||
- IDE setup recommendations
|
||||
|
||||
#### WORKSHOP_PLAN.md
|
||||
Complete facilitator reference with:
|
||||
- Pre-workshop checklist (1 week, 1 day, morning of)
|
||||
- Minute-by-minute schedule (8 segments, 120 minutes)
|
||||
- Materials checklist (digital & physical)
|
||||
- Facilitation tips (energy management, handling questions)
|
||||
- Success metrics
|
||||
|
||||
### 3. Enhanced FACILITATOR_GUIDE.md
|
||||
|
||||
**Additions:**
|
||||
- Full scripts for each segment (not just bullet points)
|
||||
- Detailed live demo section with FizzBuzz walkthrough
|
||||
- Expanded intervention table with more scenarios
|
||||
- Transition scripts between segments
|
||||
- Backup plans for running ahead/behind
|
||||
|
||||
**Structure:**
|
||||
- Each segment has "What to say", "What to do", "What success looks like"
|
||||
- Timing checkpoints throughout
|
||||
- Ready-to-use phrases for common situations
|
||||
|
||||
### 4. Enhanced Solution Files
|
||||
|
||||
**Strategy:** Add inline comments linking code to tests and explaining design evolution.
|
||||
|
||||
**Comment Types:**
|
||||
- **Test reference:** `// STEP 2: From test "rejects password with no uppercase"`
|
||||
- **Design decision:** `// Map chosen over List for O(1) lookup by name`
|
||||
- **Refactoring note:** `// Originally 5 if-blocks → extracted to rule functions`
|
||||
- **Pattern highlight:** `// This is the Open-Closed Principle in action`
|
||||
|
||||
**Benefits:**
|
||||
- Solutions become teaching tools
|
||||
- Participants see why code looks this way
|
||||
- Design patterns are explicitly named
|
||||
|
||||
### 5. Root README.md
|
||||
|
||||
**Purpose:** Orient anyone opening the repository.
|
||||
|
||||
**Sections:**
|
||||
- Workshop overview (what, why, who)
|
||||
- For facilitators (where to start)
|
||||
- For participants (how to choose a kata)
|
||||
- Repository structure explained
|
||||
- Quick start instructions
|
||||
- Links to additional resources
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: FizzBuzz Kata (30-45 minutes)
|
||||
1. Create fizzbuzz/ directory structure
|
||||
2. Set up pubspec.yaml
|
||||
3. Build kata with git commits (12 commits total)
|
||||
4. Write DEMO_SCRIPT.md
|
||||
5. Write fizzbuzz/README.md
|
||||
|
||||
### Phase 2: Documentation (45-60 minutes)
|
||||
1. Create TDD_REFERENCE_CARD.md
|
||||
2. Create SETUP_GUIDE.md
|
||||
3. Create WORKSHOP_PLAN.md (incorporate detailed schedule)
|
||||
4. Enhance FACILITATOR_GUIDE.md with scripts
|
||||
|
||||
### Phase 3: Polish (30-45 minutes)
|
||||
1. Enhance password_validator_solution.dart with comments
|
||||
2. Enhance shopping_cart_solution.dart with comments
|
||||
3. Create root README.md
|
||||
4. Review all materials for consistency
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [ ] Facilitator can run the entire 2-hour workshop using only these materials
|
||||
- [ ] Live demo kata is ready to present without preparation
|
||||
- [ ] Participants have clear setup instructions and reference materials
|
||||
- [ ] Solution files explain design decisions, not just implementation
|
||||
- [ ] All documentation uses consistent tone and terminology
|
||||
|
||||
## Open Questions
|
||||
|
||||
None - design is approved and ready for implementation.
|
||||
|
||||
## Next Steps
|
||||
|
||||
Proceed with implementation using the three-phase approach outlined above.
|
||||
Loading…
Add table
Add a link
Reference in a new issue