Posted on July 30th, 2006

Sorry I haven’t gotten the last Agile 2006 post up. We’ve just made it back to Missouri after enduring the radiator blowing up in our car (with 2 adults, a 6 week old infant, and our 2 dogs) in Chattanooga, TN. Everything should be caught up by tomorrow night at the latest.

No Comments


Posted on July 28th, 2006

First – I realized that I misnamed the days. So, I’ll just call this “Thursday”.

I decided that, because I hadn’t had a chance to hear him speak yet at this conference, I would head over to Bob Martin’s Clean Code talk first thing. And it’s a good thing I did – the room filled up quickly, and it was worth it. He took a sample program he wrote – and argument parser – and showed how an intial clean, well-tested design fell apart when he tried to scale it. He then showed some tips on how to clean it up.

But most interesting was his follow-up to a discussion he and I had earlier in the conference. We were chatting about Ruby, and he told me that Ruby has the ability to be the next big language to dominate the industry, and that no other language currently holds that distinction for him. He followed that up in this session by saying that Ruby and languages like it will be what dominates the industry in the next 10 years. And from what I’ve seen, I believe it (with apologies to Huey Lewis and the News).

After that session, I went to one entitled Project Status: Writing on the Walls where we got introduced to an interesting way of focusing on delivering value and planning for the same. We were given a stack of cards which had a story, a cost (or estimate), and a value (to the business). Our goal was to deliver as much business value as we could per iteration. What was an iteration?

Well, we had some dice. An iteration consisted of 15 rolls of a die. You would put a card up in the In Progress section, and roll the die until you had enough to cover the cost of the card, at which point you could move it over to the completed section. It was interesting in how much it simulated the real world – simply because sometimes there is a lot of uncertainty. Sure, something seems like a simple table change, until you realize you go through 25 triggers before that value is updated.

After lunc, I headed over to Michael Spayd’s talk on organizational change. He had eight concepts that had to be in place for true organizational change to take place, summarized as:

  1. There must be a burning platform that is driving the organization to change
  2. The vision must be compelling to all stakeholders
  3. Sponsorship must exist at the right level
  4. Put together a change team
  5. Key stakeholders are engaged and influence the change
  6. All stakeholders need the power to make change – with dignity
  7. Organization needs to get aligned around the change
  8. Magic has the time and space to bring about transformation

One other key phrase was No Pain, No Change which has certainly been my experience in organizations. Unless they are feeling the pain of something, they aren’t really interested in changing.

After the last session, I got the chance to talk with Mary Poppendieck about how our organization works with the teams, bonus structures, etc. She directed me to research done in the 80’s about Self-Directed teams (which she said ended up not working), and is something I’ll be taking a closer look at.

We closed out the conference with the banquet. Shuttle astronaut Greg Harbaugh gave the closing keynote with some fascinating discussions about how much astronauts have to deal with change and being flexible on a daily basis. One of the key quotes that I wrote down was:

Adverse consequences for constructive criticism detracts from a team’s caring about the outcome

By the way, The Corey Haines mentioned to me that the orginal space shuttle was developed iteratively. Now, that’s a keeper.

No Comments


Posted on July 26th, 2006

Before we get started, Dave Nicolette asked if I wouldn’t mind posting some of the discussion that came out of the interviewing talk. We had several people in an open space session discussing how they hire agile people. We all agreed that pair programming was an important part. It seemed like pretty much everyone had some sort of resume and phone screen, and then flew the people out. Thoughtworks puts their candidates through a logic test, and then pairs them in, while we do a short team interview and they spend basically the rest of the day pairing on production code, swapping across some of the teams.

We didn’t go very in-depth into things like benefits, compensation, etc, although I do find that a fascinating topic in the context of an agile team, and hope to talk more about that soon.

Now, on to the conference!

Today was the awaited Agile Leadership summit. It started out with an excellent talk by Tim Lister (of Peopleware fame) about the APLN’s Declaration of Interdependence (DoI). H took each of their points and “translated” them into what he thought it meant. Some key points that came out of it were:

  • Don’t adopt techniques. Adapt them. That’s what you are paid to do
  • Allow your team members to be leaders of their own domains
  • Process is what you don’t do naturally

One thing I happened to notice was that in all the talk about agile organizations wanting to rely on teams instead of individuals, there was still talk of individuals, even in the DoI. Tim brought up the point that people don’t throw out wild ideas, they tend to bring 15 slide PowerPoints with the full solution in hand. I asked if perhaps that was because in our culture we don’t value people who are wrong, and in fact create a culture where people are afraid of the repercussions if they are wrong.

Tim’s talk was followed up by Jim Highsmith. He discussed some aspects of agile leadership. His main theme was that our current performance management systems are hurting agile teams, and that we must change that. He laid out several examples of systems in companies to do this, but perhaps the most interesting was Intel and their Business Value Maturity Model and 17 Standard Measures of Value. Seeing an organization respond to value as the primary goal of the business, rather than things like dates or lines of code, was very interesting.

He also was highly critical of the metric collection policies of many organizations. Metrics, he argued, should only be there to provide employees with self-assesment information to allow them to self-correct. It should also really only be there to give you the next set of questions to ask. So, if you are collecting metrics, ask yourself what the next set of questions you should be asking with those numbers are. If you don’t have any, the metrics may not be providing value for you.

I also loved the quote he put up, “Doubt is not a pleasant state, but certainty is a ridiculous one”. The best part was it tied into Mary Poppendieck’s presentation about the History of Lean that was next on the agenda. One of the comments she made was that standards are expected to be constantly changes, and if they have been around for a while, something is wrong.

In fact, Mary’s talk covered a lot of good points. She gave an introduction to the Lean movement, from interchangable parts on guns through the leader of the Totota Lexus division. Some key points there were:

  • “If the learner hasn’t learned, the teacher hasn’t taught”
  • Most variation is inherent in the system
  • If you have requirements churn, you are specifying too early. If you have code-and-fix, you are testing too late
  • 64% of features are never used

One other key point, and one I think our current team is lacking on, is that you can’t fix just a defect. You must take the time to fix the root cause too. I think too many times something caused the bug, and rather than take the time to find out why and correct it – which would make us much faster in the long run, we just correct the immediate problem and continue on. Hopefully we can improve in that aspect.

After Mary’s session, I walked over near OpenSpace and plopped down. Last night I had taken a look at RSpec after the OpenSpace talk on BDD with Dan North. I have to admit that I didn’t like it at first, so I ended up being up till about 3:30 am working on a YAML/DSL based solution that did what I wanted to do. So I decided to work some more on that, since I had already talked to David Chelimsky (he wrote RSpec), and he and I were going to get together later.

So, I decided to put up a sign saying that I wanted a pair on some Ruby code, and 3 people wandered over. Very sharp guys, and we ended up spending about an hour going through some different scenarios and playing with the code. It was great fun, and proof of how great the community is here.

I then wandered over to OpenSpace, where the FIT summit was going on. We all chatted for quite a while about the various problems we had been having, and it seems like they are going to be working to shore back up the FIT/Fitnesse split. A couple of us wandered to the Goooooooogle mixer, and then abot 15 people headed over to Rock Bottom for drinks and dinner. How can you pass up that opportunity, especially with some of the bright people who were there.

David and I then got the chance to sit down with the work I had done earlier, and we discussed what some of the future of RSpec is, and realized that the work I was doing could lead to some interesting things that aren’t the core of RSpec, but fit into the context. It was a great discussion, and I’ll definately be looking more at it (and posting some more on it as soon as I get some of it worked out).

It’s hard to believe tomorrow is already the last day of the conference. Time flies when you are with so many great people. See you tomorrow!

3 Comments


Posted on July 25th, 2006

Today was a tough day with so many good sessions and OpenSpace events going on. After much debated, I started the day off in Todd Little’s Context Driven Agile Leadership. Just before his presentation started, I was talking with a genetleman from a consulting firm out of D.C. who said something interesting: “Anybody can rearrange furniture and have people stand in a circle” targetting who he called “light-weight consultants”.

A lot of Todd’s presentation was data points about his company’s implementation of Agile. It was fairly dry, though he mixed it up with some humorous clips of bull fights and the such. Some key points I pulled out were:

  • Anything more than “barely sufficient” is a waste from a process perspective
  • Don’t look to technology for silver bullets – you’ll more likely find them in people, values, communication and expectation management
  • Mike Cohn’s presentations are really loud

Afterwards, I headed over to OpenSpace. I ended up chatting with the fine folks at ObjectMentor about a vehicle they just purchased and the CARFAX report they got, when Bob Martin walked up behind us. I ended up chatting with him for about 5 minutes (doing a great job of completing misidentifying Dave Thomas as PragDave and looking like an utter fool). But he is a great person, and I got to chat with several of the other ObjectMentor folks, who just seem like an excellent bunch of people.

Bob Martin did say something very interesting. We were discussing Ruby and he said it seemed like it had the ability to be the next big language – like Java or C# or C++ was. When I asked if he thought there were any other languages in the running, he said that as far as he could tell Ruby was the only one he could see. That, folks, is some cool stuff.

Over at OpenSpace we talked about Behaviour Driven Development with the founders Dan North and Chris Matts. It was very enlightning, and Dan talked about estimating scenarios instead of stories. In other words, take your stories, break them into scenarios of implementation, and estimate those. We happen to already do this – except that we just turn the scenarios into individual stories and toss the original card.

Over lunch the CARFAX team got together and chatted for a bit. After lunch, I headed to Mike Cohn’s Agile Estimating and Planning. Mike is an outstanding speaker, and the room gets very loud (which explains my third point from Todd’s talk). He covered the topics of Ideal Hours versus Story points, estimating, and planning poker. Mike developed a playing card deck which contains enough planning poker cards for 4 team members. It was incredibly enlightning, and while I pulled a lot of points out, here is only a sample:

  • I’m the most ignorant today then I ever will be
  • He’s never been asked to estimate a project in number of lines of code (neither have I)
  • The 4 most important words are “Inspect and Adapt” + “Range” (which is what you should give someone when they ask for an estimate

I also enjoyed the exercise of taking the past iterations and calculating the means for the last 8 iterations, the mean of the worst 3 from the same period, and our last iteration, and showing where we can get to in the iteration for each number.

After Mike’s talk we had a social event before the Agile Alliance meeting. After the meeting a group of us got to head out on double-decker buses to a river boat cruise sponsored by NetObjectives and VersionOne, where I won a tres cool Agile 2006 Rugby shirt (even if it is a bit heavy duty), and got some great pictures which I’ll be posting as soon as I can borrow a USB cable.

Tomorrow is the Leadership Summit all day (which is a shame because there are some really good discussions) followed by the Google event and the IBM BoF event on the new Eclipse Process Framework. Until then, have a great night!

1 Comment


Posted on July 24th, 2006

Whew.

This is my first year being able to come to the annual Agile conference. It is definately everything I thought it would be so far, and I’m having a blast. Here’s a recap of some of the more interesting things that have happened over the past 2 days:

Sunday (Day 1):

The day started off flying from Tampa to Minneapolis. Got into the hotel only to find out that they thought I was supposed to check in Saturday, and had promptly cancelled my reservation. They seem to have it worked out, though there was a vague threat that I wouldn’t have a room past Tuesday. We’ll see.

After checking in, I wandered over to a talk by Scott Ambler on the state of Agile. I found it interesting first because I’ve heard a lot of discussion about whether Agile has “Crossed the Chasm”. Which is interesting since Agile is a collection of a lot of practices, each of which are going to apply differently to an organization. But I digress.

Scott’s talk covered a survey he did about the adoption of Agile technologies in organizations. It was pretty interesting, and I am looking forward to downloading the data and looking at it. One of the more notable things was that roughly 1100 respondents were doing XP, but only around 400 were doing Pair Programming. Nice. (Sarcasm intended – since Pair Programming is a fundamental part of XP).

After the talk, the group of us from CARFAX headed over to the pub and talked for a bit, then went back over for the icebreaker event. Lots of fun, including magic tricks, group pictures, Dance Dance Revolution, and the fun task of meeting lots of people in person that for the past 3 years I’ve only ever talked to via email.

Monday (Day 2):

The morning started off with an excellent presentation by Peter Coffee, the technical editor for EWeek. EWeek is an interesting magazine, because I always figured it was just some rehash of the week to gain advertiser dollars. But Peter’s talk was very enlightning, and it was obvious he had some clue as to what was going on. So I guess I’ll have to pay a little more attention to the magazine now.

Peter discussed several books that he always wants on his bookshelf. The four books were Robert Townsend’s “Up the Organization”, John Gall’s “Systemantics”, Tom Peters’ “Thriving on Change”, and, of course, Tom Friedman’s “The World is Flat”. Some choice ideas that came out were:

  • Trying to be like GM by imitating them is like trying to be an opera singer by gaining weight
  • Make proposals that scare people
  • The Japanese word for “large” is literally translated “not delicately crafted”

Afterwards, I wandered over to the Intro to the Agile Manifesto. Yes, I know what the Manifesto is, so why did I go? Because it was given by Jeff Sutherland, Ward Cunningham, Ron Jeffries, and Michael Feathers. I couldn’t pass up the opportunity, and they didn’t disappoint. It was a great look at the practices, even if there was a little battle where the practices were shown in the presenter’s favorite methodology. Some of the key points were:

  • The best devs are 25 times more productive than regular devs, but the best teams are 2098 times more productive
  • 50% of project problems are people problems
  • Refactoring is like applying algebra to a methematical equation to reorganize and make it clearer

We then broke for lunch, during which I attended an OpenSpace session on interviewing agile candidates. I ended up hanging out in OpenSpace for the rest of the time, attending discussions on teams emphasizing efficiency over passion, distributed XP, and something about disciplines and tools.

Afterwards I headed out to dinner with two guys I know from Florida. They are both using Agile in their companies, in some very interesting industries. In fact, I’ve been surprised at some of the companies here – including Shure (the microphone people), Seagate, Hitachi, and other companies who I primarily think of as hardware vendors. I’ll have to see if there is an embedded XP talk, and if not, maybe I’ll propose that there be one next year.

When I got back, I headed over to an excellent OpenSpace discussion on Cutting Edge Technologies for Organizational Change. I am always fascinated by organizations and the inner workings of them, and this was a fun time talking about our experiences with various organizations.

I finished up the night by passing by one guy with a laptop and a sign that said “Please pair with me on Mozilla Code”. We were joined by The Corey Haines and after about an hour we were able to get the test to pass, at which point we were rewarded with extremely nifty Firefox hats. Yay!

That wraps up the first two days of Agile 2006. I have a feeling the week is just going to fly by, and I’ll have to be driving back to Missouri before I know it. If you are at the conference, do keep an eye out and wave if you come across me.

1 Comment


Posted on July 24th, 2006

First, my apologies for the length of time since my last post. I’ve been travelling and haven’t had good access to the internet. I’m at Agile 2006 now and will be posting updates shortly. However, on July 15th, I had the pleasure of speaking at the Tampa Code Camp at the University of South Florida in Tampa, Florida. All in all I got to present 4 sessions, and had a great time.

Perhaps most interesting from this code camp was the reaction to my Test-Driven Development and Ruby/Rails demos. In the TDD sessions, people were highly skeptical of the process we were following – especially writing failing tests with code that wouldn’t even compile! (“What about intellisense?!” was a common cry). However, as we worked through our example, it became clear what TDD was really about, and even some of the people who were shaking their heads the hardest seem to figure out what it was really about.

Another observation is how much vocabulary really plays into explaining concepts to observers. Writing a failing test which we’ll make green seems like quite an esoteric comment. But saying that we are going to write a test which shows that when we write the code we want to, we’ll know it works by them, seemed to come across much better. Don’t get hung up on vocabulary – it’ll bite you quite often if you do.

So, without further ado, here’s the presentations from my Ruby, Fitnesse and TDD talks. The fourth talk was to fill time when a presenter didn’t show up, and so there’s no formal presentation for it, since it was a combination of a code demo and chalk talk.

Thanks so much to the organizers, and especially to those who took a Saturday off to come out and talk about code. I couldn’t have asked for better audiences, or a better time.

5 Comments


Posted on July 10th, 2006

I happened across a thread on the ScrumDevelopment list discussing putting out fires – in other words having time/resources available during iterations for production support that was unforeseen.

Having spent 7 years with on a fire department, the phrase has a special meaning to me. However, I started thinking about the parallels between the production resources needed on a project and fire departments themselves.

Most of the U.S is covered not by paid fire departments, but by volunteers. This means if you have a fire, these people leave their work, their homes, their warm beds and families to drive down to the station, pick up the truck, and head over. Response times can range from 5-30 minutes or more for someone to get there. And for most places, that’s acceptable – when you run 10 calls a year, paying people to sit there is hard to justify.

However, the department I worked in, we had stations that would average 80-90 calls /a day/ between 3 trucks. In this more urban setting, we had no choice but to pay people to be there – there were too many fires to put out, and the fires that did catch could be very costly.

(One of the first fires when I started was a multi-multi million dollar mansion. They were adding on a 3000 sq ft library and the contractor wired something wrong)

So, it would seem to me that the process would be similar on projects. If you have lots of fires to put out, or if the fires are very costly, you take the hit of the cost to pay people to sit just in case. If you are plugging away with very rare production support issues, you handle it as it comes in. I don’t think either way is particularly worse than the other – sometimes you just can’t help production support issues.

No Comments


Posted on July 9th, 2006

(Update: The Game.rb and GameTest.rb files were refactored and can be found here: Game.rb, GameTest.rb)

Over on the XP list, a topic was brought up about types of examples one can use in a Test-Driven Development class. That led to a discussion about a Sudoku Solver.

Sudoku is a game with a 9×9 grid which one has to fill each row, column and square with 1-9 without repeats. (See Daily Sudoku for an example).

Let’s get down to business. The first case we want to solve is a simple puzzle with only one cell not filled. So we start with a class GameTest.rb which looks like:

require 'test/unit'
require 'Game'
class GameTest < Test::Unit::TestCase

def setup
  @expected_solution = [
  3,4,5, 9,8,7, 6,2,1,
  1,9,2, 6,5,4, 3,8,7,
  8,7,6, 3,2,1, 5,4,9,

  5,2,9, 8,1,6, 4,7,3,
  4,3,1, 7,9,2, 8,5,6,
  6,8,7, 5,4,3, 1,9,2,

  2,5,3, 4,6,9, 7,1,8,
  7,1,8, 2,3,5, 9,6,4,
  9,6,4, 1,7,8, 2,3,5]
end

def test_solve_simple_game
  simple_game = [
  0,4,5, 9,8,7, 6,2,1,
  1,9,2, 6,5,4, 3,8,7,
  8,7,6, 3,2,1, 5,4,9,

  5,2,9, 8,1,6, 4,7,3,
  4,3,1, 7,9,2, 8,5,6,
  6,8,7, 5,4,3, 1,9,2,

  2,5,3, 4,6,9, 7,1,8,
  7,1,8, 2,3,5, 9,6,4,
  9,6,4, 1,7,8, 2,3,5]
  game = Game.new(simple_game)
  game.solve()
  assert(game.is_solved?)
  assert_equal(@expected_solution, game.board)
end
end

And a Game.rb of

class Game
attr_reader :board
def initialize(game_board)
  @board = game_board
end

def solve
  @board[0] = 3
end

def is_solved?
  return true
end
end

Which gets our test to pass. So let’s write another one to get us past this:

def test_solve_simple_game2
  simple_game2 = [
  3,4,5, 9,8,7, 6,2,1,
  1,9,2, 6,5,4, 3,8,7,
  8,7,0, 3,2,1, 5,4,9,

  5,2,9, 8,1,6, 4,7,3,
  4,3,1, 7,9,2, 8,5,6,
  6,8,7, 5,4,3, 1,9,2,

  2,5,3, 4,6,9, 7,1,8,
  7,1,8, 2,3,5, 9,6,4,
  9,6,4, 1,7,8, 2,3,5]
  game = Game.new(simple_game2)
  game.solve()
  assert(game.is_solved?)
  assert_equal(@expected_solution, game.board)
end

Ok. So my thought process is that we loop through the cells in the game. When we find an unsolved cell (with value 0), we find out the possible values for the row, column and square that cell is in. I had tried this last night, and ended up with a whole bunch of classes, and some really messy code. I’m going to let simpleness reign as best I can this time. Let’s see if I can!

So, since I want to have squares, rows and columns, I want to build those. I’m going to comment out the above test and get the squares and such working first. The square test is easy enough:

def test_get_square
  game = Game.new(@expected_solution)
  exp_sq = [3,4,5,1,9,2,8,7,6]
  assert_equal(exp_sq, game.get_square(1))
  exp_sq = [9,8,7,6,5,4,3,2,1]
  assert_equal(exp_sq, game.get_square(2))
  exp_sq = [6,2,1,3,8,7,5,4,9]
  assert_equal(exp_sq, game.get_square(3))
  exp_sq = [5,2,9,4,3,1,6,8,7]
  assert_equal(exp_sq, game.get_square(4))
  exp_sq = [8,1,6,7,9,2,5,4,3]
  assert_equal(exp_sq, game.get_square(5))
  exp_sq = [4,7,3,8,5,6,1,9,2]
  assert_equal(exp_sq, game.get_square(6))
  exp_sq = [2,5,3,7,1,8,9,6,4]
  assert_equal(exp_sq, game.get_square(7))
  exp_sq = [4,6,9,2,3,5,1,7,8]
  assert_equal(exp_sq, game.get_square(8))
  exp_sq = [7,1,8,9,6,4,2,3,5]
  assert_equal(exp_sq, game.get_square(9))
end

Ok, so let’s look at this. To get a square, we need to pick out the 9 cells from the array which make it up. In other words, square 1, the upper left-most square, would use cells [0,1,2,9,10,11,18,19,20] from the array. After thinking how I could express this as an algorithm, I realized it would just be easier to do:

def initialize(game_board)
  @board = game_board

  sq1 = [0,1,2,9,10,11,18,19,20]
  sq2 = [3,4,5,12,13,14,21,22,23]
  sq3 = [6,7,8,15,16,17,24,25,26]
  sq4 = [27,28,29,36,37,38,45,46,47]
  sq5 = [30,31,32,39,40,41,48,49,50]
  sq6 = [33,34,35,42,43,44,51,52,53]
  sq7 = [54,55,56,63,64,65,72,73,74]
  sq8 = [57,58,59,66,67,68,75,76,77]
  sq9 = [60,61,62,69,70,71,78,79,80]

  @squares = [sq1,sq2,sq3,sq4,sq5,sq6,sq7,sq8,sq9]

end

and then implement the get_square like

def get_square(sq)
  @squares[sq-1].collect{|i|@board[i]}
end

Sweet. That’s much better than what last night’s solution was. Best of all, our test passes! Let’s move on to rows:

def test_rows
  game_board = [
  3,4,5, 9,8,7, 6,2,1,
  1,9,2, 6,5,4, 3,8,7,
  8,7,6, 3,2,1, 5,4,9,

  5,2,9, 8,1,6, 4,7,3,
  4,3,1, 7,9,2, 8,5,6,
  6,8,7, 5,4,3, 1,9,2,

  2,5,3, 4,6,9, 7,1,8,
  7,1,8, 2,3,5, 9,6,4,
  9,6,4, 1,7,8, 2,3,5]

  (0..80).each do |i|
    val = game_board[i]
    game_board[i] = 0
    game = Game.new(game_board)
    pv = game.get_poss_row_vals(i)
    assert_equal(1, pv.length)
    assert_equal([val], pv)
    game_board[i] = val
    assert_equal(@expected_solution, game_board)
  end
end

Which loops through each cell, changes the value to 0, and asserts that the value is in the possible values list for the row. We make it pass by doing:

def get_poss_row_vals(cell_index)
  if(cell_index < 9)
    cell_index = 0
  else
    cell_index = (cell_index / 9 * 9)
  end

  row_cells = Array.new(9) {|i| cell_index+i}
  used_vals = row_cells.collect{|i| @board[i]}
  return @all_vals - used_vals
end

Which returns all of the non-used values for the given row by collecting all of the current values and then doing an Array Difference from an array of 1-9. We do similar tests for columns and squares:

def test_cols
  game_board = [
  3,4,5, 9,8,7, 6,2,1, #0-8
  1,9,2, 6,5,4, 3,8,7, #9-17
  8,7,6, 3,2,1, 5,4,9, #18-26

  5,2,9, 8,1,6, 4,7,3, #27-35
  4,3,1, 7,9,2, 8,5,6, #36-44
  6,8,7, 5,4,3, 1,9,2, #45-53

  2,5,3, 4,6,9, 7,1,8, #54-62
  7,1,8, 2,3,5, 9,6,4, #63-71
  9,6,4, 1,7,8, 2,3,5] #72-80

  (0..80).each do |i|
  &nbs
p; val = game_board[i]
    game_board[i] = 0
    game = Game.new(game_board)
    pv = game.get_poss_col_vals(i)
    assert_equal(1, pv.length)
    assert_equal([val], pv)
    game_board[i] = val
    assert_equal(@expected_solution, game_board)
  end
end

def test_squares
  game_board = [
  3,4,5, 9,8,7, 6,2,1, #0-8
  1,9,2, 6,5,4, 3,8,7, #9-17
  8,7,6, 3,2,1, 5,4,9, #18-26

  5,2,9, 8,1,6, 4,7,3, #27-35
  4,3,1, 7,9,2, 8,5,6, #36-44
  6,8,7, 5,4,3, 1,9,2, #45-53

  2,5,3, 4,6,9, 7,1,8, #54-62
  7,1,8, 2,3,5, 9,6,4, #63-71
  9,6,4, 1,7,8, 2,3,5] #72-80

  (0..80).each do |i|
    val = game_board[i]
    game_board[i] = 0
    game = Game.new(game_board)
    pv = game.get_poss_sqr_vals(i)
    assert_equal(1, pv.length)
    assert_equal([val], pv)
    game_board[i] = val
    assert_equal(@expected_solution, game_board)
  end
end

and make them pass:

def get_poss_col_vals(cell_index)
  cell_index = cell_index - (cell_index/9*9) unless cell_index < 9
  col_cells = Array.new(9){|i| cell_index + (9*i)}
  used_vals = col_cells.collect{|i| @board[i]}
  return @all_vals - used_vals
end

def get_poss_sqr_vals(cell_index)
  square = nil
  @squares.each {|sq| square = sq unless !sq.member?(cell_index)}
  used_vals = square.collect{|i| @board[i]}
  return @all_vals - used_vals
end

Ok, now, let’s tackle that puzzle test. I uncomment it (which it fails), and work on the solve method. As I mentioned above, I want to go through each cell and get the possible values for the row, column and square it is in. So I modify the solve method to look like:

def solve
  @board.each_index do |cell_index|
    if @board[cell_index] == 0
      sqr_pv = get_poss_sqr_vals(cell_index)
      row_pv = get_poss_row_vals(cell_index)
      col_pv = get_poss_col_vals(cell_index)
      pv = sqr_pv & row_pv & col_pv
      if(pv.length == 1)
        @board[cell_index] = pv[0]
      end
    end
  end
end

and is_solved to

def is_solved?
  return !@board.member?(0)
end

Which let’s our test pass! Let’s try a little more complex version:

def test_solve_complex_game
  complex_game = [
  0,4,5, 9,8,7, 6,2,1,
  1,9,2, 6,5,4, 3,8,7,
  8,7,0, 3,2,1, 5,4,9,

  5,2,9, 8,1,6, 4,7,3,
  4,3,1, 7,9,2, 8,5,6,
  6,8,7, 5,4,3, 1,9,2,

  2,0,3, 4,6,9, 7,1,8,
  7,1,8, 2,3,5, 9,6,4,
  9,6,4, 1,7,8, 2,3,5]

  game = Game.new(complex_game)
  game.solve()
  assert(game.is_solved?)
  assert_equal(@expected_solution, game.board)
end

which also passes. Sweet! Let’s try a harder version – the full puzzle:

def test_real_game
  real_game = [
  3,0,5, 0,8,0, 6,2,0,
  0,0,0, 0,0,0, 0,0,0,
  0,0,0, 3,2,1, 0,4,9,

  5,2,9, 8,0,0, 4,0,0,
  0,0,0, 0,0,0, 0,0,0,
  0,0,7, 0,0,3, 1,9,2,

  2,5,0, 4,6,9, 0,0,0,
  0,0,0, 0,0,0, 0,0,0,
  0,6,4, 0,7,0, 2,0,5]
  game = Game.new(real_game)
  game.solve()
  assert(game.is_solved?)
  assert_equal(@expected_solution, game.board)
end

Which doesn’t pass. Bummer. But I see something. The way I envisoned solve to work was to keep looping so that it could take into account cells that had already been solved. I wrap it in a 100.times do end, but I’m still only getting a partial solve. Let’s pull what we do have out into a test:

def test_get_pv
  partial_solved_game = [
  3,0,5, 0,8,0, 6,2,0,
  0,0,0, 0,0,0, 0,0,0,
  0,0,0, 3,2,1, 0,4,9,

  5,2,9, 8,1,0, 4,0,0,
  0,0,0, 0,0,0, 0,0,0,
  0,0,7, 0,0,3, 1,9,2,

  2,5,0, 4,6,9, 0,0,0,
  0,0,0, 0,0,0, 0,0,0,
  9,6,4, 1,7,8, 2,3,5]
  game = Game.new(partial_solved_game)
  assert_equal([1,3,4,6,7,8], game.get_poss_col_vals(35))
  assert_equal([3,6,7], game.get_poss_row_vals(35))
  assert_equal([3,5,6,7,8], game.get_poss_sqr_vals(35))
end

Aha! So, cell 35 (3 col, 1st row of the 3rd square in the second row) should be 3 – but only because the other two cells in the row can’t be 3. So I guess we need to take those into account. I add some additional asserts to the above test to pull out what I want:

  assert_equal([6,7], game.get_pv_for_row(35))
  assert_equal([1,3,4,6,7,8], game.get_pv_for_col(35))
  assert_equal([3,5,6,7,8], game.get_pv_for_sqr(35))

Which is saying that I want all of the possible values for the cells row, column and square of the current cell that aren’t the current cell. The thought is that I can then take the possible values, do a diff between them and this list, and if only one is remaining, that cell is solved. First things first, let’s get this test to pass:

def get_pv_for_sqr(cell_index)
  square = nil
  @squares.each {|sq| square = sq unless !sq.member?(cell_index)}
  pos_vals = Array.new
  square.each do |i|
    cell = @board[i]
    if cell == 0 && i != cell_index
      sqr_pv = get_poss_sqr_vals(i)
        row_pv = get_poss_row_vals(i)
        col_pv = get_poss_col_vals(i)
        pv = sqr_pv & row_pv & col_pv
        pos_vals = pos_vals | pv
      end
  end
  return pos_vals.sort
end

def get_pv_for_row(cell_index)
  if(cell_index < 9)
    index = 0
  else
    index = (cell_index / 9 * 9)
  end
  pos_vals = Array.new
  row_cells = Array.new(9) {|i| index+i}
  row_cells.each do |i|
    cell = @board[i]
    if cell == 0 && i != cell_index
      sqr_pv = get_poss_sqr_vals(i)
      row_pv = get_poss_row_vals(i)
      col_pv = get_poss_col_vals(i)
      pv = sqr_pv & row_pv & col_pv
      pos_vals = pos_vals | pv
    end r />  end
  return pos_vals.sort
end

def get_pv_for_col(cell_index)
  if cell_index < 9
    index = cell_index
  else
    index = cell_index - (cell_index/9*9)
  end
  pos_vals = Array.new
  col_cells = Array.new(9){|i| index + (9*i)}
  col_cells.each do |i|
    cell = @board[i]
    if cell == 0 && i != cell_index
      sqr_pv = get_poss_sqr_vals(i)
      row_pv = get_poss_row_vals(i)
      col_pv = get_poss_col_vals(i)
      pv = sqr_pv & row_pv & col_pv
      pos_vals = pos_vals | pv
    end
  end
  return pos_vals.sort
end

So, now I modify the solve method to take these into account:

def solve
  100.times do |i|
    @board.each_index do |cell_index|
      if @board[cell_index] == 0
        sqr_pv = get_poss_sqr_vals(cell_index)
        row_pv = get_poss_row_vals(cell_index)
        col_pv = get_poss_col_vals(cell_index)
        pv = sqr_pv & row_pv & col_pv
        if(pv.length == 1)
          @board[cell_index] = pv[0]
        elsif pv.length > 1
          oc_sqr_pv = get_pv_for_sqr(cell_index)
          oc_row_pv = get_pv_for_row(cell_index)
          oc_col_pv = get_pv_for_col(cell_index)
          oc_pv = oc_sqr_pv & oc_row_pv & oc_col_pv
          pv = pv - oc_pv
          if(pv.length == 1)
            @board[cell_index] = pv[0]
          end
        end
      end
    end
  end
end

Which other than being in dire need of some extract methods, let’s our tests pass. Just to see, I grab another easy puzzle of Daily Sudoku:

def test_real_game2
  real_game = [
  0,3,0,0,9,0,0,0,0,
  5,0,6,0,0,1,0,0,9,
  2,0,0,0,8,0,0,6,0,
  0,4,3,0,0,7,0,0,0,
  6,2,0,9,0,8,0,7,5,
  0,0,0,1,0,0,3,2,0,
  0,7,0,0,1,0,0,0,4,
  9,0,0,7,0,0,1,0,2,
  0,0,0,0,6,0,0,9,0]

  sln = [
  4,3,7,6,9,2,5,8,1,
  5,8,6,3,7,1,2,4,9,
  2,1,9,4,8,5,7,6,3,
  8,4,3,5,2,7,9,1,6,
  6,2,1,9,3,8,4,7,5,
  7,9,5,1,4,6,3,2,8,
  3,7,2,8,1,9,6,5,4,
  9,6,8,7,5,4,1,3,2,
  1,5,4,2,6,3,8,9,7]

  game = Game.new(real_game)
  game.solve()
  assert(game.is_solved?)
  assert_equal(sln, game.board)
end

Which also passes! Now for the moment of truth, a Very Hard Sudoku:

def test_real_hard_game
  real_hard_game = [
  1,0,0, 0,0,0, 0,0,0,
  0,3,0, 6,5,0, 0,0,2,
  0,0,8, 0,0,2, 9,0,0,

  0,8,0, 0,0,9, 1,6,0,
  0,0,0, 1,0,7, 0,0,0,
  0,7,1, 8,0,0, 0,5,0,

  0,0,5, 4,0,0, 2,0,0,
  9,0,0, 0,7,6, 0,8,0,
  0,0,0, 0,0,0, 0,0,3]

  sln = [
  1,2,6,9,8,4,7,3,5,
  7,3,9,6,5,1,8,4,2,
  4,5,8,7,3,2,9,1,6,
  2,8,3,5,4,9,1,6,7,
  5,9,4,1,6,7,3,2,8,
  6,7,1,8,2,3,4,5,9,
  3,6,5,4,9,8,2,7,1,
  9,1,2,3,7,6,5,8,4,
  8,4,7,2,1,5,6,9,3]

  game = Game.new(real_hard_game)
  game.solve()
  assert(game.is_solved?)
  assert_equal(sln, game.board)
end

And it…Doesn’t pass! Hmm. I guess I’m going to have to do some more research to see if there’s additional logic, or if this particular puzzle requires a subjective move. But, I’m pretty happy with what I’ve gotten so far, and if I have a chance to come back to look at the harder puzzles, I’ll post it here.

4 Comments


Posted on July 6th, 2006

One of the tasks my current team was given when it was started was to do things “the right way.” In other words, the company felt like maybe they weren’t /really/ practicing XP, and perhaps there was a way to crank it up to 11.

However, yesterday my pair leaned over and said, “We’re only as agile as our process”. Unfortunately he’s correct on that. The two of us do everything possible to crank XP up to 11 there. We are in constant, open, honest communication with our customer. We test-drive everything. Our customer writes Fitnesse tests to express requirements. We don’t have a big tracking process, we use stories (index cards and ProjectCards) for everything.

But, because we’re in a legacy environment, we are stuck with their process. Want to make a change to the Database? Sure. Just create a tracking ticket, then go over to the DB changes application, making sure to fill out everything correctly. Eventually a DBA will review your changes and “approve” them to go to the Test database. Then you go back in, mark that as complete, “promote” the ticket, and then once you get approval you notify change management who then also gives the green light. And then you can make your change.

For an /alter/ script. That adds one column. To a table only our app uses.

Or, maybe we want to try out a new framework, or a new version of Eclipse, or NetBeans, or Rails. Sure! Just create a tracking ticket, making sure to get approval from your manager. Send it to our Ops team. They will download it, create a secure network which doesn’t let you access the other network, place it there, and let you VNC over to a machine to play with it. Oh, you want to use it in production? Well, make sure to get the approval from the Change Management team, and the Ops team, and management and, and, and….

Or production deployment? Make sure to get QA approval to Develop, and Alpha, and Beta. And then *one* person in the whole company is allowed to move it to production. One. And we only do go lives once a day. Hope it was right!

Ed Gibbs calls it the audit excuse in a recent posting, and I think that’s exactly what it is. We are scared of the machines being different, of having something that every single person might not understand. But in XP, you can’t solve the problems with policies. You can’t solve them with tools, or software. Nor can you solve it by management. You can only solve problems by having the team recognize it, talk about it, and discuss ways to fix it. In other words, communicate.

Communication is the lifeblood of an XP team. Between developers, between the customer, between teams. Unfortunately, it seems that in a world of cover-your-butt, we are happily willing to trade communication for bureaucracy and policies and paperwork. Hopefully we can have an impact on that before it becomes really bad.

2 Comments


Posted on July 3rd, 2006

In my last post about getting NUnit running on Mono/Linux, Ed Gibbs commented:

I understand the challenge of getting something like NUnit running on Mono, but I really don’t get the point of Mono. Congrats on getting it running.

Does anyone run Mono for real production projects?

I did post some links in response, but I figured I would also point to the list of Software the Mono-Project keeps a list of that use it in the real world at http://www.mono-project.com/Software. Some notables I saw:

  • Vault (http://www.sourcegear.com/vault/index.html), from SourceGear (http://www.sourcegear.com/), relies on Mono to run on Unix systems.
  • Novell ZENworks Linux Management (http://www.novell.com/products/zenworks/linuxmanagement/) and iFolder 3.0 (http://www.novell.com/products/ifolder/index.html) (On Linux and Mac OS X) are built using Mono.
  • iFolder 3 (http://www.ifolder.com/) is a simple solution to sharing files and folders by using a simple peer-to-peer fashion or Novell’s groupware server products.

But, be sure to check out the full list on their site.

No Comments