Sample code provided here is available on the web from the projects' sites.
Tools help experimented professionals to get results with minimum efforts. There are some tools that help a cook make a perfect plate. There are other tools that will help a common person cook a given plate providing step by step instructions even though that person is not a professional cook.
There even are tools that claim you can make hundreds of different dishes just after buying them. And then it comes the real cook and says "That tool looks like it may help, but it will limit creativity and so it is not proper for a cook"
Web Software development suffers from lack of separation of concerns [1]. This is reflected in every day decisions that affect companies productivity. Certainly, a single person can build a whole and complicated website. The problem is that it seems not many developers can master the three main aspects concerning Web development: Data, Business Rules and Presentation. If these concepts are mixed, maintenance will become a problem.
The division goes on on Data, Business and Presentation layers. Presentation in particular is divided in Structure (HTML markup), behavior (Javascript) and look-and-formatting (CSS).
The question arises when a company has to grow and suddenly the developer says "I need help. Who should we hire"? Another developer that knows very well all the involved technologies? Productivity cannot be achieved in any mass industry (like World Wide Web is) without division of work. You might rotate developers to make them proficient in different areas, a concept I personally still have to see it works in software, although it has worked for Toyota and its lean line of assembly.
So the project goes to production and your first developer has to correct a serious bug. He tries to understand what could possibly be failing and then he goes straight to the pieces of code he is suspicious about just to find out the second developer did not work exactly the same way he would. "OK, we need to standardize the way we work because I had to reverse engineer the whole code to find out where the problem was", says the first developer.
They decide to use an MVC Framework. After they are done, an important client makes a request: "We want to change the whole look and feel of the site including some rich components". The response is: "We will get it done in a couple of days". But they had to correct some bugs for other clients and they are late. They are not enough people and they ask for another developer. As clients keep on coming, more developers need to be hired and so the question about productivity arises. Is there a way to have a "product" we can sell and just be customized for any number of clients so we do not need more help as we grow? And the answer is Yes, the correct architecture and workforce must be in place.
I am not going to extend about the need for Rules Engines to make the "product" really customizable. I will not debate here the need of Web Services using the same Controllers logic and more. I will concentrate on how Presentation issues slows productivity down.
As the company grows, specialists in different areas are needed. A Designer/Front End Developer, a Database Administrator, a Middle tier developer and a Technical hands-on lead are needed. The latter must be familiar with all areas and he must decide which areas will be affected by the needed implementation. Of course, as a team they correct each other to keep concepts alive. MVC is easy to understand and hard to enforce. When the build/deployment cycle is slow, people are tempted to "solve" the problem violating the MVC pattern and then maintenance problems arise. The technical lead must respond for those violations.
This post could get really long. A whole book could be written about best practices in all areas and phases of Software Development Lifecycle. That is not the purpose of this document though. Let us concentrate on what a Front End developer must do.
The Front End specialist is the owner of the structure, behavior and format of the rendered output. A browser client program shows a User Interface to the end customer and it is a responsibility of the Front End developer to ensure light markup, resource reuse and caching, rich interaction, accessibility, semantic output and more.
The development framework must give the Front End developer total control from Doctype to </html> or any other start/close tags of any markup.
Good development frameworks are view Agnostic and most of them can definitely be used as so. However the examples coming out of the box most of the time ignore best practices. They end up being proof of concepts for architects deciding which technology to use and ultimately becoming the core of any future implementation.
Let us face it: while a middle tier developer might need a tool like Dreamweaver, a real designer will not. He is the Front end cook. Then, avoid trying to guess from your framework what is the best possible markup to be rendered. Leave that part to the Designer and just give him a Domain Specific Language he can use to insert content coming from middle tier.
Without serious examples this post will be nothing. Here is an analysis of some (but not all) of the most popular Java View technologies out there.
RichFaces
Let us pick and example from http://www.mastertheboss.com/en/web-interfaces/124-jboss-richfaces-tutorial.html<%@ taglib uri="http://richfaces.org/a4j" prefix="a4j"%>
<%@ taglib uri="http://richfaces.org/rich" prefix="rich"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<html>
<body>
<f:view>
<h:form>
<div align="center">
<rich:spacer width="1" height="50" />
<rich:panel style="width:320px;">
<f:facet name="header">
<h:outputText value="Login please"></h:outputText>
</f:facet>
<h:panelGrid columns="2">
<h:outputText value="Name: "/>
<rich:inplaceInput defaultLabel="Enter username"/>
<h:outputText value="Email:"/>
<rich:inplaceInput defaultLabel="Enter password"/>
</h:panelGrid>
</rich:panel>
</div>
</h:form>
</f:view>
</body>
</html>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<html>
<body>
<f:view>
<h:form>
<div align="center">
<rich:spacer width="1" height="50" />
<rich:panel style="width:320px;">
<f:facet name="header">
<h:outputText value="Login please"></h:outputText>
</f:facet>
<h:panelGrid columns="2">
<h:outputText value="Name: "/>
<rich:inplaceInput defaultLabel="Enter username"/>
<h:outputText value="Email:"/>
<rich:inplaceInput defaultLabel="Enter password"/>
</h:panelGrid>
</rich:panel>
</div>
</h:form>
</f:view>
</body>
</html>
Problems:
* align="center" specifies a layout. Semantic Web dictates markup must specify only intention and never presentation.
* Inline css, no doctype. Performance is affected by both but ultimately cross browser compatibility is hit right up front.
spacer gif. Remember Semantic Web?
* "custom tags" are responsible to render real final markup. This will lead for sure into unaccesible sites. This can cost millions to a company: http://www.dralegal.org/cases/private_business/nfb_v_target.php
ICEfaces
Here is an example of ICEfaces code that you can download from http://facestutorials.icefaces.org/tutorial/jspStoreProject.html (Registration required):<?xml version="1.0" encoding="ISO-8859-1" ?>
<jsp:root version="1.2"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ice="http://www.icesoft.com/icefaces/component">
<jsp:directive.page contentType="text/html;charset=ISO-8859-1" pageEncoding="ISO-8859-1" />
<f:view>
<ice:outputDeclaration
doctypeRoot="html"
doctypePublic="-//W3C//DTD HTML 4.01 Transitional//EN"
doctypeSystem="http://www.w3.org/TR/html4/loose.dtd" />
<html>
<head>
<link rel="stylesheet" type="text/css" href="./xmlhttp/css/xp/xp.css"/>
</head>
<body>
<ice:form partialSubmit="true" id="cart">
<ice:dataTable border="1" value="#{store.items}" var="storeItem">
<ice:column id="column1">
<ice:outputText value="#{storeItem.label}"></ice:outputText>
<f:facet name="header">
<ice:outputText value="Item"></ice:outputText>
</f:facet>
</ice:column>
<ice:column id="column2">
<ice:outputText value="#{storeItem.quantity}" id="s"></ice:outputText>
<f:facet name="header">
<ice:outputText value="Availible"></ice:outputText>
</f:facet>
</ice:column>
<ice:column id="column3">
<ice:outputText value="#{storeItem.price}"></ice:outputText>
<f:facet name="header"><ice:outputText value="Price" id="text3"></ice:outputText></f:facet>
</ice:column>
<ice:column id="column4">
<ice:outputText value="#{storeItem.purchasedQuantity}"></ice:outputText>
<f:facet name="header"><ice:outputText value="Quantity" id="text4"></ice:outputText></f:facet>
</ice:column>
<ice:column id="column5">
<ice:outputText value="#{storeItem.subTotal}"></ice:outputText>
<f:facet name="header"><ice:outputText value="Subtotal" id="text5"></ice:outputText></f:facet>
</ice:column>
<ice:column id="column6">
<ice:commandButton value="Add" actionListener="#{storeItem.addToCart}"></ice:commandButton>
<f:facet name="header"><ice:outputText value="Add" id="text6"></ice:outputText></f:facet>
</ice:column>
<ice:column id="column7">
<ice:commandButton value="Remove" actionListener="#{storeItem.removeFromCart}"></ice:commandButton>
<f:facet name="header"><ice:outputText value="Remove" id="text7"></ice:outputText></f:facet>
</ice:column>
</ice:dataTable>
<ice:panelGrid border="0" columns="4">
<ice:outputText value="Grand Total:" style="font-weight: bold"></ice:outputText>
<ice:outputText value="#{store.grandTotal}" style="font-weight: bold"></ice:outputText>
<ice:commandButton value="Check Out" action="checkout" type="submit"></ice:commandButton>
<ice:commandButton value="Reset Cart" actionListener="#{store.resetCart}"></ice:commandButton>
</ice:panelGrid>
<ice:outputText value="#{cartRenderBean.dummy}"></ice:outputText>
</ice:form>
</body>
</html>
</f:view>
</jsp:root>
<jsp:root version="1.2"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ice="http://www.icesoft.com/icefaces/component">
<jsp:directive.page contentType="text/html;charset=ISO-8859-1" pageEncoding="ISO-8859-1" />
<f:view>
<ice:outputDeclaration
doctypeRoot="html"
doctypePublic="-//W3C//DTD HTML 4.01 Transitional//EN"
doctypeSystem="http://www.w3.org/TR/html4/loose.dtd" />
<html>
<head>
<link rel="stylesheet" type="text/css" href="./xmlhttp/css/xp/xp.css"/>
</head>
<body>
<ice:form partialSubmit="true" id="cart">
<ice:dataTable border="1" value="#{store.items}" var="storeItem">
<ice:column id="column1">
<ice:outputText value="#{storeItem.label}"></ice:outputText>
<f:facet name="header">
<ice:outputText value="Item"></ice:outputText>
</f:facet>
</ice:column>
<ice:column id="column2">
<ice:outputText value="#{storeItem.quantity}" id="s"></ice:outputText>
<f:facet name="header">
<ice:outputText value="Availible"></ice:outputText>
</f:facet>
</ice:column>
<ice:column id="column3">
<ice:outputText value="#{storeItem.price}"></ice:outputText>
<f:facet name="header"><ice:outputText value="Price" id="text3"></ice:outputText></f:facet>
</ice:column>
<ice:column id="column4">
<ice:outputText value="#{storeItem.purchasedQuantity}"></ice:outputText>
<f:facet name="header"><ice:outputText value="Quantity" id="text4"></ice:outputText></f:facet>
</ice:column>
<ice:column id="column5">
<ice:outputText value="#{storeItem.subTotal}"></ice:outputText>
<f:facet name="header"><ice:outputText value="Subtotal" id="text5"></ice:outputText></f:facet>
</ice:column>
<ice:column id="column6">
<ice:commandButton value="Add" actionListener="#{storeItem.addToCart}"></ice:commandButton>
<f:facet name="header"><ice:outputText value="Add" id="text6"></ice:outputText></f:facet>
</ice:column>
<ice:column id="column7">
<ice:commandButton value="Remove" actionListener="#{storeItem.removeFromCart}"></ice:commandButton>
<f:facet name="header"><ice:outputText value="Remove" id="text7"></ice:outputText></f:facet>
</ice:column>
</ice:dataTable>
<ice:panelGrid border="0" columns="4">
<ice:outputText value="Grand Total:" style="font-weight: bold"></ice:outputText>
<ice:outputText value="#{store.grandTotal}" style="font-weight: bold"></ice:outputText>
<ice:commandButton value="Check Out" action="checkout" type="submit"></ice:commandButton>
<ice:commandButton value="Reset Cart" actionListener="#{store.resetCart}"></ice:commandButton>
</ice:panelGrid>
<ice:outputText value="#{cartRenderBean.dummy}"></ice:outputText>
</ice:form>
</body>
</html>
</f:view>
</jsp:root>
*Here is a statement from their home page (http://www.icefaces.org/main/home/): "With ICEfaces, enterprise Java developers can easily develop rich enterprise applications in Java, not JavaScript". Domain specific Languages exist for a purpose and trying to ignore them with the formula one language does it all is like trying to use Dreamweaver for layout and formatting.
* border, inline CSS: Clear violation of separation.
* Tags wrapping final markup again.
* Why this: <ice:outputText value="Grand Total:" style="font-weight: bold"></ice:outputText> instead of just: <span id="" class="">Grand Total<span> or <div>...</div>
The bottom line here is that Java community seems to be worry about being able to use WYSIWYG tools which after all real Designers do not care about. The solution here is invasive and obtrusive. And let us not even talk about different markup WML, XHTML-BASIC. Look at Liferay forums or Seam forums, or JBoss Portal Forums about those (less than 10 questions partially answered). It looks like supporting a non-Mozilla-Internet Explorer device *always* needs a hack.
JSF
Look at this pure JSF code (from http://www.exadel.com/tutorial/jsf/jsftutorial-kickstart.html):<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<f:loadBundle basename="jsfks.bundle.messages" var="msg"/>
<html>
<head>
<title>enter your name page</title>
</head>
<body>
<f:view>
<h1>
<h:outputText value="#{msg.inputname_header}"/>
</h1>
<h:form id="helloForm">
<h:outputText value="#{msg.prompt}"/>
<h:inputText value="#{personBean.personName}" />
<h:commandButton action="greeting" value="#{msg.button_text}" />
</h:form>
</f:view>
</body>
</html>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<f:loadBundle basename="jsfks.bundle.messages" var="msg"/>
<html>
<head>
<title>enter your name page</title>
</head>
<body>
<f:view>
<h1>
<h:outputText value="#{msg.inputname_header}"/>
</h1>
<h:form id="helloForm">
<h:outputText value="#{msg.prompt}"/>
<h:inputText value="#{personBean.personName}" />
<h:commandButton action="greeting" value="#{msg.button_text}" />
</h:form>
</f:view>
</body>
</html>
* Take a look at http://www.exadel.com/tutorial/jsf/jsftags-guide.html:
* outputLabel adds a span which is wrong.
* selectOneRadio generates a whole table!!!
* Again, why not to allow standard html tags?
Please, do not ignore the real need of a real Designer in your team. After several years being part of software teams using several languages, and in many cases leading those teams, I can confirm the main reason Java teams seem to be the slowest is the lack of separation of concerns in most of the implementations using current and home-made frameworks. This is not about frameworks failing, but about architects and tech leads failing to keep best practices.
JSTL
Here is an example from Sun (http://java.sun.com/developer/technicalArticles/javaserverpages/faster/):
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<html>
<head>
<title>JSTL Implicit Objects</title>
</head>
<body bgcolor="#FFFFCC">
<h3>Header info:</h3>
<c:forEach var="head" items="${headerValues}">
param: <c:out value="${head.key}"/><br>
values:
<c:forEach var="val" items="${head.value}">
<c:out value="${val}"/>
</c:forEach>
<p>
</c:forEach>
</body>
</html>
The Java Standard Tag Library helps eliminate scriplets which make the code simply too big for a presentation layer. It avoids NullPointerException from JSPs, it provides cleaner code for iterations and that is just the beginning. It also parses XML, includes several helper functions and allows to define your own custom tags. The problem comes precisely when developers use taglibs to output markup from the library itself.
The code is definitely verbose though. Again, trying to make the code readable for tools like dreamweaver the Designer has to deal with lot of extra code and again: he does not need Dreamweaver!!!! So why <c:out value="${val}"/> instead of just ${val} or even just $val !!!
Velocity
Templates have been there for a while. I remember the big debate about if Smarty was needed given the fact that PHP was in any case created by his author thinking of it as a templating solution. Well, as a Designer, what you think about the below code taken from http://portals.apache.org/jetspeed-1/tutorial/7/velocity.html?<HTML>
<BODY>
Hello $customer.Name!
<br/>
Here is a list of your current subscriptions:<br/><br/>
<table>
#foreach( $subscription in $subscriptions )
#if ( $customer.isSubscribed($subscription) )
<tr>
<td>
$subscription.Name
</td>
</tr>
#end
#end
</table>
</BODY>
</HTML>
<BODY>
Hello $customer.Name!
<br/>
Here is a list of your current subscriptions:<br/><br/>
<table>
#foreach( $subscription in $subscriptions )
#if ( $customer.isSubscribed($subscription) )
<tr>
<td>
$subscription.Name
</td>
</tr>
#end
#end
</table>
</BODY>
</HTML>
"Yeah, cool", answered a Designer I know who -by the way- rocks! Hey Jorge, if you want credits here, I can always edit this post and provide a link to the stuff you want.
Jetspeed Portal, a competitor of Liferay, uses this templating engine. Liferay too, but somehow the community seems to favor more the use of ICEfaces.
The above syntax is as a simple as it can get, and the best solution for a problem is the one that solves it more simply.
Let us even talk about cross domain compatibility. For example, big efforts are done everyday to make sure Desktop code run in Linux can run in Windows and MAC OSX. JQuery has solved a big inter-browser compatibility problem. And the list goes on. I believe simple stuff like Velocity are cross server compatible. With Velocity templates, all you need is a parser able to receive a Context with input variables, and the output will be just existing markup in the template with the content injected from the middle tier. Simple and yet so powerful.
References
[1] http://en.wikipedia.org/wiki/Separation_of_concerns
1 comment:
Great post, Nestor.
Application development needs good semantic markup and cross-browser CSS to be efficient, and that responsibility should be on the designer and frontend developer.
Separating concerns is something any good designer already understands. Web standards require a separation of html from css and javascript.
And no good frontend person, either designer or developer, can do their job well if they don't have *full* access to html and css.
Post a Comment