tdd-workshop/FACILITATOR_GUIDE.md

6.6 KiB

Workshop Facilitator Guide — Quick Reference

Duration: 80 minutes
Format: Live demo + hands-on practice with Password Validator or Shopping Cart katas using 3-Way Ping-Pong (mob programming)
Team Size: 3 people (2 developers + you as facilitator/participant)

Note: For the complete detailed plan with minute-by-minute timing, scripts, and checklists, see WORKSHOP_PLAN.md. This guide focuses on facilitation tips and kata-specific insights.

Facilitator Role: You'll participate as the 3rd person in the rotation, experiencing TDD alongside the developers. This creates a collaborative learning environment rather than traditional top-down teaching.


Essential Documents

Before the workshop, familiarize yourself with:

  • WORKSHOP_PLAN.md — Complete schedule, scripts, and preparation checklist
  • fizzbuzz/DEMO_SCRIPT.md — Step-by-step live demo walkthrough
  • TDD_REFERENCE_CARD.md — Participant handout
  • SETUP_GUIDE.md — For helping participants with technical issues

Quick Preparation Checklist

1 Week Before

  • Send SETUP_GUIDE.md to participants
  • Confirm everyone completes setup and verifies dart test works
  • Practice FizzBuzz live demo using DEMO_SCRIPT.md

Day Of

  • Arrive 15 minutes early
  • Test projector/screen sharing
  • Open fizzbuzz kata with git log ready
  • Have solution files ready (but don't share early!)
  • Write schedule on whiteboard

Updated Session Structure

Time Activity See
0:00-0:05 Welcome & Setup Check WORKSHOP_PLAN.md
0:05-0:20 Live Demo: FizzBuzz TDD fizzbuzz/DEMO_SCRIPT.md
0:20-0:25 Exercise Intro (3-Way Ping-Pong) Section below
0:25-1:05 Hands-on Practice (Mob Programming) Circulate & nudge
1:05-1:20 Combined Retrospective WORKSHOP_PLAN.md

Live Demo: FizzBuzz (NEW SECTION)

Purpose: Show RED-GREEN-REFACTOR cycle in real-time

Setup

  1. Open fizzbuzz/ directory
  2. Have fizzbuzz/DEMO_SCRIPT.md open on second screen
  3. Terminal ready with dart test
  4. Reset git to initial commit: git reset --hard <first-commit-hash>

Key Points to Emphasize

  • Run tests frequently (every 30 seconds)
  • Minimal implementations (hardcode "1" for first test)
  • Test-driven design (algorithm emerges from tests)
  • Order matters (check 15 before 3 and 5)

Timing

  • 0-2 min: Introduce FizzBuzz rules
  • 2-4 min: Cycle 1 (input 1 → "1")
  • 4-6 min: Cycle 2 (input 2 → "2")
  • 6-9 min: Cycle 3 (input 3 → "Fizz")
  • 9-11 min: Cycle 4 (input 5 → "Buzz")
  • 11-14 min: Cycle 5 (input 15 → "FizzBuzz")
  • 14-15 min: Wrap up, show git log

See fizzbuzz/DEMO_SCRIPT.md for complete talking points and what to code at each step.


What to watch for while participating

Your dual role: You're both a participant in the rotation AND a gentle guide.

Good signs:

  • Running dart test after every small change
  • Seeing RED before touching lib/
  • Short, focused commits (or at least talking through each step)
  • Smooth keyboard passing between the 3 roles (Red, Green, Refactor)

Gentle interventions (when it's not your turn at keyboard):

  • "Have you run the test yet? What did it say?" — nudge anyone writing too much code before testing
  • "Can you make it pass with even less code?" — push toward minimal Green
  • "Now that it's Green, what could you clean up?" — prompt the Refactor step
  • "It's time to pass the keyboard! Let's rotate." — enforce the rotation

When it's your turn:

  • Model the behavior you want to see (run tests frequently, minimal code, think aloud)
  • Ask questions rather than giving answers: "What's the simplest thing that could work here?"
  • Show vulnerability: "Hmm, I'm not sure. What do you think?"

Feature A: Password Validator — facilitator notes

Likely first implementation (all rules as if-blocks):

ValidationResult validate(String password) {
  final errors = <String>[];
  if (password.length < 8) errors.add('Must be at least 8 characters long');
  if (!password.contains(RegExp(r'[A-Z]'))) errors.add('Must contain at least one uppercase letter');
  // ... etc
  return ValidationResult(isValid: errors.isEmpty, errors: errors);
}

The refactor insight to guide toward (Step 6): Each rule is just a function String? Function(String). They can live in a list. Adding a new rule = adding one function. No touching existing code. This is the Open-Closed Principle — same insight as Gilded Rose's Strategy pattern.

Talking point: "If you had 20 rules, how readable would 20 if-blocks be? What would you do?"


Feature B: Shopping Cart — facilitator notes

Likely first implementation (List-based):

final List<CartItem> _items = [];

double subtotal() => _items.fold(0, (s, i) => s + i.price * i.quantity);

The Map insight (Step 3 — remove by name): When participants try to implement removeItem(name) with a List, they'll write a .removeWhere(). This works, but nudge them: "What data structure makes 'find by name' really natural?" Let the remove-by-name test drive them toward Map<String, CartItem>.

CartItem validation (Step 5): Many will put validation in addItem(). Ask: "What if someone creates a CartItem and passes it somewhere else? Who validates it then?" This conversation leads naturally to Value Objects.

Bonus design question: The duplicate name test has no right answer. Both "replace" and "accumulate" are valid. The point is: TDD forces you to decide, and the test documents the decision permanently.


Closing discussion questions

  1. "What was the first test you wrote? Why that one?"
  2. "Did your design change as you added more tests? How?"
  3. "Did you ever feel tempted to skip the Red step and just write the code?"
  4. "How did the 3-way ping-pong dynamic change how you wrote code?"
  5. "What would have been different if you'd designed the class first, then written tests?"

Common questions and answers

"Can I write all the tests first, then implement?" Not quite — TDD is one test at a time. Write one, watch it fail, make it pass, then the next. Writing all tests upfront is a different practice (it's fine, but it's not TDD).

"What if I don't know what test to write next?" Ask: "What's the simplest behavior this thing should have that it doesn't have yet?" Start with the empty/zero case. Then one item. Then two. Then edge cases.

"Is this realistic? Do people actually do this for real code?" Yes — especially for domain logic (pricing, validation, calculations). It's less common for framework glue code, and that's okay. Apply it where behavior matters most.