Shifting to the client again

— March 15, 2012 at 16:33 PDT


This is my take on the current shift to rich, in-browser JavaScript apps.

Looking back over a few decades, this is the progression of how applications have been built:

  1. mainframes and dumb terminals
  2. minicomputers and smart terminals
  3. networked workstations
  4. workstations and shared code/data repositories
  5. web apps and static HTML
  6. web services and rich browser apps

Translation: The main body of the application code lives on the:

  1. server
  2. server + client
  3. client
  4. server + client
  5. server
  6. server + client

The server/client pendulum swings back and forth. The next logical step is apps that run on the client using standard services. Just give it a few more years...

0 commentsarchitecture

Modularized Association Methods in Rails 3.2

— January 20, 2012 at 11:03 PST


Happy Friday! It's Rails 3.2 day! The official release announcement mentions a few of the big changes, but I'd like to take a moment to highlight a relatively small change I was responsible for, one that I hope may make your life a little easier.

From the ActiveRecord CHANGELOG:

Generated association methods are created within a separate module to allow overriding and
composition using `super`. For a class named `MyModel`, the module is named
`MyModel::GeneratedFeatureMethods`. It is included into the model class immediately after
the `generated_attributes_methods` module defined in ActiveModel, so association methods
override attribute methods of the same name. *Josh Susser*

The point of this change is to allow more flexibility in working with associations in your model classes. When you define an association, ActiveRecord automagically generates some methods for you to work with the association. For example, a has_many :patches association generates the methods patches and patches= (and a few others).

Previously, those association methods were inserted directly into your model class. This change moves those methods into their own module which is then included in your model class. Your model gets the same methods through inheritance, but also gets to override those methods and still call them using super. Let's take a look at two ways this makes things easier for you.

Sometimes you want to replace the standard generated association methods. That's always been easy to do simply by defining new methods in your model class. The only wrinkle was that you had to make sure you defined your method after you set up the association, or calling has_many would overwrite your method, since last writer wins. That was usually not a problem, but sometimes plugins or other monkey patching extensions could add an association after your model's class was defined, which wouldn't give you a chance to add your method afterwards. With this change, you don't have to worry about those order dependencies anymore. Since those methods are generated in their own module, the order doesn't matter. This is a pretty small issue all told and I doubt it affected many people, but it's still worth mentioning.

The real reason for this change is being able to compose your own methods with the standard generated methods. Before this change, you'd have to use alias_method_chain or some other fancy footwork to layer your own logic on top of the standard association functionality. Either that or you'd have to somehow duplicate the standard behavior in your own method. Ick. Now you can compose methods using inheritance and super, the way Alan Kay intended you to. Here's the example from the docs:

class Car < ActiveRecord::Base
  belongs_to :owner
  belongs_to :old_owner

  def owner=(new_owner)
    self.old_owner = self.owner
    super
  end
end

If you're familiar with ActiveRecord it's probably fairly obvious what's going on there, but I'll spell it out for the new kids. When you define the belongs_to :owner association, that generates a standard owner= method, and puts it in the module named Car::GeneratedFeatureMethods, which is the closest ancestor of class Car. If you're curious what this looks like, fire up the rails console and type Car.ancestors to see the class's inheritance chain. (Or use your own app and model, since that will be much easier than making up a new app just to see that one thing.)

In this Car class, you can see that changing owners keeps track of the old owner, so the new owner knows who to call when he can't figure out how to open the trunk. The generated owner= method does a fair amount of stuff including managing counter caches, running callbacks, setting inverse associations, etc. Skipping that could break a number of things, so after saving the old owner, you also want to run the generated method. Since it's in a module that Car inherits from, you only have to call super to get that to run. No muss, no fuss!

One more step towards simpler OOP in Rails! Thanks to my fellow Ruby Rogues Avdi Grimm and James Edward Gray II for complaining about the old state of things enough to motivate me to finally go fix this.

24 commentsactiverecord, associations, rails

Yak Shaving

— January 4, 2012 at 08:23 PST


As coders, most of us are not only familiar with the term yak shaving, but spend many of our days doing nothing but. I often struggle to explain to non-technical folks what I actually spend my time doing when I'm working and what it feels like. This is the most accessible explanation I can come up with.

Say you want to go see a movie with your friend Joe. You can't get away with leaving the house when the kitchen is such a mess, so you have to load and run the dishwasher before you go. Unfortunately you're out of detergent, which means you have to run to the store to pick some up. You want to ride your bike or it will take too long to get to the store. But your bike's front tire is kind of low, so you have to pump it up first. However, your roommate borrowed your tire pump and you don't know where it is, so you have to go find your roommate and ask him about it. He's over at a neighbor's place having band practice, but it's just a short walk. When you get there they are in the middle of practice so you have to wait for a few minutes. The only place to sit is on that ratty old sofa, right next to the drummer's sister, Monica, who will only let you sit there on the condition you smoke a joint with her. But before you can do that you have to dig around in the seat cushions to find the lighter she just realized she lost. You manage to find the lighter, and before too long you are smoking out with Monica. The band finishes the number and your roommate comes over to see what's up. You take another hit off the joint and say "Hey, we should order a pizza."

9 commentsjargon, programming

I heard you liked files

— December 1, 2011 at 21:35 PST


I was going to try and be clever and do a funny riff on this whole subject, but I just can't manage it. Here's the thing. Makefile was a dumb name for a file when Stuart Feldman wrote the make utility in 1977, but you have to forgive him because file systems were quite limited back then and filenames could only be a few characters long. The pattern was <filename.ext> - 8 chars for the name, 3 for the extension. I guess config.make wouldn't fit, config.mak looked weird, so Makefile it was.

Now we have no excuse. At all.

I respect and adore Jim Weirich, but I hope he feels at least a little shame for inflicting "Rakefile" on us all. That name choice seems to have set the stage for a proliferation of copycats. Now we have an ever-growing assortment of files that helpfully tell us they are files right there in the file name. Because something siting in a directory in the file system might be something else, like maybe a turnip or a bad hair day. Capfile, Gemfile, Assetfile, Vagrantfile, Guardfile...

You may ask: What's the problem? Why should anyone care about a cute little naming convention that continues a tradition going back over 30 years?

It may not be a huge deal, but there are a couple issues with this. All of these file formats are actually a variation on a well-accepted language: Ruby. But with a name that omits the standard .rb extension, language-aware tools have no chance to help us out. Syntax highlighting? Nope. Will awk search those files for you? No way. Will RubyMine figure out the structure of the code in those files? Forget it. OK, you can add those files to all your tools' configurations, then you're good to go. Until someone creates a new Crapfile and you have to go through and update all those configurations again.

Just because your configuration file's contents are written in a DSL does not mean you should pretend it's not Ruby anymore.

I urge every maintainer of a project that uses a name like Crapfile for the configuration file to move toward using a name that is compatible with language-aware tools. If you can't think of a name yourself, allow me to suggest this:

filename.sub(/file$/, '_config.rb').downcase

UPDATE: It has been pointed out to me that RubyMine actually does a pretty good job of dealing with these file names. Not perfect, but pretty good. Anyway, I don't want to come off as bashing RubyMine (I'm spending more time with it now and it's starting to grow on me), so substitute vim or emacs or TextMate or your most-hated editor instead.

19 commentsruby

Refactoring: be eager, not reckless

— October 19, 2011 at 09:54 PDT


The illustrious Chris Eppstein recently tweeted:

If some code should be refactored, stop what you are doing and refactor it.

I was about to respond, but realized I had more to say than would fit in a tweet. (Waiting for someone to fix that problem!) (Then I got distracted and didn't finish this article for a few days, oops.)

Now, Chris is really smart and probably doesn't mean exactly what he said, but it's easy to misinterpret his advice. I'll agree with him that you should be eager to refactor code when you discover the need. Don't let that technical debt accrue interest longer than necessary! However, you shouldn't be reckless about it.

Please keep this in mind:

Don't do a refactoring in the middle of making another change.

If you are working on a story and in the middle of making a code change when you discover the need to refactor something, make a note of it (I usually create a chore in Pivotal Tracker) and forget about it until you're done with the change in progress. After you complete the change, come back and do the refactoring. Make sure all tests are green before starting to refactor, and are green when done. The refactoring change should be a separate commit in git (separate checkin in SVN, etc).

OK, I'm pragmatic and realize that that approach doesn't work all the time, but it's a good ideal to shoot for. I considered discussing cases where it would be OK to refactor something in the middle of another change, but on second thought I think I'll leave that be for now. You'll learn that for yourself better than by following someone else's advice on the subject.

7 commentsagile, refactoring

Archives