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:
fiatcode 2026-03-10 15:32:21 +07:00
commit c3355063f2
26 changed files with 4725 additions and 0 deletions

View 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:100: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
View 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

View 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.