Fog Creek Software
Discussion Board




webapp design issue: many pages, or one page?

I've built a few web applications, and am building one now. I'm also taking a look at the demo of FogBUGZ.

I'd like to get some comments on what people think is the best design strategy for building out the pages in a web application.

Do you use many pages? I.e.:

/index.jsp
then login at /register/login.jsp
then get directed to /admin/index.jsp
then to log out link to /register/logout.jsp

Or,do you embed the logic into a servlet, (or equivalent microsoft paradigm) that is acted upon by one page, with different parameters telling it what to do

i.e:

/default.jsp
then login at /default.jsp?pg=pgLogin
then get directed to /default.jsp?pg=pgAdminMain
then log out link to /default.jsp?pg=pgLogout

I usually use the first approach, but I've noticed that FogBUGZ uses the second approach. I was going to refactor my current code (not much there yet) to use the second "one page" approach. It intuitively seems like it would be easier to maintain , because there are fewer files. However, I'd like to get feedback on the pros and cons of each approach.

Thanks!

choppy
Tuesday, April 01, 2003

Actually just because you have one single index.asp doesn't mean you have very few files. In our projects we have a single access point (default.asp) but everything is broken out to
1) aid creatives in internationalization
(#include EnglishVariables.asp)

2) aid webbies in templating (#include processing.asp)

3) aid dbas in data access
(#include data.asp)

In Microsoft Commerce Server 2000 they really take it to an extreme where you end up calling main() which calls all the helper functions in ungodly numbers of asp files and components. Everything is modular.

Li-fan Chen
Tuesday, April 01, 2003

if you do your own session tracking (anti hacking anti google) you can always break the initial cookie-handling/challenge validation/failed challenge redirection/user flow state machine determination into a security.asp and include it for execution at the very beginning. Normally security goes first.

Li-fan Chen
Tuesday, April 01, 2003

Just a side note, SlashCode/ACS/OpenACS is similar, all the same spagetti mess..  we could all use a little aspect oriented programming... *wink*.

Li-fan Chen
Tuesday, April 01, 2003

Technically you might end up with a hybrid system where you get the best of both worlds.

For example we do a thing where reasonably named index.asps call the same main().

And main() would deal which each function like a portal.. calling helper functions that takes on a domain once the user flow state machine determines which domain you should take in this one single access (you can do webmail, you can do discussion groups, you can do reporting... you can admin.. so on)

and each of these helper functions can reside in separate files.. in a folder like scripts/ doing things like:

news.asp
admin.asp
discuss.asp
reporting.asp and so on..

and the access pages (used in ACTION tags in user viewable pages) would point to:

news_en.asp or news_fr.asp and so on... and all of them do the includes that includes all the actual scripts...

-- David

Li-fan Chen
Tuesday, April 01, 2003

The approach that seems to be popular today is the "action controller". In general it goes like this:

The path and page part of the URL is just a label for a particular action (e.g. /login, /cart/checkout, etc) and doesn't map directly to any particular file or code.

Instead you've configured your web application server to send all pages requests to one processor (the action controller).

The action controller then decides what bit of code should execute the request, usually based on a configuration file, and passes off processing to that code (perhaps after doing some other work).

The advantage is that you've got a layer of indirection between the URL and the code that can be much more easily changed.

This is, of course, sort of like the original poster's second example, but abstracted out in a computer programmers sort of way.

The original poster mentioned JSP files and servlets, so I'll point out that the leading action controller framework for Java web applications is called Struts.

Bill Tomlinson
Tuesday, April 01, 2003

What he said :D

Li-fan Chen
Tuesday, April 01, 2003

Let's say you write a huge console application. you can definitely do it with one main() function and zillions of parameters.

I think one of the main reasons for fewer physical webpages on the site are the following:

- psychology -- I was able to solve it in 2 files :)
- easier "programmable" templating
- easier parameters checks
- and probably lots of others.

Of course there is no word without cons.

na
Tuesday, April 01, 2003

I prefer to have separate files for separate functions, as that cuts down on the amount of code I have to search through to find the function I'm looking for.  It elminates guesswork -- rather than having to remember the name of a function so I can perform a search on it in a file, I can just skim through the half-dozen functions in the file.

You can do this in the other model too, so that the main page includes a whole bunch of other pages, but in that case I find that the central processing page turns into a big switch() statement.  I find that ugly and unnecessary, when I can just do the processing on different pages.

There also might be a performance impact; the server might be able to serve up a dozen different pages if they were all requested simultaneously, while it might have to serialize access to one central page.

Brent P. Newhall
Tuesday, April 01, 2003

It's all the same. It's all dispatch. Dispatch at the file level, dispatch inside a single file, dispatch from a dispatcher called by the system without even having a file there. Whatever makes you happy. *shrug*

Brad (dotnetguy.techieswithcats.com)
Tuesday, April 01, 2003

Oh, and there's one minor advantage to a flat dispatch system: it's easy to make relative URLs. That doesn't necessarily mean everything goes through 'default.asp', but rather that everything resides at the same 'level', ala 'http://foo.bar/login', 'http://foo.bar/list', etc.

Brad (dotnetguy.techieswithcats.com)
Tuesday, April 01, 2003

Brent mentioned, as an aside, performance issues about serialized access to a central page.

It's my understanding that all the major web application environments operate as inherently multi-threaded applications. That is, each page request is a separate thread of execution through the page code. So as long as you don't explicitly serialize access, the two design approaches we're discussing don't have that type of performance trade-off.

Bill Tomlinson
Tuesday, April 01, 2003

Well, Brad, it's true that it's all dispatch. But that's like saying "it's all ones and zeros, do whatever you want".

At some point we do have to make a design decision, so what's wrong with discussing the pros and cons of various approaches?

Bill Tomlinson
Tuesday, April 01, 2003

Fusebox.

It's a standarrd methodology for writing web apps.

In a nutshell your app is fuse, and it may have multiple circuits (actions) within it, and it maight also call out to others fuses.  You don't put it all in one file though, you break it out into subcomponents and call them as needed.

I'm horrible at explaining it so go check out the site at www.fusebox.org .  It's done wonders for our internal development, as it makes web apps much easier to test and makes it a lot easier to re-use components as well.

It was originally developed for Cold Fusion (thus the name), but it works for other languages as well.

Steve Barbour
Tuesday, April 01, 2003

You might also want to check out the Core J2EE patterns catalog at http://java.sun.com/blueprints/corej2eepatterns/Patterns/index.html especially the front controller and dispatcher view patterns.

PatternGuy
Tuesday, April 01, 2003

One minor point but all the .asp and other systems for generating web pages now make it a huge mess to save the pages to disk, as they are all called defautl.asp or something equivalent.

Still, I suppose saving to disk is jurassic anyway.

Stephen Jones
Tuesday, April 01, 2003

I was looking thru the Fogbugz code recently and I noticed that most requests are sent to the default.asp page which acts as a dispatch.

To implement this model, they #include almost every single ASP page in default.asp.  This means that IIS has to evaluate all those templates on every request to default.asp, even if only ONE or TWO functions are actually called.

Needless to say, I think this is a bad design.  Personally when I make ASP applications, I only include the classes and modules that I use on a page in that page.

Wayne
Tuesday, April 01, 2003

Furthermore, they use a LOT of ASP Tags (<% %>) in the pages which makes IIS have to parse them out before evaluating the code in between them.  Don't you think it's better to do all the logic in between one set of ASP tags and then output all the variables in the page itself?

I guess there are times you have to do loops in ASP to make a table, but that's why I use XML Databinding on the client side instead.  It's much more efficent, but then you're limited to Internet Explorer 4.0+.  The only output I ever have to put on a page is an XML Data-island that the client-side script then handles.

Wayne
Tuesday, April 01, 2003

Wayne > To implement this model, they #include almost every single ASP page in default.asp.  This means that IIS has to evaluate all those templates on every request to default.asp, even if only ONE or TWO functions are actually called.

The best thing to do is to pick your performance tuning battles. I don't think this model is the fastest, but there are ways to scale this software in ridiculous ways without worrying about this particular inefficiency.

Li-fan Chen
Tuesday, April 01, 2003

Do you feel FogBUGZ is too slow? If not, then the design is fast enough and it doesn't matter if it's not as optimal for speed as it could have been.

Thomas Eyde
Tuesday, April 01, 2003

This doesn't address the one-page/many-pages question, but is at least vaguely related to page design strategy.

Many approaches, including (especially?) the "default" approach with ASP (and still to a large extent with ASP.NET) can easily lead to pages with heavily intermixed HTML and script code, presentation and business logic, etc. This can cause inefficient server processing of the pages, and also makes it more difficult to maintain/change the pages.

The code outline shown further below is a preliminary sketch of a template structure that attempts to separate some of these functional areas into separate files that can be somewhat independently maintained and modified. This template structure is based on XHTML and CSS (and XML/XSLT), moving all of the presentation markup (FONT, COLOR, etc tags) out of the ASP page into CSS and XSL files. (I started this as a proposal for work, but haven't had time to take it any further.)

The page template shown below assumes a menu at the top of the page, but the template can be easily re-arranged for a left-side menu or other styles. Variations can be created if a site contains several different major categories of pages. A more complex template with multiple different sections in the page could also be created in this same conceptual style. The template as shown is intended for recent browsers (IE 5 and 6, Netscape 6, Opera 7, etc) that substantially support W3C web standards. The intent is that the content will still display in older browsers, but it may not be visually styled in the same way.

This approach allows the page style and appearance, menus, and content layout and style to each be developed and maintained separately (and optionally by different people). The "inner content" (the table of data, for example) is still the least separated, but once the basic style for this area is defined or created as a sample by a web designer in pure HTML, it should be relatively easy to change it (in code or CSS) in the future (especially if it uses CSS style classes - for example, <table class="TopicData"><tr class="RowOdd">...<tr class="RowEven">... instead of specific HTML attributes <table border="1"><tr bgcolor="white">...<tr bgcolor="yellow">...).

=========================================
Page.asp
--------
<%@ Language=VBScript %>
<% Option Explicit %>
<!--#INCLUDE FILE="setup-and-variables.asp" -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<!--#INCLUDE FILE="Server-common-functions.asp" -->

<head>

<!--#INCLUDE FILE="meta-and-stylesheet-links.asp" -->
<script type="text/javascript" src="JavaScript-for-all-pages.htm"></script>

<!-- ##### Includes specific to this page ################ -->
<!--#INCLUDE FILE="Server-functions-for-THIS-page.asp" -->
<script type="text/javascript" src="JavaScript-for-THIS-page.htm"></script>
<!-- ##################################################### -->

<title>Page Title Goes Here (or call a function if the title is
dynamic)</title>

</head>
<body>
<!--#INCLUDE FILE="UI-header-and-menus.asp" -->

<DIV id="PageContent">
<H3 class="PageMain">Section Header</H3>
<%

' Call function(s) in ASP file (that contains only VBscript
' code and calls to COM components, no embedded HTML) to
' generate this section of content for the page.

' This could be, for example:
Response.Write TransformXML(XML-read-from-database, XSL-for-this-set-of-data)

%>

</DIV>

<!--#INCLUDE FILE="UI-footer-copyright-etc.asp" -->
</body>
</html>
=========================================


The included files contain items such as the following: (Note - the file names shown are intended to represent the purpose of the file, not the actual file name, and may also represent more than one file.)

setup-and-variables.asp
=======================
Response.Buffer, Response.Expires, cache control, any page-level variables, perhaps authentication checking, etc

Server-common-functions.asp
===========================
Server-side (VBScript) functions that are common to all (or most) pages - such as data retrieval functions (or calls to data layer components or business layer components), XML transformation, etc.

Server-functions-for-THIS-page.asp
==================================
Server-side (VBScript) functions specific to this page

meta-and-stylesheet-links.asp
=============================
HTML META tags and stylesheet link tags, including stylesheets for printing, and alternate stylesheets

JavaScript-for-all-pages.htm
============================
Client-side JavaScript functions that are common to all pages

JavaScript-for-THIS-page.htm
============================
Client-side JavaScript functions specific to this page

UI-header-and-menus.asp
=======================
DIV blocks containing common sections (logo, navigation menus, etc) at top of page

UI-footer-copyright-etc.asp
===========================
DIV block containing common section (copyright notice, etc) at bottom of page

Philip Dickerson
Tuesday, April 01, 2003

Regarding the comment: "they #include almost every single ASP page in default.asp.  This means that IIS has to evaluate all those templates on every request to default.asp, even if only ONE or TWO functions are actually called."

I'm not sure that this is a performance problem. I did some performance testing some time ago with different styles of building pages (using IIS4, so there may be some differences with IIS5). Large numbers of include files (with many lines in each file) had an extremely small impact on performance if the includes were all script code, preferably all functions not inline code. The first time that a page is accessed, it is interpreted and cached (with all of its include files) and the unchanging parts don't need to be interpreted again on subsequent accesses.

The number of times that the context is switched between HTML and ASP (with the <% ... %> syntax) had a much larger effect on performance than the number and size of include files. The next largest performance impact was the number of times that Response.Write was called.

Philip Dickerson
Tuesday, April 01, 2003

Bill wrote: "At some point we do have to make a design decision, so what's wrong with discussing the pros and cons of various approaches?"

Mostly because there's too many variables, not the least of which is the web technology at hand (fully interpreted, pseudo-compiled, compiled, JIT compiled, etc.) and the architecture of the web site.

I wasn't being flip with my first post. It really IS just dispatching. You can let the OS do it based on filenames, you can let the web server do it based on mappings, or you can do it in your own code. It all works out the same in the end.

Brad (dotnetguy.techieswithcats.com)
Tuesday, April 01, 2003

For those of you suggesting the fusebox method, have you ever had to debug a site done entirely in it?  I remember it fondly as the Worst Month of my Life.    To me it seems like microsoft and java have completely different ideas about how to do this.  Our current application is basicly a few controler servlets that are always called, and then pick which parameters and JSP file to server up.  It works pretty well, and it lets your pages have inheritence while still having the ease of use of a JSP.  Im fairly new to the java world, but I think its a pretty standard practice.

Vincent Marquez
Wednesday, April 02, 2003

How would the fusebox method work out if you had mutiple developers working on different areas of the site?

For example I use the many page method, and often work with another developer. We then divide up which pages we are going to do. It seems to me that it would be much harder to do this using the fusebox method as we would both be working on the same file.

Matthew Lock
Wednesday, April 02, 2003

Actually, with fusebox you would probably never work on the same file separately.  The fuse has no display code or anything similar in it. 

Basically it's a case statement.

For most of my stuff basically the main fuse parses out whatever parameters (either URL encodes, formsubmits, or session stored info) and based on that calls other files.

All the files are broken out by what they do.  For action foo, the fuse will first call applocal.cfm which contains all the application wide variables and "stuff" and is always called, then it might call qryGetAllFoosFromDB.cfm which is a query (and may be called from other circuits as well), then it might call dspFoo.cfm which is the markup for the page.

That's a really simple example obviously, but you get the point.

So while you might be working on action foo, your partner can be working on action bar.  Also, there is a spec for documenting the code, called FuseDocs, which basically says that you need to put a big block of comments at the beginning of each file to describe the inputs it expects, what it accesses, what it does and what it returns, which should be a really obvious idea, but hardly anybody does it.

Usually, we'll sit down as a group with the spec (such that it is) and write the main fuse first, that gets us all on the same sheet as far as naming goes and also gives us all a good idea of what files are going to be easily reusable (queries tend to see a lot of reuse, as do portions of the presentation code), these we lock down early.  Everything else sorta falls into place after that.

Also, remember that if necessary you can always break things out into subfuses and call those as necessary.

As far as debugging, well it sure beats the interleaved presentation and logic that I find everywhere else, and it tends to encourage more code re-use than the standard "big ole mess o' code" method.

Anyway, look at it, and if it makes sense for what you do try it, if it doesn't then don't.  I'm not religious about it so long as I don't have to maintain your code.

Steve Barbour
Wednesday, April 02, 2003

Okay Brad, I'm just not understanding your point.

You seem to be saying that the web application will be funcationally the same while running regardless of what level the dispatching is done it in the code. And while I'll agree with that point, it doesn't mean that the programmer doesn't have to decide what level to do dispatching in the code.

And while it doesn't matter from a machine language perspective, it certainly matters from a development perspective. Different approaches to the dispatching issue will require different approaches to coding the application. I really don't understand your contention that it simply doesn't matter and isn't worth discussing. It's a design decision that needs to be made and does have an impact on how you develop the web application.

It may not be the most important decision that the developer needs to make, but it still needs to be decided and is worthy of consideration and discussion.

Now, you also seem to be making another point that we don't know enough about the original poster's web application environment and requirements to tell him what the best for his application is. And I'll agree with that. But I think that this discussion has focused more on explaining the different options to the original poster and the general pros and cons.

Bill Tomlinson
Thursday, April 03, 2003

My point was simply that it really isn't that important a decision to discuss it in such general terms. Each teams makes the decision that makes sense for them. There is no one "right" decision.

The post about "fusebox" (which I've never heard of) seems to hit to the heart of the matter. If you intend to do internal dispatching, then your entry point -- "default.asp" or whatever -- is simply just a dispatching service. It doesn't do anything else to deal with the call except hand it off to the entity that does know how to deal with it.

Brad (dotnetguy.techieswithcats.com)
Friday, April 04, 2003

Right, there is no one right solution, it depends on the requirements of your project. But, there are pros and cons for each approach to dispatching and you need to understand those pros and cons so that you can make the decision about what's the right approach for your project.

That's what we're discussing in this topic, the pros and cons of the one page versus many pages approaches. For someone whose very familiar with web applications, it might seem boring to go over old ground. But for someone who doesn't have that experience (like the original poster) this discussion is very useful.

Bill Tomlinson
Thursday, April 10, 2003

*  Recent Topics

*  Fog Creek Home