modperl-modular_site_design

This is part of The Pile, a partial archive of some open source mailing lists and newsgroups.



To: modperl@apache.org
From: "Scott Chapman" <scott_list@mischko.com>
Subject: [Maybe OT] Modular design - calling pages like a
subroutine with a twist.
Date: Thu, 15 Nov 2001 08:42:56 -0800

I'm very interested in making a modular site design but haven't 
found the tools yet to allow this with the twist I'm looking for.

Say I have a page that encapsulates some functionality, such as 
sending a form then validating the contents that are returned. I'd 
call that PageB.

PageB could be more than one page or a page calling itself, etc.

When PageA calls PageB, as soon as PageB finishes presenting 
the form it doesn't stop but drops out the bottom and returns 
immediately to PageA.  There are commands in some of the tools 
(Mason and soon Embperl - maybe others) to force it to stop there 
but this doesn't make for the modularity I have in mind.

PageB then gets submitted by the user and it either calls itself 
(using conditionals to then do the data validation) or another page.  
After things are validated Ok, I'd like to have it return right back to 
PageA, just where it left off using a "Return" statement. Thus, 
PageA could call a "PageB" and have it do all it's processing then 
return, just like calling a regular subroutine.

This would allow for much more modular/object oriented web site 
design. The stateless nature of this beast may preclude this type 
of functionality.  My perl skills are medium at best and C is not in 
my scope.  I'm wondering:

1) is this possible?  I expect that someone would have already 
implemented this if it were possible because it is so much like 
regular modular programming with abstraction layers.

2) are there any tools (preferrably perl) out there that support this 
cleanly.  I've worked with Embperl and glanced through the docs of 
Mason, AxKit and TT and didn't see anything looking like this.

===
To: Scott Chapman <scott_list@mischko.com>
From: Matt Sergeant <matt@sergeant.org>
Subject: Re: [Maybe OT] Modular design - calling pages like
a subroutine with
Date: Thu, 15 Nov 2001 16:45:12 +0000 (GMT)

On Thu, 15 Nov 2001, Scott Chapman wrote:

> 1) is this possible?  I expect that someone would have already
> implemented this if it were possible because it is so much like
> regular modular programming with abstraction layers.

Sure it's possible. Have a look at SmartWorker, it may be close to what
you're after. Or...

> 2) are there any tools (preferrably perl) out there that support this
> cleanly.  I've worked with Embperl and glanced through the docs of
> Mason, AxKit and TT and didn't see anything looking like this.

As far as AxKit goes, look at the CPAN docs for AxKit::XSP::PerForm, which
is how we do this kind of thing.

===

To: <modperl@apache.org>
From: "Kyle Dawkins" <kyle@centralparksoftware.com>
Subject: Re: [Maybe OT] Modular design - calling pages like
a subroutine with a twist.
Date: Thu, 15 Nov 2001 12:12:39 -0500

Scott

There is a system that exists that is very similar to what you describe.
It's called "WebObjects" and was developed by NeXT... it's now offered by
Apple.  The latest release is (unfortunately) Java only but previous
releases (still available) were (Objective) C.  Once you scratch the surface
of WO, your head almost explodes because it's so astonishingly brilliant and
far better than anything else available for rapid (web-based) application
development.  It is also very very firmly built on real OO theory, which
cannot be said for most other web app environments.  You build entirely
self-contained web components that have no dependency on anything and can be
reused in any app anywhere.  Components are (well, by default) stateful.  In
other words, any objects and variables in your component are still there,
living and breathing, when a form is submitted or a link is clicked on.

Unfortunately it's not free. $699.  And deploying it is quite complex...

You could check out smartworker (if you can find it these days...), which
has a vaguely similar philosophy.  It's mod_perl and free. It was originally
developed by me and two others... we got it into a rough shape and then it
was taken over by a team of very talented developers who have managed to do
some great things with it.  Try http://www.smartworker.org to see if there's
anything going on.

===

To: modperl@apache.org
From: Rob Nagler <nagler@bivio.net>
Subject: Re: [Maybe OT] Modular design - calling pages like
a subroutine with a twist.
Date: Thu, 15 Nov 2001 11:16:45 -0700

> When PageA calls PageB, as soon as PageB finishes presenting 
> the form it doesn't stop but drops out the bottom and returns 
> immediately to PageA.

In bOP <http://www.bivio.net/hm/download-bOP> we use "FormContext" to
solve this problem.  PageB requires context and bOP knows how to
return to PageA through the saved context.  We call this "unwinding".
You can nest the stack as deep as you like.  The context is saved in
the URL if PageA isn't a form, or in the called form's hidden fields,
if it is.  The entire form state is saved in the latter case.

PageB and PageA are FormModels in bOP.  If you visit our Pet Shop demo
<http://petshop.bivio.net>, you'll form context this used in the
LoginForm, OrderConfirmationForm, and ShippingAddressForm.  Here's all
the business logic in our ShippingAddressForm:

    sub execute_ok {
	my($self) = @_;
	# copy the current values into the OrderForm context
	$self->put_context_fields(%{$self->internal_get});
	return;
    }

    sub internal_initialize {
	my($self) = @_;
	my($info) = {
	    require_context => 1,
	    version => 1,
	    visible => [
		'Order.ship_to_first_name',
		'Order.ship_to_last_name',
		'EntityAddress_2.addr1',
		'EntityAddress_2.addr2',
		'EntityAddress_2.city',
		'EntityAddress_2.state',
		'EntityAddress_2.zip',
		'EntityAddress_2.country',
		'EntityPhone_2.phone',
	    ],
	};
	return $self->merge_initialize_info(
		$self->SUPER::internal_initialize, $info);
    }

In this case, we get the shipping address from the user, execute_ok is
called which stuffs the forms values into the calling form's context.
The infrastructure automatically unwinds to the OrderForm with the
newly filled in values.

The OrderForm doesn't know about the ShippingAddressForm.
Technically, the ShippingAddressForm doesn't know about the OrderForm.
It only requires the calling form to have fields with the same name.

The relationship between the "pages" (tasks in bOP) is not specified
by the forms.  That's handled by the control logic.  If a task has a
form, it can specify the next and cancel tasks.  This way you can
reuse the business logic quite easily.  Tasks can control the use of
context.  FormModels specify whether they can accept it or not.

===

To: scott_list@mischko.com
From: Joachim Zobel <nc-zobeljo@netcologne.de>
Subject: Re: [Maybe OT] Modular design - calling pages like
a
Date: Thu, 15 Nov 2001 21:08:30 +0100

At 08:42 15.11.01 -0800, you wrote:
>Say I have a page that encapsulates some functionality, such as
>sending a form then validating the contents that are returned. I'd
>call that PageB.
>
>PageB could be more than one page or a page calling itself, etc.
>
>When PageA calls PageB, as soon as PageB finishes presenting
>the form it doesn't stop but drops out the bottom and returns
>immediately to PageA.  There are commands in some of the tools
>(Mason and soon Embperl - maybe others) to force it to stop there
>but this doesn't make for the modularity I have in mind.
>
>PageB then gets submitted by the user and it either calls itself
>(using conditionals to then do the data validation) or another page.
>After things are validated Ok, I'd like to have it return right back to
>PageA, just where it left off using a "Return" statement. Thus,
>PageA could call a "PageB" and have it do all it's processing then
>return, just like calling a regular subroutine.

I'm using what I call the post2redirect pattern 
(http://www.catstep.de/zobel/post2redirect.html): Every POST request 
(normally a request that changes server state) must end up doing a 
redirect. This way I get two kinds of scripts: pages (GETs) and actions 
(POST).

The point is that the action scripts decide which page is to be displayed 
next (eg. same form with error messages or "data written" page)

Well, the aproach has some problems (302 is not allowed by RFC 2616 to 
change from POST to GET but works, 303 is not implemented by browsers yet) 
but it gives a good design with a very simple principle.

===

To: scott_list@mischko.com
From: Joshua Chamas <joshua@chamas.com>
Subject: Re: [Maybe OT] Modular design - calling pages like
a subroutine with a 
Date: Thu, 15 Nov 2001 11:57:51 -0800

Scott Chapman wrote:
> 
> I'm very interested in making a modular site design but haven't
> found the tools yet to allow this with the twist I'm looking for.
> 

I'll try to show how Apache::ASP could help here.  In Apache::ASP,
scripts can be executed as subroutines, even with return values,
and I think this goes to the heart of what you need here.

I would probably break abstract headers & footers out of 
each page, to be called automatically in global.asa.  This allows
all pages to not need to know about HTML headers & footers being sent:

# global.asa
sub Script_OnStart { $Response->Include('header.inc'); }
sub Script_OnEnd   { $Response->Include('footer.inc'); }

> Say I have a page that encapsulates some functionality, such as
> sending a form then validating the contents that are returned. I'd
> call that PageB.
> 
> PageB could be more than one page or a page calling itself, etc.
> 

Right ... PageB is just form logic/rendering, headers & footers
are called automatically via events in global.asa.

> When PageA calls PageB, as soon as PageB finishes presenting
> the form it doesn't stop but drops out the bottom and returns
> immediately to PageA.  There are commands in some of the tools
> (Mason and soon Embperl - maybe others) to force it to stop there
> but this doesn't make for the modularity I have in mind.
> 
#PageA
<% my @rv = $Response->Include('PageB', @args); %>
<!-- Rest of PageA -->

$Response->Include() just calls another page as a perl subroutine
is called with @args passed in as @_ in the script, and @rv returned
if return(@rv) is used in the script too.

> PageB then gets submitted by the user and it either calls itself
> (using conditionals to then do the data validation) or another page.
> After things are validated Ok, I'd like to have it return right back to
> PageA, just where it left off using a "Return" statement. Thus,
> PageA could call a "PageB" and have it do all it's processing then
> return, just like calling a regular subroutine.
> 

PageA can execute PageB, and PageB can execute PageA, but this
could cause a loop, so I am not sure what you really want here,
but hope the above showed how one might achieve this.

> 2) are there any tools (preferrably perl) out there that support this
> cleanly.  I've worked with Embperl and glanced through the docs of
> Mason, AxKit and TT and didn't see anything looking like this.
> 

The $Response->Include() mechanism is very powerful, turning pages
into subroutines, and always returns to the original caller.  
To transfer control to another page without returning, 
use $Server->Transfer().  This differs from $Response->Redirect()
in that all the globals like $Session/$Application/$Request remain
the same.  If the ASP syntax is too ugly for you, you could turn 
this into an XMLSub used like:

  <page:include file="PageB" arg1="..." arg2="..." />

where you would define:

# global.asa or page.pm or any perl module that gets loaded
sub page::include {
  my($args) = @_;
  $Response->Include($args->{'file'}, $args);
}

===

To: "Joshua Chamas" <joshua@chamas.com>,
<scott_list@mischko.com>
From: "Perrin Harkins" <perrin@elem.com>
Subject: Re: [Maybe OT] Modular design - calling pages like
a subroutine with a  twist.
Date: Thu, 15 Nov 2001 15:33:42 -0500

> I'll try to show how Apache::ASP could help here.  In Apache::ASP,
> scripts can be executed as subroutines, even with return values,
> and I think this goes to the heart of what you need here.

The original e-mail was confusing, but I think what he's after is not so
much the ability to call pages as subs but rather the ability to abstract
away the fact that a sub might actually involve multiple user interactions
(present a form, get a response, present another form, etc.) with breaks in
actual execution.  In other words, he wants to think of program execution in
terms of a linear user session (as you would with a GUI app) rather than a
series of separate requests.

In my opinion, trying to abstract that stuff away in a web application
causes to more problems than it solves, especially where back buttons and
bookmarks are concerned.  I think it's easier to take a state machine
approach, the way CGI::MxScreen or Apache::PageKit do.  (CGI::Application
sort of does, but it doesn't capture the relationships of states to each
other.)  With Apache::ASP, I think people would generally embed the state
transition logic in the pages, although this could probably be separated out
if you were careful about it.

====

To: "Joshua Chamas" <joshua@chamas.com>, "Perrin Harkins"
<perrin@elem.com>
From: "Scott Chapman" <scott_list@mischko.com>
Subject: Re: [Maybe OT] Modular design - calling pages like
a subroutine with a  twist.
Date: Thu, 15 Nov 2001 13:06:20 -0800

On 15 Nov 2001, at 15:33, Perrin Harkins wrote:

> The original e-mail was confusing, but I think what he's after is not so
> much the ability to call pages as subs but rather the ability to abstract
> away the fact that a sub might actually involve multiple user interactions
> (present a form, get a response, present another form, etc.) with breaks in
> actual execution.  In other words, he wants to think of program execution in
> terms of a linear user session (as you would with a GUI app) rather than a
> series of separate requests.

I'm sorry the original email was confusing. You've stated it exactly 
right.  I want an abstraction layer here so that web pages work like 
calling a subroutine in a regular programming language works.
 
> In my opinion, trying to abstract that stuff away in a web application
> causes to more problems than it solves, especially where back buttons and
> bookmarks are concerned.  I think it's easier to take a state machine
> approach, the way CGI::MxScreen or Apache::PageKit do.  (CGI::Application
> sort of does, but it doesn't capture the relationships of states to each
> other.)  With Apache::ASP, I think people would generally embed the state
> transition logic in the pages, although this could probably be separated out
> if you were careful about it.

Back buttons and bookmarks already cause plenty of problems, 
not really having to do with this abstraction layer idea.  The people 
who do the work with an abstraction layer will have to keep 
bookmarks and back buttons in mind just like you have to today.  It 
would be worth it to have the abstraction layer in my opinion.  I'd 
love to be able to deal with these problems!

====

To: modperl@apache.org
From: Rob Nagler <nagler@bivio.net>
Subject: Re: [Maybe OT] Modular design - calling pages like
a subroutine with a  twist.
Date: Thu, 15 Nov 2001 14:42:57 -0700

> In my opinion, trying to abstract that stuff away in a web application
> causes to more problems than it solves, especially where back buttons and
> bookmarks are concerned.

We haven't found this to be the case.  Our servers are sessionless,
so bookmarks work fine.   Back buttons aren't any more or less of a
problem.  I actually haven't heard of any problems with our sub-forms
and back buttons.  People do bookmark URLs with form context, but
that's a good thing.  It usually is the login page and they login and
it automatically restores the page which they thought they
bookmarked (which redirected to login in the first place).

> I think it's easier to take a state machine
> approach, the way CGI::MxScreen or Apache::PageKit do.

I don't think this works.  The state machine can manage states going
forward, but not backward.  Consider the problem of a Symbol Lookup on
our site (www.bivio.com).  We come into it from just about any
accounting page having to do with a stock transaction.  It's a single
task, which looks up the ticker and fills it in in the Calling form.
You need to stack the state or you have to introduce N new states
(for entry from forms A, B, C, D, ...).

It did take about two years to come up with a decent implementation of
FormContext.  It's a non-trivial problem, but it can be generalized
and it solves the problem we had.

===

To: "Rob Nagler" <nagler@bivio.net>
From: "Perrin Harkins" <perrin@elem.com>
Subject: Re: [Maybe OT] Modular design - calling pages like
a subroutine with a  twist.
Date: Thu, 15 Nov 2001 17:47:48 -0500

> > In my opinion, trying to abstract that stuff away in a web application
> > causes to more problems than it solves, especially where back buttons
and
> > bookmarks are concerned.
>
> We haven't found this to be the case.  Our servers are sessionless,
> so bookmarks work fine.

These are different (though related) concepts.  The original poster was
looking for a way to structure web programs without thinking about the
breaks caused by the request model of HTTP, and that's what I was commenting
on.  You're talking about a way to preserve data across multiple page
requests.

> > I think it's easier to take a state machine
> > approach, the way CGI::MxScreen or Apache::PageKit do.
>
> I don't think this works.  The state machine can manage states going
> forward, but not backward.

You can code a state machine that defines legal transitions from one state
to another, and that could include stepping "backward".  There's no real
concept of forward and backward in what I had in mind, just a collection of
states and legal transitions between them.

If you hit the back button, you're still okay as long as the form's data is
stored in the URL or hidden fields rather than in a global session, i.e.
going back will return you to the state you were in correctly.

Most people instinctively code a state machine when they start using CGI,
but they do it in the form of a bunch of statements like "if $form_action eq
'save'".  The frameworks I mentioned just pull it out and make it more
explicit.

If I understand your FormContext approach correctly, you are storing the
state of the current application in URLs or hidden fields.  This is what we
used at eToys as well, and I think it's a pretty common solution.  It's the
only way to safely handle possibilities like multiple browser windows using
the same application.  There are some CPAN modules that help with this kind
of thing, like CGI::EncryptForm.

===


the rest of The Pile (a partial mailing list archive)

doom@kzsu.stanford.edu