New Framework - old problems and new solutions:
by Mark Qian (3/15/2006) (Author/architect/developer)
PREFACE
There have been so many "Web Application Frameworks" (with thin client) out there
but "the old problems" are still around.
The goal of this paper is to address the problems and introduce solutions.
You may want to read the "the problems" first before you jump into solutions.
The Coolshare Web Application Framework, as one of the solutions for those problems,
is a private project run by Mark Qian.
The detail documentation about this framework is available
The goals of this project are simple:
A. Identify the problems and come out with solutions theoretically (Mark' role: author)
archiving a comprehensive result(Show detailsShow details)
B. Turn the theoretical solutions into a concrete software
structure/framework design (Mark' role: architect)
C. Deliver a highly scalable, reusable/sharable, configable and maintainable
web application framework (Mark' role: developer)
What is wrong with those most popular web application frameworks?
Many frameworks like Struts, JSF, ASP.NET, Tapestry, have been introduced for web
app developments in a variety of platforms and patterns but most of them have
major problems in following areas (Click at the link below to see the details of each
problem and solution):
- A. Overall Problem:
the power of these framework is limited within the CUPs running
the web containers, lack of integration with the rest of the
application, the browser
(The problems and solutionsShow details)
They are actually "Web Tier" frameworks instead of "Web Application" frameworks
because they only reside and have all their work done in web containers. (I will reference
them as "Web tier" application frameworks below).
In other words, it is the CPUs in the web server genterate the result (http response) and
browsers are receiving the same type of things, pieces of plain text.
They allow/"encourage" developers to build a very fat web tier like a mainframe and are
lack of integration with the browser, where most interaction occur in a web application.
So what? Well,
The problem is
----------------
- increase the load of web servers
- waste more network bandwidth
- lack of support to the client-side interaction
The result is that your applications appear with low scalability, poor performance and
poor usability
Examples
--------
a. validation
Most of them (such as Struts, JSF and ASP.NET) only support server-side validation
but a lot of "client-side doable" validation should never be done in the server side.
These "web-tier" frameworks just can't do much about it because of the limitation
of HTML protocol: plain text is always the response from the server. One of the
unreasonable example is JSF: it provides field-level validation at server-side
but field level validation most likely is at the client stage such as max, min,
required and so on.
Many server-side stage (business logic related) validation are inter-field validation
which is not covered by the taglib by default.
b. exception handling
By default, many of them (like Struts) use the solution from JSP: forwarding to an
error page. This is very poor usability since the users will lose the state of the
page posted. Then users click the "Back" button of the browser trying to "return" to
their editing environment, causing more problems.
Others solve the state problem with return the same page with error messages or red
marks on the page. But this is still not look as good as a regular (Windows) GUI.
Specially for those long pages with high access speed, users are confused since they
didn't even realize the pages have been reloaded (nothing is changed in their view)
and contain some "red" errors out of viewing area (at the top/bottom).
Exception is "big deal" and should warm use with something like a popup/plus red marks.
In term of network traffic efficiency, it is wasteful to send the redundant data back.
c. "whitten pages"
Most "web-tier" framework are assuming/encouraging developers to send their page
directly back to the server. The page sent will be whitten for a while before
the new content is reloaded.
You can always tell the quality of web application easier in a net meeting when
network latency is more obvious. The designers of "web-tier" frameworks can hardly
do much on this since this requires client-side effort. To many web applications,
a lot of user activity is "light way" required no entire page replacement.
|
You may say, "AJAX". Wait a minute...AJAX is a solution but it may not be the best for
remote scripting. (Note: AJAX is only a subset of remote scripting but people seems to use it as the
label of remote scripting). In some case, AJAX can not be a solution
(see the third issue below).
Here are some problems AJAX has when used as a mean for remote scripting, specially
when "Dynamic remote scripting":
1. "Dynamic remote scripting" means that you want to unpdate part of your screen or
browser tier data with "Objects", where execution is embedded in the returned
content. Be clear here: we want to deal with "Objects" which contain both
data and functions applied on the data. We also want the Objects to be rendered
in the same way as they are requested by a non-AJAX, a regular browser,
http request. In other words, when content returned by a remote scripting request,
we want the browser to render the data and then invoke the javascript embedded
in the Objects (content returned as the result of a remote scripting request:
data and javascript). Or even more extremely, you don't want to return any data to
be displayed directly. Instead, you like to only return script and data that is only
used by the return script together with some data reside in the browser to produce
the presentation data at the client side.
Because AJAX returns pure "data" (either as plain text or xml) in to javascript
namespaces instead the browser rederer, it is hard to run any javascript
included in the "data". Some poeple tried to make this up by a variety of
ways like parsing and evaling the header where the javascript reside with
a lot of challenge like escaping and so on.
The key point is that AJAX bypasses the core of the browser, the html
renderer.
2. There is a data building (before sending) and loading (after receiving)
process. If you are not careful enough, it may end up with redundent
codes and extra overhead. You need to escape values and so on...
3. AJAX is not a native component in some browsers and users may disable it.
For example, XMLHttpRequest appears in IE (6.x) as an ActiveX, an embedded object.
Users or security application can disable it in the "Script ActiveX controls marked
safe for scripting" from the "internet option" of control panel in Windows.
Actually, a lots of companies will have ActiveX controls disabled and many
PC protection programs also make turning off ActiveX at one of their security
level. Even IE 7.x has XMLHttpRequest as a native component but it can still
be turned off from its security setting.
If your users are the "very end" users like shopping people using
IE to access your shopping carts, using AJAX is really gambling.
You are bidding on them with ActiveX on to see your AJAX pages.
4. Other limitation
- It can't be used cross domain.
- It doesn't work with the file:// protocol: can not transfer files.
- It is hard to used for server pushing for all browsers. So far IE6 does not
support multipart. But other alternatives, such as iframe, can achieve that.
Solution of Coolshare Framework: using dynamic iframe remote scripting under
Coolshare javascript framework.
The result is:
- an "abstract" communicator handles all the asynchronized request hiddenly
- no value building/loading
- you can run any script in the "data" sent by by the server in a subscribing way
- within the Coolshare javascript framework, you can easily "plug in" a javascript
components. That means you can simply add js files into war that firing
events, handling events and so on without touching your application's codes.
The framework will pick up your components at run-time.
Note: AJAX is also used in the framework but only for "lightweight duties"
Related articles/projects/demos:
- See Mark Qian's article/real codes/demos
about AJAX and remote scripting at RemoteScriptGuru.com.
- Also see the demo of an AJAX/Google Map project, CooMap by Mark Qian, at
http://www.coolshare.com/coomap
This link is not always available since it involve polling/chating (so I have to run it in my own web server
from home, which is not always up): good luck!
|
In fact, many web applications' business logic does not reside at web-tier which
only plays three major relatively-simple roles: 1). working as a gateway - take care
security, session, and so on to make next tier "transparent" to browser tier; 2). take
care the application logic for the thin client; 3). serialize and deserialize between
http-plain-text and data format of next tier. To these kind of applications, a complicate
web-tier framework like JSF is really over killed or wasteful.
Summary:
-------
Plain text and asynchronized are the major reasons making http so popular but
is also the killer of these " Web tier" application frameworks since no matter how
great they do on the server side the result is the same to the browser: a piece
plain text without any communicatable (to the framework) conponent inside the text.
Solution of Coolshare Framework:
Building a framework at top of browser and an existing "web-tier" framework
(in this case, Struts).
Coolshare Framework consists of "Tiles". Each Tile is a couple of a client-side component
(view) and a server-side business object (model) such as an entity bean. These tiles can
be independently " plugged" into pages without worrying about any existing content.
Most communication is done by Remote Scripting (Most pages are loaded only once). See detail
description at "The design of Coolshare Framework".
Show details
- B. Browser Tier Problem:
there is no real PlugInable "Tiles"
(The problems and solutionsShow details)
The problems is
----------------
most of these web frameworks construct components/tiles at server side and then send them as
"plain text" back to browsers. But they can be hardly shared on a single page.
Examples
--------
- Struts provides "Tiles" but its tiles are only "static" pieces of JSP code blocks, JSP
includes specified in XML files. For any of these blocks, multiple instances can not
coexist with in a single HTML page without "special Javascript care".
Say, you have a tile "double list" where there is an "assigned list" and an "available
list". To send all the items in the "assigned list" back to the server, you need to do
some "preSave" process before posting. One of the way to do it is to fill all them item in
the "assigned list" in to hidden fields with the same name so that you can get them
using getParameterValues at the server side.
If you define such a "double list" as your Struts tile and you need to process specific
details for each "double list", you can not use more than one instances of it on a single
page since there will be two "preSave" JS function and in that case the second one will be
used for both tiles. You will also have similar problems like field name conflict too.
You may ask, "wait, why do I want to use more than one instances of it?", well, you want
to have different data share the same view, the double list view, so that you don't code
redundantly to maximazie you consistency, efficiency, maintainablity and so on.
You may say, "well, I have this kind of redundant codes all around my application and what
is wrong with it (it seems everyone is doing it)?". Please read on, you will see how bad
it is in the following example.
- Have you ever take are look at the projects you involved: did an entire application
(or even more than one applications) share a single view of a type like a table, tree?
(Note: same similar issue also exists across pages. I only cover the issue on
a single page here.)
You may be wondering again: why do I need to share? Well, this is why some companies keep
so many developers for so limited maintenance and development.
Let's look at the way an "ordinary" company maintains/develops a web page in a
"regular" way:
In the initial release, you have a single "form" view. The "form" view here is not necessary
a html form but a GUI "form" containing a set of label/input or label/select fields and so on
and it represents a business object, say "order" in the page. So you "hard code" it.
"Hard code it" means that you have concrete handler invoked directly by each component such
as a button or a "onchange" on a html component in the "form" and you have concrete field
names too as following
|
<script>
function doXXX1(c) {
//do submit form here
...
}
</script>
...
<body ...>
...
<!-- ---- begin of "order form" -- -->
...
<input name="field1"...>
...
<select id="orderType" onchange="doXXX(this)" ... >
<!-- ---- end of "order form" -- -->
...
</body>
...
|
A "concrete handler" above means the component, select1 (concrete name), invokes the
handler, doXXX1, directly. So far everything looks fine traditionally.
OK, here is comes with the requirements for the second release: we need to show an
additional "form" representing a new business object, "Payment", to be in the same
page when value of field "orderType" in the initial form is selected as "payable".
Note (the fact): the Payment object has the same type of view as the order object:
" containing a set of label/input or label/select fields and so on"
By "default", you can't reuse the same view because of the conflicts which we discuss
in the previous example above (there are conflicts on function and field names).
Most likely the "ordinary" approach to meet the requirement is just "hard coding" another
"form" on to the same page as following:
|
<script>
function doXXX1(c) {
//do onchange for order here
...
}
...
function doXXX2(c) {
//do onchange for payment here
...
}
</script>
...
<body ...>
...
<!-- ---- begin of "order form" -- -->
...
<input name="field1"...>
...
<select id="orderType" onchange="doXXX1(this)" ... >
<!-- ---- end of "order form" -- -->
...
<!-- ---- begin of "payment form" -- -->
...
<input name="field2"...>
...
<select id="orderType" onchange="doXXX2(this)" ... >
<!-- ---- end of "payment form" -- -->
...
</body>
...
Show details
|
Then next release you might add one more "form"...one more
"form"... The page is getting "fatter" and "fatter" and each piece of "fat" may be
added by a different developer using different coding style/technology. It is hard
to understand and maintain when coders come and go. And of course, you keep hiring:
|
<script>
function doXXX1(c) {
//do onchange for order here
...
}
...
function doXXX2(c) {
//do onchange for payment here
...
}
...
...
function doXXXN(c) {
//do onchange for NNN here
...
}
</script>
...
<body ...>
...
<!-- ---- begin of "order form" -- -->
...
<input name="field1"...>
...
<select id="orderType" onchange="doXXX1(this)" ... >
<!-- ---- end of "order form" -- -->
...
<!-- ---- begin of "payment form" -- -->
...
<input name="field2"...>
...
<select id="orderType" onchange="doXXX2(this)" ... >
<!-- ---- end of "payment form" -- -->
...
...
<!-- ---- begin of "NNN form" -- -->
...
<input name="fieldN"...>
...
<select id="orderType" onchange="doXXXN(this)" ... >
<!-- ---- end of "NNN form" -- -->
...
</body>
...
Show details
|
In term of resource sharing, you may notice that you are duplicating "form" as views
on the same page: these are the same view with different data! In fact, not only this
page need only a single view but also the entire web application even all applications
need only a single view of a type.
Summary:
The key is that we need to be able to share views not only in different pages but also
the same page in a non-context-sensitive way: different data share the same view in a
single page regardless if there is an existing tile with the same
view on the same page. In other words, one or more web application only need a single
view of a type (such as a table and a form). This will ensure the consistency, reliability,
efficiancy and maintainability.
More importantly, "PlugInable" allows tools (the "Tiles" in Coolshare Framework can be
plugged in by a web base tool, Coolshare Web Wizard).
Solution of Coolshare Framework: part of Coolshare Framework is in javascript. Any
interaction components in GUI at top Coolshare Framework such as buttons and text
fields never call any concrete handler. Instead, they register their handlers as
listeners of actions and issue events. After the JS framework receives the events
from visual components, it determents what actions (one or more) to invoke. Invoking
an action means to process through the action's listener list to carry out all the
concrete handlers. (See details in "Pluginable in Coolshare")
In other words, the communication is done in a publisher/subscriber manner
with topics (very similar to the way DOJO's event model does. One key difference
between Coolshare and DOJO is that Coolshare loads all the javascript modules dynamically...
See details in Coolshare documentation).
This Hollywood ("don't call me and I will call you") style will allow the "tile" to be
plugged in to any page regardless existing content.
Remote Scripting is heavily used by Coolshare's javascript framework.
Show details
- C. Web Tier Problem:
assuming http request contains "field/components"
(The problems and solutionsShow details)
Facts:
JSF constructs component trees;
Struts builds ActionForms;
Tapestry receives pages that contains fields;
ASP.NET uses Web Forms.
The problem is
----------------
none of them deal with "stuff" at business object level. Many pages contain one or
more business object(s) but what the "web-tier" frameworks receive are fields and
components. This "detail-exposing" causes the framework users (developers) to
unnecessarily HARD CODE a lot of value building/loading stuff. For example, a
typical block of codes, in Struts actions, is calling getters of a ActionForm and
then calling setters of the business object to build the value of the object before
they can invoke the APIs at next tier (Spring beans or EJBs).
Furthermore, these component trees (in JSF), ActionForms (in Struts) and pages
(in Tapestry) are totally "junk" from the performance point of view because
you can not use them to invoke the APIs at the next tier directly: why do we need to
construct them and then reconstruct business objects from them instead of directly
constructing business objects from parameters of http request?
This is a serious problem with maintainability. Developers have to run after the
frequently modification of PRDs release after release by changing/adding/removing
setters and getters in Struts actions because of the HARD CODING. There are
similar situations in JSF and ASP.NET. Exposing details like fields will cause a lot
of unnecessary coding.
Summary:
-------
The key point here is that what many http requests contains are not "fields" (in Struts)
nor "components" (in JSF) but one or MORE business objects. The framework should make
details such as fields and components transparent to programers and provide a way to handle
request at "entity level" instead of "field level" so that we don't need to have any hard-code
in the web-tier.
Solution of Coolshare Framework: Coolshare Framework constructs business objects
directly from parameters from http requests. No setters and getters are involved in
a hard-code way and use no ActionForm. See details in "No Hard coding in Coolshare"
You can see that a map, entityMap, of entities instead of ActionForm is passed as
a parameter to the concrete action in Coolshare Framework.
Show details
|