Just A Summary

Piers Cawley Practices Punditry

If you're going to add a hook, make it a big one 4

Posted by Piers Cawley Mon, 08 Sep 2008 06:11:00 GMT

Jay Fields responds to on Ola Bini’s Evil Hook Methods? about the common ruby idiom that lets us write:

class Fruit
  include DataMapper::Resource
  property :id, Integer, :serial => true
  property :name, String
  property :notes, Text, :lazy => false
end

What Ola and Jay don’t like about that is the way that a single include DataMapper::Resource actually adds class methods to Fruit because the implementation of DataMapper::Resource.included looks like:

module DataMapper::Resource
  sub included(module)
    module.send :include, InstanceMethods
    module.send :extend, ClassMethods
  end
end

Which is a perfectly common idiom nowadays, but which breaks include’s contract in annoying ways. Jay proposes fixing this by adding a become method to Object which would wrap the include and extend in such away that they’d be called by the including class. Huzzah. And it makes sense… sort of. But it really doesn’t go far enough.

Let’s take another look at the original code snippet shall we? The thing that I notice is the wide scope of that ‘property’ method. It really isn’t needed anywhere except for defining how a Fruit is mapped onto the database. What happens if we take a leaf out of Perl’s book:

class Fruit
  use DataMapper::Resource {
    property :id, Integer, :serial => true
    property :name, String
    property :notes, Text, :lazy => false
  }
  property :foo # => raises an exception
end

The block gives our extending module somewhere to play, it can introduce a full on domain specific pidgin for the duration of the block with no fear of polluting the including class with anything but the methods its contracted to provide. So, how do we implement use. Something like the following should serve the purpose:

class Module
  def self.use(mod, *args, &block)
    mod.used_by(self, *args, &block)
  end

  def self.used_by(mod, *args, &block)
    if instance_behaviours || class_behaviours
      mod.become(self)
    else
      mod.send(:include, self)
    end
  end

  def self.become(mod)
    include mod.instance_behaviours) if mod.instance_behaviours
    extend mod.class_behaviours if mod.class_behaviours
  end

  def self.instance_behaviours
    nil
  end

  def self.class_behaviours
    nil
  end
end

The key idea here is that, in the default case, use will ignore all its arguments beyond the first and just include that module (a more robust implementation would probably ensure that an exception was raised if any extra arguments got passed). If the module author had written her module to comply with Jay’s proposed become, then we simply call become.

The interesting stuff happens when a module wants to do something a little more trick. So a version of DataMapper might do something like:

class DataMapper::Resource
  def self.used_by(mod, &block)
    mod.become build_behaviours(mod, &block)
  end
end

And build_behaviours would instance_eval the block with an object that would capture the properties and use them to build a set of class and instance methods appropriate to the description.

Another module might simply take a hash to describe how things should be parameterized. It all depends on the needs of the module being used. The aim being to avoid polluting the caller’s namespace any more than necessary. If I use a DataMapper type package, then all I want to end up with in my client classes are appropriate instance accessor methods, I don’t need spare class methods like property or storage_names that are only of any use when I’m describing my class.

Updates

I edited one of the code snippets to remove a particularly heinous piece of brace matching. Thanks to Giles Bowkett for the catch.

Oh. Bugger 2

Posted by Piers Cawley Mon, 01 Sep 2008 08:48:00 GMT

If you asked me to name my favourite radio and TV comedy, the odds are very good that Geoffrey Perkins had a hand in most of them. When I found his obituary in this morning’s Guardian I felt almost physically winded. I never met him, I don’t know anyone who did, but he was someone who helped to make the world a pleasanter place to be in. My thoughts are with his family and friends, who are no doubt even more gutted than I am.

Get sophisticated 6

Posted by Piers Cawley Wed, 20 Aug 2008 16:25:00 GMT

Ruby’s primitives (Strings, Hashes, Arrays, Numbers – anything that has a literal syntax) are fine things. But that doesn’t mean you should use them everywhere. You’re often much better off wrapping them up in your own Value Objects.

Something I was working on at Railscamp this weekend threw up a great example of why it makes sense to replace primitives with more specific objects as soon as possible. Tom Morris asked me to take a look at Rena, an RDF/Semantic Web thingy.

The RDF spec describes two types of literals: a plain literal, which is a string with an optional language attribute and a typed literal, which is a string and an encoding (so the string might represent an integer, float, or anything else that your schema feels like expressing).

These literals can be output in one of (at least) two formats. We’ll start by looking at Literal#to_trix and see where that takes us:


def to_trix
  if @lang != nil && @lang != "" 
    out = "<plainLiteral xml:lang=\"" + @lang + "\">" 
  else
    out = "<plainLiteral>" 
  end
  out += @contents
  out += "</plainLiteral>" 
  return out
end

If we look over at TypedLiteral#to_trix we see a much more straightforward implementation:


def to_trix
  "<typedLiteral datatype=\"#{@encoding}\">#{@contents}</typedLiteral>" 
end

How do we eliminate that ugly conditional at the beginning of Literal#to_trix, and analogous conditionals in Literal#to_n3 and TypedLiteral#to_n3?

My first thought was that I wanted to be able to write something like:


def to_trix
  "<plainLiteral#{@lang.to_trix}>#{@contents}</plainLiteral>" 
end

But I didn’t want every string in the world suddenly acquiring a to_trix method. So, the solution was to intoduce a Literal::Language class and coerce our language into it, so Literal#initialize became:


def initialize(contents, lang = nil)
  @contents = contents
  @lang = Language.coerce(lang)
end  

And Language would look something like:


def self.coerce(lang)
  if lang.is_a?(self)
    return lang
  end

  new(lang.to_s.downcase)
end

def initialize(lang)
  @value = lang
end

def to_trix
  if @value == ''
    ''
  else
    " xml:lang=\"#{@value}\"" 
  end
end    

That ugly conditional’s still there though, so we introduced the Null Object pattern, and things started to look a good deal cleaner:


class Language
  class Null
    include Singleton

    def to_trix
      ''
    end
  end

  def self.coerce(lang)
    case lang
    when self
      return lang
    when nil, ''
      return Null.instance
    else
      return new(lang.to_s.downcase)
    end
  end

  ...

  def to_trix
    " xml:lang=\"#{@value}\"" 
  end
end

At this point, we’re still just pushing code around. If anything, we’ve got more lines of code now than when we started, but we’re starting to move behaviour nearer to the data it relates to, and our objects are starting to look like objects rather than data structures. So, we press on and make a TypedLiteral::Encoding class and, at this point things start to look interesting. TypedLiteral is starting to look almost exactly the same as Literal, but with an Encoding rather than a language.

That strange leading space in Language#to_trix is starting bug me. Let’s rewrite like so:


class Literal 
  class Language
    def format_as_trix(literal)
      "<plainLiteral xml:lang=\"#{@value}\">#{literal}</plainLiteral>" 
    end

    class Null
      def format_as_trix(literal)
        "<plainLiteral>#{literal}</plainLiteral>" 
      end
    end
  end

  def to_trix
    @lang.format_as_trix(@contents)
  end
end

If we make analogous change to TypedLiteral and TypedLiteral::Encoding it’s obvious that TypedLiteral and Literal were essentially the same class. Renaming @lang and @encoding to @language_or_encoding makes this blindingly obvious, so we’ll remove all of TypedLiteral’s methods except initialize. All that remains is to introduce Literal.untyped and Literal.typed factory methods to Literal, and make Literal.new into a private method and we can remove TypedLiteral in its entireity. So we change the specs to reflect the new API (wrong way round I know). Now we have a chunk of shorter, clearer code that will hopefully be easier to extend to cope with outputting literals in other formats.

Retrospective

I realise that patterns aren’t the goal of development, but by the end of the process we have a Strategy (Language/Encoding), a couple of Factory Methods (Literal.typed, Literal.untyped) and a couple of factoryish methods (Language.coerce, Encoding.coerce).

The most important aspect of the change was the introduction of the two new value object classes. Once they were introduced, they became the obvious places in which to put the varying behaviour and eliminate the repeatition of conditional code from the to_* methods. If there were to be a third output style, I would look at introducing classes like N3Stream, TrixStream and WhateverStream and have a scheme like:


def to_n3
  print_on( N3Stream.new )
end

def print_on(stream)
  language_or_encoding.print_on(stream, value)
end

but that’s almost certainly over complicating things right now.

The other thing I like about this kind of refactoring is that it drives the code towards methods and classes which obey the single responsibility principle and, at the end of the process, not only do we have fewer lines of code in total, but the individual methods involved are all substantially shorter and closer to the left hand margin.

I really should start doing this kind of thing more in my Rails practice – I keep being put off by the fact that the composed_of helper is so annoyingly not quite right and, rather than submitting a patch or making a plugin I go “Ah well… I can live with a string for a bit longer…” and I know. From hard won experience at that, that it’s going to come and bite me. It’s already bitten Rails recently when Ruby got a new String#to_chars which doesn’t work like the ActiveSupport version.

Notes

If you want to see the gory details of how the change got made, Tom has merged this weekends changes into the github repository. It didn’t happen in quite the order I’ve described it in this post, but neither is this post a complete fabrication.

Changes

Corrected a stupid typo in the first block of code. Ugly condition is actually if @lang != nil && @lang != ''

Work with us 2

Posted by Piers Cawley Thu, 03 Jul 2008 11:00:00 GMT

If the last post about our Javascript issues didn’t put you off, then you might be interested to know that we’re hiring. If you’re an experienced, test infected Ruby on Rails programmer with some Javascript and a real world consumer website or two under your belt, and you’re happy to work in Newcastle upon Tyne, then we definitely want to hear from you. I’d probably be interested in at least hearing from you if you’re an experienced dynamic language programmer who has only recently made (or is considering making) the switch to Ruby and Rails. It’s only syntax after all.

The money’s decent, the work is interesting, the people (well, apart from me, obviously) are great, and Newcastle’s a fantastic city. Drop me a line, ping me on AIM/gTalk/Twitter or just send your CV to the jobs@amazing-media.com.

Usability testing (throws) rocks 4

Posted by Piers Cawley Thu, 03 Jul 2008 09:55:00 GMT

Usability testing is wonderful. But wow, its humiliating.

I’ve spent the last few weeks working on the Amazingtunes in page player. Amazingtunes is a music site, so we need to play music. However, we don’t like the way that most music sites work; either the music stops as you go from one page to another, or the player is a huge Flash app running in its own window. There has to be a better way. There needs to be a popup window if you want to eliminate stop/start behaviour, but there’s surely no reason not to keep the controls on the main page.

So, we set about writing somthing that did just that. We settled on using Jeroen Wijering’s excellent flvPlayer, which handles the media formats we need and has good Javascript control and communications. This sits in the child window and we use Javascript cross-window communication to have a player controller in the main window that looks something like:

Piers Cawley on amazingtunes.com
Uploaded with plasq’s Skitch!

This is all done in HTML and and Javascript, the progress bar does the Safari trick of running behind the tune data links, the buttons do their AJAX magic and the whole thing is rather slick, though I say so myself.

At least, we thought it was slick until we pointed the usertesting.com legions at it. Without exception, they ignore the in page player, foreground the popup and use the teeny weeny controls on the flash player. Originally, the popup window didn’t even display any transport controls, it just had a picture of some speakers and some text asking the user not to close it because it was playing the tunes. We added transport controls as a stopgap while we made the in page player work properly.

I sound like I’m whinging don’t I? It’s certainly a blow to the ego to see something we spent so much time and attention on being ignored by our sample users. On at least one occasion, while watching the screencasts I found myself boggling at the things the users did, and if I didn’t shout “Just play some bloody music!” at the screen, then I came worryingly close.

It would be easy to retreat into a state of denial: “They’re not our target users! They’re stupid! They’re American! If they would only magically intuit the way we think they should use the site!”. And maybe it would be comforting to do so, for a while. The right thing to do is to suck it up – take away from those videos the sure and certain knowledge that bits of the site don’t work and do something about it.

We may dislike the ‘popup window for transport controls’ model of controlling music playback, but users are cool with it. And it’s not as if the work we did on making the in page player work is going to be wasted – widget is straightforwardly event driven so it’ll work just as well in the popup window, and the communication protocol will be much simpler. Having the player in its own window means we’ll be able to extend its interface in ways that would be hard when the player had to share window space with the rest of the page. In the end, it’s all good.

But… damn that in page player was sweet. I learned Javascript as I wrote it (mostly by pretending it was Perl with odd syntas) and I’m bloody proud of it. I’ll happily replace it with the next iteration (which I’m already working on), but it’ll be with a pang of remorse all the same.

Announcing Announcements for Ruby

Posted by Piers Cawley Sun, 29 Jun 2008 09:46:00 GMT

I’ve just pushed a just about usable (but horribly untested) port of Vassili Bykov’s very lovely Smalltalk Announcements framework onto github. It’s a very raw port at the moment (the interface isn’t what you’d call idiomatic ruby yet), but I shall be working on that soon. Documentation (beyond a synopsis in the readme file) is nonexistent, but I reckon that there’s the core of something useful there (I’ve got plans for using it in Typo as the basis of a Wordpressesque plugin architecture and I need it for my Sooper Sekrit Project too…).

Expect some more details on the whats and whys in this blog soon, but if you want to have a play, you’ll find it at http://github.com/pdcawley/announcements. Enjoy.

git is the monads 2

Posted by Piers Cawley Thu, 15 May 2008 06:57:00 GMT

When, in the course of learning about Haskell, I reached the point where I thought I understood what Monads were for, I wrote about it. In the comments, Seth Gordon observed that:

There are two kinds of people who try to learn Haskell: the people who give up because they can’t figure out monads, and the people who go on to write tutorials on how to understand monads.

I remembered this today as yet another git tutorial rolled by in my newsreader. Maybe git is the monads of version control.

What other ‘monads’ are there out there? RESTful routing in Rails seems an obvious candidate, but I’m sure there’s more.

Rails tip: Dealing with out of sync migrations 4

Posted by Piers Cawley Wed, 07 May 2008 15:09:00 GMT

Sometimes, for one embarrassing reason or another (usually involving chaotic branch merges…) a database migration can get leapfrogged. When this happens, it’s tempting to renumber the leapfrogged migration, but that breaks any servers where the migration didn’t get renumbered. Here’s how I dealt with it recently:

class MaybeOldMigration < ActiveRecord::Migration
  def self.up
    unless old_migration_applied?
      OldMigration.up
    end
  end

  def old_migration_applied?
    # Checks that the schema looks as it should
    # if the old migration got applied
  end
end

Yeah, it’s a hack, but it’s a fairly robust hack.

A quick Javascript formatting tip 10

Posted by Piers Cawley Wed, 16 Apr 2008 09:01:00 GMT

IE’s a pain. The particular pain I want to write about is its pickiness about Javascript object literals. Consider the following Javascript object:

{ success: function () {...},
  failure: function () {...},
}

If you’re used to programming in Perl or Ruby, that trailing comma’s perfectly fine, in fact leaving it there is sometimes considered good practice because it makes it easy to extend the hash, just add a new row and leave another trailing comma.

The trouble is, it’s not strictly legal to do that in Javascript. Pretty much every implementation out there will allow it though.

Except IE.

So, I’ve taken a leaf out of Damian Conways Perl Best Practices and writing my object literals as:

{ success: function () {...}
, failure: function () {...} 
}

By sticking the comma at the beginning of the line, I’m never going to make an object that breaks IE, and adding a new line to the hash is straightforward too. Just stick the cursor in front of the }, type my leading comma, space, attribute name, and hit return when I’m finished.

I’ve also started using the same practice pretty much everywhere else that I’ve got a comma separated list of things:

var foo
  , bar
  , baz
  ;
$.each( anArray
      , function () { ... }
      );

It looks weird at first, but trust me, it grows on you.

Update

In the comments, I make reference to tweaking Steve Yegge’s excellent js2-mode to handle leading comma style a little more gracefully. Since then, I’ve made it work and attached a diff to this issue on the project’s issue tracker.

Ads are gone 2

Posted by Piers Cawley Tue, 15 Apr 2008 06:33:00 GMT

Back when I was writing the occasional “How do you find me?” article, I would get some weird ads showing up. On one occasion, I commented that the searcher had obviously just typed a homework question into google and expected an answer. All the ads on that page ended up being for sites that would write your essays for you.

“Hmm…” I thought, “That’s not good.”, and set about adding those advertisers to the block list.

Then, in another article, I ranted about those, ah, bastions of democracy (thank you, Tom Lehrer) who indulge in comment spamming and found myself advertising them.

Rolling back the enlightenment which discussed, amongst other things, my Uncles’ marriage after 36 years together (yay!) attracted some pretty dodgy ads too.

To my shame, none of these made me rethink the advertising, I just extended the filter and shook my head at the unpleasantness of it all.

The straw that broke the camel’s back was the advertising around Fat is an economic issue ran utterly counter to the spirit of the of the article, and they were like “whack a mole”. Every time I extended the filter, another ad for another bloody health insurance leech or some other snake oil peddler popped up.

So, screw that, the Google ads are gone – it’s not as if they were making me a huge amount anyway. I’ll continue with the left margin Amazon links though – nobody ever buys anything I recommend, but I like the pictures.

Older posts: 1 2 3 ... 29



Just A Summary