Coding in the Clink V was quite some time ago. We had a fairly long hiatus this time first because CITC6 should have happened right around Christmas, but it was tough to find folks who could make it then, and second because there was kind of an administration shakeup that affected the JavaGuys.
But we got that all taken care of and held CITC6 yesterday.
For the first time, I “sold” more tickets on Eventbrite (they’re free) than there were prisoners available to attend, because in the past there have almost always been a few dropouts. It worked out perfectly. Nine prisoners were available; I “sold” 11 tickets. Three outside developers and one prisoner dropped out, so we had eight on each side.
Actually, one of the prisoners was delayed getting to the event and wasn’t able to participate in the first round, so another prisoner tripled with two outside developers, both of whom just happened to be female.
I’ll bet he enjoyed that.
Speaking of female developers, we had three this time, which is more than we’ve ever had in the past. Amber Conville is a regular, but we attracted Gabbie Gibson and Kelsey Shannahan this time too. Angela Harms was planning to show up too, but she and her husband Tracy had to drop out at the last moment because of a family emergency.
Here is the list of outside attendees; click the links to read their own blogs about CITC6.
- Amber Conville
- Jesse Cox
- DJ Daugherty
- Gabbie Gibson
- Jeff Hoover
- Ravi Nittala
- Kelsey Shannahan
- Dan Wiebe
From the inside, we had
- Steve Crotts
- Lee Leonard
- Gene Lynn
- Louis Pierce
- Darrin Pordash
- Mark Roberts
- Ron Tracy
- David Travis
(Sorry, I won’t be able to link directly to any of their blogs.)
Up until now, each of the CITC events has been very close to Corey Haines’ Code Retreat concept, with a couple of minor modifications—namely, we’ve always used Java exclusively, we’ve usually used problems other than Conway’s Game of Life, and, as Jeff pointed out, our culinary options in prison are somewhat more limited than they are outside.
But after each CITC, and especially after CITC5, there has been a growing desire among the prisoners to try a CITC where we don’t throw the code away at the end of each cycle, but leave it for the next pair to work on. Continually coming up with new approaches to the problem is not bad, but extending somebody else’s solution is a lot closer to what these fellows are going to encounter in the real world of work.
(Of course, the reason you go to a real Corey Haines-style Code Retreat is not to simulate the real world as closely as possible, but to escape from it as far as possible. That’s why it’s called a Retreat.)
So we tried it to see what it would be like, provisionally, with the understanding that if after the second cycle we hated it, we’d go back to starting over each cycle.
I figured we needed a problem a little bigger than Conway if we were going to spend several cycles on it, so I chose a form of the African children’s game of Mancala. (You can play it here if you like, except that our game started with three markers in each pit instead of four.) The specific problem was to accept a representation of a Mancala board at some mid-game point, and the specification of a move to be made, and determine what the Mancala board would look like after the move had been made. (Since I didn’t know how far we’d get on the problem, I also wanted to know whether that move ended the game and, if not, which player had the next move.)
It turns out that Mancala is an excellent problem for emergent design, because you can start out with an extremely simple concept, but exceptions are continually creeping in and causing you to refactor your design, so that you have to keep it lightweight and bouncy or else you’ll either A) spend all your time providing for the exception-ridden future and never get any real work done, or B) find yourself with no way that you can possibly hack the next exception into the horrible mess you’re working on in a 45-minute cycle.
- The board is just a circular buffer of pits—except that two of them (the mancalas) are special.
- A move is just a dead-simple sowing process—except when you turn a corner onto the other side.
- Turning a corner onto the other side isn’t that complicated—except when you turn the corner back onto your side and have to skip the opponent’s mancala.
- Remembering the last pit of a move is easy—except that the fact that you don’t sow stones in the opponent’s mancala can screw it up.
- Determining the next player to move is easy—except that a bonus move lets the same player move again.
In fact, I may lobby to see if I can get the guys to agree to using Mancala for CITC7 as well. (Especially, come to think of it, since I have a voice commitment for CITC7 from a real African, Frank Gbenah of Pillar Technology.)
We agreed to the following rules: Pick a different pair partner for every cycle but the last. Every cycle, pick a computer that neither of you worked on during the immediately previous cycle (but going back to a machine you were on cycle before last or earlier is okay). For the final cycle, return to the pair partner and the machine you had for the first cycle, just to see what happened to the design you started. (This last rule cropped up out of nowhere just before the last cycle, but I thought it proved to be a good idea.)
So for the first cycle, I paired with Louis Pierce, and convinced him to try to come up with a functional approach to the problem: you know, an immutable Board class, composed of immutable Sections—two of them, one for each player—consisting of six immutable Pits and an immutable Mancala. The top-level function would take a Board, a player number, and a pit number, and would return a MoveResult object containing a new Board, a flag saying whether the game was over, and the number of the next player to move.
We weren’t really FP wizards, though, and Java isn’t a particularly functional language, so we managed to get something with only some mutable state started. (If I remember, the Board was immutable, and you couldn’t get at the Sections to mutate them once they were in the Board, but you created the Sections empty and mutated them until they had the numbers of stones you wanted where you wanted them, then created a Board from them.) But it wasn’t that bad, because from the outside you couldn’t see the mutable state.
Our story test drove us to write a Mancala class with two static methods: startGame(), which returned an initialized Board (three stones in each pit), and move(board, player, pit), which returned a MoveResult.
Then came the all-important second cycle. This was the first one where we would encounter somebody else’s code. Would we decide to keep the code again for the third cycle, or would we recoil in horror and decide to throw it out?
I might be misremembering, but I think my second cycle was paired with Steve Crotts on a codebase where the authors had decided to represent the board as a 14-element List<Integer>, where elements 7 and 14 were treated specially, and it appeared that you were supposed to be able to address pits like “Player 2, pit 10,000” and have that translated into the index of the list element Player 2 would encounter if he started with his first pit and went around and around the board for 9,999 pits.
Unfortunately, a 14-element list doesn’t have any element 14 to treat specially, so we had to figure out how the tests could possibly be passing for code like that (it wound up looking an awful lot like the test had been substantially copied from the code, so both had the same defect), and the code to translate virtual pit 10,000 to real pit whatever was fiendishly complicated and broken.
So we spent the entire cycle writing tests to expose the problems and fixing them, and so didn’t get any actual additional functionality added that cycle. Even at the end of the cycle, we hadn’t addressed the skip-your-opponent’s-mancala issue.
The cycle retrospective was interesting. If I remember correctly, there was only one positive remark about the code encountered: DJ Daugherty said he’d been really impressed by the code left behind by Mark Roberts and Jesse Cox. Everybody else seemed to have spent the cycle improving the code they found. Only one pair admitted to completely horsing the encountered design around to something they found more palatable. However, perhaps because everybody thought they had been able to make things better, there were no objections to continuing to extend existing code, so we decided to keep the code for the third cycle as well.
And so it went, through a total of six cycles. That means everybody had five pair partners, because the first and last were the same. Let’s see if I can remember mine: Louis Pierce, Steve Crotts, Darrin Pordash, Ron Tracy, and David Travis. Yup.
We discovered that the code quality, in all our opinions, was nearly monotonically increasing over the whole day from the second cycle to the sixth. (Of course, almost everybody thought the code they encountered on the second cycle was worse than the code they wrote on the first cycle, probably because it looked nothing like the solution they’d had in mind.) This flies in the face of the accepted maxim that the quality of a piece of code is inversely proportional to the number of hands that have touched it.
At the beginning of one cycle, we encountered a badly-broken suite of tests and a comment: “GOOD LUCK :) We were in the middle of refactoring all this into the Game class when time ran out.” I was disheartened; but then I was surprised to discover how easy it was for us to figure out what the previous pair had been doing and complete it. I wish I had saved that code to look at later: I’m pretty sure that if I were interrupted in the middle of a sizable refactoring myself, my successor wouldn’t have nearly as easy a time as that figuring out what had been in my head, and a cheerful smiley comment wouldn’t have helped.
For the last cycle, I rejoined Louis and we went back to the partially-functional code we’d started, hoping that somebody had been able to rescue it.
Well, no, not so much, as it happened. It was now completely imperative from top to bottom. The Mancala class was still there, and it still had the startGame() method in it, but the move() method was now on Board, where all the state was now mutable, and Mancala had been filled with a bunch of static utility methods. The StoryTest class had a number of unit tests in it.
The moral of this story, I guess, is that if you want code to be functional, you’d better dang well make it functional, because nobody else is going to.
That last cycle both Louis and I were really beginning to fade after a day of hard programming, so we didn’t get much done except mostly implementing the capture move. We wrote a test for the implementation, and then wrote the implementation using a getOpposingPit() method that didn’t exist. We didn’t have time to drive out the getOpposingPit() method before the end of the cycle, but other than that, our suspicion was that the problem was pretty much complete.
Consensus after the last cycle was that everybody had great fun, and it was definitely something that everybody wanted to do again. Given that there were five brand-new outside developers this time, and at least two more brand-new folks who said they’d really like to be on 7, we might have the first real race for tickets on CITC7. We’ll see.
Afterwards, Ravi had to head home for a family celebration, but the rest of us ended up at Bob Evans in Marion, where we closed out the day with a lot of good discussion, good food, and good service from Jess the waitress.
It’s a terrific experience, and one I’d highly recommend to any developer in the greater central Ohio area (Amber and Jeff come down from Michigan, even). As DJ Daugherty said, “After awhile, I simply forgot I was in prison.”