01 November 2007

Moved

This blog has moved to http://blog.strangeware.ca.

13 June 2007

more fine code from the dojo

After a month of refactoring, which actually included some new functionality, we've prepared another release of RSSQ. This release ("festival") includes:

Estimates and status

Stories can be given an estimate from 1-10 ideal days. Later, this set may be user defined. Stories can be marked as complete

Persistent user experience

Any changes during a session will persist into the next session. This includes the selection in the list of stories and changes to the story content (description, status or estimate).

I hope to have this release up on the project page in the next day or two, time permitting.

Update: The current release is now available on the project download page.

27 May 2007

coding dojos around the world

After commenting about our local coding dojo on a mailing list, I was directed to a new website/wiki: www.codingdojo.org. This site explains the concept and provides links to more information. I've decided to advertise our dojo in the hopes of attracting new people.

the effect of culture

It's a rainy Sunday afternoon in the city and there were some errands that I needed to run. This seemed like an ideal opportunity to sit down and spend an hour listening to David Heinemeier Hansson and Martin Fowler talk about programming cultures.

As a long time observer (and sometimes participant) in the free software world, I've long been intrigued by micro-cultures and their effect on the software written by those cultures. In the podcast, the participants talk about how they noticed programmers who leave particular engagements in exchange for a new opportunity that makes them happier. Hansson seems to measure happiness as how closely the aesthetics of the culture align with those of a particular participant. As a firm proponent of "writing code is writing", I think there's something to this opinion.

This concept also comes up in the more technical portion of the podcast. They talk about how teams developing software need to be fully participatory: every contributor needs to have an equal role in the process. This seems to move opposite to the way of things within many established shops. Based on conversations I've had with many programmers, we seem to build odd little caste systems, usually established by language and technical knowledge, with the programmers stuck firmly in the priest class.

We, the programmers, need to stop building these caste structures. It's often the case that we have more information than other members of the group. More often than not, because we are not very capable of communicating this knowledge, other participants can be bullied down to lowest positions. I suspect this is something we are going to have to voluntarily give up in order to build cultures that increase our happiness.

As you can tell, this podcast has caused me to think about my current approach to programming and design. I'd suggest having a listen, it might influence you as well.

22 April 2007

the first chamber

Even though this blog has been quiet over the last few months, I've actually been quite busy: Inspired by conversations at Ottawa XP and OGRE gatherings, I've decided to start a local coding dojo.

A few years ago, when I briefly trained a martial art, I formed the opinion that programming might be trained in a similar fashion. Other programmers seem to have come to similar conclusions. Since then, I've been working up the courage to start a local group that would follow through on this concept.

To start, a colleague from the Ottawa XP enthusiasts joined me at a local coffee shop. Together we formed the first pair of practitioners. Hopefully others will follow.

For our first project, we elected to continue to work on the project that I've been using to fuel my previous programming related posts. For the last month and a half, we've met for a few hours a week to learn the Ruby programming language and to practise pair programming and behaviour (or test) driven-development using rspec . This effort has culminated in release1 of the project (available from SF.net as rssq).

It is my hope that this can grow into a larger collective (or guild) of programmers. This group might provide a shared facility for practitioners to expand their interests and abilities.

26 February 2007

for the first time, a user interface

This post returns to programming topics by presenting another session building a simple story organizer.

The next obvious thing that the story organizer project needed was some user interface. Looking back at the spike solution, I decided that I would implement a class which encapsulated the list of stories. The stories class from previous sessions would serve as the underlying data model for this new class: StoriesView. This graphical user interface was implemented using the Gtk+ widget set using the ruby-gtk bindings.

As with previous sessions, I started off with a very simple context. The context specifies the StoryView class and a single method, prepare which attaches a Gtk::ListStore instance to the Gtk::TreeView. It also specifies that a StoriesView instance will provide access to the same Gtk::ListStore instance via a the StoriesView::model property.

context "Preparing a StoriesView" do
setup do
@widget = Gtk::TreeView.new()
end

specify "should create a model for the widget" do
storiesView = StoriesView.new()

storiesView.prepare(@widget)
@widget.model.should_be_not_nil()
@widget.model.should_be_eql(storiesView.model)
end
end
The first time I ran the rspec tool on this context, the specification failed because neither the StoriesView class nor the model property or the prepare method were implemented. Implementing all of these gave me a basic skeleton for the StoriesView class:
class StoriesView
attr_reader :model

def prepare(widget)
end
end
This still produced a failing specification:
'Preparing a StoriesView should create a model for the widget' FAILED
nil should not nil nil
From this failure, it was quite clear that all I needed to do was instantiate a Gtk::ListStore instance:
class StoriesView
attr_reader :model

def prepare(widget)
@model = Gtk::ListStore.new(String, Integer)
widget.model = @model
end
end
In order to display items, a Gtk::TreeView instance requires column definitions and a mapping between the underlying Gtk::TreeModel implementation (Gtk::TreeStore, in this instance). This additional functionality was verified by another specification:
context "Preparing a StoriesView" do
# other specifications skipped...

specify "should define columns for the widget" do
storiesView = StoriesView.new()

storiesView.prepare(@widget)
@widget.columns.size.should_be_eql(1)
@widget.columns[0].cell_renderers[0].should_not_be_nil()
end
end
I quickly satisfied the specification by addming code to the prepare method:
def prepare(widget)
@model = Gtk::ListStore.new(String, Integer)
col = Gtk::TreeViewColumn.new("Title", Gtk::CellRendererText.new, {:text => 0 })
widget.append_column(col)
widget.model = @model
end
Since the previous specification did not verify the data mapping ( :text => 0 ), I moved on to the next specification. This specification would demonstrate that the prepare method should fill the configured Gtk::ListStore instance with data from a stories instance. Part of writing this specification required instantiating and populating a stories instance in the setup method of the context.
context "Preparing a StoriesView" do
setup do
@widget = Gtk::TreeView.new()
@stories = Stories.new();
@stories.append(Story.new('Alpha', ''))
@stories.append(Story.new('Beta', ''))
end

specify "should fill the list view widget using the title of each story" do
storiesView = StoriesView.new()

storiesView.prepare(@widget, @stories)
index = 0
storiesView.model.each {
|s, path, iter|
iter[0].should_be_eql(@stories.get(index).title)
index += 1
}

index.should_be_eql(@stories.size())
end
end
Since, in a previous session, we'd already implemented an each method, satisfying this specification was a simple matter of applying that method against the Gtk::ListStore in order to transfer the data from one object to the other. The code to satisfy this specification was added to the StoriesView::prepare.
def prepare(widget, stories)
@model = Gtk::ListStore.new(String, Integer)
col = Gtk::TreeViewColumn.new("Title", Gtk::CellRendererText.new, {:text => 0 })
widget.append_column(col)
widget.model = @model
stories.each {
|story, index|
iter = @model.append()
iter[0] = story.title
}
end

The final part of the specification was this new user interface class was a bit forward looking. From the spike solution, I knew that selecting items from the list of stories and performing prioritization operations was a core piece of functionality for this application. With this in mind, I wrote a specification which outlined selection operations on the StoriesView class. I started defining the specification by describing how the StoriesView class select method would function.
context "Preparing a StoriesView" do

specify "should provide the currently selected story index and a means to change the selection" do
storiesView = StoriesView.new()

storiesView.prepare(@widget, @stories)
storiesView.select(0)

@widget.selection.selected[0].should_be_eql(@stories.get(0).title)
@widget.selection.selected[1].should_be_eql(0)
end
end
In order to gain access to the current widget selection, the select method required access to the Gtk::TreeView widget that was passed to the prepare method. Also, we needed to store the index of a Story in the stories instance in order to perform the search through the items stored in the Gtk::ListStore. The updated StoriesView::prepare method was:
def prepare(widget, stories)
@model = Gtk::ListStore.new(String, Integer)
col = Gtk::TreeViewColumn.new("Title", Gtk::CellRendererText.new, {:text => 0 })
widget.append_column(col)
widget.model = @model
stories.each {
|story, index|
iter = @model.append()
iter[0] = story.title
iter[1] = index
}
@widget = widget
end

The new StoriesView::select method was:

def select(index)
selIter = nil
@model.each() {
|store, path, iter|
selIter = iter if ( iter[1] == index )
break if ( selIter )
}
@widget.selection.select_iter(selIter) if ( selIter )
end

To finish off the seesion, I added another method, selectedIndex to the StoriesView class, which would provided the index into the configured stories instance for the current selection in the user interface widget. Since this functionality was intrinsically linked to the select functionality, I extended its specification, rather than defining a new specification which would depend on the select method working properly.
specify "should provide the currently selected story index and a means to change the selection" do
storiesView = StoriesView.new()

storiesView.prepare(@widget, @stories)

storiesView.selectedIndex().should_be_nil()

storiesView.select(1)

@widget.selection.selected[0].should_be_eql(@stories.get(1).title)
@widget.selection.selected[1].should_be_eql(1)

storiesView.selectedIndex().should_be_eql(0)
end

After running 'spec' and discovering that I needed to implement the missing method, I came up with an implementation for selectedIndex:
def selectedIndex()
@widget.selection.selected[1] if ( @widget.selection.selected )
end
After this fast session, I had a simple View class that could form the basis of the StoryList behaviour outlined in the spike solution. The next couple of sessions will involve adding behaviours for the PriorityButtons, the Add/Remove buttons and updating the TextView which will display the story details. After those sessions, I'll provide an updated package which contains the working source code for the project.

22 February 2007

the question

The Question 1-36 (DC Comics, 1987-1990)

Recent events in DC Comics' weekly series, 52, have inspired me to read the series which introduced Charles Victor Szasz (aka "The Question") into the DC Universe. The first issue of The Question appeared in comic book stories near the end of 1986 (the cover date was February 1987).

Unlike many super-hero comics of the time, the Question was written in a more mature fashion than many contemporary series. The series tried to explore philosophical questions about our nature and our relationship with violence, with varying success. The series, unlike the more popular open-ended stories that dominate super-hero comic books, seems to have been intentionally planned as a complete storyline with a definite ending point. The main character develops from an initial crisis and reaches a conclusion about himself and his relationship to the world. Throughout the series, the main character often employs a questionable level of violence as he explores his role as a costumed vigilante. He grows to appreciate the effect his violent reputation has on the criminal element in his home city. There are even times where he considers whether it might be morally correct to kill in order for justice to prevail.

The setting for the series is Hub City (based on East St. Louis), a fictional American city collapsing into itself. After a near death experience at the hands of another well-known character, Lady Shiva, Sage makes it his mission to enforce justice in a declining environment where most authority figures are corrupt or ambivalence. Sage has a symbiotic relationship with Hub City. As the city declines into chaos and violence, so does he. As Sage struggles to deal with the elements of the city that cause this decline, he descends into a personal chaos. At the bottom of this decline, when it becomes obvious that he cannot save the city and further effort will only destroy him, Vic breaks the cycle and leaves the city.

This series reintroduced many of the martial artists that Denis O'Neil brought from Dragon's Fists into the DC Universe in the pages of Richard Dragon, Kung Fu Fighter. Since I'm partial to martial arts adventures and have been a fan of Lady Shiva and Richard Dragon for a long time, this was a special thrill for me. In my opinion, this series and Green Arrow were essential in building the wulin of the DCU. Years later, these same characters would come to a focal point around the third Batgirl, Cassandra Cain.

From a graphic perspective, Denys Cowan with Rick Magyar and Malcolm Jones provided this series with a consistent artistic voice. The artwork is crisp with good detail and a scratchy, stylized form of inking that often adds a nice flow, particularly to the martial arts scenes. The muted and washed out colours really helped convey a polluted city in decline. I would have preferred more detail in the backgrounds, though. Often, I felt like every building looked exactly the same.

Even though this series had an excellent high-concept and overall plot, many of the individual issues were not as well written as I would have hoped. Often the dialogue is either rushed, repetitive or just not well thought out. For two men who have lived together for a long time, Aristotle Roder (the inventor of Vic's featureless mask) and Sage seem to have the same conversation (about Vic's choice to be a vigilante) over and over again. The relationship between the two never develops into something interesting. The same goes for Myra, the closest thing to a love interest in Vic's life. In fact, much of the inter-character dynamic is static through the series.

In all, I did enjoy my read through the series. I found especially neat that Denis O'Neil always mentioned extra reading at the end of each letters column. Many of these books related to the philosophical aspects that O'Neil wanted to explore. Hopefully, many readers found inspiring new material via The Question.

The most surprising aspect of this series? One of the people who wrote into the letter column lived (in 1989) only half a kilometer from where I now live!

29 January 2007

more bdd and some refactoring examples

This post continues from a previous post concerning my implementation of a tiny Story organizer that I could use when working on any of my personal projects (see the spike solution post for the high-level requirements). In my previous post, I'd implemented an underlying model object capable of loading stories from a file on disk (in YAML format) and which provided an internal iterator over the collection. This session, I'll describe how I added to priority operations (see #3. in the spike solution post).

As a reminder, this was the state of affairs after that session. First, the spec file (stories_spec.rb):
context "A story collection" do
setup do
@stories = Stories.new
@stories.load() {
"---\n- !ruby/object:Story\n description: Alpha\n- !ruby/object:Story\n description: Beta\n- !ruby/object:Story\n description: Gamma"
}
end

specify "should permit loading of stories in YAML format" do
expected = ["Alpha", "Beta", "Gamma"];
@stories.get(0).description.should_be_eql(expected[0])
@stories.get(1).description.should_be_eql(expected[1])
@stories.get(2).description.should_be_eql(expected[2])
end

specify "should permit iterating stories" do
expected = ["Alpha", "Beta", "Gamma"]
expectedIndexes = [0, 1, 2]
actual = []
actualIndexes = []

@stories.each() {
|story, index|
actual << story.description()
actualIndexes << index
}

actual.should_be_eql(expected)
actualIndexes.should_be_eql(expectedIndexes)
end
end
And the code which satisfies the spec (stories.rb):
require 'yaml'

class Story
attr_accessor :description

def initialize(desc)
@description = desc
end
end

class Stories
def get(index)
@stories[index] if ( @stories && index < @stories.size() )
end

def load()
@stories = YAML.load(yield())
end

def each
@stories.each_with_index() {
|story, index|
yield(story, index)
}
end
end
The first thing I did to get myself reoriented after a brief break was to add a new specification to the "A story collection..." context. This specification described how moving a story to the highest priority should function:
specify "should allow moving a story to the highest priority" do
expected = ["Beta", "Alpha", "Gamma"];
@stories.toHighest(1)
@stories.each() {
|story, index|
story.description.should_be_eql(expected[index])
}
end
As expected, running 'rspec' on the specification file gave me an error:

NoMethodError in 'A story collection should allow moving a story to the highest'
undefined method `toHighest' for #
./stories_spec.rb:51
In an attempt to fix the failure, I added a new method, toHighest, to the implementation of the Stories class:
def toHighest(index)
end
This lead to another error,

'A story collection should allow moving a story to the highest priority' FAILED
"Alpha" should be eql "Beta"
./stories_spec.rb:54:
./stories.rb:23:in `each'
./stories.rb:21:in `each'
./stories_spec.rb:52
so I decided the next step would be to actually implement the method:
def toHighest(index)
if ( index < @stories.size ) then
s = @stories[index]
left = []
left = @stories[0, index] if ( index > 0 )
right = []
right = @stories[index + 1, @stories.size] if ( (index + 1) < @stories.size )

@stories = [s] + left + right
end
end
This successfully implementated the specification. Before moving on the the next logical priority operation, toLowest, I decided to add to the specification by performing two different toHighest operations:
specify "should allow moving a story to the highest priority" do
expected = ["Beta", "Alpha", "Gamma"];
@stories.toHighest(1)
@stories.each() {
|story, index|
story.description.should_be_eql(expected[index])
}
expected = ["Gamma", "Beta", "Alpha"];
@stories.toHighest(2)
@stories.each() {
|story, index|
story.description.should_be_eql(expected[index])
}
end

To specify the toLowest operation, I copied the toHighest operation and adjusted it accordingly:
specify "should allow moving a story to the lowest priority" do
expected = ["Beta", "Gamma", "Alpha"];
@stories.toLowest(0)
@stories.each() {
|story, index|
story.description.should_be_eql(expected[index])
}
expected = ["Beta", "Alpha", "Gamma"];
@stories.toLowest(1)
@stories.each() {
|story, index|
story.description.should_be_eql(expected[index])
}
end

Of course, the specification was unsatisfied:

NoMethodError in 'A story collection should allow moving a story to the lowest priority'
undefined method `toLowest' for #
./stories_spec.rb:66

Since copying the specification worked well (and quickly), I also copied the implementation of toHighest and modified it to satisfy the specification:
def toLowest(index)
if ( index < @stories.size ) then
s = @stories[index]
left = []
left = @stories[0, index] if ( index > 0 )
right = []
right = @stories[index + 1, @stories.size] if ( (index + 1) < @stories.size )

@stories = left + right + [s]
end
end

This satified the specification, but it didn't satisfy me. Both operations seemed to be very similar, so I decided to try to factor out a common method called move that would take advantage of Ruby's closures to implement the emerging Template Method. After implementing the common method, I updated toHighest and toLowest to take advantage of it. This resulting three methods looked like this:
def move(index)
if ( index < @stories.size ) then
s = @stories[index]
left = []
left = @stories[0, index] if ( index > 0 )
right = []
right = @stories[index + 1, @stories.size] if ( (index + 1) < @stories.size )

@stories = yield(s, left, right)
end
end

def toHighest(index)
move(index) { |story, left, right| [story] + left + right }
end

def toLowest(index)
move(index) { |story, left, right| left + right + [story] }
end

Since all the specfications were still satisfied (no errors), I moved on the the next two operations: promote and demote. Since, once again the specification for toHighest seemed similar to the functionality that I wanted for promote, I copied it into place and adjusted it to meet the new requirements:
specify "should allow promoting a story by a single priority" do
expected = ["Beta", "Alpha", "Gamma"];
@stories.promote(1)
@stories.each() {
|story, index|
story.description.should_be_eql(expected[index])
}
expected = ["Beta", "Gamma", "Alpha"];
@stories.promote(2)
@stories.each() {
|story, index|
story.description.should_be_eql(expected[index])
}
end

Having already had experience manipulating the array when implementing the previous operations, the new operation was fairly quick to write:
def promote(index)
if ( ((index - 1) >= 0) && (index < @stories.size) ) then
story = @stories[index]
@stories[index] = @stories[index - 1]
@stories[index - 1] = story
end
end

Once again, the implementation of promote gave me some code I could copy in order to write a specification for demote:
specify "should allow demoting a story by a single position" do
expected = ["Beta", "Alpha", "Gamma"];
@stories.demote(0)
@stories.each() {
|story, index|
story.description.should_be_eql(expected[index])
}
expected = ["Beta", "Gamma", "Alpha"];
@stories.demote(1)
@stories.each() {
|story, index|
story.description.should_be_eql(expected[index])
}
end

In order to satisfy this specification, I just copied the code for promote and it inverted it's logical to produce the demote operation:
def demote(index)
if ( (index >= 0) && (index + 1 < @stories.size) ) then
story = @stories[index + 1]
@stories[index + 1] = @stories[index]
@stories[index] = story
end
end
I quickly realized that, as with the previous pair there was a common element between the two new methods,. It seemed to me that I could use the same tactic as before to refactor these new operations. I extracted a new method, swap, and adjusted promote and demote. The three messages now looked like this:
def swap(to, from)
if ( (to >= 0) && (from < @stories.size) ) then
story = @stories[from]
@stories[from] = @stories[to]
@stories[to] = story
end
end

def promote(index)
swap(index - 1, index);
end

def demote(index)
swap(index, index + 1)
end

After verifying that the specification was still satisfied, I decided to finshed up for the evening by reviewing the code and refactoring were I felt that the code could be improved. My first step was to define the behaviours at boundary conditions. What should happen if I demote an index outside the boundaries of the collection? What if I operate on indexes where the item is already in the correct prority? The fastest way to quickly add these verifications to the context was to refactor the tests to streamline the checks. The result of this process can be seen in the final code for this session.

My next step was to review the documentation for the Ruby Array class to see if any of the code I'd written was actually available in the supporting runtime. Performing this refactoring would allow me to reduce any technical debt that my lack of familiarity with the supporting runtime had incurred. It's important to note that during this phase, the specification was not modified, otherwise I woud have risked changing functionality.

The code at the end of this session is available.

Next session, I hope to write a specification for the first GUI context (implemented using Gtk+). Having completed that, I hope to connect the specified GUI objects to the data level object implemented in the last two sessions.