Saturday, January 13, 2007

'Where is the MVC Split?' for web apps.. or Client Side Partials

MVC is a great way to apply serperation of concerns to an application's archtecture. Just how far should it go?

(Quick introduction to MVC)
MVC stands for Model, View, Controller. It defines a split in responsibilities between the Model (your representation of the business problem domain), the View of the data and the Controller, which knowns how to orchestrate the various actions and queries you can perform on the data Model.

The Controller works like a dvd player. When it is told to play the dvd player queries the DVD and sends the data to the TV. The TV (being the view) then decides how to present the data so you can see it.

In rails the TV would be the view templates and the bit or rails that knows how to renderthose as HTML, the DVD player would be one of the controller classes, and the DVD is represented as a model class.

The advantage of this design is the seperation of concerns. If you swap your TV for a Cinema overhead projector you don't have to change your DVDs or Player. In the same way, if you decide to render your data as XML, or provide a mobile phone version of your site, you don't have to change your controllers or models. This seperation means the graphic designers are able to experiment with the look and feel of your site without having to get code changes made.

Notice, to control the volume or brightness of the picture, you (being the user) tell the TV, not the dvd player or the DVD. These are view related actions. In rails these would be implemented using javascript (like shrinking and expanding of menus of areas of the screen).

(MVC intro. ends)

I had the following situation: I have a screen full of tree_elements, and a sidebar that lists all root tree_elements. So one is showing a subset of the data the other one is showing. If you create a new root_element, both lists need to be updated.

The sidebar is implemented as a 'partial' that is rendered by the application layout, and hence exists on all my pages. There is a 'quick_add' form in the sidebar to allow you to quickly add new root items. The quick_add form uses ajax and RJS templates to tell the page to add items to the lists.

The problem is that if you are on the screen that lists all items and add a new root item, then there are two lists to update with this item. If you are on another page, then there is only one list to update. As a result the RJS template has to have some conditional javascript logic that says 'update the sidebar list of items, and if the list of all items is on the page, then also update that one'

My concern is this... The RJS for the 'add a new tree item' has to know about all the possible places the tree item will appear, so it can tell the view (whichever one the user happens to be on) to update.

This is wrong! If I add a new screen that represents this list in another way, I would have to extend to RJS for the 'quick_form_create' action to handle yet another special case. The code smell here is 'shot gun changes' [you have to make changes all over the place unrelated to the new added thing]. Really the RJS is sending events to the browser. The page should take that event and decide what needs updating.

I am trying to find a nice way to do it. The problem I have at the moment is when the event causes the page to want to render a new item on the list, the template for it is in the partial (server side). The page could request this as a seperate call, but I want to minimize chatter between the page and the controller. Another solution is for the session to hold onto the current view so the controller knowns what to send, but this again blurs the boundry between view and controller. The controller knows too much. What I'll look into next is having the page hold onto a DOM version of the partial, so it can copy, populate it, and add it to the DOM in the right place. This seems the best solution to me but would need some nice wrapper code in ruby to make it easy to set up.

... [watch this space] ...

the story continues... :)

powered by performancing firefox

Post a Comment

GitHub Projects