[rspec-users] Depot app, Demeter's law and troubles cleanly specing
zach.dennis at gmail.com
Sun Apr 19 14:23:59 EDT 2009
On Sun, Apr 19, 2009 at 12:24 PM, Mark Wilden <mark at mwilden.com> wrote:
> On Sun, Apr 19, 2009 at 3:51 AM, Matt Wynne <matt at mattwynne.net> wrote:
>> @order_presenter.product_titles do |product_title, url|
>> <%= link_to product_title, url %>
> The presentation of an order in most apps will be constructed from
> additional columns (e.g., color, size, price, extended price). These
> columns may well be formatted differently depending on the
> circumstance (e.g, printed or on-screen).
> Now, it might be a good idea to put this construction and formatting
> in a helper or presenter outside the view (though it won't be
> TSTTCPW). But anywhere you put it, there will be non-Demeterian code
> that needs to drill down into each order's items', products'
> information (as well as non-product information, such as line-item
> discount). If the underlying model changes, this code will have to
> change - you can't avoid it.
Agreed. I think Dan Manges post is a good one on this topic as well:
His second to last paragraph:
"The crux of this is that webpage views aren't domain objects and
can't adhere to the Law of Demeter. Clearly from the examples of
behavior delegation the Law of Demeter leads to cleaner code. However,
when rendering a view, it's natural and expected that the view needs
to branch out into the domain model. Also, anytime something in a view
dictates code in models, take caution. Models should define business
logic and be able to stand alone from views. If this "train-wreck"
method calling in your views is bothersome, there is a better solution
that I will blog about later."
I tend to agree his thoughts on this, but be careful how you read the
sentence "anytime something in a view dictates code in models, take
caution". He isn't referring outside-in development practices. He's
referring to adding methods in a model for strictly presentation
purposes, which is bad because it dilutes the richness of the model,
and makes it change for reasons it shouldn't. Here's another article
which discusses why methods shouldn't be added to models for
Although if you read that article and want to try out presenters, you
should know that CachingPresenter supersedes the PresentationObject
library in the article. And you don't need a library to use
presenters, your presenters can be POROs just like Matt Wynne posted.
I tend to like the CachingPresenter library (heck I wrote it) approach
so I can utilize caching, memoization, and a slightly more declarative
API and list of helper methods.
One technique I've employed in the past along side presenters
(although it can be done w/o presenters) is to make use of partials,
and actually treat them like little view objects. So you could take
what you had:
@order.items.each do |item|
And transform it into two views, one that is concerned with the order,
and a partial which is concerned with the product of an item. :
<%= render :partial "items/product", :collection =>
And then add a "items/product" partial and spec it in isolation.
Spec'ing views (and partials) in isolation gives you the ability to
have simpler view specs, and you're able to avoid feeling the awkward
need to build up a network of objects. And you don't have to worry
about adding a bunch of little delegate methods all over the place.
More information about the rspec-users