Friday, February 4, 2011
This Blog has Moved.
Thursday, February 3, 2011
FLASH: TPP
Flash Cards: T-P Premise
I read a nice blog today exploring the Transformation Priority Premise using the flash card kata. The author did it in both lisp and C#. Let’s try it in Java.
The flash card kata is pretty straightforward. Given a set of questions and answers, ask the user each question and solicit an answer. If the answer is correct, say so and count it. If the answer is wrong show the correct answer and count the error. At the end, print the number of right and wrong answers.
The first test is wonderfully simple. Given an empty list of questions and answers, end the game immediately with a summary showing nothing right and nothing wrong.
We begin with an empty test which passes:
public class flashCardTest { @Test public void degenerateGame() throws Exception { } }
We get the test to fail by asserting the answer we want and by doing a couple of ({}–>nil) transforms. (In this case -1 is the integer equivalent of nil, e.g. a degenerate value)
public class FlashCardTest { @Test public void rightAndWrongShouldBeZeroIfGamePlayedWithNoCards() { List emptyList = new ArrayList(); playGame(emptyList); assertEquals(0, rightAnswers()); assertEquals(0, wrongAnswers()); } private int wrongAnswers() { return -1; } private int rightAnswers() { return -1; } private void playGame(List flashCards) { } }
To get this to pass just need to do some (nil->constant) transforms.
private int wrongAnswers() { return 0; } private int rightAnswers() { return 0; }
This solution is a bit ugly since it couples the test and the solution. So let’s refactor to create a class.
public class FlashCardTest { @Test public void rightAndWrongShouldBeZeroIfGamePlayedWithNoCards() { FlashCardGame flashCardGame = new FlashCardGame(); List emptyList = new ArrayList(); flashCardGame.playGame(emptyList); assertEquals(0, flashCardGame.rightAnswers()); assertEquals(0, flashCardGame.wrongAnswers()); } }
public class FlashCardGame { public FlashCardGame() { } int wrongAnswers() { return 0; } int rightAnswers() { return 0; } void playGame(List flashCards) { } }
For the next test, lets try a game with a single flash card, that the user gets right.
@Test public void rightShouldBeOneIfOneRightAnswer() { FlashCard card = new FlashCard("Q", "A"); List cards = new ArrayList(); cards.add(card); flashCardGame.playGame(cards); assertEquals(1, flashCardGame.rightAnswers()); assertEquals(0, flashCardGame.wrongAnswers()); }
This fails of course. We can make it pass by simply incrementing the right count in playGame
if the list of cards is not zero. This is a (unconditional->if) transform. That, plus a little refactoring gives us:
public class FlashCardGame { private int rightAnswers; public FlashCardGame() { } int getWrongAnswers() { return 0; } int getRightAnswers() { return rightAnswers; } void playGame(List flashCards, FlashCardTest answerer) { if (flashCards.size() != 0) rightAnswers++; } }
OK, so let’s try a wrong answer.
@Test public void wrongShouldBeOneIfOneWrongAnswer() { FlashCard card = new FlashCard("QW", "A"); List cards = new ArrayList(); cards.add(card); flashCardGame.playGame(cards); assertEquals(0, flashCardGame.getRightAnswers()); assertEquals(1, flashCardGame.getWrongAnswers()); } public String answerQuestion(String question) { if (question.equals("QR")) return "A"; else return "W"; }
This forced us to create the answerQuestion
function that pretends to be a user answering questions. If you pass in “QR” you get the right answer “A”. If you pass in “QW” you get the wrong answer “W”. To get this test to pass we’re going to have to get this function called by playGame
. We can do this by passing the test along in an argument using the Change Signature refactoring. Then we can use a (unconditional->if) transform to check the value of our new function.
public class FlashCardGame { private int rightAnswers; private int wrongAnswers; public FlashCardGame() { } int getWrongAnswers() { return wrongAnswers; } int getRightAnswers() { return rightAnswers; } void playGame(List flashCards, FlashCardTest answerer) { if (flashCards.size() != 0) { String question = flashCards.get(0).getQuestion(); if (answerer.answerQuestion(question).equals("A")) rightAnswers++; else wrongAnswers++; } } }
Of course this is hideous, so we need to refactor alot.
public interface User { String answerQuestion(String question); } ---- public class MockUser implements User { public MockUser() { } public String answerQuestion(String question) { if (question.equals("QR")) return "A"; else return "W"; } } ---- public class FlashCardGame { private int rightAnswers; private int wrongAnswers; public FlashCardGame() { } int getWrongAnswers() { return wrongAnswers; } int getRightAnswers() { return rightAnswers; } void playGame(List flashCards, User user) { if (flashCards.size() != 0) { String question = flashCards.get(0).getQuestion(); String answer = user.answerQuestion(question); if (answer.equals("A")) rightAnswers++; else wrongAnswers++; } } } ---- public class FlashCardTest { private FlashCardGame flashCardGame; private MockUser user = new MockUser(); @Before public void setUp() throws Exception { flashCardGame = new FlashCardGame(); user = new MockUser(); } @Test public void rightAndWrongShouldBeZeroIfGamePlayedWithNoCards() { List emptyList = new ArrayList(); flashCardGame.playGame(emptyList, user); assertEquals(0, flashCardGame.getRightAnswers()); assertEquals(0, flashCardGame.getWrongAnswers()); } @Test public void rightShouldBeOneIfOneRightAnswer() { FlashCard card = new FlashCard("QR", "A"); List cards = new ArrayList(); cards.add(card); flashCardGame.playGame(cards, user); assertEquals(1, flashCardGame.getRightAnswers()); assertEquals(0, flashCardGame.getWrongAnswers()); } @Test public void wrongShouldBeOneIfOneWrongAnswer() { FlashCard card = new FlashCard("QW", "A"); List cards = new ArrayList(); cards.add(card); flashCardGame.playGame(cards, user); assertEquals(0, flashCardGame.getRightAnswers()); assertEquals(1, flashCardGame.getWrongAnswers()); } }
Now let’s do two questions, one right and one wrong.
@Test public void countBothOneRightAndOneWrong() { List cards = new ArrayList(); cards.add(new FlashCard("QW", "A")); cards.add(new FlashCard("QR", "A")); flashCardGame.playGame(cards, user); assertEquals(1, flashCardGame.getRightAnswers()); assertEquals(1, flashCardGame.getWrongAnswers()); }
This fails, but we can make it pass with a (if->while) transform.
void playGame(List flashCards, User user) { for (FlashCard card : flashCards) { String question = card.getQuestion(); String answer = user.answerQuestion(question); if (answer.equals("A")) rightAnswers++; else wrongAnswers++; } }
One thing left. We need to actually compare the answer in the flashcard to the response from the user.
@Test public void countThreeNewQuestionsTwoRightOneWrong() { List cards = new ArrayList(); cards.add(new FlashCard("Q1", "1")); cards.add(new FlashCard("Q2", "2")); cards.add(new FlashCard("Q3", "wrong")); flashCardGame.playGame(cards, user); assertEquals(2, flashCardGame.getRightAnswers()); assertEquals(1, flashCardGame.getWrongAnswers()); }
We need to make a small change to the Mock.
public class MockUser implements User { public String answerQuestion(String question) { if (question.equals("QR")) return "A"; else { return question.substring(1); } } }
And now we can make this pass with a simple (expression->function) transform.
void playGame(List flashCards, User user) { for (FlashCard card : flashCards) { String question = card.getQuestion(); String answer = user.answerQuestion(question); if (answer.equals(card.getAnswer())) rightAnswers++; else wrongAnswers++; } }
There’s more to do, of course, but the plumbing is all set up, and the algorithm looks right. There were several cases where we could have used a lower transform such as (variable->assignment) but there was no need, and the algorithm came out nicely.
There is just the slightest chance that the one use of (if->while) could have been done with (statement->tail-recursion), but since this is Java, that’s probably not the best choice.
Wednesday, February 2, 2011
Fib: The T-P Premise.
Guilherme Silveira wrote a lovely blog exploring the Transformation Priority Premise using the Fibonacci sequence. He posed a suite of tests similar to these:
@Test public void fibTest() throws Exception { assertEquals(0, of(0)); assertEquals(1, of(1)); assertEquals(1, of(2)); assertEquals(2, of(3)); assertEquals(3, of(4)); assertEquals(5, of(5)); assertEquals(8, of(6)); }
He found that the proposed list of transformations did not lead him to a good solution. At first he found that the transformations led him to a solution like this:
switch(n) { case 0: return 0; case 1: return 1; case 2: return 1; case 3: return 2; ... }
Obviously this is the wrong approach, but the priority list presented in my original article did not prevent it. So I’ve added the (case) transformation to the very bottom of the list. This means that using a switch/case or an ‘else if’ is always the last option to choose.
Guilherme went on to rightly ignore the switch/case solution to see if he could get a good solution for fib by following the other priorities. I suggest you read his blog to see how that turned out. Meanwhile, let’s try it here.
The first test leads us to use the ({}–>nil) and then the (nil->constant) transformations:
public class Fibonacci { public static int of(int n) { return 0; } }
The second test forces an (unconditional->if) transformation that we can refactor with a (constant->scalar). This coincidentally makes the third test pass which is always nice.
public static int of(int n) { if (n <=1) return n; return 1; }
The fourth tests is tricky. How can we transform that ‘1’ into something that maps 1->1, 2->1, and 3->2. We know that fib(n) = fib(n-1)+fib(n-2) so we could use recursion to solve the problem. That’s the (statement->recursion) transformation.
public static int of(int n) { if (n <=1) return n; return of(n-1) + of(n-2); }
This makes all the tests pass. Hallelujah! And look how simple that was! What a pretty sight.
Unfortunately there are three things wrong with this pretty solution. First, that algorithm has a horrific runtime complexity of something like O(n2) or worse. Secondly, the algorithm does not use tail-recursion, and so uses a lot of stack space. Thirdly, Java is not a great language for recursion anyway since the JVM simply can’t optimize tail recursion (yet).
It’s a great shame that such a simple expression has so many problems! There are ways to address that, but they are beyond the scope of this article. For now we’ll focus on the three problems mentioned above.
Let’s tackle them one at a time. Is there a transformation that will at least get us to tail recursion? Of course there is, but it was missing from my original list. So I’ve modified that list as follows:
- ({}–>nil) no code at all->code that employs nil
- (nil->constant)
- (constant->constant+) a simple constant to a more complex constant
- (constant->scalar) replacing a constant with a variable or an argument
- (statement->statements) adding more unconditional statements.
- (unconditional->if) splitting the execution path
- (scalar->array)
- (array->container)
- (statement->tail-recursion)
- (if->while)
- (statement->recursion)
- (expression->function) replacing an expression with a function or algorithm
- (variable->assignment) replacing the value of a variable.
- (case) adding a case (or else) to an existing switch or if
So tail recursion is preferred over arbitrary recursion.
Now, can we use tail recursion to tranform this?
public static int of(int n) { if (n <=1) return n; return 1; }
Of course we can. It’s not as pretty as the previous solution, but it captures the same semantics. And it’s not ugly by any means.
public class Fibonacci { public static int of(int n) { if (n <=1) return n; return of(0,1,n); } private static int of(int a, int b, int n) { if (n == 0) return a; return of(b, a+b, n-1); } }
Of course we can clean this up by removing the redundant ‘if’.
public class Fibonacci { public static int of(int n) { return of(0,1,n); } private static int of(int a, int b, int n) { if (n == 0) return a; return of(b, a+b, n-1); } }
But now, how do we deal with the fact that Java doesn’t do well with recursion? If we thought that n would always stay relatively small, we could just ignore it. But let’s assume that ‘n’ will be large; forcing us to unwind the recursion and replace it with iteration. This requires a (if->while) and a few (variable->assignment) transformations.
public class Fibonacci { public static int of(int n) { return of(0,1,n); } private static int of(int a, int b, int n) { while (n != 0) { int s = a+b; a = b; b = s; n--; } return a; } }
The list of priorities prevents this from being the direct outcome of TDD because it prefers the recursive solution. So my list of proposed priorities will necessarily create Java programs that are recursive, and therefore less than optimal for the language.
That makes me think that the priority list is language specific. In Java, for example, we might move (if->while) and (variable->assignment) above (statement->tail-recursion) so that iteration is always preferred above recursion, and assignment is preferred above parameter passing.
This makes sense because Java is not a functional language, and strongly resists a functional style. So any bias towards functional style will lead to suboptimal implementations.
If the priority list is language specific, is it also application specific? Do different problem domains require different priority lists? I strongly doubt this. We are working at a level of detail so far below the problem domain that it is hard for me to see how different problems would require different solution styles.
What about teams? Will teams tweak the priority list to match their styles? I hope not; but I have to say that I think this is not improbable.
I think what this shows us is that the transformations and their priorities are a way to encode a particular programming style. So long as we have different languages and styles, we’ll likely need different transformations and priorities.
On the other hand, if we compare the Java list with the Clojure list (say), the difference is subtle. The recursive transformations would move slightly lower in the list relative to the iterative and assignment transformations. The effect is, of course, profound, but the difference in the lists is actually relatively small. All the other transformations seem to hold their positions.
So the good news is that, although there may be different styles based on language type, the vast majority of the low level coding decisions remain similar irrespective of those styles.
Wednesday, January 19, 2011
Brining Balance to the Force
I read Martin Fowler's contribution to the craftsmanship thread with interest. He spoke of the so-called "crevasse" between developers and customers. He reiterated Dan North's fear that the craftsmanship movement could widen this crevasse.
We are programmers. We need to talk about programming from time to time. We need time and space to focus on our primary discipline: programming. That discussion, and that focus, is a very positive thing. It means we care about what we do. But have we gone too far? Are we too technical? Is the Software Craftsmanship movement a movement only about techical practice and details? Have we forgotten the customer?
The Software Craftsmanship Manifesto's fourth statement: "We value not only customer collaboration but also productive partnerships" should be enough to quell those fears. Software Craftsmanship is a movement dedicated to partnering with customers. That means taking on the customer's problems as our own. That means putting ourselves in the position of our customers. Their pain becomes our pain, their problems our problems, their victories, our victories. That's craftsmanship! That's what we want. We want to be able to do our job with professionalism and skill, and to partner with our customers to achieve the best possible outcomes.
Software Craftsmanship is not, as Martin said: "A place where programming can be front and central again." It is not a movement that "underplays the vital role of customer communication". After all, those of us in the Software Craftsmanship movement have not abandoned Agile. We still read the Agile papers. We still follow the Agile threads. We still go to the Agile conferences. We are still part of the Agile community. So we are steeped in "the vial role of customer communication." So much so that we amplified that role to one of partnership.
No, the Software Craftmanship movement is not overplaying the technical role; rather it is trying to recapture the balance that the Agile movement has lost.
Martin made an amazing point about this in his article. He said that the craftsmanship movement was spawned as a reaction to the rise of non-programming topics within agile. I completely agree. Indeed, I made exactly that point just a week ago while attending an Agile Coach Camp in Norway. I, for one, consider the agile movement to have been inundated by a vocal and enthusiastic cohort of project managers, waving their scrum-master certificates, or their Lean and Kanban books. They have overwhelmed the original movement and changed it into something new. Agile is no longer about a balance between the technical and non-technical parts of development. Rather it has become a discussion almost entirely dedicated to non-technical issues. Agile is no longer about healing the divide, or closing the crevasse. The agile movement now represents one side of the crevasse.
The argument has been made that the technical issues are the simple part. That the real hard parts of software development are the people issues. So therefore we should focus on the people issues, on the customers and employers, and keep quiet about the technical stuff. If we talk too loudly about the technical stuff, then the customers may feel that we're not paying due attention to them.
Bollocks! Bollocks I say! Yes, the people part is hard. The people part is complicated. The people part needs lots of work. We should be talking a lot about the people part. But anybody who thinks the technical stuff isn't just as hard, and just as worthy of conversation, is misguided. We need both. And we need both sides to listen to each other and to trust each other. We need balance!
The imbalance is the crevasse! One side thinks their issues are more important that the other's. One side thinks their issues should dominate. And when the other side tries to talk about their issues, they are told to shush because they might alienate the other side and "widen the crevasse".
But neither side is more important than the other. Neither side should dominate. Neither side's issues should be toned down. Neither side should be told to shush for fear of what the other side might say. The only way to bring the crevasse together is to realize that both sides need each other, and need each other to be skilled and professional. Each side should be glad that the other is talking about their own issues. And each side should be willing to listen to the other side's issues. Each side must respect the other side's desire to increase their skill and professionalism. If we do that enough, maybe we'll realize that there's actually only one side.
So the next time you see some programmers talking about code retreats or koans or katas or TDD or some other deeply techincal topic, congratulate them for giving due dilligence to their practice. The next time you see an agile coach talking about Kanban, or Lean, or Iteration length, or story points, congratulate them for their dedication to their discipline. Remember, these are your team-mates. You want them to be able to play their positions with skill and professionalism. You want them to be good at their jobs. And, if you want them to repect your role, you must first respect theirs.
Monday, January 17, 2011
Software Craftsmanship: What it's all about.
I've gone from Dan North's post, to Gil Zilberfeld's to Michael Feather's to Jason Gorman's and back. And I'm at a loss.
Why is there a software craftsmanship movement? What motivated it? What drives it now? One thing; and one thing only.
We are tired of writing crap.
That's it. The fat lady sang. Good nite Gracy. Over and out.
We're tired of writing crap. We are tired of embarrassing ourselves and our employers by delivering lousy software. We have had enough of telling our customers to reboot at midnight. We don't want bug lists that are a thousand pages long. We don't want code that grows more tangled and corrupt with every passing day. We're tired of doing a bad job. We want to start doing a good job.
That's ... what ... this ... is ... about. Nothing else.
What we are not doing:
- We are not putting code at the center of everything.
- We are not turning inward and ignoring the business and the customer.
- We are not inspecting our navels.
- We are not offering cheap certifications.
- We are not forgetting that our job is to delight our customers.
What we will not do anymore:
- We will not make messes in order to meet a schedule.
- We will not accept the stupid old lie about cleaning things up later.
- We will not believe the claim that quick means dirty.
- We will not accept the option to do it wrong.
- We will not allow anyone to force us to behave unprofessionally.
What we will do from now on:
- We will meet our schedules by knowing that the only way to go fast is to go well.
- We will delight our customers by writing the best code we can.
- We will honor our employers by creating the best designs we can.
- We will honor our team by testing everything that can be tested.
- We will be humble enough to write those tests first.
- We will practice so that we become better at our craft.
We will remember what our grandmothers and grandfathers told us:
- Anything worth doing is worth doing well.
- Slow and steady wins the race.
- Measure twice cut once.
- Practice, Practice, Practice.
I suppose that some people might look askance at our code katas and our code retreats, and our practice sessions. They might think that we're turning inwards and abandoning our customers. They might think that we've given up on the real world and have yielded to the temptation to entertain ourselves. I can see how someone might come to that conclusion.
But they are as wrong as the day is long. We are doing this because we care about the customer. We are dedicating time and effort to being the best that we can be so that our employers will get the best possible value out of us.
Do you think the only time musicians play their instruments is when they are on stage? Do you think the only time that batters hit balls is during games? Do you think the only time lawyers give a closing is at trial? Of course not. These people are professionals; and professionals practice! Professionals study the minutia of their disciplines. Professionals know all the little tricks and quirks. They know the history, the theories, the anecdotes. They know techniques and methods. They know good options and bad options and how to tell them apart. And they know all this stuff because they practice, practice practice.
So when you see someone wearing a green wrist-band that says "Clean Code" or "Test First" or "Test Obsessed", it's not because they've joined a movement, or signed a manifesto, or that they somehow feel superior to everyone else. They aren't participants in a holy war. They aren't trying to join a tribe and huddle around a campfire. The green band is a personal thing. It's a promise made to one's self: "I will do a good job. I will not rush. I will write tests. I will go fast by going well. I will not write crap. And I will practice, practice practice so that I can be a professional."