- 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
7.3 KiB
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.dartandtest/fizzbuzz_test.dart - Have terminal ready at bottom with
dart test --watch(optional) or be ready to rundart testmanually - 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:
// 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:
// 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:
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:
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:
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:
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:
test('returns "Buzz" for 5', () {
expect(fizzBuzz(5), equals('Buzz'));
});
Run dart test → FAILS (Expected: 'Buzz', Actual: '5')
GREEN Phase:
What to Do:
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:
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:
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!"