Peel me a Grape :: We make things work

We Make Things Work :: Blog

Links for 15th July 2008 ()
July 15, 2008

I been continually keeping these links unread in google reader. This post is to share them and some comments – appeasing my empty inbox conscience.

How to succeed as a first time UX manager.

UXmatters post about succeeding with your first job as a UX Manager turns out to be a great article on how to be a good manager or leader.

Smashing Magazine: Sign-up Forms

A two part article titled Web Form Design Patterns: Sign-up Forms (part 2)

If you want to maximize the revenue of your service you need to maximize completion rates of your web forms.

Based on detailed analysis of the signup forms on 100 popular websites, it’s a great check list, and certainly a resource I’ll go back to. It reminds me of Defensive Design for the Web – on steroids!

I highly recommend Smashing Magazine as a source of design inspiration.

ZURB

ZURB made a job posting to jobs.rubynow.com – but they went the extra yard and made it stand out. So instead of the dozens of postings like this:

they caught my eye with:

It makes a good zeroth impression, before I even know what they do. Zurb go on to list 17 reasons to join, from profit sharing to free house cleaning.

I not a fan of time tracking software – who is? Bit there is a need. The tool used in my last job was so distasteful, that someone else filled in my time for me – thanks Tom ;)

Time tracking software should be simple and quick to use, letting you get on with what you’re good at. I got a demo of 1time at Crunch Ludd – it’s neat.

Posted as part of Tuesday Push – a collaborative initiative, kicked off by prolific blogger Damien Mulley to help promote Irish tech companies. Pushing 1time.

ActiveSupport adds many conveniences to standard classes. to_s on times/dates is one of these.

Instead of using strftime you can use to_formatted_string (aliased as to_s) – with many useful defaults.

>> t = Time.now
=> Fri Jul 11 23:07:37 +0100 2008
>> t.to_s(:short)
=> "11 Jul 23:07" 
>> t.strftime('%d %b %H:%M')
=> "11 Jul 23:07"

I want to display dates using the time_ago_in_words helper – but display any dates older than a week as a normal date.

Time::DATE_FORMATS accepts procs to do the formatting – so with a little bit of coercion we can use the helper in our proc. Put the following in config/initializers/time_formats.rb

class Helper
  extend ActionView::Helpers::DateHelper
end
Time::DATE_FORMATS[:ago] = lambda { |time| time >= 7.days.ago ? "#{Helper.time_ago_in_words(time)} ago": time.to_s(:short) }

gives you

>> 1.day.ago.to_s(:ago)
=> "1 day ago" 
>> 10.days.ago.to_s(:ago)
=> "01 Jul 23:32"

One good reason not to use time_ago_in_words like this is that it makes anywhere you display dates like that less cacheable (if you want accurate dates). I’ll look into how we could instead use javascript to implement the time_ago_in_words in browser, not sacrificing cacheability in another post.

respond_to allows us to emit different views using the same action:

def index
  @people = Person.find(:all)
  respond_to do |format|
    format.html
    format.xml { render :xml => @people.to_xml }
  end
end

In this case you could retrieve xml or html using the same url – by varying the ‘Accept’ header. But it turns out this header is used quite inconsistently across browsers, and the order of your format calls in the respond_to block can be significant. (Which isn’t obvious)

Disabling use of the Accept header is a welcome change.

Most people probably haven’t relied on it for a while. The prefered approach is to use formatted urls (eg. /people/1.xml or /people.js), which will still be routed to the same action – through the default route of /:controller/:action/:id.:format. or with map.resources.

Changes like these show how rails is evolving – correcting mistakes as it goes. A case study in continual improvement.

atom.will_paginate ()
July 06, 2008

The Atom spec mandates the use of link elements with rel=next|prev to support paginating collections of entries. The Atom Wiki has a page explaining the meaning of various link tags. A developerWorks article on Paging Atom suggests rel=first|last are also standard. last is useful to indicate how large the collection is, first is meaningful in the context of pagination – self has the same meaning – albeit somewhat ambiguous in this context (is it url for this page or url for the first page?).

Anyways…. I’d like to paginate my atom feeds with the same ease I paginate my html views with will_paginate

<%= will_paginate @articles %>
simplest way is with a helper method giving you something like
will_paginate_atom(@articles, builder)
with a helper like this:

def will_paginate_atom(collection, builder)
    total_pages = WillPaginate::ViewHelpers.total_pages_for_collection(collection)
    builder.link(:rel => 'next', :href => atom_url(:page => collection.current_page + 1)) unless collection.current_page.eql?(total_pages)
    builder.link(:rel => 'prev', :href => atom_url(:page => collection.current_page - 1)) unless collection.current_page.eql?(1)
    builder.link(:rel => 'last', :href => atom_url(:page => total_pages))
end

We could monkey patch atom_feed_helper to allow even nicer syntax. TODO.

atom_feed do |feed|
....
  feed.will_paginate(@articles)
.... 
end

Note: Feedburner doesn’t support paginating like this at the moment – so your next/prev/last links won’t be rewritten as feedburner.

Happy paginating!

Now with Disqus ()
June 27, 2008

I can count the number of legitimate commenters to this blog on one hand (thanks guys!) – but would need hundreds of hands to count the spam attempts.

So – we now use the increasingly popular Disqus for comments. It’s a nice piece of work!. Hell, you can even make video comments thanks to Seesmic.

Noel Rappin blogs with some great examples of how awsome named_scope is. It’s probably my most used feature in rails 2.1 so far. In excitement I neglected to read the docs or source until yesterday… I stumbled upon rails-doc the new kid on the block of rails doc apps. I realised you can use named_scopes with has_many associations. Sweet!!

I started off going nuts with named_scopes and lambda’s, now realising I can delete lots of code and make use of my association proxies instead.

class Post < ActiveRecord::Base
  belongs_to :user
  named_scope :by_user, lambda {|user| {:conditions=> {:user_id => user.id}}}
  named_scope :recent, {:limit => 10, :order => 'created_at desc'}
end

class User < ActiveRecord::Base
  has_many :posts
end

Post.by_user(user).recent 

becomes

class Post < ActiveRecord::Base
  belongs_to :user
  named_scope :recent, {:limit => 10, :order => 'created_at desc'}
end

class User < ActiveRecord::Base
  has_many :posts
end

user.posts.recent 

One downside is that it’s no longer as easy to test the combined proxy_scope when using has_many with named_scope. I had a quick play with AssociationReflections but have yet to find a solution. For example – it would be nice to be able to do stuff like this:


user.posts.proxy_scope.should == {:conditions => {:user_id => 123 }}
user.posts.recent.proxy_scope.should == {:conditions => {:user_id => 123 }, :order => 'created_at desc', :limit => 10}

DTO, NDP and Transport 21 are consulting the public about the future of transport in the Greater Dublin Area. In principle it’s great. They’re reaching out the the people they serve to help influence their plans. Their approach sucks.

It starts by asking what 3 words should appear in the Vision Statement. Who cares about vision statements when they’re stuck in an hour long commute? The needs of DTO/NDP/Transport21 to produce a document don’t equate to users/citizens actual needs, in this case improvements to transport in Dublin over the next 20 years.

Ask structured questions and you’ll get boring answers, encourage conversation and you’ll get inspiration.

Question 3vii of 5 is a good one. Looks like question 9 of 11 to me… I felt cheated when I got to question 6 of 5… and nearly left the site.

question 9 of 5. Wtf?

I can’t think of any sane person who wouldn’t agree with all 5 statements – so what’s the point – make your users annoyed?

If you must use a questionnaire – make it an exceptional. (note google returns 4 pages for the query ‘exceptional questionnaire’

So who can 2030 vision learn from? Dell manage to get tens/hundred of thousands of people to create/promote and filter ideas about how dell can improve their business and products. 2030vision could do with some ideastorming. One person’s idea can spark a conversation and result in change. Companies like Zappos trive by engaging with customers on Twitter. 2030vision might only reach to a minority on twitter, but it would be a massive step towardness openness and involvement. Change your culture by changing behaviour.

How about tweet ideas to @2030vision? Can we change this page no tweet of 2030vision

Summary

Apple online store experience sucks! but I had a great experience with the telephone support line.

Some Good

I ordered a Mac Pro for work recently. I was delighted with the prompt delivery and have no problems with the product.

Some Bad

I had problems getting the apple web store to accept payment (I was paying with Campbell’s card) – it took me three attempts with slight variations on billing address for the order to be submitted successfully.

Some Weird

I noticed I’d received two order confirmation emails – but glossed over it – since in fact I often receive multiple copies of the same email from apple (with no consistency…)

Apple regularly send me multiple copies of the same email

Some Weird

I double checked the emails and noticed they had different order numbers – and slightly different billing addresses… So wasn’t surprised the next day when the delivery agent arrived with two, he suggested that perhaps they’d mistakenly dispatched 2 and made it simple for me to refuse delivery of one of them . In the mean time I received a third order confirmation…

Some even weirder stuff

  1. I received email addressing me as Darragh Scott…

Apple call me Darragh Scott

  1. My apple account page calls me Campbell Scott….

Apple call me Campbell Scott

  1. While ‘logged in’ to apple.com store it regularly asks me to login – as if they’ve problems with their session management.

Some Bad

Took a while to find the number to call in Ireland : 18508820480.

Some Good

I got through to Susan. She asked all the right questions, and gave me all the right answers. She never questioned that I may have been in error. And she finished the call by explaining what would happen (I’d receive a returns number, a courier would collect it, and we’d be refunded the extra payments), and telling me she’d follow up with a clear email summarising the case and including her direct contact details.

I’m not impressed by all the weirdness with Apple’s online store – even the best can’t get the simple things right. Overall, my good feelings about Apple have been restored thanks to the very pleasant and successful interaction with Susan.

flash.now sets a flash only available for the current action. Controller/Functional testing flash.now can be problematic. This is now fixed on edge rails.

Previously one approach was to stub out the sweep method on flash in your tests.

Here’s how to do that nicely if you’re using rspec. Apply a global before block to all controller behaviours, a handy thing to know about.

Spec::Runner.configure do |config|
  config.before(:each, :behaviour_type => :controller) do
    @controller.instance_eval { flash.stub!(:sweep) }
  end
end

Dublin Accomodation Links ()
May 20, 2008

I keep telling people about this and forgetting to send the links, so:

IIA congress highlights ()
May 16, 2008

I attended the IIA contress today (Thursday…). I hadn’t been before.

Joe Newell talked about Ammado. They’ve done a great job in penetrating the global market. I was a little bit surprised that ‘Donate Now’ wasn’t a feature introduced earlier. Although that just says that the community alone was enough to attract hundreds/thousands of not for profits and charities.

Barry Meehan from worldwidecycles impressed me. He came across as being incredibly down to earth and genuine. Sharing great experiences about how he’s using blogging, flickr, youtube to build a community around his business. His attitude is very much – add value to your community, and it will reward you in return.

Dell came across very well as innovators in customer engagement. I still dread few things more than having to call their call center, and their main store website is sucky…. Dell employ many people with job of contributing to their various customer engagement sites, and conversations emerging elsewhere on the web.

Bebo talked about some interesting stuff they’re doing – particularly with what you might call online interactive social television, Kate Modern, The Gap Year etc.. Interesting that some of these shows which started online are now being shown on traditional tv channels. Powerful ideas, and great revenue models – i don’t buy it – plenty of kids/teens do.

I ended up at the conference because I started working for IGOPeople about 2 weeks ago. CEO Campbell Scott presented about some of the trends behind the IGO idea and a few stories about what people can achieve on IGOpeople when it’s launched. I felt it went great – and I’m looking forward to launching out beta later this year. Mixed feelings on twittersphere – better than no feelings ;)

There was great consistency in the messages people talked about – consistent to the theme of the conference: ‘Beyond Websites: Business Uses of Social Networking and New Media’. Next year I’d love to see a little more diversity, in both the talks and the audience they attract. Kinda tiring hearing the same thing again and again for the day.

Feed the monkey metric ()
May 15, 2008

If I’m working late, hard at it, and you’re puzzled as to how you can help, be a servant leader. Ordering or collecting food is a great start! So many people and companies let themselves down on this – I’m glad I work with people that do it right,.

Monkey on Chicken!

Not too long ago Google launched static maps which will generate an single image of the map you want. This rocks! so often one wants to just show a particular view of a map - without the overhead of loading the entire Google Maps UI.

I was curious about how to convert a static map into a normal Google Map - perhaps 95% of the time I wouldn't be interested in browsing or changing a map - but want that option if needs be.

Den Odell points out an example of how to load Google Maps javascript on demand - by inserting a script tag into the DOM, and using the callback parameter to specify a function to call when the script is loaded.

Here's a quick example converting a simple static map. (go here if map isn't loading - key used in example is only valid the articles main page.)

convert
static map

Download example source

I wanted to check out the Java Closures Prototype , but when I downloaded it I found that it had a few shell scripts (javac, java, javadoc) that you should call instead of the jdk ones. I found this annoying, so I set up some ant to do it instead.

So, https://please.peelmeagrape.net/svn/public/java/closures/closures_ant.xml is an ant script that you can include:
    <import file="closures_ant.xml"/>
And then, if you call the ‘setup_closures’ target, it will download and extract the prototype, and override the definitions of the javac, java and javadoc ant tasks to use the closures prototype:
    <target name="build" depends="setup_closures">
        <mkdir dir="class"/>
        <javac srcdir="src" destdir="class" debug="true"/>
    </target>

Note: You will need java 1.6. On OSX, you can download this from The ADC . This will not change the system default jdk, so you need to put something like this in your .antrc:

JAVACMD=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Commands/java

With that all done, you can play with the closures prototype proper. I have a project in svn that uses this ant script. I have pasted in most of the source code from the Closures tutorial by Zdeněk Troníček so you can compile and run it (using ant tutorial). The ant decompile target will decompile (using jad) the code generated by the prototype on windows or mac, so you can see what kind of stuff it’s doing under the covers.
svn co https://please.peelmeagrape.net/svn/public/java/closures/ closures
cd closures
ant tutorial
So, now you can do stuff in java like (EnumerableStuff.java ):
List<String> words = Arrays.asList("The quick brown fox jumped over the stupid dog".split(" "));

System.out.println(map(words,{String s=> s.length()}));
System.out.println(select(words,{String s=> s.length()<=4}));
System.out.println(first(words,{String s=> s.length()>5}));
giving you:
[3, 5, 5, 3, 6, 4, 3, 6, 3]
[The, fox, over, the, dog]
jumped

Hopefully java 7 will see this and extension methods , and then I can stop feeling like I’m continuously compiling 1 line of ruby in my head into 6 or 7 on the keyboard!