Today's noun is: Reification 4
Reification: The mental conversion of a person or abstract concept into a
thing. Also, depersonalization, esp. such as Marx thought was due to capitalist
industrialization in which the worker is considered as the quantifiable labour
factor in production or as a commodity. – OED
In the sense that the OED has it, I’m not what you could call a fan of
reification. At work, we have a rule that anybody who starts talking about
‘resources’ when they mean ‘people’ gets a (verbal) slap.
However, in OO circles (or maybe just in my head), reification is a
good thing. It’s the process of taking something abstract and turning it into
a ‘real’ object. Usually, the word gets used for big things like turning an
intractable method into an object as a step on the way to refactoring that
method. I tend to use it in a slightly broader sense. For me, reification is
the process of turning something (a method or a data structure usually) into a
full blown object with its own behaviour.
Back when I was working on Pixie (a cunning, but weird, object persistence tool
written in Perl) we had a data structure which was used for keeping track of
managed objects. It started life as a hash. Everything was fine at first, but over
time we ended up with more and more code being repeated across the codebase
that was concerned with manipulating the cache hash. So, we replaced the
hash with a new object and pulled all the repeated code into methods on that
object, which gave us cleaner code to extend, and a strong feeling that we
should have turned the cache into an object much earlier in the game. (By
leaving it so long, we had a lot more code to move about, some of it in fairly
obscure places; tracking down the last bit took a while.)
Data structures like hashes and arrays are really useful in languages that have
them. The catch is, they have this habit of acquiring code. When this
starts to happen, it’s time to reify – to replace the hash with a task specific
object. In Ruby, it’s easy enough to inherit from Hash, but Hash comes with a
pile of methods that probably aren’t relevant to your particular
need. Generally it’s better to delegate. The first cut doesn’t have to be that
complicated, just decorate the hash with a new class and initialize an instance
of the class at the point where you had just made the hash.
Once that’s done, you can go through your code and move the bits that treat the
hash as a data structure onto your new class. As you gather all the common
behaviour to the new class, you’ll start to see places where you can improve
code quality by merging common behaviours, replacing complex conditionals with
polymorphism (you’ll probably have to introduce a factory method if you do
that) and pulling hash keys out into instance variables.
Stalled reification
Reifying your data structure isn’t an end in itself, it’s a step along the way
as you refactor your code.
There’s an example of a stalled reification to be found in
ActionController::Routing::Resources. Consider the implementations of
map_resource and map_singleton_resource, which are the worker methods used
whenever you do a map.resource or map.resources in your routes.rb.
def map_resource(entities, options = {}, &block)
resource = Resource.new(entities, options)
with_options :controller => resource.controller do |map|
map_collection_actions(map, resource)
map_default_collection_actions(map, resource)
map_new_actions(map, resource)
map_member_actions(map, resource)
if block_given?
with_options(:path_prefix => resource.nesting_path_prefix, &block)
end
end
end
def map_singleton_resource(entities, options = {}, &block)
resource = SingletonResource.new(entities, options)
with_options :controller => resource.controller do |map|
map_collection_actions(map, resource)
map_default_singleton_actions(map, resource)
map_new_actions(map, resource)
map_member_actions(map, resource)
if block_given?
with_options(:path_prefix => resource.nesting_path_prefix, &block)
end
end
end
There’s a lot of repetition there. The only differences are the classes of the
resource object, name of the second function called in the with_options
block. If we take a look at, map_collection_actions things start to look even
fishier. Here’s map_collection_actions, for example:
def map_collection_actions(map, resource)
resource.collection_methods.each do |method, actions|
actions.each do |action|
action_options = action_options_for(action, resource, method)
map.named_route("#{resource.name_prefix}#{action}_#{resource.plural}", "#{resource.path};#{action}", action_options)
map.named_route("formatted_#{resource.name_prefix}#{action}_#{resource.plural}", "#{resource.path}.:format;#{action}", action_options)
end
end
end
resource.collection_methods.each? Let’s see what happens if we the various
map_foo_actions methods into methods on ActionController::Resources::Resource. While
we’re about it, we can rename map_default_collection_actions to
map_default_actions on Resource, and map_default_singleton_actions to
map_default_actions on SingletonResource, which inherits from
Resource. map_collection_actions becomes:
def map_collection_actions(map)
collection_methods.each do |method, actions|
actions.each do |action|
map.with_options(action_options_for(action, method)) do |m|
m.named_route("#{name_prefix}#{action}_#{plural}",
"#{path};#{action}")
m.named_route("formatted_#{name_prefix}#{action}_#{plural},
"#{path}.:format;#{action}")
end
end
end
end
(we move action_options_for onto resource as well, of course).
Once we’ve moved the various mapping helpers onto the resource classes, we can
revisit map_resource and map_singleton_resource
def map_resource(entities, options={}, &block)
resource = Resource.new(entities, options)
with_options(:controller => resource_controller) do |map|
resource.map_collection_actions(map)
resource.map_default_actions(map)
resource.map_new_actions(map)
resource.map_member_actions(map)
end
if block_given?
with_options(:path_prefix => resource.nesting_path_prefix, &block)
end
end
def map_singleton_resource(entities, options={}, &block)
resource = SingletonResource.new(entities, options)
with_options(:controller => resource.controller) do |map|
resource.map_collection_actions(map)
resource.map_default_actions(map)
resource.map_new_actions(map)
resource.map_member_actions(map)
end
if block_given?
with_options(:path_prefix => resource.nesting_path_prefix, &block)
end
end
And now, we no longer have two method bodies that look very similar, apart from
the resource class, we have to methods that look identical apart from the
resource class. So, if we pull out the common bits and put them onto Resource,
like so:
class ActionController::Resources::Resource
def install_routes_in(map, &block)
map.with_options(:controller => controller) do |m|
map_collection_actions(m)
map_default_actions(m)
map_new_actions(m)
map_member_actions(m)
end
if block_given?
map.with_options(:path_prefix => nesting_path_prefix, &block)
end
end
end
Then map_resource and map_singleton_resource become
def map_resource(entities, options = {}, &block)
Resource.new(entities, options).install_routes_in(self)
end
def map_singleton_resource(entities, options = {}, &block)
SingletonResource.new(entities, options).install_routes_in(self)
end
Where’s the benefit?
Apart from making the active_record/lib/resources.rb a bit shorter (a
laudable result in itself), where’s the benefit here?
From my own experience of implementing datestamped_resource, a routing
plugin that we use in Typo, it makes the life of anyone writing a resource like
routing helper for Rails a great deal easier. With datestamped_resource I
ended up subclassing ActionController::Resources::Resource, doing the
refactoring I’ve outlined here, but leaving the original Rails methods where
they were and just implementing the ‘moved’ methods on DatestampedResource
(well, not quite, map_collection_actions is pretty different from the
default Resource implementation, but the other actions are pretty much the
same.
In another project I’m working on, I’m trying to retain meaningful urls with
(potentially) deep resource nesting, and it’d be really handy to have an
inflected_resource route helper. The problem with using a meaningful
to_param on your models is, avoiding permalinks that share a name with your
actions. You could set up validations so that, say, ‘new’ is an illegal
permalinks, but it’s clumsy.
However, if you arrange things so that your URLs are inflected, you can always
tell that a URL that begins /resource/new will be a particular resource, with the permalink ‘new’, and /resources/new will be the virtual new resource.
If the
resource system is factored as I outlined, this is almost trivial, you can
introduce a InflectedResource subclass of Resource
class InflectedResource < Resource
def member_path
@new_path ||= #{path_prefix}/#{singular}/:id
end
end
and you’re pretty much done. Admittedly, something like that (plus a small
amount of copy and paste) would work with the current system, but then we’re
looking at 3 substantially identical methods in ActionController::Resources and
if it wasn’t time to refactor before, it’d definitely be time to refactor
then.
Conclusions
Reification shouldn’t be something you do every day, but nor should it be
something you do once a flood. Take a look at some of your projects and some of
the places where you’re using hashes. Are those really hashes, or would they
benefit from having some behaviour of their own? You can track down stalled
reification by looking for anaemic classes; classes which have a lot of
accessors but very little behaviour. Once you’ve found an anaemic class, look
for all the places that instances of it get used. Try moving some of the client
code into methods on your anaemic class. Do that a few times and you’ll end up
with a real object.
If you’re fussy about never putting HTML in your models, you could end up with
a mediating builder/presenter object as well, but until you start wanting to
render the same structured info in different formats, I’d suggest biting the
bullet and living with HTML in the model as a lesser evil than structural
code. Your mileage may vary.

Have you submitted this to Rails as a patch? There’s actually a ton of tiny repetitions in Rails, cleaning it up is a very very worthy goal. It’s getting to the point where it’s a pretty large code base.
I haven’t, no. I have some fairly serious differences of opinion with the Rails code base – I think every bug I’ve reported on the trac (admittedly not many) has been resolved as ‘wontfix’ with commentary that leads me to believe that me and the chaps in the core team are thinking at right angles. Which makes me somewhat hesitant to go submitting a patch that adds no new features and won’t have any new tests associated with it.
Still, there’s always the next patch I guess.
All that said, I’m very close to having a patch ready to post to the trac which does the refactoring sketched in the article.
I’m not sure what the core team is thinking much of the time, and I’ve had plenty to say about it (though not always very publicly). It’s not that I don’t appreciate the effort, but when I see some of the code connected to ‘david’, ‘rick’, or ‘bitsweat’, I wonder. I know it’s not all produced by them, but they are the ones who committed it.
That’s not the point, anyway. The real reason I wanted to leave a comment is because my father once called me up to ask what ‘reify’ meant and my initial reaction was ‘to make royal’.