2008-04-21

Model View Controller and Enterprise Applications

I would like to share a few articles I've written back in 2005/2006 while working on an open source project - Hierarchical MVC Web framework - Claw:

Long gone post #1.

At this era of frameworks popping out of nowhere, crowds of people being obsessed with Ruby on Rails and Zend releasing their own framework, it's really a headache to choose the right tools for the right job. One thing is for sure – every good web developer knows – Model-View-Controller pattern is the right way to go.

Yes, MVC is a great pattern, no doubt that it's necessary to separate your business logic from graphical representation and database implementation. However, let's try implementing the following application using MVC:



What we have here is a simple structure of online shop, where users can choose the goods either by browsing categorized list of products, or by using the search feature. Product items may also have customer reviews, and visitors may add their own opinion for every product in the store. In real world you application structures are far more complicated than this one, but still, let's try modeling the MVC approach for this application.

Model

As a great fan of Object Oriented Programming, I would use a Domain Model pattern for the business logic part of the application. My components would be:

Category – tied up to the Product with many-to-many relation

  • getProducts - retrieves a list (an array) of Product objects, which belong to the Category
  • getTitle - retrieves a string with Category title
Product – tied up to Category with many-to-many relation, and to Review with one-to-many relation
  • getCategories - retrieves a list of Category objects, which the Product belongs to
  • getTitle - retrieves a string with Product title
  • getPrice – retrieves a price value object (to make it simple – just float value)
  • getReviews – retrieves a list of Reviews for this Product
  • addReview(Review) – adds a Review for this Product
Review
  • getAuthor – gets the author of Product review
  • getContent – gets the text
  • getRating – gets rating given to Product by the reviewer
After having my Domain Model ready, I would take care of persisting it to Database. Here you are on your own. I would go for Active Record implementation this time, as my model is dead simple. For more sophisticated cases Active Record would be a pain in the rear, so I would go for a serious ORM tool (such as Propel – http://propel.phpdb.org for PHP or Hibernate – http://www.hibernate.org for Java). So, we're done with our Model. No sweat! Time for the letter V in the MVC triad.

View

Personally for me, View part of any web application is the major headache, especially when you have got a State of Art prototype to follow, and your designer often complains that checkbox should be two pixels down in Internet Explorer, but four pixels up in Opera. Anyway, despite these annoying things implementing View in the MVC triad is a piece of cake. I prefer a Two Step View even in simplest situations, so I am going for it. There would be a plain HTML skeleton with empty body as the second step layer for each View, and the first step is upon the Controller.
The following problem may occur if you would want the following things done properly within your Views for current application architecture – How to Back-link Product items with the list they were accessed from. It may be the Category List, Search Result List or none, if user went directly to product. Of course, user can use browser back button, but what if he/she goes to read Product Reviews, afterwards, add a new one, then returns to Product View? I believe back button will not help you here. You could store required information in session or cookie variables, however, this adds unwanted complexity and introduces possible new bugs. Avoiding this functionality may annoy visitors, forcing them to repeat their search again, perhaps navigate through result pages to reach the point they were at. For now, let's keep our mind off this and see how to deal with Controllers.

Controller

Finally, we are about to liven up our application with user request processors, referred as Controllers. Normally, MVC frameworks use a Front Controller as one entry point for the whole application, which routes URL requests, invoking Input Controllers and their actions. How could the Controller architecture look with our current Online Shop application? It would probably end up like this:

Front Controller – the entry point which routes URL requests

Front
  • index – the action that is taken when user comes directly to your application root. Main page layout is set for View, some promo Product links attached, navigation menu for Product categories and search input
  • search – this is the action that search input leads to. It processes search query and forms a list of results, paging is involved.
  • category – here we have a list of Products by category, perhaps there would be options to sort items by title, price, ascending and descending order, also, including paging.
Product
  • index – action is taken when user views the product. Some identification should be passed along with request variables.
  • reviews – displays current product reviews
  • review – displays a form where user can add the review for the Product. It also processes form variables, validates them and writes the review to database.
Simple as that. We have mapped out our application with merely two Input Controllers! Let's see how some user URL request scenarios may look like and what would they map to:
  • / -> Front/index
  • /search -> Front/search (may display a search form with advanced options)
  • /search?q=sledgehammer&page=3 -> Front/search (third page of search for “sledgehammer”)
  • /search/sledgehammer/3 -> Front/search (same third page of search for “sledgehammer” with custom request rewriting – I will go on using this style of requests from now on)
  • /category/tools -> Front/category (category type is tools, first page of listing)
  • /category/food/price/asc/4 -> Front/category (food Products listed by price in ascending order, fourth page of navigation)
  • /product/2455 -> Product/index (would display information of product #2455)
  • /product/2455/reviews -> Product/reviews (displays all reviews for product #2455)
  • /product/2455/review -> Product/reviews (displays a form where user can submit her/his own review)
Everything looks nice, this scheme would work perfectly well, but the problem is – there are certain points where you loose the flow. Likewise, imagine you were at /search/sledgehammer/3, and clicked on a lovely “Almighty Masher”, which linked to /product/2455. You've certainly wanted some reviews of this great tool in action, and followed the “User Reviews” link to /product/2455/reviews. After reading for a while, you discover that “Almighty Masher” is just one overpriced piece of junk, and you want to fall back to the search you were doing. Well, back button is fine, click one, click two, and we're back on the track! But what if your application required users to be logged in to read the reviews? When you happily click “User Reviews” link, an unexpected screen appears asking you to log in, or even worse, offering you to register. Wise applications usually redirect user back to where he was going after logging in / registration process. It does not break the back button, you say? Perhaps, but it sure decreases the comfort of navigation (especially if your registration process had 7 steps).

Another disadvantage is that if you are in /product/2455/reviews and you still want to see the information of your product in the Reviews View, you will have to pull out the Product using the ID which comes along with request. And you will have to do this in /product/2455/review as well, or the reviewer may simply forget the exact title of the item. That leads to code duplication – every method of Product input controller must have some lines that find the Product. It's like shooting darts to different areas on the target – each area gets hit on it's own, as you cannot hit for both “10” and “15” with single shot due to the fact that there is no union on the target grid. With MVC pattern developers usually map the native applications tree (or in sophisticated cases – graph) hierarchy into plain two-dimensional grid enriched with variables. It can be compared to mapping Objects with many references, collections and relationships into Relational Database Management System. It's simple when your application is Farmer Joe's personal guest book, but what if you're working on something as large as E-bay or Amazon.com? You would sweat cats and dogs and spend months on writing meta-data and configuring your ORM tools to make your beautiful hierarchy broken down to the grid. And you would sure have to do the same with your controllers. But do you have to? I would not take this burden upon my shoulders, as my choice is Hierarchical MVC.

No comments:

Post a Comment

Spam comments (i.e. ones that contain links to web development services) will be reported along with user profiles!

Note: only a member of this blog may post a comment.