Welcome to Cykod. We are a fully-integrated, self-funded web-development startup located in Boston, MA.

Effectively Using Low Ceremony Objects

One of my favorite things about working in a higher level language is what I like to call "Low Ceremony Objects" (If there's another more popular term for them please let me know and excuse my ignorance)  - a.k.a. arbitrary data structures built off of combinations of general purpose containers like arrays and hashs. They are an effective way to quickly create and manipulate data that has a short lifespan but can be counter productive both in terms code readability and maintainability when over-used and sometimes more structured data or traditional objects are much more effective.

When used correctly - LCO's (Yup, tired of typing Low Ceremony Object already) Data structures generally exist for only brief chunks of time that are only defined insomuch as they are used. The existence of general purpose containers in higher level languages and the minimal amount of code needed to create and access them means that data that would otherwise sit in a predefined data structure now often ends up sitting in a combination of Hashes and Arrays ( or Lists and Dictionaries if you swing that way, or PHP's bastard stepchild of both)

As for the name - why low ceremony? Well, like a Vegas shotgun wedding, these generally don't come with a lot of planning -  no design documents or even a set structure - so there's generally not a lot of set guidelines involved. Now why Low Ceremony Objects and not Low Ceremony Data or Low Ceremony Structures? Because a large part of the value of using these objects built out of general purpose containers is the large and easy-to-use toolkit of methods either in the objects themselves (ruby, python, java) or the standard accessor functions (php, lisp) which aid greatly in manipulation of the data - adding, removing, searching, sorting etc.

Reading a book on Clojure got me thinking about this again (after struggling with it a couple of years ago - see the footnote) as in the Lisp variant I first learned - Scheme - pretty much every piece of data is a Low Ceremony Object that you can car, cdr, or caaaaadr to your hearts content, but without some additional structure or abstraction added on top of the language complex data quickly becomes difficult to work with.

When used correctly - Low Ceremony Objects are a great boon to development both in programmer productivity and in code cohesion and DRY philosophy - since they are defined instead of declared - their definition is always close in the code base to their usage. If you make a change to the creation of the LCO you have effectively changed it's declaration. You don't need to dig up a header file or separate class source file to make a modification. Want a quick data structure to hold a menu? Two lines and it's done:

[ { :title => 'Item 1', :url => '/item1' },
  { :title => 'Item 2', :url => '/item2', :selected => true } ]

If that menu is going to be created and digested during a portion of 1 Web request then you don't really want to go through the effort of creating a class, especially if that class is just going to be used as a data structure and isn't going to have any of it's own methods. What does the following actually get you:

class MenuItem
    attr_reader :title, :url

   def initialize(title,url)
      @title = title
      @url = url
   end    

end

class MenuItemList
 def addItem(item)
   @items ||= []
   @items << item
 end

 def item(idx)
   @items[idx]
 end
end

lst = MenuItemList.new()
lst.addItem(MenuItem.new('item1','/item1')
lst.addItem(MenuItem.new('item2','/item2')

Not a whole lot (Ignoring that no one in their right mind wouldn't just use an Array for MenuItemList unless some more functionality was added). Ruby provides the Struct construct for just this reason - but I'm not sure that using Struct gets you all that much more than just using a Hash. In particular I'm not a fan of passing in a huge parameter list to the constructor as you need to remember the exact order of your properties every time you read code using the initializer otherwise you'll have problems. For my money:

menu_item = { :title => 'Item 1', :url => '/item1',
   :selected => true, :dropdown => false, :green => true }

Is more readable than:

menu_item Struct::MenuItem.new("Item 1","/item1",true,false,true)

There are a lot of situations where LCO's are great, but there's two guidelines I now try to follow:

  1. Only use a Low Ceremony Object if it is going to be created and consumed in relatively close proximity code-wise.
  2. Once a LCO gets too complicated to understand easily by looking at it's definition or a debug output of the data, it's time move on to something else.


The reason for the first rule is that as soon as you are moved away from the definition of the object errors are going to creep in since there's no help from the interpreter or compiler in properly generating and consuming the LCO.

The second guideline should be pretty self evident - since you only have a definition of the data and not a declaration of the type, once the data gets too difficult to understand you are going to make mistakes using it because you don't have a declaration to fall back on.

LCO's can also be limiting because data can be hard to extend when a small piece of custom code could achieve the same effect. Let's go back to our menu item - what if we made the menu item responsible for displaying itself? Suddenly the whole menu system could be a lot more powerful by overloading the base class (or just duck-typing some other type in there):

class MenuItem
  ...Previous Definition...
  def display; "<li><a href='#{@url}'>#{@title}</a></li>"; end
end

class BlinkingMenuItem < MenuItem
  def display;  "<li><a href='#{@url}' style='text-decoration:blink;'>#{@title}</a></li>"; end
end

class MenuItemList
  ...Previous Definition...
  def display; "<ul>" + @items.map { |itm| itm.display }.join + "</ul>"; end
end

menu = MenuItemList.new
menu.addItem(MenuItem.new('Item1','/item1'))
menu.addItem(BlinkingMenuItem.new('Item2','/item2'))
print menu.display


Because who doesn't like blinking menu items? Achieving the same sort of functionality with just a data structure would mean adding in a conditional branch for each added option - to the point where your code can degenerate into if/elsif/else spaghetti.

Because of how easy LCO's are to create, they may tend to get overused when some additional design level decisions take more effort than just throwing together an Array of Hashes - don't lose all the benefits of years of work in OOP design just because high level languages make LCO's so easy to create and consume.

One of my least favorite examples of an LCO is the form system in the Drupal Content Management System - the way to create forms is to generate an enormous associative array where different pound-sign prefixed keys have different meaning and different nested arrays create different functional groups in the form.

This fails both of the LCO tests - most people generating drupal forms never look at the drupal code that actually uses them (I took a couple of looks and while it's nice, modular code, it's also very far away from what we're generating) - and since there's no strong typing it's impossible to know what went wrong when your form doesn't show up correctly (this may have been fixed with additional error checking in newer releases.)  Secondly with huge forms with dozens of items, it's hard to look at the data that you're generating and say with any certainty whether or not there's a mistake. Lastly, let's say I want to add a special widget to a form (like a slider for example) - I wouldn't even know where to start since the data that I'm passing into the form just gets magically transformed into HTML output on the other end, I don't have any control over it (other than just putting HTML directly into the form).

So, in conclusion: LCO's are great where you need to quickly create data types to be consumed just as quickly, but can become a drag on a project when they get too complicated ...

Because of the lack of meta-programming at the class level PHP code in general can suffer from a the downsides of lots of complicated LCO's, let's take the Cake PHP framework. From their tutorial, here's an example of a model:

class User extends AppModel {
   var $name = 'User';
   var $validate = array(
     'login' => 'alphaNumeric',
     'email' => 'email',
     'born' => 'date'
    );
 }


Compare this to an example in Rails:

class User < DomainModel
  table_name 'users'
  validates_as_alphanum :login
  validates_as_email :email
  validates_date :born
end

Wait you say - validates_as_alphanum, validates_as_email and validates_date don't exist in Rails - except that they do in the super class:

class DomainModel < ActiveRecord::Base
    def self.validates_as_alphanum(field,options={})
       validates_format_of field, options.merge({ :with => ..REG_EXP..})
    end
    ...
end   

The same thing is doable in CakePHP, but you end up adding instance methods instead of being able to meta program at the class level since the use of a data structure instead of a method forces the implementation to rely on conditional branching and dispatching instead of letting the language handle that part itself. The advantage of using code instead of a LCO in this case is that there's a lot more help from the language compiler/interpreter than when you try to create a Domain Specific Language solely out of data. You effectively need to write an interpreter for the DSL while on the other hand building it out of meta-constructs allows you to use the development language itself as the interpreter (in which case, you'll probably end up fullfilling some variation on Greenspun's Tenth Rule [via Proggit]).

So, in conclusion: LCO's are great where you need to quickly create data types to be consumed just as quickly, but can become a drag on a project when they get too complicated or are used as complicated interfaces as they don't self-document and can make it difficult to track down bugs when they become overly complex. Of course given the apparent rise of Schema-free databases (Like CouchDB ) and the NoSQL movement, I might soon be in the minority arguing against the limiting overuse of LCO's.
---------
Footnote:

As an aside, in the development of Webiva (Our newly-released, newly-open-sourced Rails CMS) we came across the problem that CMS's require a boatload of customizable features so that modules can be developed effectively and generally. This customization must be easy to add into the system from a developer perspective and easier to extend later on as more options are needed. The former cried out for the support and validation offered by ActiveRecord while the later made more sense using an LCO - after all who wants to update a bunch of models or the database every time a new option is added to the thousands of existing ones.

I started out using just Hash's as that's what comes in via the params object with some custom-inline validation. But that quickly became painful and repetitious, so finally what we ended up with  was the HashModel - a hybrid between using an LCO and using a full model that allows easy standard ActiveRecord usage in forms but is easy to create, update and use and store in generic DB text fields. Here's an made-up example usage:

class BlogDisplayOptions < HashModel
  attributes :blog_id => nil, :per_page => 20, :category => '', :active=>true

  integer_options :per_page
  boolean_options :active
 
  def blog
   @blog ||= Blog.find_by_id(self.blog_id)
  end   

  def validate
   # we need a valid blog
   self.errors.add(:blog_id,:invalid) unless self.blog
  end
end   

Usage - storing values as a hash in a serialized column:

@options = BlogDisplayOptions.new(params[:blog])
if @options.valid?
  paragraph.data = @options.to_hash
  paragraph.save
end     

Or:

@options = BlogDisplayOptions.new(paragraph.data)
if(@options.blog)
 ...Do something..
end


Switching from Hash's to HashModel's was a huge win in reusability and simplicity. Now I just need to fix all the other places in the system where I ignored the two rules from above.

Posted Thursday, Oct 22 2009 04:59 AM by Pascal Rettig | Development, Rails

Comments    Leave a comment

Posted by andrew cooke at 06:28AM on October 22 2009

you seem to be using untyped (aka dynamically typed) languages, where the only way to get type info is by adding ceremony, and there is a kind-of-implicit assumption that low ceremony therefore has to mean type unsafe.

i’m kind of stating the obvious here, but there are languages where you can have (statically) typed, low ceremony objects: haskell, ml, even scala. that gets you the best of both worlds (low ceremony plus type safety), and once you’ve used it, the issues you mention can really drive you crazy…

so i guess i am saying, don’t try a strongly typed langauge with inference, or you’ll end up as frustrated with lisp et al as i am :o)

Posted by Jake Mcarthur at 08:16AM on October 22 2009

@andrew cooke

Even in Haskell, though, it often pays to create a new abstraction, especially considering how easy it is to just wrap your “LCO” in a newtype and define some appropriate operations on it. The purpose is similar: to make your code clearer by hiding irrelevant details.

Leave a Comment

Display Name:


Your Email (Optional, not displayed):

Add a Comment: