codahale.com٭blog

This is my old blog. My current writing is here: codahale.com

Singletons: Only The Lonely

I’ve never really spent much time on design patterns, but recently I’ve been reading Head First Design Patterns and I can’t help but notice how much easier Ruby makes certain patterns. Composition over inheritance becomes as easy as sneezing with mixins, and the thoughtful Ruby folks have already implemented quite a few.

I don’t use Singleton as much as I should (preferring instead to just stuff all the methods in the class), but for objects which have an expensive or complicated instantiation method, it’s extremely useful. (I mean, that’s why it’s a pattern, right?) Also, the Singleton mixin takes care of all the threading complications to which Singletons often fall prey.

But effective and useful it may be, Singleton is ugly, and for one big reason: instance. I hate typing instance all over the place, and it’s been a big stumbling block in my acceptance of the Singleton mixin. I understand why it’s there–the pattern doesn’t mention moving methods from instance to class scope–but on a syntactic level it irks me. If I’m using a singleton, I really shouldn’t need to know that it is a singleton–it could be a magic happy fairy princess castle for thread-safe methods, for all I care.

So yeah, I went and did something about it. I combined the power of Singleton and Proxy. Check it out:

module Singleton
  class << self
    def included_with_proxy(base)
      included_without_proxy(base)
      base.class_eval do
        class << self
          def method_missing_with_proxy(m, *args)
            if instance.respond_to?(m)
              instance.send(m, *args)
            else
              method_missing_without_proxy(m, *args)
            end
          end
          alias_method_chain :method_missing, :proxy

          def methods_with_proxy
            return (methods_without_proxy + instance.methods).uniq
          end
          alias_method_chain :methods, :proxy

          def respond_to_with_proxy?(m)
            return respond_to_without_proxy?(m) || instance.respond_to?(m)
          end
          alias_method_chain :respond_to?, :proxy
        end
      end
    end
    alias_method_chain :included, :proxy
  end
end

You’ll need to require singleton and activesupport for this one, and since it uses alias_method_chain, you’ll need to either be running Rails edge or grab it from the source.

What it does is pretty simple: if it’s not already a class method, Singleton passes it on to its instance:

class Magician
  include Singleton

  def dove
    "*poof* A dove!"
  end

  def segway
    "*rides Segway around*"
  end
end

Magician.dove   #=> "*poof* A dove!"
Magician.segway #=> "*rides Segway around*"

No more instance, though it’s there if you need it.

14 comments »

Rails programmer needed!

So I’m going to be leaving Gilsson shortly for a new startup in Berkeley, which means that my old job is now open. If you’re within commuting distance from Hayward, CA and are looking for a Rails/IT position, check this out:

Responsibilities:

  • Maintain local network of 5-10 workstations and 1-2 file and database servers, with a mix of Windows XP and Linux.
  • Improve and extend our Rails-powered e-commerce codebase, eventually rolling out new versions of two of our online stores.
  • Improve and maintain our Rails-powered product management database.
  • Maintain our Fedora Core 5 production Rails web server (Apache 2.2 + Mongrel, natch).
  • Develop custom applications for in-house use.

Requirements:

  • Strong experience with Ruby on Rails, web development and associated technologies, including Javascript, XHTML/CSS, XML, AJAX/AHAH, and RSS.
  • Experience with SQL in general, and using and configuring MySQL specifically.
  • Experience with e-commerce.
  • Commitment to web standards and accessibility.
  • Experience with test-driven development.
  • Familiarity with Subversion and Trac a plus.
  • Ability to be self-directed, complete tasks with minimal management oversight.
  • Flexibility and good on-the-fly problem-solving skills.

It’s a great place to work, and Ming (the CEO) is an awesome boss. There’s a lot of flexibility in work hours, and a lot of autonomy in the position–you get problems, you make solutions. (Plus, if you apply, you’ll probably get to meet me.) All of the code is well-documented, and all the important bits have full test coverage–no Daily WTF material here.

If this sounds like your kind of gig, email your resume to ming@gilsson.com with the subject line “IT Manager”. If you have any questions about the job, email me and I’ll do my best to answer them.

Regarding the new job, I’m going to be doing some Rails programming with a small team of people who I really admire, including the author of one of the books on my desk right now. I guess that’s one book I can leave for the new person… ;-)

2 comments »

Le Tour De WTF

Okay, so right off the bat, Hincapie disappears in a puff of disappointment–the guy at the Link said he lost too much weight too quickly, and he’s down to like 155lbs, which for a guy who’s just a touch shorter than I am is Jack The Pumpkin King territory–and Landis, after having dropped a bomb (”oh, bee-tee-dub, I’ve got the hips of an 80-year old woman who’s allergic to calcium”), somehow pops to the top! I’m happy to see a Yank in the front, but I’m kind of confused–a “destroyed” hip joint and a yellow jersey seem like they’d clash. Then in Stage 16, Landis conks out in the Alps and drops a full eight minutes behind the leader, kind of killing his shot at the Tour.

That’s more like it, I thought, that’s the familiar disappointment that I’d managed to not feel for the past seven years.

Until I crack open the Bloglines this morning to find this:

American Floyd Landis (Phonak) chased down and destroyed an 11-man breakaway, then soloed away to win the 17th stage of the Tour de France Thursday in Morzine after 200.5km of racing on the final day in the Alps.

He goes from bonking out in the Alps to some kind of Robocop-in-bicycle-mode breakaway in less than a day. And this isn’t just a last gasp on his way out–he put almost six whole minutes of shame in everyone else’s game, and now he’s 30 seconds away from the yellow jersey again.

God, I’m almost happy Lance retired–this is an amazing Tour.

3 comments »

My New Mantra

My new mantra, as displayed in my WordPress 'new post' page: DO NOT INSULT THE PEOPLE YOU LIKE

My last post caused a bit of a stir, mainly because I was a bit of a jerk and quickly dismissed some folks who are, by many objective standards, actually cooler than I am. Sometimes I tend to get carried away with knocking down ideas which annoy me, and I forget that there are people and contexts behind those ideas which lend them a lot more weight and reason than I’d originally seen.

So to everyone I pissed off, I sincerely apologize. Matz is nice, so we are nice.

(I still don’t think search fits into CRUD, and I’m more than happy to haggle that one out to the bloody end.)

8 comments »

CRUD is not the only user interaction metaphor, thank you

Update: This post takes some liberties with the context and intent of the quotes within it. Most of this was unintentional, but all of it was thoughtless of me; they deserve better. The post itself is not all that interesting, but the comments within have some really awesome back-and-forth over the semantics of web applications.

Update 2: Evan Weaver has written a post which makes a much better set of points than I have, but he agrees with me, so I’ll pretend like I had it all worked out ahead of time but just didn’t feel like typing it all up. ;-)

With that in mind…


There’s been a huge push lately to integrate RESTful web services into the core of Rails, and I think that’s awesome. Anything that advances the cause of light-weight, human-readable web services strikes me as a good idea. The Rails approach is a good one, not just because it has characteristically beautiful code, but also because it looks fantastically easy to work with.

That said, I think some people are taking it a little too far, like this article on habtm, “if your models aren’t namespaced, why should your controllers be?”:

The New CRUD is about using your controllers to expose your models and various other things as objects. If your models aren’t namespaced, why should your controllers be?

With this new approach, you start thinking about how to move your controllers over to a flat namespace and still have your separate backend layouts for editing actions.

First, the reason that your models are not modularized is because the unit testing framework dies a horrible death when you use modularized models, not because it’s a design decision that makes any sense. Thus the flat namespace for Rails models is not a solid base from which to extrapolate the design of the controllers.

Second, namespaced controllers fit just fine with the latest CRUD push by rails-core. Rails 1.1.3 breaks the default routing for modularized controllers, but that’s fixed for 1.1.4. A bug in a revision release shouldn’t determine your architecture plans, and in the meantime you can work around this issue by either freezing Rails to the stable branch or adding explicit routes to your modularized controllers:

map.connect 'admin/users/:action/:id', :controller => 'admin/users'

Finally, and most importantly: CRUD is not the only user interaction metaphor. You should choose an interface (and thus, a controller’s structure) based on what your users’ goals are, not what your system metaphor ideology dictates.

When people use modularized controllers, it’s usually because they realize that they have two or more groups of people using their application who have overlapping yet mutually exclusive needs. For an online store, the information returned by a Read action for customers will be different than that of an action for store employees. To try to shoehorn these two needs into the same interface is bad design, plain and simple.

A flat namespace for your controllers only makes sense when your users are all doing roughly the same thing. That’s not always the case, and to overlook that possibility in order to stuff your application domain into some cool new paradigm is not responsible software development. Don’t take this to mean I don’t like RESTful systems–I do–or that I think the latest CRUD push in Rails is bad–I think it’s awesome–but the idea that CRUD is the one, true pattern of user interaction… well, that just seems a bit silly.

Speaking of silly, search does not work with a CRUD metaphor, despite what people may think:

Instead, consider using a Search model. Create a search resource that holds all the options for the query. Then you can execute it whenever you want. POST /searches (post data contains query options) would redirect to GET /searches/42 or GET /people/?searches=42. You could even make it so that searches are unbound until execution, like blocks: GET /searches/42?on=people.

*sigh*

Why is this a good idea? So a single HTTP transaction can be replaced with two? Because the POST verb just doesn’t get enough love these days? A search session is a Read operation, end of story. Instead of saying “give me the record whose ID is 4,” you’re saying “give me the records which have ‘frankenberry’ in the description.” Not, “create a search session with these parameters, then read it and the magic results you have appended to the end of it without my say-so, then finally destroy it.”

So why would people want to do this?

Now, I just do a quickie insert of the pertinent info into our DB, then apply the search to the engine (totally different middleware). Boom! Instant ’search history’. To find out why someone did something ‘downstream’ in the app, looking up their most recent search is trivial.

Shorter version: “I confuse searching with logging.”
Solution: Rename your model LoggedSearch.

Consider this: have you ever wanted to:

  • Know what your users are searching for?
  • Allow your users to save their search criteria for later use?
  • Define a “google alert” type feature in your app?

If you wanted to do any of these, having a search model object would save your bacon. Imagine having an Alert object that has a 1-many relationship with your Search object.

Shorter version: “I confuse searching with logging, preferences, and alerts.”
Solution: Make LoggedSearch, SearchSetting, and SearchAlert models.

This is the kind of crap which buried XML-RPC, folks: overengineering a solution because you’ve got a shiny, new hammer and the world is your nail. The first thing one should do when modeling an application domain is to figure out what people actually want to do with it. If that lines up with CRUD, awesome. If not, don’t force it. It just adds complexity where none is needed, which is exactly the thing RESTful web services were designed to avoid.

Moral of the story? No single metaphor fully expresses the richness of human-object interaction, and any totalist ideology will result in a poorer user experience. CRUD is a solution, not the solution.

37 comments »