MVC is not Templates
After studying the general misconception of "no logic in JSPs" in a previous post, I now deal with what I consider the most harmful misconception in the J2EE world: the general confusion with the MVC pattern and Template View Pattern, that drives architects and frameworks to introduce the template view concept as an evident and inevitable consequence of the MVC overall implementation.
Let's take a look at a typical Struts-based application:
We have three Struts actions. The first and the second do some business logic, and then redirect to the jsp that shows the list of all customers in the system. The third action does no business logic at all, but redirects to the customersList.jsp as well.
A seasoned architect can quickly detect a problem here. We have the same code repeated in all three actions. The three actions share the same jsp to redirect, which is a reasonable architecture strategy, but they all have to prepare exactly the same data for the jsp. The jsp can change its data requirements, which is a very usual thing, by presenting more objects, or presenting less, or presenting different objects. And every action calling the jsp must be aware of the changes. This is a clear example of duplication of code. All actions are sharing the code:
What is wrong here? The key is that the data preparation and the jsp itself are very coupled issues. If the jsp will present the current date, the date must be prepared for the jsp. If the jsp will present the customer's name, age, and address, all this information must be prepared. The jsp is who better knows what to present, because it's all about view logic, as long as no model changes are performed in between. Every attempt to remove this logic from the jsp doesn't respond to a genuine architecture philosophy, but to the mistaken concept "No logic in JSPs".
If you are trying to remove all code from your jsp in such a way, you are in fact implementing a Template View pattern. In such a pattern the same data is prepared by a view delegate that then chooses a way to present this data by executing a different template depending on the case. Consider you have an application that serves HTML pages, as well as WML pages. A template view pattern is a sound pattern to be implemented here, as long as you have the same data to be visualized in different ways. Other reasons for adopting this pattern are "HTML Design and Application Programming are different skills", and "Development Tool Support". Template View Pattern has pros and cons, but it has definitely nothing to do with the MVC goal.
Remember: MVC is not Templates
These patterns are orthogonal, and you could use them independently, by adopting one of them, both or none. So, if you really need to adopt the Template View Pattern, Struts is a very poor tool to do it. You better use XSLT, or Velocity. But not Struts.
Moreove the example above is not only bad because of mistaking the Template View Pattern, but it also fails in accomplishing one of the purposes of the MVC pattern itself!
Can be interpreted as:
The same action has Action logic as well as View logic in it, and it isn't separating both logics after all. This pattern implementation is useless. But if we keep the real MVC principles the code becomes clear and straight-forward.
The data preparation has been moved to the customerList.jsp itself, which is now requesting information directly from the model. As an additional benefit, the ListCustomers action disappears because it's no longer needed, since other jsps can directly call to the customersList.jsp. The complexity has been reduced.
According to SmallTalk MVC definition: "[...] the model manages the behavior and data of the application domain, responds to requests for information about its state (usually from the view), and responds to instructions to change state (usually from the controller)". In MVC, The controller is NOT a Mediator between the view and the model. The controller does not sit in between the model and the view. Both the controller and the view have equal opportunity to access the model. Although we removed the Template View pattern from this implementation, notice that MVC pattern remains and is more useful than ever.
In future posts we will see a clean, easy-to-learn, easy-to-maintain, configuration-free MVC implementation based on jsps: POJM (Plain Old Jsp MVC).
Let's take a look at a typical Struts-based application:
public class CreateCustomer extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
try{
// .. Create the actual customer
}catch(Exception e){
// Some kind of error
return(mapping.findForward("createCustomer.jsp"));
}
// .. Prepare the data for the jsp
return(mapping.findForward("customersList.jsp"));
}
}
public class DeleteCustomer extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
try{
// .. Delete the actual customer
}catch(Exception e){
// Some kind of error
return(mapping.findForward("deleteCustomer.jsp"));
}
// .. Prepare the data for the jsp
return(mapping.findForward("customersList.jsp"));
}
}
public class ListCustomers extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
// .. Prepare the data for the jsp
return(mapping.findForward("customersList.jsp"));
}
}
We have three Struts actions. The first and the second do some business logic, and then redirect to the jsp that shows the list of all customers in the system. The third action does no business logic at all, but redirects to the customersList.jsp as well.
A seasoned architect can quickly detect a problem here. We have the same code repeated in all three actions. The three actions share the same jsp to redirect, which is a reasonable architecture strategy, but they all have to prepare exactly the same data for the jsp. The jsp can change its data requirements, which is a very usual thing, by presenting more objects, or presenting less, or presenting different objects. And every action calling the jsp must be aware of the changes. This is a clear example of duplication of code. All actions are sharing the code:
// .. Prepare the data for the jsp
return(mapping.findForward("customersList.jsp"));
What is wrong here? The key is that the data preparation and the jsp itself are very coupled issues. If the jsp will present the current date, the date must be prepared for the jsp. If the jsp will present the customer's name, age, and address, all this information must be prepared. The jsp is who better knows what to present, because it's all about view logic, as long as no model changes are performed in between. Every attempt to remove this logic from the jsp doesn't respond to a genuine architecture philosophy, but to the mistaken concept "No logic in JSPs".
If you are trying to remove all code from your jsp in such a way, you are in fact implementing a Template View pattern. In such a pattern the same data is prepared by a view delegate that then chooses a way to present this data by executing a different template depending on the case. Consider you have an application that serves HTML pages, as well as WML pages. A template view pattern is a sound pattern to be implemented here, as long as you have the same data to be visualized in different ways. Other reasons for adopting this pattern are "HTML Design and Application Programming are different skills", and "Development Tool Support". Template View Pattern has pros and cons, but it has definitely nothing to do with the MVC goal.
Remember: MVC is not Templates
- MVC: Separation of model logic, view logic, and action logic (for user interaction with the model).
- Templates: Isolating the HTML from the programming language code.
These patterns are orthogonal, and you could use them independently, by adopting one of them, both or none. So, if you really need to adopt the Template View Pattern, Struts is a very poor tool to do it. You better use XSLT, or Velocity. But not Struts.
Moreove the example above is not only bad because of mistaking the Template View Pattern, but it also fails in accomplishing one of the purposes of the MVC pattern itself!
public class CreateCustomer extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
try{
// .. Create the actual customer
}catch(Exception e){
// Some kind of error
return(mapping.findForward("createCustomer.jsp"));
}
// .. Prepare the data for the jsp
return(mapping.findForward("customersList.jsp"));
}
}
Can be interpreted as:
public class CreateCustomer extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
// ... Action logic
// ... View logic
return(mapping.findForward("customersList.jsp"));
}
}
The same action has Action logic as well as View logic in it, and it isn't separating both logics after all. This pattern implementation is useless. But if we keep the real MVC principles the code becomes clear and straight-forward.
public class CreateCustomer extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
try{
// .. Create the actual customer
}catch(Exception e){
// Some kind of error
return(mapping.findForward("createCustomer.jsp"));
}
return(mapping.findForward("customersList.jsp"));
}
}
public class DeleteCustomer extends Action {
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
try{
// .. Delete the actual customer
}catch(Exception e){
// Some kind of error
return(mapping.findForward("deleteCustomer.jsp"));
}
return(mapping.findForward("customersList.jsp"));
}
}
The data preparation has been moved to the customerList.jsp itself, which is now requesting information directly from the model. As an additional benefit, the ListCustomers action disappears because it's no longer needed, since other jsps can directly call to the customersList.jsp. The complexity has been reduced.
According to SmallTalk MVC definition: "[...] the model manages the behavior and data of the application domain, responds to requests for information about its state (usually from the view), and responds to instructions to change state (usually from the controller)". In MVC, The controller is NOT a Mediator between the view and the model. The controller does not sit in between the model and the view. Both the controller and the view have equal opportunity to access the model. Although we removed the Template View pattern from this implementation, notice that MVC pattern remains and is more useful than ever.
In future posts we will see a clean, easy-to-learn, easy-to-maintain, configuration-free MVC implementation based on jsps: POJM (Plain Old Jsp MVC).
