Just A Summary

Piers Cawley Practices Punditry

So... I was wondering 3

Posted by Piers Cawley Sat, 17 Nov 2007 18:54:23 GMT

Has anyone written an Atompub client in JavaScript yet?

Rails tip: Side effect filters

Posted by Piers Cawley Mon, 08 Oct 2007 12:13:00 GMT

Some bugs are easy to overlook. One that has a habit of catching me out is a Rails filter that returns false occasionally when it’s being evaluated purely for its side effects. Here’s how I’ve started working round the issue:

def side_effect_filter
  return if some_conditions_not_met?
  ...
ensure
  return true
end

What happens here is that the ensure catches any return and returns true instead. The catch is that if something throws an uncaught exception anywhere, it too gets caught by the ensure and true is returned. Which may not be what you were looking for. Here’s how to fix that issue:

def side_effect_filter
  error = nil

  return if some_conditions_not_met?
  ...
rescue Exception => error
ensure
  raise error if error
  return true
end

This catches the exception in a rescue and stashes it in the error variable, then the ensure checks to see if an exception was thrown and rethrows it, otherwise, it just returns true. Which is bulletproof, but ugly. Let’s wrap the ugliness up in a method:

def self.side_effect(method, &block)
  def_method(method) do
    error = nil
    begin
       instance_eval(&block)
    rescue LocalJumpError # catches an explicit return
    rescue Exception => error
    ensure
      raise error if error
      return true
    end 
  end
end

side_effect :side_effect_filter do
  return if some_conditions_not_met?
  ...
end

Again, not pretty inside, but all we actually care about anywhere else is that the interface is good and does what it’s supposed to do. Encapsulated ugliness has its own beauty. Especially if you get the interface right.

Homework

This should pluginize quite nicely, just install the method in ActionController::Base and ActiveRecord::Base and you have a very useful tool, but I’m still not sure that the method name is right, so I’m holding off on it. If someone were to come up with a bulletproof name and release a plugin, that would be wonderful though.

Updates

Fixed a scoping issue in the encapsulated version of the code. Replaced yield with instance_eval(&block)

Blessed are the toolmakers 2

Posted by Piers Cawley Tue, 05 Dec 2006 17:07:00 GMT

My dad drives a vintage Fraser Nash. I say drives, but that’s only half the battle, a large part of his Nash time is spent fettling it. It’s an old car; bits wear out, break or drop off. And because it’s an old car, you can’t just nip round to Halfords and pic up a replacement; nor can you head down to the breaker’s yard and cannibalize something else. So he has a lathe and a milling machine and a bewildering collection of tools. When he needs a part, he will disappear into the machine shop and, after sufficient swearing and/or bleeding, he will emerge with a newly made part. For dad, it’s all part of the fun of running a vintage car. If he weren’t able to do the work, the Nash would have had to remain a pleasant pipedream.

I don’t know my way around a machine shop, except in the vaguest and most theoretical way. The tools I’ve grown up knowing to use are programming languages, editors, fine manuals and the mental tools a grounding in mathematics brings.

So, when I’m putting a new photography business together, and I realise that a couple of the supporting software tools that I had vaguely assumed ‘should exist’ don’t actually exist, I know that it doesn’t matter. I may not know Cocoa programming yet, but I know programming, so I’m confident that, like dad in his machine shop, I’ll be able to knock something up that does the job.

On reflection, I realised that this is probably a good thing. If I can set up and run the business with a combination of off the shelf software, then it’s trivial for potential competitors to reverse engineer the business and do the same (let’s assume here that the business is a success) and I’m left competing on margin in a service industry. No fun at all.

Being able to make my own tools gives me a competitive edge.

Why aren’t there more tool makers?

Because I’m a programer, I know that if my working environment isn’t habitable, it’s possible to fix it. I carry that approach to working with other capable software – keep typing ‘teh’ when I mean ‘the’? Add a macro, autocorrect rule, snippet or whatever you want to call it to the tool I’m using and wonder if it might be a good idea to implement some kind of central repository for such things so I don’t have to repeat myself with every new tool.

The tools to do this sort of thing are there; they’ve never been more available, and in many cases they’re not hard to use, but surprisingly few people seem to be using them. Why is that? Why do people put up with annoying software when (often) the fix is only a couple of settings away? Why are programmers so rare?

I wish I knew. Or maybe I don’t – as long as people don’t realise how easy it is to fix/make things, I’ve got an edge.

Taking control of your tools

If you let your tools shape you, then you’re going to be awfully uncomfortable. Make a commitment to at least capture your annoyances with the tools you use most frequently. Make a note of the problems and think about what you wish the software would do and blog about it. Here’s a couple of stories based on some of the things I need to be able to do for my business:

Auto Slideshows

As an onsite picture editor, I need to run a ‘smart’ slideshow on a secondary display while I working on images on the primary display. The slideshow should be based on an Aperture album and should automatically pick up any changes in the underlying album.

Auto crediting

As an onsite picture editor, I need my slideshow to display a credit on any images in the slideshow that weren’t taken by me. If the Credit metadata doesn’t match ‘Piers Cawley’ the string “by ” should be added as a ‘watermark’ to the displayed image.

If you’re a programmer yourself, you’ve just given yourself a nice list of projects to be working on when you have the time. If you’re not, then you’ve just written a useful set of requirements. Tag your post ‘lazyweb’ and if you’re lucky someone might know how to do exactly what you want without having to write a line of code, or someone else might agree that it’s something that needs fixing and actually fix it. If neither of those two happen, well, at least you’ve vented your frustration, and that’s not a bad thing either.

A sketch of declarative ActiveRecord Migrations

Posted by Piers Cawley Fri, 24 Nov 2006 12:18:00 GMT

Writing migrations can get pretty tedious when you’re being scrupulous about writing both the up and the down side of the migration. Okay, so the Textmate ninjas amongst you can use scarily clever snippets to populate the down migration while you write the up method, but I can’t be the only Mac user who still prefers Emacs. And not everyone gets to run on Macs either.

So, inspired by something Jamis Buck wrote about designing a DSL, I’ve been sketching out a DSL for describing the easy parts of a migration in declarative style. None of this is implemented yet, but I’m pretty sure that it’s relatively simple to implement for a decent Ruby metaprogrammer. I’m brain dumping it here so I can come back to it later, or, you never know, someone might have implemented it by the time I revisit…

The sketch

class AdjustContentTable < ActiveRecord::Migration
  class Content < ActiveRecord::Base
    include ActiveRecord::Migration::Delta

    delta do
      +(:extended, :text)
      -(:excerpt, :text)
      +index :text_filter_id
     end
   end
  end

  callbacks_for(:up) do
    before_any_changes
    Content.before_changes { ... }
    Content.before_additions {...}
    Content.after_additions {...}
    Content.before_removals {...}
    Content.after_removals {...}
    Content.after_changes {...}
    after_any_changes
  end

  callbacks_for(:down) do
    ...
  end
end

Implementation Pointers

By making delta do its work in a block, it’s possible to instance_eval the block using a Delta object that has appropriate implementations of + and -.

Then callbacks_for[:up] puts its block into, say @callbacks[:up] and the block is yielded to to set up the callbacks by the default implementation of up. The default up probably looks something like:
  def self.up
    @callbacks[:up].call
    apply_all_deltas
  end
Of course the fun bit is the implementation of apply_all_deltas – the per class apply_delta is reasonably simple:
  def self.apply_delta(direction)
    callback(:before_changes)
    apply_additions(direction)
    apply_removals(direction)
    callback(:after_changes)
  end

  def self.apply_additions(direction)
    if has_additions?(direction)
      callback(:before_additions)
      eval additions_for(direction).to_ruby
      callback(:after_additions)
    end
  end

  ...

Thinking about it, apply_all_deltas is going to take a certain amount of grovelling about in the namespace to work out what classes need to have their deltas applied, but even with just per class delta declarations, this should be a useful thing to implement.

Braindump ends

Sorry this doesn’t come with a handy dandy Rails plugin with it all implemented; your contributions in this area would be very gratefully received.

Dear LazyWeb

Posted by Piers Cawley Tue, 14 Nov 2006 13:24:00 GMT

I would love to be able to run a slideshow on a second screen based on a ‘live’ album in Aperture. So, when I drop an image into an Aperture album on my primary screen, it shows up when appropriate in the secondary screen slideshow.

I can live with having to take an explicit ‘publish changes’ type step from within Aperture, but I’d rather not, and I certainly don’t want the secondary slideshow to stop.

Dear LazyWeb

Posted by Piers Cawley Fri, 11 Aug 2006 18:32:00 GMT

I was just about to start writing a multimethod system for ruby when I realised how much I miss Perl tools like Module::Starter. CPAN has a whole suite of tools which make it at least as easy to do the Right Thing when setting up your project than it is to succumb to ad hockery. Start your project using Module::Starter, and you get a sensibly laid out that works well with standard Perl build/installation tools, a stub of your module, with the various boilerplate bits of the documentation filled in, a test directory, README, etc…

It shouldn’t be impossible to do the same thing for Ruby. Most of the tools are already here. Just use the Rails generator to build a standard stub directory layout, complete with gemspec, readme, license, tests, etc. To a certain extent, the only real issue is deciding on what a sensible project template should be.

Or maybe this already exists and I just haven’t found it.



Just A Summary