Archive for November, 2006

Functional Testing of Forms and AJAX

Wednesday, November 29th, 2006

Ever run into problems testing your forms? Your test works every time so you confidently demonstrate it to someone and the actual user-interface fails. This happened to me today – I renamed a parameter, changed the test but forgot to change the form – so my demo did absolutely nothing. It looks like form_test_helper is what I need.

And as for testing those pesky RJS calls – stick it up your ARTS. A nice convenient syntax for checking that the Javascript in your template is doing what you think it should be doing (much better than hunting the log files).

How to get Referrals

Tuesday, November 28th, 2006

I have a lot to lose if I refer a friend to you. You might screw up, in which case she’ll hate me. Or you might somehow do something that, through no fault of your own, disappoints. If I recommend a greek restaurant and my friend goes and they don’t have skordalia, and she loves skordalia… oops.

Am I being thick?

Saturday, November 25th, 2006

I’ve been trying to follow Mr Hansson’s recommendations for controllers – CRUD in the controller so it becomes little more than a wrapper for the model. Add extra models for relationships. Add extra models for processes. I can see the benefits – especially when it comes to using conventions to build web-services.

But it feels wrong. Maybe Mr Hansson is much smarter than me and I’m being thick. It just reminds me of this.

Verbs are important. Object Orientation is about behaviour not things. But this makes the “things” more important than everything else. The only verbs are create, read, update and delete. What about do_this, do_that, do_the_other? They become “create a ThisDoer”, “update a ThatDoer”, “delete a TheOtherDoer”. Wrong wrong wrong.

Bingo!

Saturday, November 25th, 2006

User Bingo

Caring what the users think is something that just about any company claims to do, but even when they say it, what they really mean is, “Of COURSE we care what the customers think of us” when they should care about what the customer thinks of himself in relation to the product.

Design Decision: Page Width

Saturday, November 25th, 2006

On my new project I have just taken the decision to fix the page width. Each controller must decide whether to use the ‘narrow’ or ‘wide’ layouts – these are identical apart from the width given to the “main_content” div: 750px and 1200px respectively.

Why those values? Well, my target market is not likely to be using the latest and greatest computers. Most systems ship with a default resolution of 1024×768 nowadays, but because of my target I have chosen to use a narrow view (which is most of the application) of 750px – meaning it will look good at 800×600. As for the wide view, that is specifically designed for 1024×768 or higher. The layout includes a left-justified menu panel that is 180px wide – so at 1024 you can use the horizontal scrollbar to look at the entirety of the page sans menu. And if you are lucky enough to have a widescreen laptop or a higher resolution display, you can see the lot in one go.

Of course, if you’ve got a 1600 screen then these fixed widths are going to be annoying. But, as I say, my target market is unlikely to have these – so I’ll deal with that once the complaints start rolling in.

Collecting things

Sunday, November 19th, 2006

I was helping someone out on Friday night (such an exciting life I lead) … I have no idea of his programming background but at one point we needed to iterate through a collection. His hands started typing out i = 0 and then within the loop accessing the elements via an index. And I said ‘ … you don’t need a counter … this is Ruby!‘.

I’ve mentioned before that my favourite piece of Rails isn’t part of Rails at all. In fact, it’s not even part of Ruby. It’s the Smalltalk style collections.

people.each do | person |  puts person.nameend

and

ages = people.collect do | person |  person.ageend

are directly descended from

people do: [ :person |  Transcript show: person name].

and

ages := people collect: [ :person |  person age].

I think the similarity is pretty clear.

But why is this so good? Why is it probably my favourite piece of code ever? Most design decisions “smell” right to me … it’s only after a lot of analysis that I come to realise the arguments underlying why it smells right. Years after my first experience with Smalltalk I’m beginning to understand why I love it so.

The equivalent in Delphi or other ‘old-school’ hybrid OO language would be:

var I: Integer;begin  for I:= 0 to People.Count - 1 do    Writeln((People[I] as TPerson).Name);end;

Ignoring the typecast (a necessary artifact for any language that does not support duck typing/late binding) how does this compare to the Ruby and Smalltalk examples above?

First of all, we need to define an index. Not a big deal but it’s still an obstacle getting in the way of what we want to do (and it’s the obliteration of those tiny obstacles that makes Rails so great).

Next we have to count the number of items in the collection. We don’t actually care how many items there are, we just want the data written out, but we still need to ask the collection for this piece of its private state.

We also need to understand that this collection starts its index at zero and ends at count minus one. These are implementation details about the collection but we have to know this to make use of it. Any (classic) VB or Realbasic programmer knows all about getting this one wrong.

And then we access the actual object through an index. Effectively dictating that random access is the only access – even if the implementation is a linked list, the current index is thrown away and we re-access at I + 1 at the next iteration.

So the Delphi code relies upon us knowing private implementation details about our collection (the count and the beginning index) and means that the collection cannot optimise its own access, as everything is done through random access.

What about the equivalent in C#?

foreach (Person p in people) {  System.Console.WriteLine(p.name);}

That’s better. Who cares if we are starting at index zero or index one? Who cares how many items there are in this collection? In fact, apart from the Smalltalk/Ruby, this is my favourite version of the code (even though it lacks duck typing and blocks).

The downside here is that we have had to add a new piece of syntax to the language – foreach. As Java programmers discovered moving from 1.4 to whatever they called 1.5 (I gave up at this point). And that means, as well as polluting the language and adding more reserved words, if we design our own fantastic, new, optimised collection, the foreach operator would know nothing about its internal optimised access methods and would resort to whatever it resorts to with any other collection.

Speaking of Java, how would you do the same in 1.4?

Iterator i = people.iterator();while (i.hasNext()) {  System.out.println(((Person)i.next()).getName());}

This puts the duty of handling iteration where it belongs – it’s an implementation detail of the collection itself. No knowledge about the number of elements is required. No knowledge of how the indexes are structured is required. And if we designed our super-fast collection we could also design our own implementation of Iterator to ensure that super-fast access is maintained (actually I’m hoping that foreach will just ask the collection for an Iterator – I have no idea if that’s true).

My problem with the Java code is it looks ugly to me. The iteration is divorced from the collection rather than being intrinsic to it. This is a direct result of Java not having blocks and, in effect, allowing us to use the Visitor pattern with our collection. Speaking of which, I also think the Smalltalk looks better than the Ruby, but that’s because Smalltalk treats a block as just another object, where Ruby treats it as a syntactic artefact that must be yielded to.

So Smalltalk (and hence Ruby) collections keep private state private, keep iteration as an intrinsic function internal to the collection, do not pollute the language namespace (Smalltalk has seven reserved words), allow painless implementation optimisation and the resulting code is compact, uses blocks and just looks good (IMO). And, given that after your base Object, your collections are the most important Class in your library, that is why they smell fantastic.

Why the time is right for web-based products and services

Wednesday, November 15th, 2006

Joel Spolsky wrote ages ago about commoditising your complements. The basic idea is that for every product there are complements – things that are necessary, or useful, additions.

For example, no matter how good your shop is, if you have no parking and no bus routes nearby, you will struggle. The transport is a complement of retail. Cars are useless without petrol. I have even read about a cinema chain that offers creche facilities – babysitting is the complement of a night out.

Our existing product has the following complements: Microsoft Sql Server, Microsoft Windows 2003, a network administrator, reasonably specced client machines. What do all of these have in common? Cost. None of them are cheap.

Compare that to a web-based product or service, like Basecamp. What are its complements? A decent internet connection and a web browser. What do they have in common? They are extremely cheap, or free.

Of course, your product has to be good, and not every piece of software lends itself to a browser interface (even one as amazing as the Joyent UI) but if ever the wind was blowing towards web-based products it is now.

What’s in a name?

Wednesday, November 15th, 2006

A quick recommendation: if you’re looking for a domain name try Name Boy.

Type in one or two words, it runs them through a thesaurus and then does a domain name search on various combinations. For example type in ruby and rails and it will tell you that rubyrails.com is taken but railsruby.com is available. As is rubytramway.com and gemrails.com.

Very useful if you’re stuck for a product name – start with a pair of words, see what it comes up with and combine one of those words with one of the suggestions. And repeat. It’s not 100% – we decided upon our product name today and nameboy said that the .com was available, but it turns out it was not. But we’re grabbing the .net which is even better.

… and so it begins

Monday, November 13th, 2006

Zune

Interestingly, a music lawyer friend of mine suggests that the “MS is trying to ruin Apple’s next round of negotiations” and the Universal has Microsoft over a barrel schools of thought are both true.

Active Record validations and transient objects

Wednesday, November 8th, 2006

There I was, handling a multi-stage function using a nice transient object stored in the session. And I got to thinking about the error states. Important you see, those error states.

And I thought to myself “I want to use error_messages_for”. So I grab my copy of “Rails Recipes” (if you haven’t got it, you probably should) and turn to Recipe 64 “Using Validations outside of Active Record“. The recipe is reasonably simple: all the validations stuff is in a module called ActiveRecord::Validations. In theory, you just need to include that and you’re all set. Except it’s not quite that easy. ActiveRecord::Validations expects you to have a few extra methods – save! and the like. So Chad Fowler defines a new module, Validateable, that includes ActiveRecord::Validations and defines a few blank methods. I faithfully copied all this code, deliberately typed in some invalid data and hit “Save”, expecting the nice .field_with_errors stuff to appear. Instead I got a “method missing human_attribute_name”. Search through the docs. Nothing. Search through the source. Nothing. I tried defining my own, both in the Validateable module and in my transient object. Arses.

Mr Fowler does state, in his book, that the recipe depends upon the internals of ActiveRecord, which are subject to change. The book is from Rails 1.1. I’m on Rails 1.16. So I guess they have changed.

I asked for help on a mailing list, and got the response “when Rails starts making something hard, it’s probably the wrong thing to do“. Which is true. So I cheated.

I created a new ActiveRecord model called Pseudo. The migration for this model looks like:

class CreatePseudos < ActiveRecord::Migration  def self.up    create_table :pseudos do |t|      t.column :type, :string    end  end  def self.down    drop_table :pseudos  endend

In other words, there’s not much to it.

Then I defined Pseudo itself.

class Pseudo < ActiveRecord::Base  def save    raise "Cannot save a Pseudo Model"  end  def method_missing(symbol, *params)    send $1 if (symbol.to_s =~ /(.*)_before_type_cast$/)  end  def transfer_attributes(params)    params.each do | name, value |      self.send("#{name}=", value) if self.respond_to?("#{name}=")    end  endend

Again, not much to it. I overrode save as these models are never intended to be stored in the database. I overrode method_missing to deal with ActiveRecord’s field_before_type_cast method. And I created a new method, transfer_attributes, for reasons that will become clear later.

Finally, I defined my transient object.

class Transient < Pseudo  attr_accessor :field1  attr_accessor :field2  validates_numericality_of :field1  validates_inclusion_of :field2, :in => ['value1', 'value2']end

So Pseudo, the base class, and its associated table have no real storage associated with them. The descendant class defines all its properties using attr_accessor and just validates against these. To check you call transient.valid? rather than transient.save – and your view can then call error_messages_for to show the errors collection. The only issue remaining is that you cannot use

@transient.update_attributes params[:transient]

in your controller because none of your ‘fields’ exist in the underlying table – meaning ActiveRecord complains. Which is the reason for the ‘transfer_attributes’ method in Pseudo – it does the same thing but works with any property setter, regardless of whether there is an underlying field or not.

So, it’s not quite “using validations outside of ActiveRecord” but it is “using ActiveRecord validations on transient objects“.