Squeak
  links to this page:    
View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide
SBlog - Day 2 Web Interface
Last updated at 12:54 pm UTC on 22 January 2009

Web User Interface

On the other side of the fence is the Web UI. Remember that the group decided to use Seaside as their web development toolkit. Seaside is a rich continuations based environment designed for building dynamic web pages. At first, one might think that using such a tool for the challenge is overkill. After all, the expected web interaction seems easy.

However, upon further examination one starts to take the full breadth of the user interaction into account and realizes that a significant part of the server application is concentrated doing mundane tasks such as handling information flow through web based forms. Using a powerful tool such as Seaside speeds such development of such tasks immensely, thus making a great "secret weapon" in the challenge.

Seaside and the user interface

One of the things that sets Seaside apart from most other web application development environments is that it is continuation based. So what does that mean? Avi Bryant and Julian Fitzell gave a talk at Smalltalk Solutions on this very topic. Their abstract states:


Dijkstra may have taught us 45 years ago that GOTO was a bad idea, but web development has barely caught up. In the CGI model of web applications, each link that is followed triggers an entirely new execution of the program. Building complex control flow out of these abrupt transitions can lead to a tangled and brittle mess of interdependent pages. Modern frameworks such as WebObjects and Struts may remove many of the difficulties of CGI scripting, but they do not escape the web's inherent GOTO: moving from one page to the next, whether through anchors, actions, forms, or forwards, is still a simple one-way jump.

Seaside is a framework for developing web-based applications that insulates the developer from the HTTP request/response loop, presenting the illusion of a continuous interactive session with the user. Each page or form acts much like a subroutine, which returns a value to its caller based on user input. Complex, conditional or looping workflows can be described in a single piece of straightforward Smalltalk code as a sequence of calls to individual pages. The benefits this brings to the reusability and maintainability of web applications closely mimick the advances made by structured programming long ago.


For the members of the challenge team (and I'm sure that you've noticed that Avi is a member ;) this means that a lot of the low level book keeping normally associated with writing web services disappears. The programmer is at a much higher level, defining the program flow. An analogy is programming in assembler versus a high level language. There are advantages to each, but in general the better a problem can be abstracted and modeled, the better the solution that is produced will be.

Seaside is a rich user interface and web development tool, and as such is not "simple" as is the case for all such things. One of the keys to the way that Seaside works is something called a session. A unique key identifies the current user session. Unlike most web frameworks (which provide a session object only as a place to keep state and focus mostly on individual request/response cycles), Seaside treats a session very much like a thread or a process. Seaside starts a session running at a well defined application entry point, and the application proceeds linearly from there, pausing to display web pages to the user and wait for input.

The class of the session to be associated with the Squeak Weblog Server is BlogSession. When the application starts, an instance of the session is created. Examining the class, you'll notice that the method BlogSession>>initialize sets up the BlogStore, and creates some sample data. Note that this is an initial implementation, and the data is created for testing purposes.

Instead of named pages or actions, Seaside applications consist of interacting components, objects which model the state and logic of a portion of the UI. When the session starts, a single component instance is created. That component enters a response loop: it displays itself to the user, and then waits for input. The input (a clicked link or a submitted form) will trigger a corresponding method of the component, and when that method is done, the component will display itself again. These triggered methods may simply update the state of the application or of the current component, or they may create and transfer control to another component, which will enter a response loop of its own.

Each component has three responsibilities:
  1. Maintaining its' UI state
  2. Reacting to user input
  3. Displaying itself as HTML
The entry point for the Squeak Weblog Server in this initial implementation is the class BlogLoginTask. This is the entry point that the user enters into the weblog server application.

go
	| author |
	author _ self call: (BlogLogin new).
	self session isolate: [self call: (BlogAuthorFrame new author: author)]

So there it is! Here's where the magic starts. Unlike a traditional web application which is mostly stitched together spaghetti code, Seaside introduces the concept of procedure calls.
Analagous to subroutines, web pages in Seaside can call and return to each other.

Rather than to go into full low level detail of how Seaside works, we'll stick with an explanation of how this application works. The first call to method call: essentially calls a new instance of the class BlogLogin. BlogLogin is a component that authenticates a user when they 'log-in' to the server. How does BlogLogin accomplish this?

As you remember, each component has three responsibilities, one of which is displaying (rendering) HTML code. Look at the instance method:

renderContentOn: html
	html form: [
		html table: [
			html tableRowWithLabel: 'Username:' column: [
				html textInputWithValue: username callback: [:v | username _ v].
			].
			html tableRowWithLabel: 'Password:' column: [
				html passwordInputWithCallback: [:v | password _ v].
			].
			html attributes alignCenter.
			html tableRowWith: [
				html submitButtonWithAction: [self login] text: 'Login'
			] span: 2.
		].
	] 
Then look at the web form in the browser that it generates. You notice several things. First, not explicitly stated, the parameter html is a string; this string will be returned as the code to be rendered within the users web browser. Thus, most of the method calls sent to html append different HTML tags and such to the string. Examining the above method you can see how the code for the page is generated, and how it translates to what the browser is displaying.

Another thing to notice is the use of callbacks. Callbacks in Seaside are Smalltalk blocks (of code) that are associated with specific input actions. In the cases above, the callbacks are associated with a text input box and a password input box on a web form. When called, the callbacks stuff the value of the text boxes into instance variables, username and password.

A control element to notice is in the line:
 html submitButtonWithAction: [self login] text: 'Login'
This code basically says, "When the user inputs a password and hits 'Login', call my method named login. Looking through the code, you'll notice that the login method searches for the given user to authenticate her against a known list of authors. If the author is found, the entire page returns (back to BlogLoginTask) via a call to the method answer:. The page returns with a parameter, which is the authenticated author.

Once the author has been authenticated, BlogLoginTask executes:
self session isolate: [self call: (BlogAuthorFrame new author: author)]
which creates a new component BlogAuthorFrame. BlogAuthorFrame is the main entry point to the blog authoring area. BlogAuthorFrame builds a page which allows the author to log out, create a new weblog, or edit an existing weblog. Selecting an existing weblog takes you to that weblogs editing area which allows the author to add new posts to the weblog, or edit previous posts.

SBlog Challenge Participants Area
sblog top