Just A Summary

Piers Cawley Practices Punditry

Today's Noun is: Reticence 2

Posted by Piers Cawley Thu, 27 Sep 2007 23:30:29 GMT

What does the OED say reticence is?

Reticence: Maintenance of silence; avoidance of saying too much or of speaking freely; disposition to say little.

Pretty straightforward. When I chose reticence as one of my five nouns for programmers it was another reminder that objects are not the same as datastructures. Well designed objects keep their cards (instance variables) close to their chest. Client code tells objects what to do, it doesn’t ask them to kiss and tell. In Smalltalk Best Practice Patterns, (you don’t have a copy yet? Are you mad?) Kent Beck recommends that you put your accessor methods in the private protocol unless you have a very good reason for indicating that the accessors should be used by clients by putting the accessors in, say, the accessing protocol or some other, more suitably named, protocol. (In Smalltalk, all methods are public, but you can and should organize them into protocols/categories, either by choosing some existing protocol, or coming up with a new protocol name). In less flexible OO languages, you should probably at least mark your accessors as protected unless you have the aforementioned very good reason.

What about parameter objects then?

One obvious ‘exception’ to the rule of reticence is the parameter object. Say you have an unwieldy method that takes a bunch of arguments and fills the screen with its implementation. Being a conscientious programmer, you want to apply the ‘composed method’ pattern to the method so you’ll still end up with a screen’s worth of code, possibly more, but the individual methods will be much more focussed in what they achieve. What stops you is that bunch of parameters which are used through out the method. So, you introduce a parameter object. Bundle up the parameters into a single object, replace each parameter variable in the body of the code with an accessor call on the parameter object, and have at it. You can extract methods easily and you’ll only ever have to pass a single object.

It’s tempting not to bother creating a ‘real’ object, it’s very easy to just use an options hash, a la Ruby on Rails. And, because the options hash is a common pattern through your code, you can start adding helper methods like with_options, and you’ll get an awful lot of leverage out of it.

However, what’s often missed in discussions of the parameter object pattern is that it’s a waystation, not a destination. It may be handy, but if you persist in treating it as a datastructure, you’re missing out on the good stuff. Now you have a parameter object, you can start to move behaviour onto the parameter object and before you know it you’ll end up with a real object doing real, testable (mockable?), work.

Homework

Find a method where you’re using an options hash. Try using that hash to build a parameter object and then apply the principle of reticence. What happens to it? Where does the behaviour go? If, like me, you’ve come to OO from procedural coding styles, making your objects reticent is not a natural thing to do, it can feel extremely odd. But the more you practice it, the better you’ll get at thinking in a truly object oriented fashion. Sometimes an options hash really is the way to go, but not as often as you’d think.

Try it, maybe you’ll be converted.

Today's Noun Is: Notation 4

Posted by Piers Cawley Tue, 28 Aug 2007 21:20:00 GMT

Remember back when I wrote about metaprogramming and programming being the same thing?

Well, Libraries, Domain Specific Languages, Domain Agnostic Languages, Pidgins, YAML, .INI files and the like are all the same thing. They’re all notation.

That’s the thing to remember. Good notation makes life easy. Bad (or inappropriate) notation makes it hard (or, in some cases, fun). There’s no point striving to write a pidgin or DSL if your problem can be solved easily enough with a well factored set of loosely coupled classes. After all, even the neatest and cleanest of domain specific languages has to be learned. Meanwhile a class library that’s respects the language of your problem domain can be easier to learn because the notation with which the library is implemented is plain old YFL and your team already knows that (and if it doesn’t, you have bigger problems). Learning the class library is like learning about the problem domain and vice versa. Learning one supports learning the other.

I’m of the opinion that DSLs and pidgins are at their most when their domains are generic. So ActiveRecord’s most useful language like interfaces are related to general problems like expressing the relationships between objects or describing how to validate an object. Backus-Naur Form, Perl compatible regular expressions, parser combinators are all useful for solving the generic parsing and lexing problems that crop up everywhere. Data serialization notations like YAML, FASTA, XML, CSV, JSON and all the others are useful when you want a generic way to pass data between systems. All of these notations are narrow in their focus, but broad in the sense that the things that they focus on are ubiquitous.

The most useful notation for your specific task is almost always a well factored set of classes or functions (depends on your language of choice) which reflects the language of your problem domain. Different parts of your program might well make use of a wide range of ‘donor’ notations, but it’s a rare problem that’s going to require to you implement a full blown language in order to solve it.

Don’t worry about whether something’s a DSL, pidgin or a library. What it is is notation. A better question is is “does this notation help me solve my problem?”. If the answer is no, find better notation. Or keep plugging on with what you’ve got, but don’t fool yourself about your reasons for using the notation – not everyone’s here for the hunting after all.

Today's noun is: Reification 4

Posted by Piers Cawley Wed, 22 Aug 2007 23:22:00 GMT

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.

Five nouns for programmers 5

Posted by Piers Cawley Mon, 20 Aug 2007 23:45:00 GMT

  • Reification
  • Notation
  • Reticence
  • Lucidity
  • Intent

Learn ‘em. Live by them.

What did I miss? Which ones don’t belong on the list. What am I talking about?



Just A Summary