That is, I think it's not too bad

Mostly, but not always, about developing software.

Friday, June 18, 2010

Specifications with ActiveRecord named scopes

The specification pattern is a useful technique for encapsulating the (potentially complex) logic for selecting or validating domain objects in small, composable classes or code blocks.

Previously on Java projects I'd used Hibernate's Criteria API to provide chaining across composed selection criteria (validation is the subject for a different post). For Ruby/ActiveRecord, there are a few projects that have implemented similar APIs, but none are especially mature. Handily, ActiveRecord's own named scopes provides a nice way to achieve what I needed (or at least the Rails 2 version of them, things have changed in Rails 3).

In particular, the undocumented scoped class method can be used to "disconnect" selection criteria from the model object and encapsulate them in Specification classes. A simple specification can be:

class IsEffectiveProductSpecification

def criteria
{ :conditions => ["effective_from <= :today", { :today => Date.today}] }
end

end

To chain specifications, a composite applies each composed specification's criteria against the model's scoped method:

class CompositeSpecification < Array

def all
self.inject(Product.scoped(nil)) do |combined_scope, specification|
combined_scope.scoped(specification.criteria)
end
end

Now in the model we can provide the selection interface that selects from one or more assembled specifications:

class Product

def self.select_satisfying(specification)
satisfying = specification.all
# apply more complex selection, such as selecting across different combination of model objects
end

end

I'd be interested in any Rails 3 (or other) approaches that might improve on this implementation.

Tuesday, October 6, 2009

Moving to modular Javascript

Once in a while, you come across a site that has exactly the information you're after, when you need it. Recently I was bashing out some Javascript in my usual function-frenzy, randomly adding various comments like

// TODO: get rid of all these globals
// TODO: make this more modular and nice
// TODO: I know this is bad, but I'll fix it up later

JavaScript Programming Patterns does a terrific job of showing in simple terms some of the approaches to better programming styles for Javascript. I especially like how it discusses moving from the "Old-School Way" (that's me) to my current favourite, "Revealing Modular Pattern". It took me about 15 mins to refactor to this pattern, and I'm already feeling the benefits, particularly in introducing some much needed testing.

Tuesday, June 16, 2009

Iterative website development with Webby

Recently I was involved in building a static website and chose to use Webby to help build and manage the site. Written in Ruby, Webby is a command line tool that allows you to keep the site content separate from the layout; simple Textile (or other markup languages) content files are rendered into HTML layouts. I soon found that Webby provided nice benefits when we wanted to add functionality to the site incrementally.

For the first iteration we focused on the static design of the site. A common menu linked to secondary pages. Because Webby lets me use ERB, I can write (and test, naturally) simple helper methods in Ruby to build up the menu:


def menu_items
@pages.find(:all, :in_directory => "/main", :sort_by => 'order')
end

Then in the layout (which is mostly HTML but can also use ERB):


<% menu_items.each do |page| %>
<% if is_current_page?(page) %>
<li class='current'><p><%= page.title %></p> </li>
<% else %>
<li><%= link_to_page(page) %></li>
<% end %>
<% end %>


If this needs to be reused, it too can be moved into a helper - Webby is great for DRYing up site code.

After we had the initial design, we naturally decided to sprinkle some effects. Rather than have the menu links load new pages, we used a JQuery animation to fade in the linked content on the main page. For this iteration, we just had to change our full pages into partials (by simply adding an underscore to the filename). Now in our layout, we can generate each partial's content into hidden divs:


<% @partials.find(:all, :in_directory => "/main") do |partial| %>
<div id='<%= partial.name %>' style='display: none'>
<div><%= render(:partial => partial) %></div>
</div>
<% end %>


Some simple Javascript now lets the menu items update the main content area with a nice fade effect and no full page load.

But now we've actually incurred some information loss: instead of a nice url such as http://somedomain.com/about, our menu links use http://somedomain.com/#, with Javascript doing the work of detecting which link was clicked. Now we can't easily publish our nice urls, plus we might negatively affect SEO. The next iteration fixes that.

Our content pages have become partials, which can easily be re-used. By creating new Webby pages for each content page, we can simply render each partial. So in the about content file, we just have to:


---
title: About Us
order: 1
filter: erb
---
<%= render(:partial => "main/about") %>


and we get back our full, url-addressable content page.

So now after a couple of iterations our site has a bit of sizzle, is SEO-friendly and even works with Javascript turned off! Webby has been a great benefit in achieving this by letting us make small, incremental changes with minimal code duplication. And it means I get to write Ruby code for my HTML/CSS/Javascript website!

Portable agile burn-down charts


Great idea, Erik

Monday, June 15, 2009

Open gem in Textmate

I frequently use the gemdoc bash completion to quickly view Ruby Gem RDocs. A quick addition lets me open a gem in Textmate:


gemmate() {
mate $GEMDIR/gems/`$(which ls) $GEMDIR/gems | grep $1 | sort`
}
complete -o default -o nospace -F _gemdocomplete gemmate


Now I can do

gemmate webby-0.9.4

Wednesday, April 8, 2009

Remembering Kurt

Early on April 9th 1994, I was getting ready to fly to Canada with the band I was playing in at the time (yes I was in a band). It was the biggest day of our musical career, and the start of a pretty big and fairly torrid adventure into the unknown. The overnight news was coming in of Kurt Cobain's death. At the time I was in like (not love) with Nirvana, but the impact of that event is still with me, and it's unsettling to re-visit the news footage and to remember the house and attic that was shown so often as the story broke.

In the couple of days after we arrived in Vancouver, we took a trip down to Seattle. I remember a service station buried in some woods off the highway and watching some fairly stereotypical redneck types pick up a magazine with Kurt on the cover, put cocked fingers in their mouths and have a good laugh about the whole thing. We didn't stick around - we didn't exactly look like locals and were driving a friend's old Chevy (?) with bullet holes in the front windscreen.

In Seattle, we went straight the Sub Pop shop and met up with the label guys. At the time we had just had a single released on Sub Pop, so we were feeling pretty cool and a bit self important. It became pretty clear pretty quickly that we were in Kurt's heartland, and folks weren't taking it all that well. There were lots of candlight vigils going on, even church signs that were normally displaying anti-abortion messages were showing messages of support for the fans that were taking it so hard.

I think that seeing the impact Kurt's death had on so many people is part of what ultimately rebounded on me. After we got back from the trip (which broke the band btw, probably compounding the impact of the recent events) I had a drink with a friend who, until then, I didn't even know liked anything other than electro. He was seriously depressed, and even broke down after a few. He said he just couldn't get over Kurt's death. This was months after.

Kurt's music wasn't life-altering for me by any means, but his death just might have been. I think it scarred a lot of people back then, and I expect it's bringing back some sad memories with the 15th anniversary.

Tuesday, March 31, 2009

Back to index cards

Over a range of projects that have been based around user stories, I have seen a number of different means of story management, including XPlanner, Mingle, spreadsheets, Pivotal Tracker and index cards. Each of these has good and bad points (some more than others), but I've come to regard index cards blue-tack'ed to the wall as the simplest and best option.

The major factor is visibility: regardless of what lanes you use, it is close to instant to view where each story is at and who is working on what. Compare this with logging onto your web-based story management tool (you remember your password/have enough licenses don't you?), selecting the right project, applying a few filters, removing the lanes you aren't interested in and hopefully getting a view of the current iteration.

Of course, you still might want to use a tool for history, backups or to share across team sites. I know of one rambunctious manager who likes to wander around project rooms silently removing random cards from stories walls, just to see what would happen!

Twitter Updates

    follow me on Twitter

    Followers