Showing posts with label presenter. Show all posts
Showing posts with label presenter. Show all posts

Sunday, October 14, 2007

Rails: Rise, Fall, and Potential Rebirth of the Presenter Pattern

The default architecture for Ruby on Rails, Model View Controller, can begin to break down as Controllers become bloated and logic begins to creep into view templates.

The Presenter pattern addresses these problems in concert by creating a class representation of the state of the view...
And on it goes, the description for my RailsConf Europe 2007 talk. Unfortunately, this talk was the worst of my career. Pretty much everything went poorly. No one came in to make sure the microphone was working (it wasn't). They ran out of water bottles. I had a fever (103 degrees Fahrenheit, when checked later that evening). But, worst of all, I did a poor job of getting my message across. This post is an attempt to clarify what wasn't expressed well in Berlin.

This post assumes you've read the blog entry: Presenter Pattern

I first applied the presenter pattern to a Rails codebase in June of 2006. I had a complicated view that displayed several models aggregated into a single, readonly report. I was working on the code for a while and couldn't find an easy way to test that the view displayed what I was looking for. All of my models were being created and aggregated in the controller. There wasn't a single uber model that could have handled the aggregation, it simply didn't make sense to model it that way.

After spending a bit of time trying to make it work I decided that I needed a more testable solution. Instead of creating and aggregating all the data in the controller I created a PORO that assumed those duties. The presenter had clear responsibilities: find and manipulate the data so that the view can display it by simply calling @presenter.output. This solution turned out beautifully; it was easy to test and maintain. That project contained one presenter, the one spot where it made sense.

In November of 2006 I joined a new project. The new project was basically a wizard that collected several bits of data. Unfortunately, the views didn't easily map to the domain model. Some views needed to validate portions of a model and other views needed to validate multiple models. We decided to use presenters to aggregate and adapt the models to fit the views. The situation was different this time though; this time the views needed to accept post data. There were several implications that came with this choice. The presenters now needed to handle synchronization with the models instead of simply pulling data from the models. The presenters also took the responsibility of validating where it made sense. This experience led to another blog entry: Another Rails Presenter Example.

Presenters worked well on this project; however, the responsibilities of presenters had grown. At the time I didn't realize it, but they were only able to cope with the additional responsibilities because the application followed such a strict convention: Always post and move forward or backward. Like I previously mentioned, this was an application that was basically a wizard. Every page posted, checked for valid data and moved forward or backward. Because the behavior was so limited we were able to easily metaprogram that behavior into the presenters. As a result, we rarely had to do anything interesting in the presenter other than write the formatting, validation, and synchronization code. Again the pattern worked well, so I decided it was time to put out something describing the pattern. The Presenter Pattern blog entry was a result of the combined successes of applying the pattern.

At this point David and Jamis had added a few presenters to Highrise and Jamis had written several blog entries with a very similar idea. It seemed like a great time to submit the presenter pattern as a talk for RailsConf Europe 2007.

Then in April of 2007 I moved on to another project. This project was a more typical Rails application. It didn't follow the wizard pattern. It's views where both readonly and read/write. It often needed to validate something and do interesting things based on those validations. There was no easy convention for the views to follow. Presenters were being used when I joined the project, but they weren't proving to be a good fit. We struggled to find a canonical example within our codebase. We also struggled to find which responsibilities were a good fit and which weren't.

Then, Yogi Kulkarni joined the project. Yogi pointed out that our presenters were responsible for far too much. Yogi wasn't the first person to say this, but he was the first person to say what objects we were missing: Services (Domain Driven Design). We started adding services to the application and the presenters became slimmer and more easily testable. The suggested implementation from my previous blog entry had failed; however, we were able to remove the service related responsibilities and make use of the other benefits of using presenters. Ultimately, the svelte presenters provided a better solution.

That's where my RailsConf talk really fell down. I wasn't able to express that Presenters weren't a silver bullet, but they did seem to work well in various forms.

Several people came up to me after the presentation and said "I'm using presenters to... do you think that's a good idea?" My answer was yes to each query, and those people had found valid ways to use presenters to make their life easier. The key was figuring out how presenters helped you and limiting their responsibilities to those tasks.

Following my experience on my last project I was hesitant to look for a general solution similar to presenters. It's still a pain to test views and controllers, but adding another layer that also felt painful didn't seem like a good solution. Again, I think presenters have their place, but I wasn't sure that a general solution was available.

Then, at RailsConf Europe, Marcel Molina Jr showed me a version he was working on. He's currently using presenters in a non-intrusive way that allows you to use vanilla Rails by default, and add presenters where necessary. Marcels solution looks promising, but it's not publicly available. That's actually a good thing since he's maturing it a bit before releasing it.

I'm looking forward to Marcel's results, but in the mean time I think everyone can benefit from the experiences of the people who have begun blazing the presenter trail. In the blog entry Presenter Links I provide links to entries by Jamis and Courtney. Those are the more popular links, but several other people have written about their own experiences.

The conclusion I failed to express is this: If you are feeling pain testing views or controllers, you aren't alone. I haven't seen the silver bullet solution, but I have seen several solutions that worked very well for specific systems. I believe the current best solution is to read up on the experiences of others and see if anyone has solved a situation similar to yours; if so, try out their suggested implementation. If you find yourself with a unique problem, look for why the existing solutions worked well for their respective problems. Take what applies to you and form your own solution, then write about your experiences so that other people can benefit from your experience.

Friday, June 15, 2007

RailsConf Europe 2007: Presenter Pattern

My talk on Extending Rails to Use the Presenter Pattern was accepted for RailsConf Europe.

See you in Berlin

Friday, March 16, 2007

Rails: Presenter Pattern

The default architecture for Ruby on Rails, Model View Controller, can begin to break down as Controllers become bloated and logic begins to creep into view templates. The Presenter pattern addresses this problem by adding another layer of abstraction: a class representation of the state of the view.

Presenter was inspired by the various GUI patterns documented by Martin Fowler.

How It Works
The Presenter pattern addresses bloated controllers and views containing logic in concert by creating a class representation of the state of the view. An architecture that uses the Presenter pattern provides view specific data as attributes of an instance of the Presenter. The Presenter's state is an aggregation of model and user entered data.

When To Use It
As non-trivial applications grow Controllers can approach sizes that compromise maintainability. Complex controller actions may require instantiation of multiple objects and take on the responsibility of aggregating data from various objects. A Presenter can encapsulate this aggregation behavior and leave the controller with more focused responsibilities. This also allows for testing of aggregation or calculation behavior without a dependency on setting up a Controller to a testable state.

Since views are templates they can also contain behavior. The most common behavior you encounter in a view is formatting; however, since the view is a template you will occasionally see computations or worse. Because this logic is stored in a template it can be problematic to test. Presenters address this problem by pulling all formatting, computation, and any additional behavior into a class that can be easily tested.

Presenters do add an additional layer, and thus more complexity. A presenter is not likely to be a automatic decision or standard. Presenters are generally introduced when actions are required to act upon various models or the data in the database needs to be manipulated in various ways before it is displayed in the view.

Example
The example used to demonstrate a usage of the Presenter pattern is a page that allows you to enter your address information, personal information, and user credentials.



To get to our example page (and the following page) we'll need to add a few routes to routes.rb.
ActionController::Routing::Routes.draw do |map|
map.with_options :controller => 'order' do |route|
route.complete "complete", :action => "complete"
route.thank_you "thank_you", :action => "thank_you"
end
...
end
The example relies on three different models: address, user_account, user_credential. The migration for creating these tables is straightforward.
class CreateModels < ActiveRecord::Migration
def self.up
create_table :user_accounts do |t|
t.column :name, :string
end
create_table :addresses do |t|
t.column :line_1, :string
t.column :line_2, :string
t.column :city, :string
t.column :state, :string
t.column :zip_code, :string
end
create_table :user_credentials do |t|
t.column :username, :string
t.column :password, :string
end
end

def self.down
drop_table :user_accounts
drop_table :addresses
drop_table :user_credentials
end
end
The models need not contain any behavior for our example.
class Address < ActiveRecord::Base
end

class UserAccount < ActiveRecord::Base
end

class UserCredential < ActiveRecord::Base
end
The template for our example view is also straightforward, and this is one of the large benefits for using a presenter.
<% form_for :presenter do |form| %>
<table>
<tr><td colspan="2">Billing Information:</td></tr>
<tr>
<td>Name</td>
<td><%= form.text_field :name %></td>
</tr>
<tr>
<td>Address Line 1</td>
<td><%= form.text_field :line_1 %></td>
</tr>
<tr>
<td>Address Line 2</td>
<td><%= form.text_field :line_2 %></td>
</tr>
<tr>
<td>City</td>
<td><%= form.text_field :city %></td>
</tr>
<tr>
<td>State</td>
<td><%= form.text_field :state %></td>
</tr>
<tr>
<td>Zip Code</td>
<td><%= form.text_field :zip_code %></td>
</tr>
<tr><td colspan="2">Account Information:</td></tr>
<tr>
<td>Username</td>
<td><%= form.text_field :username %></td>
</tr>
<tr>
<td>Password</td>
<td><%= form.text_field :password %></td>
</tr>
</table>
<%= submit_tag "Complete Order" %>
<% end %>
And, the last example before we dive into the Presenter will be the controller. The controller is also simple, thus maintainable, due to the usage of the Presenter.
class OrderController < ApplicationController
def complete
@presenter = CompletePresenter.new(params[:presenter])
redirect_to thank_you_url if request.post? && @presenter.save
end

def thank_you
end
end
Finally, the CompletePresenter aggregates all the data for the view.
class CompletePresenter < Presenter
def_delegators :user_account, :name, :name=
def_delegators :address, :line_1, :line_2, :city, :state, :zip_code
:line_1=, :line_2=, :city=, :state=, :zip_code=
def_delegators :user_credentials, :username, :password, :username=, :password=

def user_account
@user_account ||= UserAccount.new
end

def address
@address ||= Address.new
end

def user_credentials
@credentials ||= UserCredential.new
end

def save
user_account.save && address.save && user_credentials.save
end
end
The CompletePresenter does inherit from Presenter, but only to get Forwardable behavior and a constructor that allows you to create an instance with attributes set from a hash.
class Presenter
extend Forwardable

def initialize(params)
params.each_pair do |attribute, value|
self.send :"#{attribute}=", value
end unless params.nil?
end
end
By using the presenter an easily testable layer has been created. This additional layer can coordinate with the models that this view is responsible for. The added layer also allows the models to be tested independent of any controller behavior. The presenter also provides the ability for extension where other solutions prove inadequate. For example, in a real scenario, the models would also likely contain validations. The presenter provides a layer that can validate the various models and merge their errors collections to provide one error collection that the view can work with.

Used appropriately, Presenters greatly benefit an application's architecture and maintainability

Sunday, February 18, 2007

Rails: Presenters - An additional layer alternative.

The first time I wrote about Presenters was back in September. The title of the article contains a question mark for a reason, at the time it was a brand new idea that I wanted to share, but not endorse as "a good thing".

Time passed, a new project started for me, and Jamis wrote Skinny Controller, Fat Model, Moving associated creations to the model, and a blog entry that mentioned (in the comments) that he and David have been thinking about the pattern.

An important thing to note about Presenter is that it adds an additional layer; therefore, more complexity. This is definitely a trade off worth considering, and the reason that I believe that Skinny Controller, Fat model is the way to go if you can get away with it. However, when you begin working with multiple models on one view, I do believe it's time to give a presenter a chance. Which is why I created an entry with another presenter example in response to Jamis' Moving associated creations to the model entry.

I closed the Another Rails Presenter Example entry with the following paragraph
Using Presenters has additional advantages such as their ability to easily integrate with ActiveRecord validations, separation of view behavior from models (such as formatting a phone number), and allowing you to put validation error messages somewhere other than in a model. I'll address each of these scenarios in upcoming blog entries.
Since I wrote that entry I've touched on a few of these topics, but never brought it all together.

So, taking the paragraph one sentence at a time, here's my explaination.
Using Presenters has additional advantages such as their ability to easily integrate with ActiveRecord validations
This statement was somewhat misleading. Presenters do easily integrate with ActiveRecord::Base models. They can easily aggregate errors from multiple models and display those errors from the presenters errors collection. However, this is currently possible if you include Validatable, and ActiveRecord::Base validations could simply add this behavior and presenters would provide no superior solution. There's a discussion around whether models aggregating errors is a good thing, but that's an discussion for another entry.
[Presenters allow] separation of view behavior from models (such as formatting a phone number)
This is quite true, and one of my favorite aspects of using presenters. Consider an Order class that contains a total attribute. The total is stored in the database as a Number (Oracle). The total needs to be displayed to the user (in the view), formatted as currency, but without the unit ($). The easy solution is to put the following code in the view.
number_to_currency(@order.total, :unit => "")
While this does work, it's basically not unit testable. It is functionally testable, but not nearly as neatly as I'd prefer. An alternative solution is to mix ActionView::Helpers::NumberHelper into the model. Then I can unit test my ActiveRecord::Base subclass, but adding view behavior to models can begin to lead you down (or, some may argue, you are already on) the wrong path. Therefore, adding a presenter, an object that represents your view, allows you clearly separate concerns and create more maintainable tests. Since presenters are class versions of your views, including ActionView::Helpers::NumberHelper in a presenter makes perfect sense. And, Presenters should be easy to test without relying on rendering and other framework dependencies.
[Presenters] allow you to put validation error messages somewhere other than in a model.
Putting error messages, that will be used as display text, in a model might or might not bother you. There's an academic argument available, but actual software delivery is what I'm interested in. Unfortunately, pulling errors messages out of models isn't simply an academic issue on my current project. We have requirements that include storing errors messages in a database so they can be manipulated by business users instead of programmers. There are few things in developing software that I believe are black and white, but empowering subject matter experts is one thing that I see little merit in arguing against. So, this wasn't just a requirement, but something I believed was the right idea.

Since we chose to use presenters, we were able to specify keys in our validations. Those keys were used by the presenters to pull the appropriate errors messages from the database. This solution was simple, and more importantly, easily testable.

Shortly after I wrote Another Rails Presenter Example, Jay D. left a comment on the original Presenter entry.
...in the example you gave I would have moved the code to the model.

"However, a better example would have been if the necessary data is spread across various models."

I still don't see why it wouldn't work in the model...

My controllers are clean like the one in your example and I can easily test the data aggregation/manipulation in my unit tests. Why would this be a bad thing?
By the time this comment came across, I had been using Presenters heavily (1 per view and often 1 per partial) on my current project. I still don't believe that they are required; however, I do now believe that they can be a valuable pattern when applied correctly. I responded to Jay D. as a comment; however, I believe Jay D's question is common enough that my answer is worth repeating in this entry.
The classic example for using a Presenter is a summary page. For example, if you buy books from Amazon, the final page has information about each book that you bought, tax information, shipping information, billing information, user account information, etc. In that scenario, I'd prefer to aggregate all that data in a Presenter.

Presenters offer other opportunities for separation of concerns that models do not. For example, if you want to validate that the user entered two matching passwords or email addresses you must add 'virtual' attributes to your models. The same is true if you would like to create an acceptance attribute (to use validates_acceptance_of). You could argue that since these attributes are not persisted to the database that they should not live in the model.
Presenters are no more a silver bullet than any other pattern provided in the past; however, they can be helpful when used correctly.

Saturday, January 20, 2007

Adding Validations to any Class

On my current project we have data that needs to be collected and then sent to a service. This data needs to be validated, but since it is never put into a model it cannot be validated by using ActiveRecord's validations. To handle this scenario we designed something similar to the module below that can add validations to any class that includes it, which are generally Presenters on my project.
module Validatable
module ClassMethods
def validates_format_of(*args)
validate_all(args) do |attribute, options|
self.validations << ValidatesFormatOf.new(attribute, options[:with], options[:message] || "is invalid")
end
end

def validates_presence_of(*args)
validate_all(args) do |attribute, options|
self.validations << ValidatesPresenceOf.new(attribute, options[:message] || "can't be empty")
end
end

def validate_all(args, &block)
options = args.last.is_a?(Hash) ? args.pop : {}
args.each do |attribute|
yield attribute, options
end
end
protected :validate_all

def validations
@validations ||= []
end

def validate(instance)
self.validations.each do |validation|
instance.errors.add(validation.attribute, validation.message) unless validation.valid?(instance)
end
instance.errors.empty?
end
end

def self.included(klass)
klass.extend Validatable::ClassMethods
end

def valid?
errors.clear
self.class.validate(self)
end

def errors
@errors ||= Validatable::Errors.new
end
end
As you can see I only included the code to expose the validates_presence_of and validates_format_of validations. We actually have quite a bit more, but I think those two are all that's necessary to follow the example. I like the way we designed the validation classes because they can easily be tested and are all treated the same way when it comes time to verify if they are valid or not (the validate method). The code below shows all that is necessary for both the ValidatesPresenceOf and ValidatesFormatOf classes.
module Validatable
class ValidationBase
attr_accessor :message
def initialize(message)
self.message = message
end
end

class ValidatesPresenceOf < ValidationBase
attr_accessor :attribute
def initialize(attribute, message)
self.attribute = attribute
super message
end

def valid?(instance)
(!instance.send(self.attribute).nil? && instance.send(self.attribute).strip.length != 0)
end

end

class ValidatesFormatOf < ValidationBase
attr_accessor :attribute, :regex, :message
def initialize(attribute, regex, message)
self.attribute = attribute
self.regex = regex
super message
end

def valid?(instance)
instance.send(self.attribute) =~ self.regex
end
end
end
The only other piece to the puzzle is the errors collection. The code for this is also very straightforward.
module Validatable
class Errors
extend Forwardable

def_delegators :@errors, :empty?, :clear

def on(attribute)
@errors[attribute.to_sym]
end

def add(attribute, message)
@errors[attribute.to_sym] = message
end

def initialize
@errors = {}
end
end
end
Another important thing to note is that these validations integrate directly with the ActionView::Helpers::ActiveRecordHelper.error_message_on method. This means the same code in the view that displays ActiveRecord errors can also display errors from any object that includes Validatable.
<%= error_message_on :presenter, :name %>
And, here's a few tests if you want to ensure that it works as expected.
class ValidatableTest < Test::Unit::TestCase
test "given no presence when object is validated then valid returns false" do
klass = Class.new
klass.class_eval do
include Validatable
attr_accessor :name
validates_presence_of :name
end

assert_equal false, klass.new.valid?
end

test "given no presence when object is validated then it contains errors" do
klass = Class.new
klass.class_eval do
include Validatable
attr_accessor :name
validates_presence_of :name
end
instance = klass.new
instance.valid?
assert_equal "can't be empty", instance.errors.on(:name)
end

test "given invalid format when object is validated then valid returns false" do
klass = Class.new
klass.class_eval do
include Validatable
attr_accessor :name
validates_format_of :name, :with=>/.+/
end

assert_equal false, klass.new.valid?
end

test "given invalid format when object is validated then it contain errors" do
klass = Class.new
klass.class_eval do
include Validatable
attr_accessor :name
validates_format_of :name, :with=>/.+/
end
instance = klass.new
instance.valid?
assert_equal "is invalid", instance.errors.on(:name)
end

test "given valid data after it is previously invalid when object is validated then it is valid" do
klass = Class.new
klass.class_eval do
include Validatable
attr_accessor :name
validates_format_of :name, :with=>/.+/
end
instance = klass.new
assert_equal false, instance.valid?
instance.name = "Jay"
assert_equal true, instance.valid?
end
end

Sunday, January 14, 2007

Another Rails Presenter Example

Jamis Buck recently posted an entry about Moving associated creations to the model. His solution is cool and probably sufficient for the needs of most; however, if you don't fall into that group you may be interested in an alternative solution using a Presenter.

In the example the view contains fields that collect person, email, and phone number information. Jamis shows what the html would actually look like, but I'm going to show what I would put in the view (rhtml) for my example.
<% form_for :presenter do |form| %>
...
<%= form.text_field :name %>
...
<%= form.text_field :email %>
...
<%= form.text_field :phone %>
<% end %>
Given the above view, the controller could contain the following code.
def create
@person = UsersPresenter.new(params[:presenter]).create_person(current_account)
redirect_to person_url(@person)
end
Using a Presenter limits the responsibilities of the controller without requiring that the model take on those responsibilities. For our example we'll assume the same Person class that Jamis already defined, except ours only needs the associations defined.
class Person < ActiveRecord::Base
has_one :email_address
has_one :phone_number
end
Finally, the Presenter brings all of this together.
class UsersPresenter
attr_accessor :name, :email, :phone

def create_person(account)
person = account.people.create(:name => name)
person.create_email_address(:address => email) unless email.nil?
person.create_phone_number(:number => phone) unless phone.nil?
end

def initialize(hash={})
hash.each_pair { |key, value| self.send :"#{key}=", value }
end
end
While the UsersPresenter class is fairly straightforward it does require the effort to create the additional class. I don't believe that it is worth the trouble for strictly academic reasons (e.g. a separation of concerns debate). However, I do believe that the resulting presenter class may be more easily testable. For example, testing the presenter can be done using a mocking framework such as Mocha.
class UsersPresnterTest < Test::Unit::TestCase
test "a person is successfully initialized from create_person" do
account=mock
account.expects(:people).returns(people=mock)
people.expects(:create).with(:name => "Jay").returns(person=mock)
person.expects(:create_email_address).with(:address => "j@j.com")
person.expects(:create_phone_number).with(:number => "2125551212")
presenter = UsersPresenter.new(:name => "Jay", :email => "j@j.com", :phone => "2125551212")
presenter.create_person(account)
end
end
Using Jamis' (admittedly simpler) solution would require saving data to the database and verifying it's existence.

Using Presenters has additional advantages such as their ability to easily integrate with ActiveRecord validations, separation of view behavior from models (such as formatting a phone number), and allowing you to put validation error messages somewhere other than in a model. I'll address each of these scenarios in upcoming blog entries.