What's all this nonsense about Katas? 52
There has been an increase in interest in Software Katas of late. What is all this buzz about, and why might it be important?
Several years ago (Pragmatic) Dave Thomas started a special blog about coding katas. The idea was simple: Professionals practice.
This thought might not have occurred to you before; but it’s self-evidently true. Professional musicians practice. Professional dancers practice. Doctors practice. Soldiers practice. Indeed, any kind of professional craftsman or artisan must practice their adopted trade in order to execute it well when it counts.
Dave’s point was that professional programmers need to practice like any other professional. He set forth a number of simple exercises and problems that programmers could solve during their practice time. He also suggested that practice time needs to be scheduled and protected as part of the normal routine of a software developer.
At XP2005 in Shefield, UK, I attended Laurent Bossavit’s and Emmanuel Gaillot’s Coding Dojo session. I blogged about it at the time. I left that session with a different view of what a Kata might be. In Dave Thomas’ view a kata is an exercise to solve. Each time you solve it you try a different approach. Dave’s notion is that a kata is a way to explore the solution space of a problem. But in Martial arts a kata is something different; it is a set of motions that one memorizes in minute detail. A martial arts kata is a precisely executed dance. I left Sheffield with the idea that a coding kata could be more like a martial arts kata.
About a year ago, Corey Haines (our wandering minstrel of code) stopped by and told me about some mini-conferences that had adopted the notion of coding kata. What he described sounded more like a group dance than a bunch of people independently solving a given problem. This got me thinking. So at the next Software Craftsmanship meeting at 8th Light (Which, not coincidentally, takes it’s name from a martial arts philosophy) I conducted a simple kata session in dojo style.
I, acting as the Sen Sei, had everyone file in to the room as they would to a dojo. I had them put their green bands on their wrists (mine was black!). I bade them to sit, and then gestured for silence. For the next 15 minutes I led them through the Prime Factors Kata in Java without uttering a word (well, almost). I would write a simple test case, then gesture for them to do the same. Then I would make the test pass, and again gesture for them to repeat my moves.
Then, this Fall, I attended Programming with the Stars at Agile 2009. As I watched the contestants perform their programming sessions, I realized that they were not simply demonstrating programming prowess; indeed they were competing in how well they performed their session. That’s when it struck me. This was a performance art!
It seems absurd to think of programming as a performance art. And yet watching those people up on stage working through routines that they had clearly practiced over and over again, was delightfully entertaining to me, and to the crowd. There were cheers and applause when a performing pair did something especially well. There was laughter when a pair executed a clever joke in code, or in behavior. For programmers, watching other programmers perform well practiced routines was fun!
Now I had seen martial arts katas executed as performance art during competitions. Indeed, it is a beautiful thing to watch a skilled and well practiced martial artist peform a kata. And that started me thinking. Why would a martial artist practice these forms so intensely that they could be performed as an art?
The goal of martial arts is not to perform on stage. The goal of martial arts is self defense! And yet, when a martial artist is at the peak of his skill, his practice takes on the quality of a performance art. When you watch a skilled martial artist perform, you know you don’t want to fight him. The performance is a demonstration, and a realization, of mastery.
And yet the performance is not the goal. No martial artist practices his art so that they can perform on stage. A martial artist practices to achieve personal perfection in the art of self defense. The fact that the practice can be performed is a (pleasant) side effect.
Could it be that these coding kata that we’ve been dabbling with for the last few years could be performed? Is there a benefit to practicing them so much that performance is an option? Is there really any reason for a programmer to create and then memorize a routine down to the level of individual keystrokes? Is there profit to be gained from practicing that routine so thoroughly that you can do it at high speed with virtually no errors? This August I decided to find out.
I started with the Prime Factors Kata in Java, and set it to music inspired by this video of dancing kites. The piece is about 4 minutes long, and I figured I’d need about twice that, so I found two different version of the music and played them back to back. But working in Java is ponderous, and I could not complete the kata before the two pieces had finished. So I switched to Ruby. Using Ruby and Rspec I was able to finish the Kata with plenty of time to spare.
Thereupon began an evolution. Since I had time, I added more features to the kata. As I improved in my practice I found I had even more time, so I added even more features. I refined and polished. I refactored my refactorings. I trimmed keystrokes, and learned many new keyboard shortcuts in the process. I completely abandoned the mouse; and then later reacquired it for flourishes and highlights (but never for actual coding).
Week after week, I set aside 30 minutes or so every day to practice, and practice, and practice—just the way I used to practice my Jiu Jitsu Katas. I would practice on airplanes while flying to clients. I would practice in bed with my laptop in my lap. I would practice late at night in hotel rooms after a long day consulting for clients. I would practice early in the morning before shower and breakfast. And the practice started to pay off.
Ten weeks later I finally decided I was ready to create a screencast. I reduced my screen resolution to 1024X768. I configured SnapZ ProX to record the whole screen at 80% size. And I began to record.
Performing a coding kata in time to music is a very difficult thing to do. Maintaining the timeline is critical. There are very few errors that you can effectively recover from. If you miss a stroke, the whole sequence melts down. And melt down it did. Over and over and over again. I spent weeks trying to record a reasonably good session. I must have done hundreds of takes. It was very frustrating.
But day by day I got better and better at it. Finally, after weeks of trying, I got what I consider to be a recording that, though not perfect, is good enough to present. You can watch that recording here.
Has this paid off in the regular programming I do? I think it has. My mouse usage is much less than it used to be. I know a much larger number of keyboard shortcuts than I used to, and I can use them almost instinctively. My typing and accuracy have improved quite a bit, and I now type more punctuation and number keys without looking. So, yes, I think the effort has paid off; though I’m not at all sure the payoff compensates for the effort.
But something else compensates for the effort. Making this recording was fun—it was a lot of fun. And that’s probably the real answer to the question posed in the title of this blog.
C++ Bowling Kata Result 18
I’m teaching a TDD and Refactoring class this week using C++. Since I had not recently wrote the bowling kata in C++, I figured it was about time to do it again.
Unlike the previous Scala version, this one only addresses the happy-path. I do not consider throwing too many balls or scoring too many pins in any frame. However, having just written this in Scala, I’m sure I could do something similar in C++.
I just switched to CppUTest 2.0 and something I noticed is that if you use <vector> or other std-based classes, you need to make sure to include those first before including <CppUTest/TestHarness.h>. This is because CppUTest overloads new and delete, which causes havoc with the std-based classes. No big deal, I just made sure to include that file as the last header (rather than the first, which is what I used to do).
Here are the various files: RunAllTests.cpp
1 2 3 4 5 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | |
I sure do miss refactoring tools!-)
TDD Triage 112
With all controversy that has been generated buy my last two blogs (1, 2), I thought it would be wise to talk bout where TDD works and where it doesn’t
Is TDD a replacement for architecture?
No, of course not. The notion that you can generate a viable architecture by starting with a blank screen and then writing one test case after the other is sheer folderol. There are decisions that you need to make that have nothing to do with tests.
Of course many of these decisions can, and should, be deferred for as long as possible. For example, the database schema is something that can likely wait for quite a long time. The decision to use Spring, JSF, Hibernate, JPA, etc. can also likely wait. The beauty of business rules is that they can, and should, be implemented independently of database and GUI models.
In FitNesse, we deferred the database decision as long as possible. In the end we deferred it indefinitely and used flat files instead. At the beginning we did not think flat files would be the solution, we thought we’d be using mysql. But we kept on postponing that decision, and making our test cases pass. Finally, one of the stubs we’d been using to save fitnesse pages into flat files proved to be good enough.
Interestingly enough, one year later a user of FitNesse needed it to use mysql (because of corporate bureaucracy). It took him a day to make the changes. The architecture of FitNesse was so flexible, because of all the tests and stubbing, that shimming mysql in at the very end was trivial.
On the other hand, some architectural decisions need to be made early. For example you really do need to choose your programming language pretty early on. You also probably need to know whether you will be working in a web (batch) environment, or using a more intimate user interface. If you are in an enterprise environment, you’ll need to understand the existing database and plan how you will isolate your application from it.
When we started FitNesse, we made a very early architectural decision that has had a profound impact on the structure of the system. That decision was named “Download and go.” Before the first line of code was written we decided that FitNesse should not be bound to any other independent system, that you should be able to download it, and then execute it with a single command. In 2001 this meant we had to write our own web server…
Here’s the bottom line. You cannot derive a complete architecture with TDD. TDD can inform some of your architectural decisions, but you cannot begin a project without an architectural vision. So some up front architecture is necessary. One of the most important up front architectural activities is deciding which architectural elements can be deferred and which cannot.
Is TDD a replacement for design?
No. You still need all your design skills. You still need to know design principles, and design patterns. You should know UML. And, yes, you should create lightweight models of your proposed software designs.
TDD’s role is to inform your design decisions, not to replace them. The Bowling Game Kata is an example of how TDD can utterly invalidate early design decisions; but the Bowling Game is an extreme case. Usually TDD works to validate, and/or augment your design decisions.
A team of developers needs to have a design vision that they have agreed upon. This vision can often be gained with a relatively short design session at the beginning of each iteration. UML models can be proposed and negotiated on a white board. This gives everyone the context required to make progress without stepping all over each other.
However, the models should not be considered law. They are nothing more than an initial rough draft of the design. As the teams practice TDD, they will undoubtedly discover weaknesses in the designs, and uncover better solutions. These improvements should be quickly communicated to the rest of the team.
The bottom line is that TDD is a_ design technique but should not be the _sole design technique. All the old design rules and skills still apply; and TDD is a powerful way to inform and augment them.
Should TDD be used for every line of code?
No. There is a set of problems for which TDD is not particularly helpful. GUIs are an example.
In FitNesse, for example, we use Velocity templates to create our web pages. There is a lot of coding that goes into a Velocity template. But to use TDD for those templates would be absurd. The problem is that I’m not at all sure what I want a page to look like. I need the freedom to fiddle around with the formatting and the structure until everything is just the way I want it. Trying to do that fiddling with TDD is futile. Once I have the page the way I like it, then I’ll write some tests that make sure the templates work as written.
Of course it’s not just GUIs. It is the notion of fiddling that is the key. If you must massage the code into place. If you must fiddle with some aspect in order to please the customer. If there is some uncertainty that can only be resolved by a very rapid cycle of edit-and-run, then TDD is likely to be more of a hindrance than a help.
As another example, I once worked with a trading company that had to parse incoming streams of trading data. These streams did not have a well defined format. The teams had to fiddle with regular expressions and parsers in order to get the decoding just right. TDDing this would not have been wise. Writing the tests afterwards was imperative.
The trick to manage this is intense decoupling. You want to make sure you identify every bit of the code that does not need to be fiddled, and separate that code into modules that you can write with TDD. Make sure that the fiddled code is isolated and kept to a bare minimum.
For example, the Velocity templates in FitNesse draw their data from data structures that are built by the business rule processes (we call them Responders). I relentlessly use TDD to make sure those data structures are right. So when I fiddle with the templates, at least I’m not fiddling with the code that generates the data for those templates.
NOTE! Just because GUIs need to be fiddled with, does not mean that most of the code around the GUI should not be TDD’d. In fact, most of that code should be TDD’d. It’s just the tiny thin veneer of code that controls the format that needs to be fiddled. All code that can and should be TDD’d should be decoupled from that veneer. So, decouple, decouple, decouple, and then finally fiddle.
Well, if you are going to write some tests afterwards, why not write all tests afterwards?
Well, first, there’s the George-Williams study, which showed that teams who are instructed to write tests afterwards, don’t write tests at all. Of course this is human nature. Once you have the code “working” why write tests? Writing tests for code that you believe works feels like a waste of time.
But that can be countered with sheer discipline. The real reason to follow The Three Laws of TDD and write your tests first is that it greatly enhances the chances that every line and every decision is tested.
Code coverage is a sneaky metric. It is quite possible to create extremely high levels of coverage without a single assert. I don’t need to tell you that coverage without asserts is less than meaningful. When you write tests first, your assertion coverage is very high. When you write tests after, you assertion coverage simply cannot be that high. Even the most dedicated and determined developer will make some coding decisions that block later testability. When you write the tests first, this simply cannot happen. When you write the tests first every coding decision you make must support testability.
Clearly writing the tests first forces an extremely high degree of compatibility between the tests and the code. Writing the tests first also means that your first thoughts about the code are from the point of view of a user, not an author; and that also has benefits.
So, all else being equal, test-first is clearly better than test-after.
Given that we accept the need for tests, why the resistance to test-first?
Honestly, I don’t know. Clearly it can’t be a productivity issue since we are going to write the tests anyway.
Perhaps some people don’t like the fact that writing tests first interrupts the flow. It’s true, when you write tests first, you cannot write a whole algorithm. You have to assemble that algorithm bit by bit as you add one test case after another. Maybe some people just don’t feel comfortable working this way. Personally, I find working this way to be highly beneficial. It’s a way for me to think critically about the code I am writing. But I accept that some folks may find it difficult.
I once worked with an assembly language programmer who simply could not understand pointers. No matter how hard I tried to explain them, he simply could not grasp the concept. This made it hard for him to write certain kinds of programs. I fear that the folks who cannot train their brains to think in a test-first way are working at a similar kind of disadvantage, though not nearly so severe.
Wouldn’t it be faster without such high test coverage?
I’ll paraphrase Kent Beck once again. “If I don’t need to make it work, I can go a lot faster.”
I once consulted for a team that followed this rule. For them, the definition of “Done” was “checked in”. If the checked in code had bugs, then fixing those bugs went on a different schedule. Eventually the team started checking in empty source files in order to be “done” on time.
But let’s take the original question seriously. Do we really need to have close to 100% automated test coverage? Doesn’t the insistence on such a high level of coverage slow the development team down?
In a legacy environment it certainly does. Indeed, in a legacy environment I would not insist on high test coverage at first. I’d set the goal pretty low, and then gradually ramp it up over a period of months to years.
Legacy code (defined by Michael Feathers as: code without tests) is a big problem. Getting that code under automated test is a difficult and long-term activity. The pay-off is huge, but you can’t get there quickly.
In a non-legacy environment, and for all new code within a legacy environment the situation is different. High coverage with automated tests speeds you up; and it speeds you up a lot.
The reason isn’t difficult to understand. Firstly, you don’t do much debugging. How could you if you have tested virtually every line of code? My own experience with debug time is that it all but disappears. In the last year of intense development effort on FitNesse I have spent almost no time debugging. If I had to quantify that time, I’d put it at 5 hours or less.
Secondly, I simply cannot inadvertently break the code. The test suite finds such breakage within seconds! And this makes me fearless. When you are fearless, you can go a lot faster.
Thirdly, My tests are little examples of how to work the system. Whenever I forget how some part of the system works, I read the tests. They quickly get me back up to speed.
Fourthly, I’m not fighting a continuous barrage of bugs from the field. Even though I have thousands of users, my bug list is tiny. The time I spend in support is less than an hour a week, and usually that’s just pointing people at the right spot in the user guide.
So to counter Kent Beck’s quote above: “When your code works you can go a lot faster.”
Summary
I’m quite sure this blog will not quell the controversy. I expect that those folks who consistently berate TDD will continue to do so. But perhaps those who have honest doubts will find this blog useful, or even convincing.
Scala Bowling Kata - still in the middle I suppose 5
"One more roll on a game with 20 rolls and an open 10th frame" should {
20 times { roll(1) }
roll(1) must throwA[IllegalArgumentException]
}
"Two more rolls a game with 10 spares" should {
10 times { spare }
roll(1)
roll(1) must throwA[IllegalArgumentException]
}
"Two marks in the 10th frame should" should {
18 times { roll(1) }
strike
spare
roll(1) must throwA[IllegalArgumentException]
}On my flight from DFW to SNA, I got these behaviors implemented. The code was pretty ugly!
However, ugly code in hand, passing examples, a slight understanding of some of the problems with my code and a desire to make the BowlingScorer immutable was all I needed to make progress.
I removed the index instance field by rewriting the score method and injecting a tuple into foldLeft (written here using the short-hand notation /:): def scoreAt(frame:Int) =
((0,0) /: (1 to frame)) { (t, _) =>
(t._1 + scoreAtIndex(t._2), t._2 + incrementAt(t._2))
}._1 def onFirstThrow = {
var index = 0
while(index < rolls.length)
if(isStrike(index)) index += 1 else index += 2
index == rolls.length
}While I am happy I was able to remove the index variable, which was really a parameter being passed around in a field (ugly), I am not happy with this method.
I changed the roll method to return a new instance of a BowlingScorer, making the bowling scorer immutable: def roll(roll:Int) = {
validate(roll)
new BowlingScorer(rolls ++ Array(roll))
}So I think I’m still somewhere in the middle of working through this code. Again, I’m still learning Scala. I have a lot to learn. I really only barely understand functional programming and, frankly, the Eclipse IDE, while functional, is getting in the way quite a bit. So for a toy example it is OK. Given the choice of this environment or vi and the command line, I’d not pick the former. (I might give the other IDE’s a go, but that’s not really what I’m interested in learning right now.)
So here’s the next version. I plan to work through all of the comments I’ve yet to process from the previous blog posting over the next few days. If you can recommend a better implementation of onFirstThrow, I’d appreciate it.
Other general comments also welcome.
BowlingScorerExampleGroup.scala
package com.om.example
import org.specs._
object BowlingScorerExampleGroup extends SpecificationWithJUnit {
var scorer = new BowlingScorer(Nil);
def roll(value:Int) =
scorer = scorer.roll(value)
def haveAScoreOf(expected:Int) =
scorer.score must_== expected
def strike =
roll(10)
def spare {
roll(5)
roll(5)
}
implicit def intToDo(count: Int) = {
new {
def times(f: => Unit) = {
1 to count foreach { _ => f }
}
}
}
"A Newly Created Bowling Scorer" should {
haveAScoreOf(0)
}
"A game with all 0's" should {
20 times { roll(0) }
haveAScoreOf(0)
}
"A game with all 1's" should {
20 times { roll(1) }
haveAScoreOf(20)
}
"A game with a single spare followed by a 5" should {
spare
roll(5)
haveAScoreOf(20)
}
"A game with all 5's" should {
10 times { spare }
roll(5)
haveAScoreOf(150)
}
"A game with a single strike followed by a 4" should {
strike
roll(4)
haveAScoreOf(18)
}
"A game with a strike, spare then an open frame with two 3's" should {
strike
spare
2 times { roll(3) }
haveAScoreOf(39)
}
"A game with strike, spare then an open frame with two 3's" should {
spare
strike
2 times { roll(3) }
haveAScoreOf(42)
}
"A Dutch 200 game, Spare-Strike" should {
5 times {
spare
strike
}
spare
haveAScoreOf(200)
}
"A Dutch 200 game, Strike-Spare" should {
5 times {
strike
spare
}
strike
haveAScoreOf(200)
}
"A Perfect game" should {
12 times { strike }
haveAScoreOf(300)
}
"The score for each frame of a Perfect game, each frame" should {
12 times { strike }
1 to 10 foreach { frame => scorer.scoreAt(frame) must_== 30 * frame }
}
"An individaul roll of > 10" should {
roll(11) must throwA[IllegalArgumentException]
}
"An iniviaul roll of < 0" should {
roll(-1) must throwA[IllegalArgumentException]
}
"A frame trying to contain more than 10 pins" should {
roll(8)
roll(3) must throwA[IllegalArgumentException]
}
"One more roll on a game with 20 rolls and an open 10th frame" should {
20 times { roll(1) }
roll(1) must throwA[IllegalArgumentException]
}
"Two more rolls a game with 10 spares" should {
10 times { spare }
roll(1)
roll(1) must throwA[IllegalArgumentException]
}
"Two marks in the 10th frame should" should {
18 times { roll(1) }
strike
spare
roll(1) must throwA[IllegalArgumentException]
}
}BowlingScorer.scala
package com.om.example
class BowlingScorer(rollsSoFar:List[Int]){
val rolls:List[Int] = rollsSoFar
def roll(roll:Int) = {
validate(roll)
new BowlingScorer(rolls ++ Array(roll))
}
def validate(roll:Int) {
if(invalidRoll(roll))
throw new IllegalArgumentException("Individaul rolls must be from 0 .. 10")
if(frameRollTooHigh(roll))
throw new IllegalArgumentException("Total of rolls for frame must not exceed 10");
if(willBeTooManyRolls)
throw new IllegalArgumentException("Game over, no more rolls allowed")
}
def invalidRoll(roll:Int) =
(0 to 10 contains(roll)) == false
def frameRollTooHigh(roll:Int) =
openScoreAt(indexToValidate) + roll > 10
def willBeTooManyRolls =
tenthRolled(indexOf10thFrame) && nextRollTooMany(indexOf10thFrame)
def tenthRolled(tenthIndex:Int) =
tenthIndex < rolls.length
def nextRollTooMany(tenthIndex: Int) =
allowedTenthFrameRolls(tenthIndex) < rollsInTenthFrame(tenthIndex) + 1
def indexOf10thFrame =
(0 /: (1 until 10)) {(c, _) => c + incrementAt(c)}
def allowedTenthFrameRolls(index:Int) =
if(isMark(index)) 3 else 2
def rollsInTenthFrame(index: Int) =
rolls.length - index
def indexToValidate =
if(onFirstThrow) rolls.length else rolls.length - 1
def onFirstThrow = {
var index = 0
while(index < rolls.length)
if(isStrike(index)) index += 1 else index += 2
index == rolls.length
}
def scoreAt(frame:Int) =
((0,0) /: (1 to frame)) { (t, _) =>
(t._1 + scoreAtIndex(t._2), t._2 + incrementAt(t._2))
}._1
def score = scoreAt(10)
def scoreAtIndex(index:Int) =
if(isMark(index)) markScoreAt(index) else openScoreAt(index)
def incrementAt(index:Int) =
if(isStrike(index)) 1 else 2
def isMark(index:Int) =
isStrike(index) || isSpare(index)
def isStrike(index:Int) =
valueAt(index) == 10
def markScoreAt(index:Int) =
sumNext(index, 3)
def isSpare(index:Int) =
openScoreAt(index) == 10 && valueAt(index) != 10
def openScoreAt(index:Int) =
sumNext(index, 2)
def sumNext(index:Int, count:Int) =
(0 /: (index until index+count))(_ + valueAt(_))
def valueAt(index:Int) =
if(rolls.length > index) rolls(index) else 0
}Echoes from the Stone Age 84
The echoes from Joel Spolsky’s Duct Tape blog continue to bounce off the blogosphere and twitterverse. Tim Bray and Peter Seibel have both written responses to Joel, me, and each other.
Here are some stray thoughts…
TDD
Anyone who continues to think that TDD slows you down is living in the stone age. Sorry, that’s just the truth. TDD does not slow you down, it speeds you up.
Look, TDD is not my religion, it is one of my disciplines. It’s like dual entry bookkeeping for accountants, or sterile procedure for surgeons. Professionals adopt such disciplines because they understand the theory behind them, and have directly experienced the benefits of using them.
I have experienced the tremendous benefit that TDD has had in my work, and I have observed it in others. I have seen and experienced the way that TDD helps programmers conceive their designs. I have seen and experienced the way it documents their decisions. I have seen and experienced the decouplings imposed by the tests, and I have seen and experienced the fearlessness with which TDDers can change and clean their code.
To be fair, I don’t think TDD is always appropriate. There are situations when I break the discipline and write code before tests. I’ll write about these situations in another blog. However, these situations are few and far between. In general, for me and many others, TDD is a way to go fast, well, and sure.
The upshot of all this is simple. TDD is a professional discipline. TDD works. TDD makes you faster. TDD is not going away. And anyone who has not really tried it, and yet claims that it would slow them down, is simply being willfully ignorant. I don’t care if your name is Don Knuth, Jamie Zawinski, Peter Seibel, or Peter Pan. Give it a real try, and then you have the right to comment.
Let me put this another way. And now I’m talking directly to those who make the claim that TDD would slow them down. Are you really such a good programmer that you don’t need to thoroughly check your work? Can you conceive of a better way to check your work than to express your intent in terms of an executable test? And can you think of a better way to ensure that you can write that test other than to write it first?
If you can, then I want to hear all about it. but I don’t want to hear that you write a few unit tests after the fact. I don’t want to hear that you manually check your code. I don’t want to hear that you do design and therefore don’t need to write tests. Those are all stone-age concepts. I know. I’ve been there.
So there. <grin>
The Design Pattern Religion
Tim Bray said:
My experience suggests that there are few surer ways to doom a big software project than via the Design Patterns religion.
He’s right of course. The Design Patterns religion is a foul bird that ravages teams and cuts down young projects in their prime. But let’s be clear about what that religion is. The Design Patterns religion is the ardent belief that the use of design patterns is good.
Here’s a clue. Design Patterns aren’t good. They also aren’t bad. They just are. Given a particular software design situation, there may be a pattern that fits and is beneficial. There may also be patterns that would be detrimental. It’s quite possible that none of the currently documented patterns are appropriate and that you should close the book and just solve the problem.
Here’s another clue. You don’t use patterns. You don’t apply patterns. Patterns just are. If a particular pattern is appropriate to solve a given problem, then it will be obvious. Indeed it is often so obvious that you don’t realize that the pattern is in place until you are done. You look back at your code and realize: “Oh, that’s a Decorator!”.
So am I saying that Design Patterns are useless?
NO! I want you to read the patterns books. I want you to know those patterns inside and out. If I point at you and say “Visitor” I want you at the board drawing all the different variants of the pattern without hesitation. I want you to get all the names and roles right. I want you to know patterns.
But I don’t want you to use patterns. I don’t want you to believe in patterns. I don’t want you to make patterns into a religion. Rather I want you to be able to recognize them when they appear, and to regularize them in your code so that others can recognize them too.
Design Patterns have a huge benefit. They have names. If you are reading code, and you see the word “Composite”, and if the author took care to regularize the code to the accepted names and roles of the “Composite” pattern, then you will know what that part of the code is doing instantly. And that is powerful!
Minimizing Concurrency.
In my first Duct Tape blog I made the statement:
I found myself annoyed at Joel’s notion that most programmers aren’t smart enough to use templates, design patterns, multi-threading, COM, etc. I don’t think that’s the case. I think that any programmer that’s not smart enough to use tools like that is probably not smart enough to be a programmer period.
Tim responds with:
...multi-threading is part of the problem, not part of the solution; that essentially no application programmer understands threads well enough to avoid deadlocks and races and horrible non-repeatable bugs. And that COM was one of the most colossal piles of crap my profession ever foisted on itself.
Is concurrency really part of the problem? Yes! Concurrency is a really big part of the problem. Indeed, the first rule of concurrency is: DON’T. The second rule is: REALLY, DON’T.
The problem is that some times you have no choice. And in those situations, where you absolutely must use concurrency, you should know it inside and out!
I completely and utterly reject the notion that ignorance is the best defense. I reject that lack of skill can ever be an advantage. So I want you to know concurrency. I want to shout “Dining Philosophers” and have you run to the board without hesitation and show me all the different solutions. If I holler “Deadlock”, I want you to quickly identify the causes and solutions.
Here’s a clue. If you want to avoid using something, know that something cold.
Sudoku
At the end of his blog, Peter jumps on the pile of bodies already crushing Ron Jeffries regarding the Sudoku problem from July of 2006.
I find the pile-up disturbing. Ron had the courage to fail in public. Indeed he announced up front that he might “crash and burn”. And yet he got lambasted for it by people who hid behind someone else’s work. The responses to Ron’s tutorial blogs were completely unfair because the authors of those blogs had everything worked out for them by Dr. Peter Norvig before they published their screeds. They were comparing apples to oranges because their responses were about the solution whereas Ron’s blogs were about the process.
Which one of us has not gone down a rat-hole when hunting for a solution to a complex problem? Let that person write the first blog. Everyone else ought to be a bit more humble.
Do the people on the pile think that Ron is unable to solve the Sudoku problem? (Some have said as much.) Then they don’t know Ron very well. Ron could code them all under the table with one hand tied behind his back.
Personal issues aside, I find the discussion fascinating in it’s own right. Ron had attempted to solve the Sudoku problem by gaining insight into that problem through the process of coding intermediate solutions. This is a common enough TDD approach. Indeed, the Bowling Game and the Prime Factors Kata are both examples where this approach can work reasonably well.
This approach follows the advice of no less than Grady Booch who (quoting Heinlein) said: “when faced with a problem you do not understand, do any part of it you do understand, then look at it again.“
Ron was attempting to use TDD to probe into the problem to see if he could gain any insight. This technique often bears fruit. Sometimes it does not.
Here is a classic example. Imagine you were going to write a sort algorithm test first:
- Test 1: Sort an empty array. Solution: Return the input array.
- Test 2: Sort an array with one element. Solution: Return the input array.
- Test 3: Sort an array with two elements. Solution: Compare the two elements and swap if out of order. Return the result.
- Test 4: Sort an array with three elements. Solution: Compare the first two and swap if out of order. Compare the second two and swap if out of order. Compare the first two again and swap if out of order. Return the result.
- Test 5: Sort an array with four elements. Solution: Put the compare and swap operations into a nested loop. Return the result.
The end result is a bubble sort. The algorithm virtually self assembles. If you had never heard of a bubble sort before, this simple set of tests would have driven you to implement it naturally.
Problems like Bowling, Prime Factors, and Bubble Sort hold out the interesting promise that TDD may be a way to derive algorithmms from first principles!
On the other hand, what set of tests would drive you to implement a QuickSort? There are none that I know of. QuickSort and Sudoku may require a serious amount of introspection and concentrated thought before the solution is apparent. They may belong to a class of algorithms that do not self-assemble like Bowling, Prime Factors, and Bubble Sort.
This blog by Kurt Christensen provides all the links to the various Sudoku articles, and sums it up this way.
TDD may not be the best tool for inventing new algorithms, it may very well be the best tool for applying those algorithms to the problem at hand.
Actually I think TDD is a good way to find out if an algorithm will self-assemble or not. It usually doesn’t take a lot of time to figure out which it’s going to be.
Scala Bowling Kata - somewhere in the middle... 9
- Installed the Eclipse Scala Plugin
- Installed Scala using Mac Ports
- Figured out how to get those things playing nice (the plugin page pretty much did that, but in a nutshell, add a few jar files to the classpath)
- We don’t need YADT – Yet another damn term
- Trait is a heavily overloaded word
- I like the term BDD better and it fits.
Anyway, one such choice was Specs, which is what I decided to use.
So back to yak shaving:- I added another jar to my classpath in Eclipse
- Then read how to get it running in Eclipse. Not too bad, I suppose.
So now I need to learn Scala. Sure, I’ve used it, but far less than Ruby. So it took me several hours to get specs running along with writing some Scala code to score a game – I’m glad I know the domain at least.
I wanted to make similar behaviors to the ones I wrote for the Ruby version, which I did.
However, unlike the Ruby version, I was curious what would happen if I:- Took an approach similar to Uncle Bob – strikes take one slot in an array
- Added input validation
On the one hand, there are some interesting things I managed to create. On the other hand, I’ve got a bit of a mess. I have a stateful object to avoid passing parameters so that I can write some of the code cleanly. I know I need to add in an intermediate computational object, and I’m going to get to that. However, I wanted to get feedback on what I’ve put out there so far.
Specifically,- What do you think of the (bdd-style) examples from specc?
- What is the correct way to write the Times(20).Do( ...) thing I came up with, there has be a better way?
- For the part of the bowling scoring code that is not stateful (read this as, does not violate the SRP), what do you think of it?
- How would you remove most/all of the state (other than the individual rolls) out of the Bowling scorer class? (Or would you choose to have the roll() method return a new instance of BowlingScorer with the new score recorded?)
- Notice that the class maintains a mini state machine in the form of tracking whether the first ball of he current frame (not tracked) has or has not been thrown. That’s only there to be able to perform input validation. I considered:
- Walking the array
- Going to 2 slots for every frame (making it easy to find the frame)
- Storing a frame object (ok, I didn’t really consider it, but I did think about it)
- The mini state machine
- nextFrameScore uses the index instance variable, and changes it. This both violates command-query separation and demonstrates a violation of the SRP, but it made the scoreAt method look nice.
An interesting side effect is that scoring marks (strikes and spares) uses the same approach, sum up three rolls total.
I know this needs work. What I’ve got works according to its current specification (its examples), so in a sense, that’s a good thing because I’ve already stared experimenting with trying out different solutions. However, I am painfully aware of how unaware I am of Scala at the moment, so your (hopefully gentle) feedback will tell me what I need to learn next.
Looking forward to the virtual beating …
Brett
Here are the two files I’ve created so far (and to be clear, all of the examples pass): BowlingScorerExampleGroup.scalapackage com.om.example
import org.specs._
object BowlingScorerExampleGroup extends SpecificationWithJUnit {
var scorer = new BowlingScorer();
def roll(value:Int) {
scorer.roll(value)
}
def rollMany(rolls:Int, value:Int) {
0.until(rolls).foreach { arg => scorer.roll(value) }
}
def haveAScoreOf(expected:Int) {
scorer.score must_== expected
}
def strike {
roll(10)
}
def spare {
rollMany(2, 5)
}
abstract class IDo {
def Do(block: => Unit)
}
def Times(count:Int): IDo = {
return new IDo {
def Do(block: => Unit) {
1.to(count).foreach( arg => block )
}
}
}
"A Newly Created Bowling Scorer" should {
haveAScoreOf(0)
}
"A game with all 0's" should {
Times(20).Do( roll(0) )
haveAScoreOf(0)
}
"A game with all 1's" should {
Times(20).Do { roll(1) }
haveAScoreOf(20)
}
"A game with a single spare followed by a 5" should {
spare
roll(5)
haveAScoreOf(20)
}
"A game with all 5's" should {
Times(10).Do( spare )
roll(5)
haveAScoreOf(150)
}
"A game with a single strike followed by a 4" should {
strike
roll(4)
haveAScoreOf(18)
}
"A game with a strike, spare then an open frame with two 3's" should {
strike
spare
Times(2).Do( roll(3) )
haveAScoreOf(39)
}
"A game with strike, spare then an open frame with two 3's" should {
spare
strike
Times(2).Do( roll(3) )
haveAScoreOf(42)
}
"A Dutch 200 game, Spare-Strike" should {
Times(5).Do {
spare
strike
}
spare
haveAScoreOf(200)
}
"A Dutch 200 game, Strike-Spare" should {
Times(5).Do {
strike
spare
}
strike
haveAScoreOf(200)
}
"A Perfect game" should {
Times(12).Do( strike )
haveAScoreOf(300)
}
"The score for each frame of a Perfect game, each frame" should {
Times(12).Do( strike )
1.to(10).foreach{ frame => scorer.scoreAt(frame) must_== 30 * frame }
}
"An individaul roll of > 10" should {
roll(11) must throwA[IllegalArgumentException]
}
"An iniviaul roll of < 0" should {
roll(-1) must throwA[IllegalArgumentException]
}
"A frame trying to contain more than 10 pins" should {
roll(8)
roll(3) must throwA[IllegalArgumentException]
}
}BowlingScorer.scala
package com.om.example
class BowlingScorer {
var rolls:Array[Int] = Array()
var index:Int = 0
var firstBallInFrameThrown: Boolean = false;
def roll(roll:Int) = {
validate(roll)
record(roll)
}
def validate(roll:Int) {
if((0).to(10).contains(roll) == false)
throw new IllegalArgumentException("Individaul rolls must be from 0 .. 10")
if(openScoreAt(indexToValidate) + roll > 10)
throw new IllegalArgumentException("Total of rolls for frame must not exceed 10");
}
def record(roll: Int) {
rolls = rolls ++ Array(roll)
firstBallInFrameThrown = firstBallInFrameThrown == false && roll != 10
}
def indexToValidate = {
if(firstBallInFrameThrown) rolls.length - 1 else rolls.length
}
def scoreAt(frame:Int) = {
1.to(frame).foldLeft(0) { (total, frame) => total + nextFrameScore }
}
def score = {
scoreAt(10)
}
def nextFrameScore = {
var result = 0;
if(isStrike(index)) {
result += markScoreAt(index)
index += 1
} else if(isSpare(index)) {
result += markScoreAt(index);
index += 2
} else {
result += openScoreAt(index);
index += 2
}
result
}
def isStrike(index:Int) = {
valueAt(index) == 10
}
def markScoreAt(index:Int) = {
sumNext(index, 3)
}
def isSpare(index:Int) = {
openScoreAt(index) == 10
}
def openScoreAt(index:Int) = {
sumNext(index, 2)
}
def sumNext(index:Int, count:Int) = {
index.until(index+count).foldLeft(0)(_ + valueAt(_))
}
def valueAt(index:Int) = {
if(rolls.length > index) rolls.apply(index) else 0
}
}Bowling Game Kata in Ruby 15
I have not really used Ruby much. I’ve written a few tutorials, messed around with RSpec and Test::Unit and even Rails a bit, but I really don’t know Ruby that well. I get Ruby (the MOP, instances, blocks, open classes, ...) but there’s a difference between understanding that stuff and using it day-to-day.
Last night we had a Dojo in Oklahoma City and I wanted to get refreshed with RSpec, so I decided to jump in and do the bowling game kata. I did not follow uncle bob’s lead exactly. For one, I went ahead and stored two throws for each frame. While what he ends up with is a bit shorter, it bothers me a little bit. I’ve also seen people surprised by how bob stores his scores, so in a sense it violates the law of least astonishment.
That’s neither here nor there, I got it working just fine – though handling strikes was a bit more difficult because I decided to store two rolls instead of one (so clearly, there’s no best answer, just ones that suck for different reasons).
After my first go around, I had a single spec with examples all under a single describe (what’s that term they’d use for what the describe expression creates?). I added several examples for partial scores, to make sure I was handling incomplete games correctly. I restructured those a bit and tried to make the names a bit more clear, not sure if I was successful.
In my original version I started with a frame in the score method as a local variable, but it quickly got converted to an index, and the index was mostly passed around after that. The approach was very c-esque. I didn’t like that index all over the place, so I tried to remove it by refactoring. It took several false starts before I bit the bullet and simply duplicated each of the methods, one at a time, using parallel development. The old version using an index, the new one use a 1-based frame number. After I got that working with frames, I removed most of the methods using an index, except for a few.
What follows is the spec file and the ruby class. If you read the names of some of the examples, you might think I used to bowl in league, I did. My average was a paltry 158, my best game ever a 248. Best split I ever picked up? 4, 6, 7, 10.
Comments welcome.
bowling_score_card_spec.rb
require 'bowling_score_card'
describe BowlingScoreCard do
before(:each) do
@bowling_game_scorer = BowlingScoreCard.new
end
def roll value
@bowling_game_scorer.roll value
end
def roll_many count, value
count.times { roll value }
end
def score_should_be value
@bowling_game_scorer.score.should == value
end
it 'should score 0' do
score_should_be 0
end
describe 'Scores for Complete Games' do
it 'should score 0 for an all gutter game' do
roll_many 20, 0
score_should_be 0
end
it 'should show 20 for an all 1 game' do
roll_many 20, 1
score_should_be 20
end
it 'should score game with single spare correctly' do
roll_many 3, 5
roll_many 17, 0
score_should_be 20
end
it 'should score game with single strike correctly' do
roll 10
roll 5
roll 2
roll_many 17, 0
score_should_be 24
end
it 'should score a dutch-200, spare-strike, correclty' do
10.times do
roll_many 2, 5
roll 10
end
roll_many 2, 5
score_should_be 200
end
it 'should score a dutch-200, strike-spare, correctly' do
10.times do
roll 10
roll_many 2, 5
end
roll 10
score_should_be 200
end
it "should score all 5's game as 150" do
roll_many 21, 5
score_should_be 150
end
it 'should score a perfect game correctly' do
roll_many 12, 10
score_should_be 300
end
it 'should not count a 0, 10 roll as a strike' do
roll 0
roll 10
roll_many 18, 1
score_should_be 29
end
end
describe 'Scoring for open games' do
it 'should score just an open frame' do
roll 4
roll 3
score_should_be 7
end
it 'should score just a spare' do
roll_many 2, 5
score_should_be 10
end
it 'should score partial game with spare and following frame only' do
roll_many 3, 5
score_should_be 20
end
it 'should score an opening turkey correctly' do
roll_many 3, 10
score_should_be 60
end
end
describe 'Scoring open game starting with a srike' do
before(:each) do
roll 10
end
it 'should score partial game with only strike' do
score_should_be 10
end
it 'should score partial game with strike and half-open frame' do
roll 4
score_should_be 18
end
it 'should score partial game with strike and open frame' do
roll 3
roll 6
score_should_be 28
end
it 'should score partial game with strike and spare' do
roll 3
roll 7
score_should_be 30
end
end
describe 'Open game starting with two Strikes' do
before(:each) do
roll 10
roll 10
end
it 'should have a score of 30' do
score_should_be 30
end
it 'should score correctly with following non-mark' do
roll 4
score_should_be 42
end
it 'should score correclty with third frame open' do
roll 4
roll 3
score_should_be 48
end
end
endbowling_score_card.rb
class BowlingScoreCard
def initialize
@rolls = []
end
def roll value
@rolls << value
@rolls << 0 if first_throw_is_strike?
end
def score
(1..10).inject(0) { |score, frame| score += score_for frame }
end
def score_for frame
return strike_score_for frame if is_strike_at? frame
return spare_score_for frame if is_spare_at? frame
open_score_for frame
end
def first_throw_is_strike?
is_first_throw_in_frame? && @rolls.last == 10
end
def is_first_throw_in_frame?
@rolls.length.odd?
end
def open_score_for frame
first_throw_for(frame) + second_throw_for(frame);
end
def spare_score_for frame
open_score_for(frame) + first_throw_for(next_frame(frame))
end
def strike_score_for frame
score = open_score_for(frame) + open_score_for(next_frame(frame))
if is_strike_at? next_frame(frame)
score += first_throw_for(next_frame(next_frame(frame)))
end
score
end
def next_frame frame
frame + 1
end
def is_spare_at? frame
(open_score_for frame) == 10 && is_strike_at?(frame) == false
end
def is_strike_at? frame
first_throw_for(frame) == 10
end
def first_throw_for frame
score_at_throw(index_for(frame))
end
def second_throw_for frame
score_at_throw(index_for(frame) + 1)
end
def index_for frame
(frame - 1) * 2
end
def score_at_throw index
@rolls.length > index ? @rolls[index] : 0
end
endAs the tests get more specific, the code gets more generic. 10
I tweeted this not too long ago. The basic idea is that as you add tests, the tests get more and more specific. This makes sense since tests are, after all, specifications. The more specifications you have, the more specific the whole body of specifications becomes.
As a general rule, good design dictates that the more specific your requirements become, the more general your code needs to be. This is saying roughly the same thing as Greenspun’s Tenth Rule of Programming: “Any sufficiently complicated [...] program contains an ad hoc informally-specified bug-ridden slow implementation of half of Common Lisp.” Or rather, as more and more constraints pile upon a program, the designers look for ways to push those constraints out of the program itself and into the data.
In return for my tweet people asked for examples.
One of the better examples (though perhaps a bit trivial) is the Prime Factors Kata. This lovely little experiment grows and grows as you add test cases, and then suddenly collapses into an elegant three line algorithm.
The tests continue to become ever more specific. The production code starts out just as specific as the tests. But with the second or third test the programmer must make a decision. He can write the production code to mirror the tests (i.e. writing it as an if/else statement that detects which test is running and supplying the expected answer) or he can come up with some kind of more general algorithm that satisfies the tests without looking anything like them.
The algorithm grows and warps and twists; and then, just when it looks like it’s destined to become a wretched mess; it simply evaporates into a lovely little three line nested loop.
We see the principle at work in other ways as well. Often the programmers have a whole list of tests that they know must pass. As they write them one by one, they write the production code that satisfies them. Then, as in the Bowling Game Kata the tests start to pass unexpectedly. You were done with the code, and you weren’t aware of it. You continue writing tests, expecting one to fail, but they all pass. The test code grows, but the production code remains the same.
Sometimes this happens in a less surprising way. Sometimes you know that you have implemented an algorithm that will pass all remaining tests, but you write those tests anyway because they are part of the specification
The point is that test code and production code do not grow at the same rate. Indeed, as the application increases in complexity, the test code grows at a rate that is faster than the production code. Sometimes the production code actually shrinks as the test code grows because the programmers moved a load of functionality out of the code and into the data.
Consider FitNesse. A year ago there were 45,000 lines of code, of which 15,000 were tests, so 33% of the total were tests.
Now Fitnesse is 58,000 lines of code of which 26,000 are tests. We added 13,000 lines of code overall, but 8,000 (61%), are tests! The tests have grown to over 44% of the total.
Uncle Bob, JSPS: Learning Clojure 33
(JSPS: Just Some Poor Schmuck)
I’m trying to learn Clojure, and I’m finding the effort challenging. Perhaps you can help me.
Programming in Clojure (A derivative of Lisp) requires a certain “inside-out” thinking. I’m finding the combination of the shift in thought process and TDD quite difficult to resolve. So I thought I’d ask for your help.
Below is the Bowling Game written in Clojure complete with unit tests. I’m not at all pleased with the result. The tests, especially, look bizzare and backwards to me.
Please post your own solutions to this so that we can all compare and contrast them.
Tests
(ns bowling-game)
(use 'clojure.contrib.test-is)
(use 'bowling-game)
(defn roll-list [game list]
(if (empty? list)
game
(roll-list (roll game (first list)) (rest list))
))
(defn roll-many [game n pins]
(loop [i n g game]
(if (zero? i)
g
(recur (dec i) (roll g pins)))))
(defn gutter-game [game] (roll-many game 20 0))
(deftest can-create-game
(is (not (nil? (new-game)))))
(deftest gutter-game-should-score-0
(is (= 0 (score (gutter-game (new-game))))))
(deftest all-ones-should-score-20
(is (= 20 (score (roll-many (new-game) 20 1)))))
(deftest one-spare
(is (= 16 (score
(roll-many
(roll-list (new-game) [5 5 3])
17 0)))))
(deftest one_strike
(is (= 24 (score
(roll-many
(roll-list (new-game) [10 3 4])
16 0)))))
(deftest perfect-game
(is (= 300 (score (roll-many (new-game) 12 10)))))
(run-tests 'bowling-game)
Code
(ns bowling-game)
(defn new-game [] [])
(defn next-two-balls [rolls]
(+ (rolls 0) (rolls 1)))
(defn score-strike [rolls]
[1 (+ 10 (+ (rolls 1) (rolls 2)))])
(defn score-spare [rolls]
[2 (+ 10 (rolls 2))])
(defn score-no-mark [rolls]
[2 (next-two-balls rolls)])
(defn score-next-frame [rolls]
(if (= 10 (first rolls))
(score-strike rolls)
(if (= 10 (next-two-balls rolls))
(score-spare rolls)
(score-no-mark rolls))))
(defn score [game]
(loop [frame 1 rolls game score 0]
(if (> frame 10)
score
(let [frame-score (score-next-frame rolls)]
(recur (inc frame) (subvec rolls (frame-score 0)) (+ score (frame-score 1)))))))
(defn roll [game pins]
(conj game pins))
What's your favorite Kata? 15
I’m looking to collect several katas for the OkC CoCo Dojo to make sure we have plenty of future practice sessions already in place. Ultimately I want it to be at least bi-weekly (or weekly) and self sustaining. Along those lines, I’d like to hear what are your favorite katas.
I’d prefer you mention things you’ve tried yourself. Please post links and your impressions in response to the blog. I’ll collect them here, and let me know if you’d like me to credit you with pointing me to the idea (or for the idea itself if you created it).
FWIW, after a little thinking, my favorite kata based on the number of times I’ve used it in one manner or another is Monopoly®.
Older posts: 1 2
