Successfully reported this slideshow.
Your SlideShare is downloading. ×

Test First Teaching - GoGaRuCo 2010

Loading in …3

Check these out next

1 of 42 Ad

Test First Teaching - GoGaRuCo 2010

Download to read offline

Alex Chaffee and Sarah Allen talk about and test first teaching in general at Golden Gate Ruby Conference 2010

Alex Chaffee and Sarah Allen talk about and test first teaching in general at Golden Gate Ruby Conference 2010


More Related Content


Test First Teaching - GoGaRuCo 2010

  1. Test First Teaching Alex Chaffee @alexch Sarah Allen @ultrasaurus
  2. Why should you care? • you want to learn Ruby • you want to improve your Ruby skills • you have a friend or colleague who wants to learn Ruby • you want to help us improve our materials • by teaching, you learn...
  3. No, seriously: by teaching, you learn! • the best engineers are good teachers • we live and work in collaborative environments • it is not enough to know any thing well • we must teach in order to effectively produce software
  4. What is Test-First Teaching? • teacher provides microtests • student makes them pass • one test at a time • can be used guided (in classroom) or solo • or with a pair
  5. Pairing Is Teaching
  6. Pairing in the classroom • students learn together and teach each other • each pair can proceed through exercises at their own pace • teacher is freed to wander the room
  7. How do we know it's a good idea? 2002 Alex Chaffee jGuru Java curriculum 2005 Mike Clark many Ruby Learning Tests independent 2006 ara.t.howard inventors Ruby Quiz #67 "Metakoans" 2008 Yehuda Katz & Matt Aimonetti Ruby on Rails training Who else?
  8. How do we know it's a good idea? it works
  9. Learning Ruby via Tests • [Test-First Teaching]( by Sarah Allen and Alex Chaffee • [Ruby Koans]( by Jim Weirich and Joe O’Brien • [Metakoans]( by ara.t.howard
  10. Other Guided Learning • [ruby-warrior]( by Ryan Bates - a game written in Ruby for learning Ruby • [Try Ruby]( runs a Ruby interpreter in your browser, with hints and advice • [Growing OO Software In Ruby]( blog/2009/12/17/growing-object-oriented-software-in-ruby/) by Brian Marick • Ruby version of [Growing Object-Oriented Software Guided by Tests](http://www.growing-object-oriented-
  11. Created by: Sarah Allen Alex Chaffee Liah Hansen and friends Test-First Teaching.... Maybe we should call it Test-First Learning
  12. Traditional Professional Programming Classes Big, Boring Lecture Followed by Exercises • multiple choice • fill in the blanks with words or pseudocode • skeleton code - big program with chunks excised and replaced with comments • large task - soup to nuts without feedback
  13. writing code is engaging
  14. Methodology • Run the test • Watch it fail • Write code to fix the first failure • See it pass • Refactor Sound familiar?
  15. Why TFT? • makes the assignment very clear • student gets immediate feedback on progress (or lack thereof) • removes the magic • leads the student through all the steps to writing the code • teaches student to read errors
  16. Embrace Failure
  17. Embrace Failure • start from a point of failure • it feels like it's not your fault • people learn better when they're not stressed • playfulness enhances learning
  18. In a classroom setting, do more... • Conceptual Overview • Experimentation (Play, irb) • Live Coding a Real-World Example • Simple hands-on exercise • Name what they learned
  19. TFT Examples Let's look at some code
  20. Arithmetic require "calculator" describe Calculator do before do @calculator = end it "adds 0 and 0" do @calculator.add(0,0).should == 0 end it "adds 2 and 2" do @calculator.add(2,2).should == 4 end it "adds positive numbers" do @calculator.add(2,6).should == 8 end it "subtracts numbers" do @calculator.subtract(10,4).should == 6 end end
  21. require "pig_latin" describe "#translate" do Strings include PigLatinTranslator it "should translate a simple word" do s = translate("nix") s.should == "ixnay" end it "should translate a word beginning with a vowel" do s = translate("apple") s.should == "appleay" end it "should translate a word with two consonants" do s = translate("stupid") s.should == "upidstay" end it "should translate two words" do s = translate("eat pie") s.should == "eatay iepay" end it "should translate many words" do s = translate("the quick brown fox") s.should == "ethay ickquay ownbray oxfay" end end
  22. Pig Latin Solution module PigLatinTranslator def translate(s) do |word| v = first_vowel(word) word.slice(v..-1) + word[0,v] + "ay" end.join(" ") end def first_vowel(word) if word =~ /^qu/ 2 else word.gsub(/[aeiou].*$/, '').size end end end
  23. Another Pig Latin Solution module PigLatinTranslator def translate(s) words = s.split s = do |s| l = s.length if /^[aeiou]/ .match(s) s + "ay" elsif /^qu/ .match(s[0..1]) s[2..(l+1)] + s[0..1] + "ay" elsif /[aeiou]/ .match(s[1..1]) s[1..(l+1)] + s[0..0] + "ay" else s[2..(l+1)] + s[0..1] + "ay" end end s = s.join(" ") end end
  24. And Another Pig Latin Solution module PigLatinTranslator def translate(word) words = word.split(" ") arrResult = [] words.each do |word| m = word.match(/^(qu)*[^aeiou]*/) if(m.nil?) arrResult << add_ay(word) else arrResult << add_ay(m.post_match + m.to_s) end end arrResult.join(" ") end def add_ay(word) word + "ay" end end
  25. Iterators describe Calculator do before do @calculator = end describe "#sum" do it "computes the sum of an empty array" do @calculator.sum([]).should == 0 end it "computes the sum of an array of one number" do @calculator.sum([7]).should == 7 end it "computes the sum of an array of two numbers" do @calculator.sum([7,11]).should == 18 end it "computes the sum of an array of many numbers" do @calculator.sum([1,3,5,7,9]).should == 25 end end
  26. Iterators require "array_extension" describe Array do describe "#sum" do it "should be 0 for an empty array" do [].sum.should == 0 end it "should add all of the elements" do [1,2,4].sum.should == 7 end end end (and open classes)
  27. TDD Extra Credit! # Test-Driving Bonus: once the above tests pass, # write tests and code for the following: it "multiplies two numbers" it "multiplies an array of numbers" it "raises one number to the power of another number" # describe "#factorial" do it "computes the factorial of 0" it "computes the factorial of 1" it "computes the factorial of 2" it "computes the factorial of 5" it "computes the factorial of 10" end end
  28. But... that's impossible
  29. Solutions for Challenging Idioms blocks time method missing builder pattern
  30. Blocks require "performance_monitor" (and mocks) it "takes exactly 1 second to run a block that describe PerformanceMonitor do sleeps for 1 second (with stubs)" do before do fake_time = 100 @monitor = Time.stub!(:now).and_return {fake_time} end do fake_time += 1 it "takes about 0 seconds to run an empty block" do end.should == 1 do end end.should be_close(0, 0.1) end it "runs a block N times" do n = 0 it "takes exactly 0 seconds to run an empty block do (with stubs)" do n += 1 Time.stub!(:now).and_return(100) end do n.should == 4 end.should == 0 end end it "returns the average time, not the total time, it "takes about 1 second to run a block that sleeps when running multiple times" do for 1 second" do run_times = [8,6,5,7] do run_index = 0 sleep 1 fake_time = 100 end.should be_close(1, 0.1) Time.stub(:now).and_return { fake_time } end do fake_time += run_times[run_index] run_index += 1 end.should == 6 end end
  31. method_missing, nested closures, and the builder pattern require "xml_document" it "nests several levels" do describe XmlDocument do @xml.hello do before do @xml.goodbye do @xml = @xml.come_back do end @xml.ok_fine(:be => "that_way") end it "renders an empty tag" do end @xml.hello.should == "<hello/>" end.should == end "<hello><goodbye><come_back><ok_fine be='that_way'/ ></come_back></goodbye></hello>" it "renders a tag with attributes" do end @xml.hello(:name => 'dolly').should == "<hello name='dolly'/>" it "indents" do end @xml = @xml.hello do it "renders a randomly named tag" do @xml.goodbye do tag_name = (1..8).map{|i| @xml.come_back do ('a'..'z').to_a[rand(26)]}.join @xml.ok_fine(:be => "that_way") @xml.send(tag_name).should == "<#{tag_name}/>" end end end end.should == it "renders block with text inside" do "<hello>n" + @xml.hello do " <goodbye>n" + "dolly" " <come_back>n" + end.should == "<hello>dolly</hello>" " <ok_fine be='that_way'/>n" + end " </come_back>n" + " </goodbye>n" + it "nests one level" do "</hello>n" @xml.hello do end @xml.goodbye end end.should == "<hello><goodbye/></hello>" end
  32. threads (sorry for the Java) public void testThreadSafe() throws InterruptedException { int DEPOSITORS = 50; int AMOUNT = 2; // note: increase this value until it *fails* on your CPU. // Then fix it. int REPS = 25000; Account account = new Account("Joe", 0); Thread[] depositors = new Thread[DEPOSITORS]; for (int i=0; i< DEPOSITORS; ++i) { depositors[i] = new Depositor(account, AMOUNT, REPS); depositors[i].start(); } for (int i=0; i< DEPOSITORS; ++i) { depositors[i].join(); } assertEquals(REPS * DEPOSITORS * AMOUNT, account.getBalance()); }
  33. ruby koans • self-guided, test-driven • Ruby language basics • very fun, whimsical and elegant
  34. ruby koans example require File.expand_path(File.dirname(__FILE__) + '/edgecase') class AboutStrings < EdgeCase::Koan def test_double_quoted_strings_are_strings string = "Hello, World" usually self- assert_equal __, string.is_a?(String) end contained def test_single_quoted_strings_are_also_strings just tests and fixtures, string = 'Goodbye, World' with no class declaration assert_equal __, string.is_a?(String) end def test_use_single_quotes_to_create_string_with_double_quotes “fill in the string = 'He said, "Go Away."' assert_equal __, string blanks” end technique def test_use_double_quotes_to_create_strings_with_single_quotes string = "Don't" assert_equal __, string end teaching through def test_use_backslash_for_those_hard_cases practice and a = "He said, "Don't"" b = 'He said, "Don't"' challenge assert_equal __, a == b end
  35. TFT != TDD • Mechanics of testing are hard to learn • TFT teaches programming; TDD is design • At the end of some modules, students write their own tests for “extra credit” • doesn’t really flex the creative muscles required for software design
  36. What about TDD? • easier to learn TDD, post-TFT • know the language • know the test framework • used to the rhythm of test-first • study design patterns, or check out [GOOS] ( growing-object-oriented-software-in-ruby).
  37. Credits • Mr. Clean® is a registered trademark of Procter & Gamble, used without permission • Parody is fair use! • Fail Whale illustrated by Yiying Lu (http:// • Pair Programming photos by Lee Lundrigan • Thank you Flickr and Creative Commons (see slides for attribution)
  38. Sarah Blazing Cloud
  39. Alex @alexch Erector Moodlog Cohuman Wrong
  40. Learning should be fun • Questions?

Editor's Notes

  • TFT is not sufficient for learning, but needs to be one component of a curriculum or course of self-study.