Skip to content

Commit

Permalink
Hints and links to screencasts
Browse files Browse the repository at this point in the history
  • Loading branch information
luontola committed Apr 20, 2015
1 parent 632ad03 commit 46b1bcd
Showing 1 changed file with 6 additions and 4 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,18 @@ The Steps of the Tutorial

Use the tests in the [src/test/java/tetris](http://github.com/orfjackal/tdd-tetris-tutorial/tree/tutorial/src/test/java/tetris/) directory to write a Tetris game. Implement code to pass the tests, one file and one test at a time, in the same order as they are listed below, starting with `FallingBlocksTest`.

When you first run the tests, you should see the first test (`A_new_board.is_empty`) failing. Fix the code and run the tests to see it pass. Then uncomment the following test (`A_new_board.has_no_falling_blocks`). When that test passes, uncomment the next one (`When_a_block_is_dropped.the_block_is_falling`) and make it pass, until finally you have written code which passes all tests in that class. Then open the next test class and keep on continuing in the same fashion.
When you first run the tests, you should see the first test (`A_new_board.is_empty`) failing. Fix the code (a one-line change) and run the tests to see it pass. Then uncomment the following test (`A_new_board.has_no_falling_blocks`). When that test passes, uncomment the next one (`When_a_block_is_dropped.the_block_is_falling`) and make it pass, until finally you have written code which passes all tests in that class. Then open the next test class and keep on continuing in the same fashion.

Reference implementations for the steps of this tutorial have been [tagged in its Git repository](https://github.com/orfjackal/tdd-tetris-tutorial/tags) (the [beyond branch](http://github.com/orfjackal/tdd-tetris-tutorial/tree/beyond) contains the most complete implementation). It might be helpful to have a look at them *after* you have yourself implemented this tutorial that far. The reference implementation may teach you something about writing clean code.
Reference implementations for the steps of this tutorial have been [tagged in its Git repository](https://github.com/orfjackal/tdd-tetris-tutorial/tags?after=take2%2Fpomodoro1). There are also [Let's Code screencasts](http://www.orfjackal.net/lets-code#tdd-tetris-tutorial) of implementing the [take3 branch](https://github.com/orfjackal/tdd-tetris-tutorial/tree/take3). Also the [beyond](https://github.com/orfjackal/tdd-tetris-tutorial/tree/beyond) and [take2](https://github.com/orfjackal/tdd-tetris-tutorial/tree/take2) branches have reference implementations. It might be helpful to have a look at them *after* you have yourself implemented this tutorial that far or you get stuck with your design.

1. **FallingBlocksTest**

In Tetris, the most important feature is that there are blocks which fall down, so that is the first behaviour which we will specify by writing tests. It is good to start the writing of a program with a very trivial test. In this case, we will first make sure that we have an empty game board.

We'll use the [Simplification strategy](http://www.infoq.com/presentations/responsive-design) and first deal with just falling 1x1 blocks. We can expand that later to handle more complex multi-block pieces. It's best to avoid taking too big steps.

*Design Hint:* In line with YAGNI, avoid introducing new classes or patterns until there is a [demonstrated need](http://www.jbrains.ca/permalink/the-four-elements-of-simple-design) for them. For example, don't introduce class when just a `char` is enough. Don't introduce a two-dimensional array when just a scalar field is enough. Later when the real need for them arises, you will have learned more about the code's needs and you'll be able to make a better design without having to undo your old designs.

2. **RotatingPiecesOfBlocksTest**

Rotating the pieces in Tetris is also very important, so let's code that next. You might need pen and paper when figuring out how the shape coordinates change when the shape is rotated.
Expand All @@ -57,13 +59,13 @@ Reference implementations for the steps of this tutorial have been [tagged in it

Also notice that the I shape has only two possible orientations and the O shape has only one orientation. The tests are the way they are by design. Did you know that Tetris has many alternative [rotation systems](http://tetris.wikia.com/wiki/Category:Rotation_Systems)?

If you are thinking of making the `Tetromino` class extend the `Piece` class, first read about the [Liskov Substitution Principle](http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod) to know when it's right for a class to inherit another. In general, it's best to [favor composition over inheritance](http://www.artima.com/lejava/articles/designprinciples4.html).
*Design Hint:* If you are thinking of making the `Tetromino` class extend the `Piece` class, first read about the [Liskov Substitution Principle](http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod) to know when it's right for a class to inherit another. In general, it's best to [favor composition over inheritance](http://www.artima.com/lejava/articles/designprinciples4.html).

4. **FallingPiecesTest**

Next we will connect the falling blocks and the rotatable pieces. In order to make the first test pass, you will probably need to refactor your code quite much (for me it took 1½ hours). You will need to build suitable abstractions, so that single-block pieces and multi-block pieces can be handled the same way (changing the test code should not be necessary). When refactoring, you must keep the tests passing between every small change, or you will end up in [refactoring hell](http://c2.c2.com/cgi/wiki?RefactoringHell). If more than five minutes have passed since the last time all tests passed, it's best to revert your code from source control to the last version where all tests passed.

The difficulty of this refactoring depends on how well factored the code is. You could even say that the difficulty of this refactoring is inversely proportional to the length of the `Board.tick()` method (if most of the logic is in that one method, instead of using [Composed Method](http://www.infoq.com/presentations/10-Ways-to-Better-Code-Neal-Ford), then you're in trouble). If you get stuck, you may get some hints from [this example refactoring](http://www.cs.helsinki.fi/u/luontola/tdd-2009/kalvot/04.1-Refactoring-Example.pdf).
The difficulty of this refactoring depends on how well factored the code is. You could even say that the difficulty of this refactoring is inversely proportional to the length of the `Board.tick()` method (if most of the logic is in that one method, instead of using [Composed Method](http://www.infoq.com/presentations/10-Ways-to-Better-Code-Neal-Ford), then you're in trouble). If you get stuck, there are refactoring examples in [this PDF presentation](http://www.cs.helsinki.fi/u/luontola/tdd-2009/kalvot/04.1-Refactoring-Example.pdf) and [this YouTube video](https://www.youtube.com/watch?v=nU3-sCxQMq0).

5. **MovingAFallingPieceTest**

Expand Down

0 comments on commit 46b1bcd

Please sign in to comment.