Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Get Kata

521 views

Published on

Presented at Foo Café

Programmers use coding katas to kick the tyres of their programming languages, paradigms and practices. Typically anchored in a TDD cycle, katas are simple problems that give programmers the opportunity to exercise deliberate practice and explore different approaches, whether programming style, pair programming or test-first programming.

But the simplicity can be deceptive, with many programmers tiring of these katas too soon, missing out on some of the more mind-bending and paradigm-expanding opportunities on offer.

This session will pick on a couple of katas and dig deeper into TDD, lambdas, language(s), (dys)functional programming and Alcubierre drive. It will present code in a variety of languages, highlight the weaknesses of some common mantras, play around with ideas — and blend code, humour and general nerdiness to be both an enjoyable and educational session.

Published in: Software
  • Be the first to comment

Get Kata

  1. 1. Get Carter Michael Caine
  2. 2. Get Kata @KevlinHenney
  3. 3. @KevlinHenney
  4. 4. @KevlinHenney
  5. 5. @KevlinHenney
  6. 6. form
  7. 7. pattern
  8. 8. style
  9. 9. way
  10. 10. training exercise
  11. 11. You do deliberate practice to improve your ability to perform a task. It’s about skill and technique. Deliberate practice means repetition. You do deliberate practice to master the task, not to complete the task. Jon Jagger Do Lots of Deliberate Practice
  12. 12. Rien n’est plus dangereux qu’une idée, quand on n’a qu’une idée. Émile-Auguste Chartier
  13. 13. Nothing is more dangerous than an idea, when you have only one idea. Émile-Auguste Chartier
  14. 14. a b c a2 + b2 = c2
  15. 15. a2 b2 c2 a2 + b2 = c2
  16. 16. c2
  17. 17. a2 b2 a2 + b2 = c2
  18. 18. c2 ½ab ½ab ½ab ½ab c2 + 2ab
  19. 19. (a + b)2 a2 + b2 + 2ab
  20. 20. a2 + b2 + 2ab = c2 + 2ab
  21. 21. a2 + b2 = c2
  22. 22. ½c2 ½ab ½ab ½c2 + ab
  23. 23. ½(a + b)2 ½a2 + ½b2 + ab
  24. 24. ½a2 + ½b2 + ab = ½c2 + ab
  25. 25. a2 + b2 = c2
  26. 26. Fizz buzz is a group word game for children to teach them about division. http://en.wikipedia.org/wiki/Fizz_buzz
  27. 27. Players generally sit in a circle. The player designated to go first says the number "1", and each player thenceforth counts one number in turn. However, any number divisible by three is replaced by the word fizz and any divisible by five by the word buzz. Numbers divisible by both become fizz buzz. A player who hesitates or makes a mistake is eliminated from the game. http://en.wikipedia.org/wiki/Fizz_buzz
  28. 28. Players generally sit in a circle. The player designated to go first says the number "1", and each player thenceforth counts one number in turn. However, any number divisible by three is replaced by the word fizz and any divisible by five by the word buzz. Numbers divisible by both become fizz buzz. A player who hesitates or makes a mistake is eliminated from the game. http://en.wikipedia.org/wiki/Fizz_buzz
  29. 29. Players generally sit in a circle. The player designated to go first says the number "1", and each player thenceforth counts one number in turn. However, any number divisible by three is replaced by the word fizz and any divisible by five by the word buzz. Numbers divisible by both become fizz buzz. A player who hesitates or makes a mistake is eliminated from the game. http://en.wikipedia.org/wiki/Fizz_buzz
  30. 30. Adults may play Fizz buzz as a drinking game, where making a mistake leads to the player having to make a drinking- related forfeit. http://en.wikipedia.org/wiki/Fizz_buzz [citation needed]
  31. 31. Fizz buzz has been used as an interview screening device for computer programmers. http://en.wikipedia.org/wiki/Fizz_buzz
  32. 32. FizzBuzz was invented to avoid the awkwardness of realising that nobody in the room can binary search an array. https://twitter.com/richardadalton/status/591534529086693376
  33. 33. public class FizzBuzzTests { @Test public void testFizzBuzz() { ... } }
  34. 34. public class FizzBuzzTests { @Test public void testFizzBuzzIsOK() { ... } }
  35. 35. public class FizzBuzzTests { @Test public void fizzBuzzOf1Is1() { ... } }
  36. 36. public class FizzBuzzTests { @Test public void fizzBuzzOf1Is1() { ... } @Test public void fizzBuzzOf2Is2() { ... } }
  37. 37. public class FizzBuzzTests { @Test public void fizzBuzzOf1Is1() { ... } @Test public void fizzBuzzOf2Is2() { ... } @Test public void fizzBuzzOf3IsFizz() { ... } }
  38. 38. public class FizzBuzzTests { @Test public void fizzBuzzOf1Is1() { ... } @Test public void fizzBuzzOf2Is2() { ... } @Test public void fizzBuzzOf3IsFizz() { ... } ... }
  39. 39. public class FizzBuzzCalculator { ... }
  40. 40. I have yet to see any problem, however complicated, which, when you looked at it in the right way, did not become still more complicated. Anderson's Law
  41. 41. public class FizzBuzzCalculator { private static final String FIZZ = "Fizz"; private static final String BUZZ = "Buzz"; private static final String FIZZBUZZ = "FizzBuzz"; private int fizzMultipleValue; private int buzzMultipleValue; private int fizzBuzzMultipleValue; public FizzBuzzCalculator(int fizzMultipleValue, int buzzMultipleValue) { this.fizzMultipleValue = fizzMultipleValue; this.buzzMultipleValue = buzzMultipleValue; calculateFizzBuzzMultipleValue(); } private void calculateFizzBuzzMultipleValue() { fizzBuzzMultipleValue = fizzMultipleValue * buzzMultipleValue; } public int getFizzMultipleValue() { return fizzMultipleValue; } public void setFizzMultipleValue(int fizzMultipleValue) { this.fizzMultipleValue = fizzMultipleValue; calculateFizzBuzzMultipleValue(); } public int getBuzzMultipleValue() { return buzzMultipleValue; } public void setBuzzMultipleValue(int buzzMultipleValue) { this.buzzMultipleValue = buzzMultipleValue; calculateFizzBuzzMultipleValue(); } public String returnFizzBuzzOrNumber(int n) { if (isFizzBuzz(n)) return FIZZBUZZ; if (isFizz(n)) return FIZZ; if (isBuzz(n)) return BUZZ; return new Integer(n).toString(); } private static boolean isFizz(int n) { return n % fizzMultipleValue == 0; } private static boolean isBuzz(int n) { return n % buzzMultipleValue == 0; } private static boolean isFizzBuzz(int n) { return n % fizzBuzzMultipleValue == 0; } }
  42. 42. def fizzbuzz(n) { result = '' if (n % 3 == 0) result += 'Fizz' if (n % 5 == 0) result += 'Buzz' if (!result) result += n result }
  43. 43. def fizzbuzz(n) { if (n % 15 == 0) 'FizzBuzz' else if (n % 3 == 0) 'Fizz' else if (n % 5 == 0) 'Buzz' else n.toString() }
  44. 44. def fizzbuzz(n) { n % 15 == 0 ? 'FizzBuzz' : n % 3 == 0 ? 'Fizz' : n % 5 == 0 ? 'Buzz' : n.toString() }
  45. 45. def fizzbuzz(n) { n in (0..100).step(15) ? 'FizzBuzz' : n in (0..100).step(3) ? 'Fizz' : n in (0..100).step(5) ? 'Buzz' : n.toString() }
  46. 46. fizzes = [''] + ([''] * 2 + ['Fizz']) * 33 + [''] buzzes = [''] + ([''] * 4 + ['Buzz']) * 20 numbers = (0..100)*.toString() def fizzbuzz(n) { fizzes[n] + buzzes[n] ?: numbers[n] }
  47. 47. $0 % 3 == 0 { printf "Fizz" } $0 % 5 == 0 { printf "Buzz" } $0 % 3 != 0 && $0 % 5 != 0 { printf $0 } { printf "n" }
  48. 48. echo {1..100} | tr ' ' 'n' | awk ' $0 % 3 == 0 { printf "Fizz" } $0 % 5 == 0 { printf "Buzz" } $0 % 3 != 0 && $0 % 5 != 0 { printf $0 } { printf "n" } '
  49. 49. echo {1..100} | tr ' ' 'n' | awk ' $0 % 3 == 0 { printf "Fizz" } $0 % 5 == 0 { printf "Buzz" } $0 % 3 != 0 && $0 % 5 != 0 { printf $0 } { printf "n" } ' | diff - expected && echo Pass
  50. 50. 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz
  51. 51. We instituted a rigorous regression test for all of the features of AWK. Any of the three of us who put in a new feature into the language [...], first had to write a test for the new feature. Alfred Aho http://www.computerworld.com.au/article/216844/a-z_programming_languages_awk/
  52. 52. Red Write a failing test for a new feature Green Write enough code to pass the test Refactor Refine code and tests Test-First Cycle
  53. 53. Red Write a failing test for a new feature Green Write enough code to pass the test Test-First Dumbed Down
  54. 54. assert fizzbuzz(1) == '1' def fizzbuzz(n): return '1'
  55. 55. assert fizzbuzz(1) == '1' assert fizzbuzz(2) == '2' def fizzbuzz(n): if n == 1: return '1' return '2'
  56. 56. assert fizzbuzz(1) == '1' assert fizzbuzz(2) == '2' assert fizzbuzz(3) == 'Fizz' def fizzbuzz(n): if n == 1: return '1' if n == 2: return '2' return 'Fizz'
  57. 57. assert fizzbuzz(1) == '1' assert fizzbuzz(2) == '2' assert fizzbuzz(3) == 'Fizz' assert fizzbuzz(4) == '4' assert fizzbuzz(5) == 'Buzz' assert fizzbuzz(6) == 'Fizz' assert fizzbuzz(7) == '7' assert fizzbuzz(8) == '8' assert fizzbuzz(9) == 'Fizz' assert fizzbuzz(10) == 'Buzz' assert fizzbuzz(11) == '11' assert fizzbuzz(12) == 'Fizz' assert fizzbuzz(13) == '13' assert fizzbuzz(14) == '14' assert fizzbuzz(15) == 'FizzBuzz' def fizzbuzz(n): if n == 1: return '1' if n == 2: return '2' if n == 3: return 'Fizz' if n == 4: return '4' if n == 5: return 'Buzz' if n == 6: return 'Fizz' if n == 7: return '7' if n == 8: return '8' if n == 9: return 'Fizz' if n == 10: return 'Buzz' if n == 11: return '11' if n == 12: return 'Fizz' if n == 13: return '13' if n == 14: return '14' return 'FizzBuzz'
  58. 58. assert fizzbuzz(1) == '1' assert fizzbuzz(2) == '2' assert fizzbuzz(3) == 'Fizz' assert fizzbuzz(4) == '4' assert fizzbuzz(5) == 'Buzz' assert fizzbuzz(6) == 'Fizz' assert fizzbuzz(7) == '7' assert fizzbuzz(8) == '8' assert fizzbuzz(9) == 'Fizz' assert fizzbuzz(10) == 'Buzz' assert fizzbuzz(11) == '11' assert fizzbuzz(12) == 'Fizz' assert fizzbuzz(13) == '13' assert fizzbuzz(14) == '14' assert fizzbuzz(15) == 'FizzBuzz' ... assert fizzbuzz(98) == '98' assert fizzbuzz(99) == 'Fizz' assert fizzbuzz(100) == 'Buzz' def fizzbuzz(n): if n == 1: return '1' if n == 2: return '2' if n == 3: return 'Fizz' if n == 4: return '4' if n == 5: return 'Buzz' if n == 6: return 'Fizz' if n == 7: return '7' if n == 8: return '8' if n == 9: return 'Fizz' if n == 10: return 'Buzz' if n == 11: return '11' if n == 12: return 'Fizz' if n == 13: return '13' if n == 14: return '14' if n == 15: return 'FizzBuzz' ... if n == 98: return '98' if n == 99: return 'Fizz' return 'Buzz'
  59. 59. def fizzbuzz(n): if n == 1: return '1' if n == 2: return '2' if n == 3: return 'Fizz' if n == 4: return '4' if n == 5: return 'Buzz' if n == 6: return 'Fizz' if n == 7: return '7' if n == 8: return '8' if n == 9: return 'Fizz' if n == 10: return 'Buzz' if n == 11: return '11' if n == 12: return 'Fizz' if n == 13: return '13' if n == 14: return '14' if n == 15: return 'FizzBuzz' ... if n == 98: return '98' if n == 99: return 'Fizz' if n == 100: return 'Buzz'
  60. 60. def fizzbuzz(n): return { 1: lambda: '1', 2: lambda: '2', 3: lambda: 'Fizz', 4: lambda: '4', 5: lambda: 'Buzz', 6: lambda: 'Fizz', 7: lambda: '7', 8: lambda: '8', 9: lambda: 'Fizz', 10: lambda: 'Buzz', 11: lambda: '11', 12: lambda: 'Fizz', 13: lambda: '13', 14: lambda: '14', 15: lambda: 'FizzBuzz', ... 98: lambda: '98', 99: lambda: 'Fizz', 100: lambda: 'Buzz' }[n]()
  61. 61. def fizzbuzz(n): return { 1: '1', 2: '2', 3: 'Fizz', 4: '4', 5: 'Buzz', 6: 'Fizz', 7: '7', 8: '8', 9: 'Fizz', 10: 'Buzz', 11: '11', 12: 'Fizz', 13: '13', 14: '14', 15: 'FizzBuzz', ... 98: '98', 99: 'Fizz', 100: 'Buzz' }[n]
  62. 62. def fizzbuzz(n): return [ '1', '2', 'Fizz', '4', 'Buzz', 'Fizz', '7', '8', 'Fizz', 'Buzz', '11', 'Fizz', '13', '14', 'FizzBuzz', ... '98', 'Fizz', 'Buzz' ][n-1]
  63. 63. Red Write a failing test for a new feature Green Write enough code to pass the test Refactor Refine code and tests Test-First Cycle
  64. 64. Plan Establish hypothesis, goal or work tasks Do Carry out plan Study Review what has been done against plan (a.k.a. Check) Act Revise approach or artefacts based on study Deming/Shewhart Cycle
  65. 65. Write Create or extend a test case for new behaviour — as it's new, the test fails Reify Implement so that the test passes Reflect Is there something in the code or tests that could be improved? Refactor Make it so! Test-First Cycle
  66. 66. actual = [fizzbuzz(n) for n in range(1, 101)] truths = [ every result is 'Fizz', 'Buzz', 'FizzBuzz' or a decimal string, every decimal result corresponds to its ordinal position, every third result contains 'Fizz', every fifth result contains 'Buzz', every fifteenth result is 'FizzBuzz', the ordinal position of every 'Fizz' result is divisible by 3, the ordinal position of every 'Buzz' result is divisible by 5, the ordinal position of every 'FizzBuzz' result is divisible by 15 ] assert all(truths)
  67. 67. actual = [fizzbuzz(n) for n in range(1, 101)] truths = [ all(a in {'Fizz', 'Buzz', 'FizzBuzz'} or a.isdecimal() for a in actual), all(int(a) == n for n, a in enumerate(actual, 1) if a.isdecimal()), all('Fizz' in a for a in actual[2::3]), all('Buzz' in a for a in actual[4::5]), all(a == 'FizzBuzz' for a in actual[14::15]), all(n % 3 == 0 for n, a in enumerate(actual, 1) if a == 'Fizz'), all(n % 5 == 0 for n, a in enumerate(actual, 1) if a == 'Buzz'), all(n % 15 == 0 for n, a in enumerate(actual, 1) if a == 'FizzBuzz') ] assert all(truths)
  68. 68. A work of art is the unique result of a unique temperament. Oscar Wilde
  69. 69. https://twitter.com/wm/status/7206700352
  70. 70. / WordFriday
  71. 71. bi-quinary coded decimal, noun ▪ A system of representing numbers based on counting in fives, with an additional indicator to show whether the count is in the first or second half of the decimal range, i.e., whether the number represented is in the range 0–4 or 5–9 (or in the range 1–5 or 6–10). ▪ This system is found in many abacus systems, with paired columns of counters (normally aligned) representing each bi- quinary range. ▪ The Roman numeral system is also a form of bi-quinary coded decimal.
  72. 72. proc roman numerals = (int year) string: skip;
  73. 73. assert (roman numerals (1) = “I”)
  74. 74. proc roman numerals = (int year) string: “I”;
  75. 75. assert (roman numerals (1) = “I”); assert (roman numerals (5) = “V”)
  76. 76. proc roman numerals = (int year) string: if year = 5 then “V” else “I” fi;
  77. 77. assert (roman numerals (1) = “I”); assert (roman numerals (5) = “V”); assert (roman numerals (10) = “X”)
  78. 78. proc roman numerals = (int year) string: if year = 10 then “X” elif year = 5 then “V” else “I” fi;
  79. 79. assert (roman numerals (1) = “I”); assert (roman numerals (5) = “V”); assert (roman numerals (10) = “X”); assert (roman numerals (50) = “L”); assert (roman numerals (100) = “C”); assert (roman numerals (500) = “D”); assert (roman numerals (1000) = “M”)
  80. 80. proc roman numerals = (int year) string: if year = 1000 then “M” elif year = 500 then “D” elif year = 100 then “C” elif year = 50 then “L” elif year = 10 then “X” elif year = 5 then “V” else “I” fi;
  81. 81. [] struct (int value, string letters) mapping = ( (1000, “M”), (500, “D”), (100, “C”), (50, “L”), (10, “X”), (5, “V”), (1, “I”) );
  82. 82. proc roman numerals = (int year) string: begin string result := ""; for entry from lwb mapping to upb mapping do if value of mapping[entry] = year then result := letters of mapping[entry] fi od; result end;
  83. 83. proc roman numerals = (int year) string: ( string result := ""; for entry from lwb mapping to upb mapping do if value of mapping[entry] = year then result := letters of mapping[entry] fi od; result );
  84. 84. [] proposition roman numerals spec = ( ("Decimal positions correspond to numerals", ((1, "I"), (10, "X"), (100, "C"), (1000, "M"))), ("Quinary values correspond to numerals", ((5, "V"), (50, "L"), (500, "D"))) );
  85. 85. [] proposition roman numerals spec = ( ("Decimal positions correspond to numerals", ((1, "I"), (10, "X"), (100, "C"), (1000, "M"))), ("Quinary intervals correspond to numerals", ((5, "V"), (50, "L"), (500, "D"))) ); test (roman numerals, roman numerals spec)
  86. 86. mode test = struct (int input, string expected); mode proposition = struct (string name, flex [1:0] test tests);
  87. 87. proc test = (proc (int) string function, [] proposition spec) void: for entry from lwb spec to upb spec do print (name of spec[entry]); string report := "", separator := " failed:"; [] test tests = tests of spec[entry]; for test from lwb tests to upb tests do int input = input of tests[test]; string expected = expected of tests[test]; string actual = function (input); if actual /= expected then report +:= separator + " for " + whole (input, 0) + " expected " + expected + " but was " + actual separator := “,” fi od; print (if report = "" then (new line) else (new line, report, new line) fi) od;
  88. 88. [] proposition roman numerals spec = ( ("Decimal positions correspond to numerals", ((1, "I"), (10, "X"), (100, "C"), (1000, "M"))), ("Quinary intervals correspond to numerals", ((5, "V"), (50, "L"), (500, "D"))), ("Multiples of decimals are additive", ((2, "II"), (30, "XXX"), (200, "CC"), (4000, "MMMM"))) );
  89. 89. proc roman numerals = (int year) string: ( string result := ""; int value = year; for entry from lwb mapping to upb mapping do if value mod value of mapping[entry] = 0 then while value > 0 do result +:= letters of mapping[entry]; value -:= value of mapping[entry] od fi od; result );
  90. 90. [] proposition roman numerals spec = ( ("Decimal positions correspond to numerals", ((1, "I"), (10, "X"), (100, "C"), (1000, "M"))), ("Quinary intervals correspond to numerals", ((5, "V"), (50, "L"), (500, "D"))), ("Multiples of decimals are additive", ((2, "II"), (30, "XXX"), (200, "CC"), (4000, "MMMM"))), ("Non-multiples of decimals are additive", ((6, "VI"), (23, "XXIII"), (273, "CCLXXIII"), (1500, "MD"))) );
  91. 91. proc roman numerals = (int year) string: ( string result := ""; int value = year; for entry from lwb mapping to upb mapping do while value >= value of mapping[entry] do result +:= letters of mapping[entry]; value -:= value of mapping[entry] od od; result );
  92. 92. [] proposition roman numerals spec = ( ("Decimal positions correspond to numerals", ((1, "I"), (10, "X"), (100, "C"), (1000, "M"))), ("Quinary intervals correspond to numerals", ((5, "V"), (50, "L"), (500, "D"))), ("Multiples of decimals are additive", ((2, "II"), (30, "XXX"), (200, "CC"), (4000, "MMMM"))), ("Non-multiples of decimals are additive", ((6, "VI"), (23, "XXIII"), (273, "CCLXXIII"), (1500, "MD"))), ("Numeral predecessors are subtractive", ((4, "IV"), (9, "IX"), (40, "XL"), (90, "XC"), (400, "CD"), (900, "CM"))) );
  93. 93. [] struct (int value, string letters) mapping = ( (1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), (90, "XC"), (50, "L"), (40, "XL"), (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I") );
  94. 94. [] proposition roman numerals spec = ( ("Decimal positions correspond to numerals", ((1, "I"), (10, "X"), (100, "C"), (1000, "M"))), ("Quinary intervals correspond to numerals", ((5, "V"), (50, "L"), (500, "D"))), ("Multiples of decimals are additive", ((2, "II"), (30, "XXX"), (200, "CC"), (4000, "MMMM"))), ("Non-multiples of decimals are additive", ((6, "VI"), (23, "XXIII"), (273, "CCLXXIII"), (1500, "MD"))), ("Numeral predecessors are subtractive", ((4, "IV"), (9, "IX"), (40, "XL"), (90, "XC"), (400, "CD"), (900, "CM"))), ("Subtractive predecessors are additive", ((14, "XIV"), (42, "XLII"), (1968, "MCMLXVIII"))) );
  95. 95. We could, of course, use any notation we want; do not laugh at notations; invent them, they are powerful. In fact, mathematics is, to a large extent, invention of better notations. Richard Feynman
  96. 96. $ ./roman 42 XLII $ cat roman printf %$1s | tr ' ' 'I' | sed ' s/IIIII/V/g s/IIII/IV/ s/VV/X/g s/VIV/IX/ s/XXXXX/L/g s/XXXX/XL/ s/LL/C/g s/LXL/XC/ s/CCCCC/D/g s/CCCC/CD/ s/DD/M/g s/DCD/CM/ ' echo
  97. 97. Style is time’s fool. Form is time’s student. Stewart Brand

×