I’m trying to master the more subtle elements of Rubyish OO design, and
am having trouble with the following aspect:
I have a complicated, nested, value object ( eg
order.customer.address.zipcode, or order.product.description).
This object needs to be sent to various feeds (usually XML, sometimes
REST / HTTP form ) run by other companies. Each company has a slightly
different format in which they want some of the items (eg, some might
want CA and some California, some might want the description to use one
set of abbreviations and some another).
Now, the feeds are added fairly frequently, and so a goal of the design
is to allow new feeds to be created without having to modify the core
- Which object should be responsible for formatting a field according
to one spec’s choice? Should it be
feedX.format_description(product) ? “Tell, don’t ask” would indicate
the first. The product knows better than anyone how to describe
itself. But there are two arguments for the latter: A) New feeds can
be added without touching the product code and B) Feeds know which type
of formats they need - very often, different feeds could use the same
formats for many fields.
It seems that the root of the problem is that OO design tells us to put
logic with the data it operates on, and to push decisions out to that
thing. But here, the question can be answered only by two things
working together: the order (which knows about itself) and the feed
(which knows what type of formatting it needs).
- What type of method call should I use to format the fields? It can
get cumbersome to always add a formatter, even when it’s not needed (eg
I’d rather just pass order.customer.address.zipcode, and have the to_s
called implicitly, than have to always write
order.customer.address.zipcode.format_for(feedX) - when zipcodes are
almost always formatted the same). The code could be made more succint
by just adding an instance variable @formatter, and having to_s
automatically use that. But there are two problems with that A) How
would subobjects find the @formatter? In other words, we can set
order.formatter, but how will order.customer.address find the
formatter? and B) This violates encapsulation - if, in the middle, we
need a field in a different format, we can mess things up without
So: Is there a good solution to avoid having the repetition of
constantly appending .format_for(feedX)?
All ideas/comments/criticisms/creativity appreciated
PS Yes, I know that a nested value object arguably violates demeter.
PPS If it’s relevant, the XML is generated using ERB templates.