Presentation is loading. Please wait.

Presentation is loading. Please wait.

Scrum and Hyper-productivity Object Mentor, Inc. Copyright  1998-2007 by Object Mentor, Inc All Rights Reserved fitnesse.org www.objectmentor.com www.junit.org.

Similar presentations


Presentation on theme: "Scrum and Hyper-productivity Object Mentor, Inc. Copyright  1998-2007 by Object Mentor, Inc All Rights Reserved fitnesse.org www.objectmentor.com www.junit.org."— Presentation transcript:

1

2 Scrum and Hyper-productivity Object Mentor, Inc. Copyright  1998-2007 by Object Mentor, Inc All Rights Reserved fitnesse.org www.objectmentor.com www.junit.org Robert C. Martin

3 2 The inevitable trade-off. Good (Quality) Fast (Time to Market) Cheap (Cost Effectiveness) Done Pick any three…

4 3 Finding the optimum solution. We need to manage the project to the best possible outcome. An outcome that maximizes all four qualities. To do this, we need: Data.

5 4 Wouldn’t this be great?

6 5 …and this…

7 6 If we had these two charts on the wall… Then managers could just look at them to see The status of the project.

8 7 What is the first thing known about a project? The Management Paradox

9 8 ! ! ! !

10 9 The Delivery Date is Frozen

11 10 The Spec V1 The Spec V2 The Spec V3 The Spec V3 The Spec VN.1 The Spec VN.2 The Spec is Never Frozen

12 11 Analysis Design Implementation DFDERDDDST 1 May1 Nov1 Jul1 Sep The Waterfall Model Managing the Development of Large Software Systems Dr. Winston W. Royce — 1970

13 12 Royce’s actual diagram.

14 13 Royce’s Observation

15 14 Royce’s Conclusion

16 15 Analysis Design Implementation DFDERDDDST 1 May1 Nov1 Jul1 Sep Let’s go to a meeting.

17 16 Iterative Development. UI Comms Control Some UI, Comms, and Control for some behavior Data is generated and used to calibrate the plan

18 17 Calculate the Date. The Calculated Date.... []

19 18 More data shrinks the error bars. The Calculated Date.... []

20 19 But when we have data… Managers can…. manage.

21 20 The control knobs of project mgt. Schedule Quality Staff Scope

22 21 SCRUM Small Releases Whole Team Planning Game Daily Scrum

23 22 This can lead to a Mess. Messy Code is: rigid fragile not reusable has high viscosity

24 23 Rigidity The impact of a change cannot be predicted If not predicted, it cannot be estimated Time and cost cannot be quantified Managers become reluctant to authorize change Official Rigidity for “Roach Motel” modules Rigidity is the inability to be changed

25 24 Fragility A single change requires a cascade of subsequent changes New errors appear in areas that seem unconnected to the changed areas Quality is unpredictable. The development team loses credibility Software changes seem to exhibit non-local effects

26 25 Immobility Desirable parts of the design are dependent upon undesirable parts The work and risk of extracting the desirable part may exceed the cost of redeveloping from scratch.

27 26 Viscosity When the “right changes” are much more difficult than hacking, the viscosity of the system is high. Over time, it will become increasingly difficult to continue developing the product. Viscosity is resistance to fluid motion.

28 27 What to do? A good SCRUM team solves this problem By adopting corrective disciplines. What are those disciplines?

29 28 Hyper-productive SCRUM Metaphor Collective Ownership Sustainable Pace Continuous Integration Small Releases Acceptance Tests Whole Team Planning Game Simple Design Pairing Test Driven Development Refactoring Daily Scrum

30 29 The Three Laws of TDD You cannot write any production code until you have written a failing unit test. You cannot write more of a unit test than is sufficient to fail. You cannot write more production code than is sufficient to pass the failing test.

31 30 The Litany of TDD Benefits 30 Second cycle time means less debugging. A bevy of tests keeps the code flexible The tests are design documents Testable code is decoupled code.

32 User Stories

33 32 Stories Name of a feature, or short description Brief specifications of customer requirements Is a token for a conversation Owned by the customer A good user story criteria Has business value Is estimable Is testable Return Car

34 33 Story Estimation Team assigns a estimate or price to each story Estimates are in dimensionless but proportional units A 2 takes twice as much effort as a 1 Customer uses price to juggle priorities and acquire resources Unknowns can be eliminated through use of spikes, a research story

35 34 User Stories Define the Project Backlog

36 Agile Planning User Stories Release Planning Iteration Planning

37 36 The Purpose of Planning It is more important to work on the most valuable things first than to predict the future. Even the best plans must be continually refined Requires continuous and meaningful feedback

38 37 Object Mentor’s Third Law of Agile Development “In preparing for battle I have always found that plans are useless, but planning is indispensable. ” Dwight David Eisenhower

39 38 Exploration Attendees Whole team Input Product Vision Initial Story List (verbal) Critical dates Output – on Flip Chart Sheets Deck of initial stories. Stakeholder Identification Customer Team Identification Architectural Vision Initial Estimates Velocity guestimate

40 39 Release Planning Attendees Whole team (as appropriate) Inputs Stack of estimated stories Team Velocity Critical dates or initial release functionality Outputs Release plan – series of iterations, with significant dates 1 2 3 4 5 6 7

41 40 Release Planning The 4-way Decision. Important Expensive Important Cheap Unimportant Expensive Unimportant Cheap

42 41 USER STORY USER STORY USER STORY Managing Scope USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY USER STORY GetHigher Business Value Lower Business Value Source: Object Mentor Training Don’t get (yet)

43 42 Release Planning Summary Customers write stories Programmers estimate cost of stories Customers prioritize based on business value and estimated costs Release velocity: number of story points completed Yesterday’s weather

44 43 Release Plan 1 2 3 4 5 6 7 Release 1Release 2

45 44 Iteration Planning Monday Morning: Confirm the stories for the iteration Revise estimates based on new information For each story Write story on top of flip chart page Review acceptance tests Break story into engineering tasks Do quick design session as needed Sign up.

46 45 Iteration Planning Summary Developers break stories into tasks Developers sign up for stories. Customers may need to change, split, merge stories to fit iteration Once in the iteration, the stories are fixed Iteration velocity: number of story points completed Never extend the iteration date

47 46 Iteration Tracking Bulletin Board Selected Accepted Started Done?

48 47 Iteration Tracking Bulletin Board Selected Accepted Started Done?

49 48 How do you know a story is done? 1 2 3 4 5 6 7 Working Code Passing Tests

50 Writing Automated Acceptance Tests Object Mentor, Inc. Copyright  1998-2001 by Object Mentor, Inc All Rights Reserved

51 The Role of QA in an Agile Project

52 51 The Traditional schedule for Quality. Waiting at the sphincter muscle. Analysis Design Implementation 1 May1 Nov1 Jul1 Sep Test

53 52 When Quality comes at the end. It is under the most pressure. It has the least flexibility. It is a high stress tedious job. It is error prone. Quality cannot be tested in.

54 The Agile View: Quality is a specification role… …not a verification role!

55 A feature is not specified… Until it’s acceptance test is written.

56 55 Who Writes Acceptance Tests? Business Analysts Happy path. QA Test Writers, and Testers Corner and boundary cases. Try to break it.

57 56 Acceptance Tests Are… Automated. written in a very high level language. executed frequently. written by the stakeholders.

58 57 Imagine you have a button to press that would tell you if the system worked How often would you press it?

59 58 It becomes a conditioned response.

60 When is the best time to write Automated Acceptance Tests?

61 60 At the start of each iteration. Test

62 61 Tests specify each iteration.

63 62 Tests specify each iteration.

64 How do you know a feature is done?

65 A feature is not done… Until all it’s acceptance tests pass.

66 65 Knowing when a feature is done allows... These features have passed their Automated Acceptance Tests.

67 What do they look like?

68 A Simple Example

69 The result.

70 69 When is the best time to write AATs? Astute test managers Talk to the stakeholders days before each iteration. Write initial acceptance tests for the features they plan to schedule. Elaborate those acceptance tests once scheduled.

71 70 When is the best time to run them? Continuously. At every check-in. No change is allowed to break any passing tests. Continuous Integration.

72 71 Who runs them? Developers. Testers. Managers. Stakeholders. …They are run automatically. …Results are displayed on the wall.

73 72 This keeps the data accurate… …and actionable.

74 73 Evolution: Manual Tests Used for lack of any better approach Are better than nothing Terribly Inefficient In a crunch they are not run Unfortunately still among the most commonly used approach

75 74 Evolution: Ad Hoc Text-based CSV or Tab delimited files Allowed for automation of tests Does not scale well Very unconventional Everyone used a different scheme Not very customer friendly

76 75 Evolution: XML-based Still automated Scalable Visions of frameworks began XML introduces extra complexity Not customer friendly

77 76 GUI Testers Mercury Robot Canoo WebRunner Etc.

78 77 Testing through GUI is a trap. We have a client with 15,000 acceptance tests run through the GUI. Old DOS based GUI. Can’t update GUI because tests would fail. Stuck!

79 FitNesse The solution we all agreed upon.

80 79 Writing Requirements as Tests Requirements are written with example tables. The tables are really tests. Writing tests as a table is an interesting paradigm Some tests naturally fit into tables Some tests require thought to put them in the form of a table

81 80 The Mechanics The first row of a FIT table is the title of the table. This title is the name of something called a “fixture”. Fixtures are simple programs written by the developers to connect the application to the data in the table.

82 81 The Mechanics When you run a test the fixture gathers the data from the table and calls the appropriate functions in the application. The fixture then gathers data from the application and compares them with entries in the table, turning them green or red.

83 82 Acceptance Testing with Fit/FitNesse The Application Interface UI Fit FixturesFit/FitNesse The Application Logic

84 The Test-Bus Imperative

85 84 Many Industries build testability in. Telecommunications Manufacturing Electronic Hardware

86 85 But not the software industry. Testability is almost always an afterthought If it is thought of at all.

87 86 Untestable Dependencies. Networ k READY Too often applications directly depend on external and third party resources.

88 87 Dependency Management Networ k READY Interfaces isolate the system from external dependencies.

89 88 Testability! Tests and Simulations Tests and Simulations Tests and Simulations

90 Measuring Project Status

91 90 Project Management Tool When done properly, Acceptance Tests produce valuable data.

92 91 ATs keep the PM data accurate… …and actionable.

93 92 Iteration Management

94 93 Agile Software Development Practices Metaphor Collective Ownership Sustainable Pace Continuous Integration Small Releases Acceptance Tests Customer Collaboration Scrum Simple Design Pairing Test Driven Development Refactoring

95 Bowling Game Kata Copyright  2005 by Object Mentor, Inc All copies must retain this page unchanged.

96 95 Scoring Bowling. The game consists of 10 frames as shown above. In each frame the player has two opportunities to knock down 10 pins. The score for the frame is the total number of pins knocked down, plus bonuses for strikes and spares. A spare is when the player knocks down all 10 pins in two tries. The bonus for that frame is the number of pins knocked down by the next roll. So in frame 3 above, the score is 10 (the total number knocked down) plus a bonus of 5 (the number of pins knocked down on the next roll.) A strike is when the player knocks down all 10 pins on his first try. The bonus for that frame is the value of the next two balls rolled. In the tenth frame a player who rolls a spare or strike is allowed to roll the extra balls to complete the frame. However no more than three balls can be rolled in tenth frame.

97 96 The Requirements. Write a class named “Game” that has two methods roll(pins : int) is called each time the player rolls a ball. The argument is the number of pins knocked down. score() : int is called only at the very end of the game. It returns the total score for that game.

98 97 A quick design session Clearly we need the Game class.

99 98 A quick design session A game has 10 frames.

100 99 A quick design session A frame has 1 or two rolls.

101 100 A quick design session The tenth frame has two or three rolls. It is different from all the other frames.

102 101 A quick design session The score function must iterate through all the frames, and calculate all their scores.

103 102 A quick design session The score for a spare or a strike depends on the frame’s successor

104 103 Begin. Create a project named BowlingGame Create a unit test named BowlingGameTest import junit.framework.TestCase; public class BowlingGameTest extends TestCase { }

105 104 Begin. Create a project named BowlingGame Create a unit test named BowlingGameTest import junit.framework.TestCase; public class BowlingGameTest extends TestCase { } Execute this program and verify that you get the following error: No tests found in BowlingGameTest

106 105 The first test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { public void testGutterGame() throws Exception { Game g = new Game(); }

107 106 The first test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { public void testGutterGame() throws Exception { Game g = new Game(); } public class Game { }

108 107 The first test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { public void testGutterGame() throws Exception { Game g = new Game(); } public class Game { }

109 108 The first test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { public void testGutterGame() throws Exception { Game g = new Game(); for (int i=0; i<20; i++) g.roll(0); } public class Game { }

110 109 The first test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { public void testGutterGame() throws Exception { Game g = new Game(); for (int i=0; i<20; i++) g.roll(0); } public class Game { public void roll(int pins) { }

111 110 The first test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { public void testGutterGame() throws Exception { Game g = new Game(); for (int i=0; i<20; i++) g.roll(0); assertEquals(0, g.score()); } public class Game { public void roll(int pins) { }

112 111 The first test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { public void testGutterGame() throws Exception { Game g = new Game(); for (int i=0; i<20; i++) g.roll(0); assertEquals(0, g.score()); } public class Game { public void roll(int pins) { } public int score() { return -1; } expected: but was:

113 112 The first test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { public void testGutterGame() throws Exception { Game g = new Game(); for (int i=0; i<20; i++) g.roll(0); assertEquals(0, g.score()); } public class Game { public void roll(int pins) { } public int score() { return 0; }

114 113 The Second test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { public void testGutterGame() throws Exception { Game g = new Game(); for (int i = 0; i < 20; i++) g.roll(0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { Game g = new Game(); for (int i = 0; i < 20; i++) g.roll(1); assertEquals(20, g.score()); } public class Game { public void roll(int pins) { } public int score() { return 0; }

115 114 The Second test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { public void testGutterGame() throws Exception { Game g = new Game(); for (int i = 0; i < 20; i++) g.roll(0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { Game g = new Game(); for (int i = 0; i < 20; i++) g.roll(1); assertEquals(20, g.score()); } public class Game { public void roll(int pins) { } public int score() { return 0; } - Game creation is duplicated - roll loop is duplicated

116 115 The Second test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { public void testGutterGame() throws Exception { Game g = new Game(); for (int i = 0; i < 20; i++) g.roll(0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { Game g = new Game(); for (int i = 0; i < 20; i++) g.roll(1); assertEquals(20, g.score()); } public class Game { public void roll(int pins) { } public int score() { return 0; } - Game creation is duplicated - roll loop is duplicated expected: but was:

117 116 The Second test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } public void testGutterGame() throws Exception { for (int i = 0; i < 20; i++) g.roll(0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { for (int i = 0; i < 20; i++) g.roll(1); assertEquals(20, g.score()); } public class Game { private int score = 0; public void roll(int pins) { score += pins; } public int score() { return score; } - roll loop is duplicated

118 117 The Second test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } public void testGutterGame() throws Exception { int n = 20; int pins = 0; for (int i = 0; i < n; i++) { g.roll(pins); } assertEquals(0, g.score()); } public void testAllOnes() throws Exception { for (int i = 0; i < 20; i++) g.roll(1); assertEquals(20, g.score()); } public class Game { private int score = 0; public void roll(int pins) { score += pins; } public int score() { return score; } - roll loop is duplicated

119 118 The Second test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } public void testGutterGame() throws Exception { int n = 20; int pins = 0; rollMany(n, pins); assertEquals(0, g.score()); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testAllOnes() throws Exception { for (int i = 0; i < 20; i++) g.roll(1); assertEquals(20, g.score()); } public class Game { private int score = 0; public void roll(int pins) { score += pins; } public int score() { return score; } - roll loop is duplicated

120 119 The Second test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testAllOnes() throws Exception { for (int i = 0; i < 20; i++) g.roll(1); assertEquals(20, g.score()); } public class Game { private int score = 0; public void roll(int pins) { score += pins; } public int score() { return score; } - roll loop is duplicated

121 120 The Second test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public class Game { private int score = 0; public void roll(int pins) { score += pins; } public int score() { return score; } - roll loop is duplicated

122 121 The Second test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public class Game { private int score = 0; public void roll(int pins) { score += pins; } public int score() { return score; }

123 122 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { g.roll(5); g.roll(5); // spare g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public class Game { private int score = 0; public void roll(int pins) { score += pins; } public int score() { return score; } - ugly comment in test.

124 123 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { g.roll(5); g.roll(5); // spare g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public class Game { private int score = 0; public void roll(int pins) { score += pins; } public int score() { return score; } - ugly comment in test. expected: but was:

125 124 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { g.roll(5); g.roll(5); // spare g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public class Game { private int score = 0; public void roll(int pins) { score += pins; } public int score() { return score; } - ugly comment in test. tempted to use flag to remember previous roll. So design must be wrong.

126 125 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { g.roll(5); g.roll(5); // spare g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public class Game { private int score = 0; public void roll(int pins) { score += pins; } public int score() { return score; } - ugly comment in test. roll() calculates score, but name does not imply that. score() does not calculate score, but name implies that it does. Design is wrong. Responsibilities are misplaced.

127 126 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } // public void testOneSpare() throws Exception { // g.roll(5); // g.roll(5); // spare // g.roll(3); // rollMany(17,0); // assertEquals(16,g.score()); // } } public class Game { private int score = 0; public void roll(int pins) { score += pins; } public int score() { return score; } - ugly comment in test.

128 127 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } // public void testOneSpare() throws Exception { // g.roll(5); // g.roll(5); // spare // g.roll(3); // rollMany(17,0); // assertEquals(16,g.score()); // } } public class Game { private int score = 0; private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { score += pins; rolls[currentRoll++] = pins; } public int score() { return score; } - ugly comment in test.

129 128 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } // public void testOneSpare() throws Exception { // g.roll(5); // g.roll(5); // spare // g.roll(3); // rollMany(17,0); // assertEquals(16,g.score()); // } } public class Game { private int score = 0; private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { score += pins; rolls[currentRoll++] = pins; } public int score() { int score = 0; for (int i = 0; i < rolls.length; i++) score += rolls[i]; return score; } - ugly comment in test.

130 129 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } // public void testOneSpare() throws Exception { // g.roll(5); // g.roll(5); // spare // g.roll(3); // rollMany(17,0); // assertEquals(16,g.score()); // } } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; for (int i = 0; i < rolls.length; i++) score += rolls[i]; return score; } - ugly comment in test.

131 130 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { g.roll(5); g.roll(5); // spare g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; for (int i = 0; i < rolls.length; i++) score += rolls[i]; return score; } expected: but was: - ugly comment in test.

132 131 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { g.roll(5); g.roll(5); // spare g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; for (int i = 0; i < rolls.length; i++) { if (rolls[i] + rolls[i+1] == 10) // spare score +=... score += rolls[i]; } return score; } This isn’t going to work because i might not refer to the first ball of the frame. Design is still wrong. Need to walk through array two balls (one frame) at a time. - ugly comment in test.

133 132 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } // public void testOneSpare() throws Exception { // g.roll(5); // g.roll(5); // spare // g.roll(3); // rollMany(17,0); // assertEquals(16,g.score()); // } } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; for (int i = 0; i < rolls.length; i++) score += rolls[i]; return score; } - ugly comment in test.

134 133 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } // public void testOneSpare() throws Exception { // g.roll(5); // g.roll(5); // spare // g.roll(3); // rollMany(17,0); // assertEquals(16,g.score()); // } } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; int i = 0; for (int frame = 0; frame < 10; frame++) { score += rolls[i] + rolls[i+1]; i += 2; } return score; } - ugly comment in test.

135 134 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { g.roll(5); g.roll(5); // spare g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; int i = 0; for (int frame = 0; frame < 10; frame++) { score += rolls[i] + rolls[i+1]; i += 2; } return score; } expected: but was: - ugly comment in test.

136 135 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { g.roll(5); g.roll(5); // spare g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; int i = 0; for (int frame = 0; frame < 10; frame++) { if (rolls[i] + rolls[i + 1] == 10) // spare { score += 10 + rolls[i + 2]; i += 2; } else { score += rolls[i] + rolls[i + 1]; i += 2; } return score; } - ugly comment in test.

137 136 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { g.roll(5); g.roll(5); // spare g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; int i = 0; for (int frame = 0; frame < 10; frame++) { if (rolls[i] + rolls[i + 1] == 10) // spare { score += 10 + rolls[i + 2]; i += 2; } else { score += rolls[i] + rolls[i + 1]; i += 2; } return score; } -ugly comment in test. -ugly comment in conditional. -i is a bad name for this variable

138 137 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { g.roll(5); g.roll(5); // spare g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; int frameIndex = 0; for (int frame = 0; frame < 10; frame++) { if (rolls[frameIndex] + rolls[frameIndex + 1] == 10) // spare { score += 10 + rolls[frameIndex + 2]; frameIndex += 2; } else { score += rolls[frameIndex] + rolls[frameIndex + 1]; frameIndex += 2; } return score; } -ugly comment in test. -ugly comment in conditional.

139 138 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { g.roll(5); g.roll(5); // spare g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; int frameIndex = 0; for (int frame = 0; frame < 10; frame++) { if (isSpare(frameIndex)) { score += 10 + rolls[frameIndex + 2]; frameIndex += 2; } else { score += rolls[frameIndex] + rolls[frameIndex + 1]; frameIndex += 2; } return score; } private boolean isSpare(int frameIndex) { return rolls[frameIndex] + rolls[frameIndex + 1] == 10; } -ugly comment in test.

140 139 The Third test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase { private Game g; protected void setUp() throws Exception { g = new Game(); } private void rollMany(int n, int pins) { for (int i = 0; i < n; i++) g.roll(pins); } public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { rollSpare(); g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } private void rollSpare() { g.roll(5); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; int frameIndex = 0; for (int frame = 0; frame < 10; frame++) { if (isSpare(frameIndex)) { score += 10 + rolls[frameIndex + 2]; frameIndex += 2; } else { score += rolls[frameIndex] + rolls[frameIndex + 1]; frameIndex += 2; } return score; } private boolean isSpare(int frameIndex) { return rolls[frameIndex] + rolls[frameIndex + 1] == 10; } -

141 140 The Fourth test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase {... public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { rollSpare(); g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public void testOneStrike() throws Exception { g.roll(10); // strike g.roll(3); g.roll(4); rollMany(16, 0); assertEquals(24, g.score()); } private void rollSpare() { g.roll(5); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; int frameIndex = 0; for (int frame = 0; frame < 10; frame++) { if (isSpare(frameIndex)) { score += 10 + rolls[frameIndex + 2]; frameIndex += 2; } else { score += rolls[frameIndex] + rolls[frameIndex + 1]; frameIndex += 2; } return score; } private boolean isSpare(int frameIndex) { return rolls[frameIndex] + rolls[frameIndex + 1] == 10; } - ugly comment in testOneStrike. expected: but was:

142 141 The Fourth test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase {... public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { rollSpare(); g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public void testOneStrike() throws Exception { g.roll(10); // strike g.roll(3); g.roll(4); rollMany(16, 0); assertEquals(24, g.score()); } private void rollSpare() { g.roll(5); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; int frameIndex = 0; for (int frame = 0; frame < 10; frame++) { if (rolls[frameIndex] == 10) // strike { score += 10 + rolls[frameIndex+1] + rolls[frameIndex+2]; frameIndex++; } else if (isSpare(frameIndex)) { score += 10 + rolls[frameIndex + 2]; frameIndex += 2; } else { score += rolls[frameIndex] + rolls[frameIndex + 1]; frameIndex += 2; } return score; } private boolean isSpare(int frameIndex) { return rolls[frameIndex] + rolls[frameIndex + 1] == 10; } -ugly comment in testOneStrike. -ugly comment in conditional. -ugly expressions.

143 142 The Fourth test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase {... public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { rollSpare(); g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public void testOneStrike() throws Exception { g.roll(10); // strike g.roll(3); g.roll(4); rollMany(16, 0); assertEquals(24, g.score()); } private void rollSpare() { g.roll(5); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; int frameIndex = 0; for (int frame = 0; frame < 10; frame++) { if (rolls[frameIndex] == 10) // strike { score += 10 + strikeBonus(frameIndex); frameIndex++; } else if (isSpare(frameIndex)) { score += 10 + spareBonus(frameIndex); frameIndex += 2; } else { score += sumOfBallsInFrame(frameIndex); frameIndex += 2; } return score; } private int sumOfBallsInFrame(int frameIndex) { return rolls[frameIndex]+rolls[frameIndex+1]; } private int spareBonus(int frameIndex) { return rolls[frameIndex + 2]; } private int strikeBonus(int frameIndex) { return rolls[frameIndex+1]+rolls[frameIndex+2]; } private boolean isSpare(int frameIndex) { return rolls[frameIndex]+rolls[frameIndex+1] == 10; } -ugly comment in testOneStrike. -ugly comment in conditional.

144 143 The Fourth test. import junit.framework.TestCase; public class BowlingGameTest extends TestCase {... public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { rollSpare(); g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public void testOneStrike() throws Exception { g.roll(10); // strike g.roll(3); g.roll(4); rollMany(16, 0); assertEquals(24, g.score()); } private void rollSpare() { g.roll(5); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; int frameIndex = 0; for (int frame = 0; frame < 10; frame++) { if (isStrike(frameIndex)) { score += 10 + strikeBonus(frameIndex); frameIndex++; } else if (isSpare(frameIndex)) { score += 10 + spareBonus(frameIndex); frameIndex += 2; } else { score += sumOfBallsInFrame(frameIndex); frameIndex += 2; } return score; } private boolean isStrike(int frameIndex) { return rolls[frameIndex] == 10; } private int sumOfBallsInFrame(int frameIndex) { return rolls[frameIndex] + rolls[frameIndex+1]; } private int spareBonus(int frameIndex) { return rolls[frameIndex+2]; } private int strikeBonus(int frameIndex) { return rolls[frameIndex+1] + rolls[frameIndex+2]; } private boolean isSpare(int frameIndex) { return rolls[frameIndex]+rolls[frameIndex+1] == 10; } -ugly comment in testOneStrike.

145 144 The Fourth test.... public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { rollSpare(); g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public void testOneStrike() throws Exception { rollStrike(); g.roll(3); g.roll(4); rollMany(16, 0); assertEquals(24, g.score()); } private void rollStrike() { g.roll(10); } private void rollSpare() { g.roll(5); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; int frameIndex = 0; for (int frame = 0; frame < 10; frame++) { if (isStrike(frameIndex)) { score += 10 + strikeBonus(frameIndex); frameIndex++; } else if (isSpare(frameIndex)) { score += 10 + spareBonus(frameIndex); frameIndex += 2; } else { score += sumOfBallsInFrame(frameIndex); frameIndex += 2; } return score; } private boolean isStrike(int frameIndex) { return rolls[frameIndex] == 10; } private int sumOfBallsInFrame(int frameIndex) { return rolls[frameIndex] + rolls[frameIndex+1]; } private int spareBonus(int frameIndex) { return rolls[frameIndex+2]; } private int strikeBonus(int frameIndex) { return rolls[frameIndex+1] + rolls[frameIndex+2]; } private boolean isSpare(int frameIndex) { return rolls[frameIndex]+rolls[frameIndex+1] == 10; }

146 145 The Fifth test.... public void testGutterGame() throws Exception { rollMany(20, 0); assertEquals(0, g.score()); } public void testAllOnes() throws Exception { rollMany(20,1); assertEquals(20, g.score()); } public void testOneSpare() throws Exception { rollSpare(); g.roll(3); rollMany(17,0); assertEquals(16,g.score()); } public void testOneStrike() throws Exception { rollStrike(); g.roll(3); g.roll(4); rollMany(16, 0); assertEquals(24, g.score()); } public void testPerfectGame() throws Exception { rollMany(12,10); assertEquals(300, g.score()); } private void rollStrike() { g.roll(10); } private void rollSpare() { g.roll(5); } public class Game { private int rolls[] = new int[21]; private int currentRoll = 0; public void roll(int pins) { rolls[currentRoll++] = pins; } public int score() { int score = 0; int frameIndex = 0; for (int frame = 0; frame < 10; frame++) { if (isStrike(frameIndex)) { score += 10 + strikeBonus(frameIndex); frameIndex++; } else if (isSpare(frameIndex)) { score += 10 + spareBonus(frameIndex); frameIndex += 2; } else { score += sumOfBallsInFrame(frameIndex); frameIndex += 2; } return score; } private boolean isStrike(int frameIndex) { return rolls[frameIndex] == 10; } private int sumOfBallsInFrame(int frameIndex) { return rolls[frameIndex] + rolls[frameIndex+1]; } private int spareBonus(int frameIndex) { return rolls[frameIndex+2]; } private int strikeBonus(int frameIndex) { return rolls[frameIndex+1] + rolls[frameIndex+2]; } private boolean isSpare(int frameIndex) { return rolls[frameIndex]+rolls[frameIndex+1] == 10; }

147 End

148 147 Contact Information Robert C. Martin unclebob@objectmentor.com unclebob@objectmentor.com Website: www.objectmentor.com www.objectmentor.com FitNesse: www.fitnesse.org www.fitnesse.org


Download ppt "Scrum and Hyper-productivity Object Mentor, Inc. Copyright  1998-2007 by Object Mentor, Inc All Rights Reserved fitnesse.org www.objectmentor.com www.junit.org."

Similar presentations


Ads by Google