Wednesday, March 4, 2009

Practice Sudoku Git Repository Approaches

I've been talking for a while about starting a series of git repositories that can be used as tools for doing focused practices, the first of which will be a sudoku solver. This is the story of my initial attempt at setting up the git strategy, having troubles, then having David Chelimsky help me find what I think will be a better way. I am just a beginner with git, so building these repositories is also a way for me to practice my own git-fu.

I'll write about my initial, failed strategy, then explain the approach that David recommended, as well as paraphrase a bit on the approach we took to get there. Of course, I'm interested in other people's opinions and ideas, as well, so feel free to comment below or write a blog post. I'm planning more of these repositories, so I expect that experience will guide me to a better repository strategy.

Goal: I would like to have a git repository that contains a set of cucumber features for a sudoku solver. These features would contain many sudoku boards of differing difficulty, allowing someone to bypass the initial bother of finding boards to use in practice session.

While I'm building the features, I am also going to be writing a sudoku solver, as well. I want to maintain a branch with just the features in it, as that will be what is pushed to github.

Attempt 1

master = cucumber features + step definitions
rspec = rspec examples + implementation

As I add cucumber features on master, I then rebase over to the rspec branch. The rspec branch will always have the most up-to-date features from the beginning, so I can see if things are still working, as well as access them. The rebasing will put all the feature stuff at the start of my commit tree, so it will be a similar situation to someone who is using it after all the features are written.

result: massive pain
This worked great until I started having to make some small changes to the features/support/env.rb file to include my lib code for the features to run. Well, I did it in the rspec branch, since it wasn't related to the core features. Well, this caused some merge conflicts when I was trying to rebase the master over to the rspec branch. Plus, it was a bit confusing to me to have to jump from branch to branch depending on what I was working on.

I only got a reasonable idea of the differences between rebase and merge last week from Tom Kersten, so I had a bit of a naive view of its uses. I still like the idea of having a clean branch with just the cucumber features, but rebasing doesn't seem to be the correct approach.

Why do I even want to have the cucumber features all placed at the beginning of my commit history on the actual implementation branch? Why not just merge? With hindsight (and perhaps a bit of foresight would have been good), my initial idea doesn't really hold much water. My commit history is based on the incremental development of the features, so trying to take more recent changes that affect my implementation and pushing them back to the front of the commit log just sounds like a recipe for grief. And, amazingly, it did end with much wailing and gnashing of teeth.

Paraphrase/Summary of Conversation with David

While David was making oatmeal, I explained the rebase/merge conflict problems. After explaining my approach, he started offering some ideas around using rebasing. Pretty quickly, though, he switched his questioning more towards why I was trying to do what I was doing. It didn't take long to get to the heart of what my goal was: have a clean repository that contained just the cucumber features that would be needed to begin implementation of a sudoku solver. Here's the suggestion that David offered, and the one that I'm going to switch to.

Attempt 2

master = cucumber features + step definitions
implementation = rspec examples + implementation

Develop entirely on the implementation branch.
Any changes in features directory are committed atomically
Feature commits are marked prominently for easy identification
Master branch gets cherry-picked feature commits merged in periodically
Squash feature atomic commits on master into larger ones, if appropriate

foreseeable result:
Branch 'master' contains clean history of cucumber feature development. Branch 'implementation' contains always working code that actually contains a wonderful history of how I developed the practice features.

A Couple Thoughts

Popping the 'why' Stack

While David and I were talking, there was a definite point when his questions took a turn towards understanding what my root problem was. After a couple of questions, the phrase 'popping the why stack' came to my mind; that was what David was doing. After making it to the root of what I wanted, he was able to offer a solution that satisfied my needs in a much simpler way. When I mentioned 'popping the why stack' to him later, he said, "that's the BDD way."

Tell Don't Ask

Thinking about the proposed approach, it appears much simpler, smoother and more flexible. As I was comparing the two, it occurred to me that this was a form of the "tell don't ask" principle that we use in code. In approach 1, as I'm working on my implementation branch, I'm constantly 'asking' the master for any changes to the features. This means that, over time, we may get more and more out of sync, and I'll run into a situation when it is just too difficult to bring in any changes. In approach 2, I'm adjusting the features alongside the implementation, then I am 'telling' the master branch what changes to merge. Since the master branch isn't really doing anything with them, other than reporting on them to github, it is a much more effective design to tell it the updates.

No comments:

Post a Comment