<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:iweb="http://www.apple.com/iweb" version="2.0">
  <channel>
    <title>In the Trenches</title>
    <link>http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/In_the_Trenches.html</link>
    <description>Some notes about object-oriented programming, software development and teaching these topics. A view from the trenches.&lt;br/&gt;&lt;br/&gt;    Roger Whitney</description>
    <generator>iWeb 2.0.4</generator>
    <image>
      <url>http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/In_the_Trenches_files/iStock_000000251197Small.jpg</url>
      <title>In the Trenches</title>
      <link>http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/In_the_Trenches.html</link>
    </image>
    <item>
      <title>Dialogs in Seaside</title>
      <link>http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2007/7/9_Dialogs_in_Seaside.html</link>
      <guid isPermaLink="false">43326904-9290-4d4a-b158-57adc56d529f</guid>
      <pubDate>Mon, 9 Jul 2007 16:25:53 -0700</pubDate>
      <description>&lt;a href=&quot;http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2007/7/9_Dialogs_in_Seaside_files/iStock_000001389194Small.jpg&quot;&gt;&lt;img src=&quot;http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Media/iStock_000001389194Small_1.jpg&quot; style=&quot;float:left; padding-right:10px; padding-bottom:10px; width:206px; height:137px;&quot;/&gt;&lt;/a&gt;A common task in web applications is asking users for information. At some point one needs to obtain data like a users name, address, phone number, credit card number, password, etc. Typically one does the following:&lt;br/&gt;Display some overall explanatory text&lt;br/&gt;Display a text field or other appropriate input widget for each datum&lt;br/&gt;Display a label for each datum&lt;br/&gt;Display some explanatory text, perhaps on request, for each datum&lt;br/&gt;Validate each datum&lt;br/&gt;Save the data in a database&lt;br/&gt;The request for the data may be spread across multiple pages for a number of reasons. At this is a common task a web framework should make this easy. We will look at several ways this can be done in Seaside. The database access is not discussed here. That is a subject for a later post.&lt;br/&gt;The examples are done using VisualWorks Smalltalk 7.5, Seaside 2.61.140 and Magritte lr.193. This version of Seaside still used both original renderer, WAHtmlRenderer and the newer WARenderCanvas. As the later will be the only render in Seaside 2.8, it is used here.&lt;br/&gt;For our examples we will restrict the requested information to:&lt;br/&gt;Name&lt;br/&gt;Phone number&lt;br/&gt;We will start with the following &quot;model&quot; class for this information.&lt;br/&gt;Smalltalk.Seaside defineClass: #Contact&lt;br/&gt;	superclass: #{Core.Object}&lt;br/&gt;	instanceVariableNames: 'name phoneNumber '&lt;br/&gt;&lt;br/&gt;name&lt;br/&gt;	^name&lt;br/&gt;&lt;br/&gt;name: anObject&lt;br/&gt;	name := anObject&lt;br/&gt;&lt;br/&gt;phoneNumber&lt;br/&gt;	^phoneNumber&lt;br/&gt;&lt;br/&gt;phoneNumber: anObject&lt;br/&gt;	phoneNumber := anObject &lt;br/&gt;&lt;br/&gt;hasValidName&lt;br/&gt;	^name notNil&lt;br/&gt;&lt;br/&gt;hasValidPhoneNumber&lt;br/&gt;	phoneNumber ifNil:[^false].&lt;br/&gt;	^phoneNumber size &gt; 6&lt;br/&gt;&lt;br/&gt;By Hand&lt;br/&gt;We will start by creating a single component to perform the task. As you can see below the code is not too bad. The good news is that we have complete control over all aspects of the application - how to display the request, validation, how to display the errors, etc. The bad news is that there is a lot of logic that is repeated each time we do this. Note in particular the logic needed to detect and handle errors. &lt;br/&gt;The class methods handle different aspects of registering the component as a web application, hence are not directly related to the issues at hand. &lt;br/&gt;&lt;br/&gt;Smalltalk.Seaside defineClass: #FormExample&lt;br/&gt;	superclass: #{Seaside.WAComponent}&lt;br/&gt;	instanceVariableNames: 'contact errors '&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;Class Methods&lt;br/&gt;canBeRoot&lt;br/&gt;	&quot;Allow the component to be standalone application&quot;&lt;br/&gt;	^ true &lt;br/&gt;&lt;br/&gt;initialize&lt;br/&gt;	&quot;Register application url&quot;&lt;br/&gt;	(self registerAsApplication: 'whitneyExamples/form') &lt;br/&gt;&lt;br/&gt;description&lt;br/&gt;	&quot;Application description&quot;&lt;br/&gt;	^'Doing it the hard way' &lt;br/&gt;&lt;br/&gt;Instance Methods&lt;br/&gt;renderContentOn: html &lt;br/&gt;	html heading: 'Enter your information'.&lt;br/&gt;	self hasErrors &lt;br/&gt;		ifTrue: &lt;br/&gt;			[html text: ['Please correct the following errors'].&lt;br/&gt;			html unorderedList addAll: errors].&lt;br/&gt;	html form: &lt;br/&gt;			[html text: 'Name'.&lt;br/&gt;			(html textInput)&lt;br/&gt;				on: #name of: contact;&lt;br/&gt;				exampleText: 'John Doe'.&lt;br/&gt;			html break.&lt;br/&gt;			html text: 'Phone'.&lt;br/&gt;			html textInput on: #phoneNumber of: contact.&lt;br/&gt;			html break.&lt;br/&gt;			html submitButton callback: [self ok]]&lt;br/&gt;&lt;br/&gt;rendererClass&lt;br/&gt;	&quot;Use new rendering engine&quot;&lt;br/&gt;	^WARenderCanvas &lt;br/&gt;&lt;br/&gt;hasErrors&lt;br/&gt;	^errors size &gt; 0&lt;br/&gt;&lt;br/&gt;ok&lt;br/&gt;	&quot;Action on submitting data&quot;&lt;br/&gt;	self validate.&lt;br/&gt;	self hasErrors ifTrue:[^self].&lt;br/&gt;	self answer: contact&lt;br/&gt;&lt;br/&gt;updateRoot: anHtmlRoot&lt;br/&gt;	super updateRoot: anHtmlRoot.&lt;br/&gt;	anHtmlRoot title: 'Form Decorator Example'.&lt;br/&gt;&lt;br/&gt;validate&lt;br/&gt;	errors := OrderedCollection new.&lt;br/&gt;	contact hasValidName ifFalse:&lt;br/&gt;		[errors add: 'You must enter a valid name'].&lt;br/&gt;	contact hasValidPhoneNumber ifFalse:&lt;br/&gt;		[errors add:  'Enter a valid phone number']. &lt;br/&gt;&lt;br/&gt;initialize&lt;br/&gt;	contact := Contact new. &lt;br/&gt;&lt;br/&gt;Using Decorators&lt;br/&gt;Seaside supports the decorator pattern on components. We will use the following standard decorators:  WAMessageDecoration, WAValidationDecoration and WAFormDecoration. The complete code for the example is below.&lt;br/&gt;First we will look at setting up the decorator chain. The order of the decorators in given in the following diagram.&lt;br/&gt;&lt;br/&gt;In the FormDecoratorExample&gt;&gt;initialize method the decorator chain is created with the code:&lt;br/&gt;form := WAFormDecoration new buttons: self buttons.&lt;br/&gt;self addDecoration: form.&lt;br/&gt;self validateWith: [:aContactOrSelf | aContactOrSelf validate].&lt;br/&gt;self addMessage: 'Please enter the following information'.&lt;br/&gt;&lt;br/&gt;The addDecoration: method in WAComponent add decorators to the front of the decorator chain of a component. The methods validateWith: and addMessage: are helper methods that create the decorators for us. &lt;br/&gt;A WAMessageDecoration object just displays the message (string actually) that it is given. The WAMessageDecoration is place first on the chain so that any error messages occur after the message. If you want the error messages to appear above the message then place the WAMessageDecoration object after the WAValidationDecoration object.&lt;br/&gt;When creating a WAValidationDecoration object you give it a block, which it runs to validate your component. This validation is done when your component &quot;exits&quot; using answer or answer:. When the exit is done via answer: the argument of answer:  is passed as the argument to the validation block. When the exit is done via answer the sender of the method answer is the argument of the validation block. If the validation code detects a problem it raises the WAValidationNotification error to indicate a problem. Typically this is done by calling the Object&gt;&gt;validationError: method. The argument of the method is the error message that is to be displayed to the user. Below is the validation code in the Contact class.&lt;br/&gt;Contact&gt;&gt;validate&lt;br/&gt;	self hasValidName &lt;br/&gt;		ifFalse:&lt;br/&gt;            [self validationError: 'You must provide a valid name'].&lt;br/&gt;	self hasValidPhoneNumber &lt;br/&gt;		ifFalse:&lt;br/&gt;            [self validationError: 'You must provide a valid phone &lt;br/&gt;                number'].&lt;br/&gt;&lt;br/&gt;Since one can only pass a string as an argument of Object&gt;&gt;validationError: it is hard to provide multiple error messages that can be displayed reasonable. The validation code above only indicated one error at a time, which is a poor way to treat a user. Below is a screen shot after the user click on the Ok button without entering either a name or a phone number. The layout is the default produced by the decorators. Use CSS to provide a better view. The message is marked with &amp;lt;h3&gt; tag. The error message is in a &amp;lt;div class=&quot;validation-error&quot;&gt; tag. Seaside makes it easy to view the source of a page, so you can determine what tags you need CSS for to improve the layout &amp;amp; look of the page.&lt;br/&gt;&lt;br/&gt;The WAFormDecoration object requires a list of buttons (as a collection of strings or symbols) for the form. The text displayed in each button is generated from the text in the list of the buttons. The first letter of the string is capitalized. A space is added before any capital letters inside the string. So &quot;cancel&quot; is displayed as &quot;Cancel&quot; and &quot;goHome&quot; is displayed as &quot;Go Home&quot;. The buttons above were generated from #(ok cancel). The unmodified text for the button also is the callback message sent to the component. So in our example the FormDecoratorExample class needs to implement the methods ok and cancel. FormDecoratorExample also needs to implement the method defaultButton which is to return the string for the button the form is to treat as default button. The form decorator sends this message to the next item in the decorator chain. This message is not part of the standard decorrator protocol and is not passes on the chain in the version of Seaside used for these examples. As a result no decorators can be between the form decorator and your component.&lt;br/&gt;Smalltalk.Seaside defineClass: #FormDecoratorExample&lt;br/&gt;	superclass: #{Seaside.WAComponent}&lt;br/&gt;	instanceVariableNames: 'contact '&lt;br/&gt;&lt;br/&gt;Class Methods&lt;br/&gt;initialize&lt;br/&gt;	(self registerAsApplication: 'whitneyExamples/formDecorator') &lt;br/&gt;&lt;br/&gt;description&lt;br/&gt;	^'Using a form decorator' &lt;br/&gt;&lt;br/&gt;canBeRoot&lt;br/&gt;	^ true &lt;br/&gt;&lt;br/&gt;Instance Methods&lt;br/&gt;initialize&lt;br/&gt;	| form |&lt;br/&gt;	super initialize.&lt;br/&gt;	contact := Contact new.&lt;br/&gt;	&quot;Add decorators&quot;&lt;br/&gt;	form := WAFormDecoration new buttons: self buttons.&lt;br/&gt;	self addDecoration: form.&lt;br/&gt;	self validateWith: &lt;br/&gt;        [:aContactOrSelf | aContactOrSelf validate].&lt;br/&gt;	self addMessage: 'Please enter the following information'.&lt;br/&gt;&lt;br/&gt;renderContentOn: html &lt;br/&gt;	&quot;Display labels and input fields&quot;&lt;br/&gt;	html text: 'Name'.&lt;br/&gt;	(html textInput)&lt;br/&gt;		on: #name of: contact;&lt;br/&gt;		exampleText: 'John Doe'.&lt;br/&gt;	html break.&lt;br/&gt;	html text: 'Phone'.&lt;br/&gt;	html textInput on: #phoneNumber of: contact&lt;br/&gt;&lt;br/&gt;rendererClass&lt;br/&gt;	^WARenderCanvas &lt;br/&gt;&lt;br/&gt;buttons&lt;br/&gt;	^#(ok cancel)&lt;br/&gt;&lt;br/&gt;cancel&lt;br/&gt;	&quot;User clicked on the Cancel button&quot;&lt;br/&gt;	self answer&lt;br/&gt;&lt;br/&gt;defaultButton&lt;br/&gt;	^self buttons first&lt;br/&gt;&lt;br/&gt;ok&lt;br/&gt;	&quot;user clicked on the Ok button&quot;&lt;br/&gt;	self answer: contact&lt;br/&gt;&lt;br/&gt;validate&lt;br/&gt;	&quot;Only called when cancel (self answer) is call, so nothing to &lt;br/&gt;        validate&quot;&lt;br/&gt;	^true&lt;br/&gt;&lt;br/&gt;updateRoot: anHtmlRoot&lt;br/&gt;	super updateRoot: anHtmlRoot.&lt;br/&gt;	anHtmlRoot title: 'Form Decorator Example'.   &lt;br/&gt;&lt;br/&gt;Labeled Dialog&lt;br/&gt;The decorator solution is better than the first solution in that some of the logic common to dialogs can be reused and some of the low level details are done for us. The decorator solution still requires one to layout the input widgets and their labels, which can be automated. In Seaside the WALabelledFormDialog component does just that.&lt;br/&gt;WALabelledFormDialog is an abstract class. To use it one must create a subclass. Your subclass needs to implement the methods labelForSelector:, model and rows. If you want to change the default set of buttons used on the form you need to override the buttons method in your class. For each submit button on the form you need to implement a callback method. &lt;br/&gt;WALabelledFormDialog uses the same decorator structure as we used in the decorator example FormDecoratorExample. &lt;br/&gt;&lt;br/&gt;Since WALabelledFormDialog already adds a WAFormDecoration we do not need to add it to the decorator chain. Here is the initialize method for the LabelledFormDialogExample (full source code for the example is below). &lt;br/&gt;LabelledFormDialogExample&gt;&gt;initialize&lt;br/&gt;	super initialize.&lt;br/&gt;	contact := Contact new.&lt;br/&gt;	self validateWith: [:aContact | aContact validate].&lt;br/&gt;	self addMessage: 'Please enter the following information'.&lt;br/&gt;&lt;br/&gt;As mentioned above we need to implement the methods labelForSelector:, model and rows in our subclass of WALabelledFormDialog. The model method just returns the object whose fields we wish to populate with date. The rows method returns a collections of symbols. One symbol for each row of data in the dialog. The symbol is used generate the accessor methods for the data in the model. The method labelForSelector: returns the labels for each row and each submit button in the form. See the source code for the example below.&lt;br/&gt;The contact example generates the following page:&lt;br/&gt;&lt;br/&gt;The default input widget is the html input tag. To override the default implement the method renderXOn:, where x is the symbol for the row, in your subclass of WALabelledFormDialog. To use a different input widget for &quot;name&quot; in our example we would use:&lt;br/&gt;LabelledFormDialogExample&gt;&gt;renderNameOn: html&lt;br/&gt;	html&lt;br/&gt;		selectFromList: #( 'Roger' 'Pete')&lt;br/&gt;		selected: 'Roger'&lt;br/&gt;		callback: [:v | contact name: v]&lt;br/&gt;&lt;br/&gt;The resulting page is below. Since I am using Seaside 2.6 the renderer passed to this method is WAHtmlRenderer. In Seaside 2.8 that renderer is completely replaced by WARenderCanvas. Since in Seaside 2.6 WALabelledFormDialog uses WAHtmlRenderer you cannot use WARenderCanvas in your subclass.&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;Here is the complete Contact example using WALabelledFormDialog.&lt;br/&gt;Smalltalk.Seaside defineClass: #LabelledFormDialogExample&lt;br/&gt;	superclass: #{Seaside.WALabelledFormDialog}&lt;br/&gt;	instanceVariableNames: 'contact '&lt;br/&gt;	Class Methods&lt;br/&gt;&lt;br/&gt;canBeRoot&lt;br/&gt;	^ true &lt;br/&gt;&lt;br/&gt;initialize&lt;br/&gt;	(self registerAsApplication: 'whitneyExamples/formDialog') &lt;br/&gt;&lt;br/&gt;description&lt;br/&gt;	^'Using a form Dialog' &lt;br/&gt;&lt;br/&gt;Instance Methods&lt;br/&gt;initialize&lt;br/&gt;	super initialize.&lt;br/&gt;	contact := Contact new.&lt;br/&gt;	self validateWith: [:aContact | aContact validate].&lt;br/&gt;	self addMessage: 'Please enter the following information'. &lt;br/&gt;&lt;br/&gt;model&lt;br/&gt;	^ contact&lt;br/&gt;&lt;br/&gt;rows&lt;br/&gt;	^ #(name phoneNumber) &lt;br/&gt;&lt;br/&gt;ok&lt;br/&gt;	self answer: contact &lt;br/&gt;&lt;br/&gt;labelForSelector: aSymbol&lt;br/&gt;	aSymbol == #name ifTrue: [^'Your Name'].&lt;br/&gt;	aSymbol == #phoneNumber ifTrue: [^'Phone Number'].&lt;br/&gt;	aSymbol == #ok ifTrue: [^'Ok'].&lt;br/&gt;	^ super labelForSelector: aSymbol&lt;br/&gt;&lt;br/&gt;updateRoot: anHtmlRoot&lt;br/&gt;	super updateRoot: anHtmlRoot.&lt;br/&gt;	anHtmlRoot title: 'Form Dialog Example'. &lt;br/&gt;&lt;br/&gt;Edit Dialog&lt;br/&gt;WAEditDialog is useful in editing new or existing model objects. The main thing it adds to WALabelledFormDialog is the automatic rollback of the model if the user cancels the operation. WAEditDialog is an abstract subclass of WALabelledFormDialog. Your subclass needs to implement the methods labelForSelector: and rows. The method labelForSelector: does not have to handle the form buttons. Your model class has to implement the method copyFrom: as it is used to rollback changes when the user cancels the edit. Here is the method for our Contact class.&lt;br/&gt;Contact&gt;&gt;copyFrom: aContact&lt;br/&gt;	name := aContact name.&lt;br/&gt;	phoneNumber := aContact phoneNumber &lt;br/&gt;&lt;br/&gt;Since it is used to edit existing model objects WAEditDialog operates slightly differently than WALabelledFormDialog. When a WAEditDialog object returns from a call it returns a boolean not the model. Here is sample code using a WAEditDialog subclass.&lt;br/&gt;contact := Contact new.&lt;br/&gt;editor := EditFormExample model: contact.&lt;br/&gt;wasChanged := self call: editor.&lt;br/&gt;&lt;br/&gt;Note in the source for EditFormExample how the validate block has changed from previous examples. Don't get too fond of WAEditDialog as it was dropped in Seaside 2.8.&lt;br/&gt;Smalltalk.Seaside defineClass: #EditFormExample&lt;br/&gt;	superclass: #{Seaside.WAEditDialog}&lt;br/&gt;	instanceVariableNames: ''&lt;br/&gt;&lt;br/&gt;Instance Methods&lt;br/&gt;initialize&lt;br/&gt;	super initialize.&lt;br/&gt;	self validateWith: &lt;br/&gt;        [:saved | saved  ifTrue:[self model validate]].&lt;br/&gt;	self addMessage: 'Please enter the following information'. &lt;br/&gt;&lt;br/&gt;labelForSelector: aSymbol&lt;br/&gt;	aSymbol == #name ifTrue: [^'Your Name'].&lt;br/&gt;	aSymbol == #phoneNumber ifTrue: [^'Phone Number'].&lt;br/&gt;	^ super labelForSelector: aSymbol&lt;br/&gt;&lt;br/&gt;rows&lt;br/&gt;	^ #(name phoneNumber) &lt;br/&gt;&lt;br/&gt;updateRoot: anHtmlRoot&lt;br/&gt;	super updateRoot: anHtmlRoot.&lt;br/&gt;	anHtmlRoot title: 'Edit Dialog Example'. &lt;br/&gt;&lt;br/&gt;Magritte&lt;br/&gt;Magritte, developed by Lukas Renggli, provides a different approach to these types of dialogs. In Magritte one provides meta-data about the model. This meta-data is used to generate the dialogs. For each instance variable of interest you create a class method called descriptionX, where X is some meaningful text. The description contains information about the type and restrictions of the described instance variable and its display location. &lt;br/&gt;Given the Contact class below we generate a dialog page using:&lt;br/&gt;	contact := Contact new asComponent.&lt;br/&gt;	contact addValidatedForm.&lt;br/&gt;	self call: contact.&lt;br/&gt;&lt;br/&gt;which generates the page:&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;If one clicks on the Save button without entering any text one gets the following page.&lt;br/&gt;&lt;br/&gt;Magritte is an interesting system. There are a number of things that need to be covered about Magritte, but that will have to wait for another posting.&lt;br/&gt;Smalltalk.Seaside defineClass: #Contact&lt;br/&gt;	superclass: #{Core.Object}&lt;br/&gt;	instanceVariableNames: 'name phoneNumber '&lt;br/&gt;	classInstanceVariableNames: ''&lt;br/&gt;	imports: '&lt;br/&gt;			Magritte.*&lt;br/&gt;			'&lt;br/&gt;	category: 'SeasideExamples'&lt;br/&gt;&lt;br/&gt;Class Methods&lt;br/&gt;&lt;br/&gt;descriptionName&lt;br/&gt;	^(MAStringDescription auto: 'name' label: 'Name' priority: 30)&lt;br/&gt;		beRequired;&lt;br/&gt;		yourself.&lt;br/&gt;&lt;br/&gt;descriptionNumber&lt;br/&gt;	| description |&lt;br/&gt;	description := MAStringDescription &lt;br/&gt;				auto: 'phoneNumber'&lt;br/&gt;				label: 'Phone number'&lt;br/&gt;				priority: 40.&lt;br/&gt;	^description&lt;br/&gt;		beRequired;&lt;br/&gt;		addCondition: &lt;br/&gt;			[:value | value size &gt; 6] &lt;br/&gt;          labelled: 'invalid phone number';&lt;br/&gt;		yourself&lt;br/&gt;&lt;br/&gt;Instance Methods&lt;br/&gt;name&lt;br/&gt;	^name&lt;br/&gt;&lt;br/&gt;name: anObject&lt;br/&gt;	name := anObject &lt;br/&gt;&lt;br/&gt;phoneNumber&lt;br/&gt;	^ phoneNumber&lt;br/&gt;&lt;br/&gt;phoneNumber: anObject&lt;br/&gt;	phoneNumber := anObject &lt;br/&gt;&lt;br/&gt;Special Purpose Dialogs&lt;br/&gt;Seaside comes with some special purpose dialogs. Below I give a code snippet showing the use and the small screenshot of the result. Two of the dialogs (WAInputDialog and WAYesOrNoDialog) can be used via connivence methods, which I use. &lt;br/&gt;WAChoiceDialog&lt;br/&gt;selection := WAChoiceDialog options: &lt;br/&gt;    #('Smalltalk' 'Perl' 'Python' 'Ruby').&lt;br/&gt;result := self call: selection.&lt;br/&gt;&lt;br/&gt;WASelection&lt;br/&gt;selection := WASelection new.&lt;br/&gt;selection items: #(1 'cat' 'rat').&lt;br/&gt;selectedItem := self call: selection.&lt;br/&gt;&lt;br/&gt;WAYesOrNoDialog&lt;br/&gt;aBoolean := self confirm: 'Time to sleep?'.&lt;br/&gt;&lt;br/&gt;WAInputDialog&lt;br/&gt;aString := self &lt;br/&gt;				request: 'Do you like Seaside?'&lt;br/&gt;				label: 'Ok'&lt;br/&gt;				default: 'Suggested answer'.&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;If you are using Seaside 2.6 you may notice that some dialogs are missing. For Seaside 2.8 dialog classes that were not being used were removed to clean up the Seaside core. The dialogs that were removed are:&lt;br/&gt;WAChangePassword&lt;br/&gt;WAEditDialog&lt;br/&gt;WAEmailConfirmation&lt;br/&gt;WAGridDialog&lt;br/&gt;WALoginDialog&lt;br/&gt;WANoteDialog</description>
      <enclosure url="http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2007/7/9_Dialogs_in_Seaside_files/iStock_000001389194Small.jpg" length="122959" type="image/jpeg"/>
    </item>
    <item>
      <title>Static Abuse</title>
      <link>http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2007/5/21_Static_Abuse.html</link>
      <guid isPermaLink="false">0ff4293f-da7b-440d-8521-3671efb73be1</guid>
      <pubDate>Mon, 21 May 2007 21:51:38 -0700</pubDate>
      <description>&lt;a href=&quot;http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2007/5/21_Static_Abuse_files/iStock_000000939096XSmall.jpg&quot;&gt;&lt;img src=&quot;http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Media/iStock_000000939096XSmall_1.jpg&quot; style=&quot;float:left; padding-right:10px; padding-bottom:10px; width:182px; height:273px;&quot;/&gt;&lt;/a&gt;I just finished an end-of-the semester marathon session of grading programs. I noticed a number of students that misuse static method and static fields. To help illustrate I will use a Stack class.&lt;br/&gt;&lt;br/&gt;class Stack {&lt;br/&gt;    private ArrayList elements = new ArrayList();&lt;br/&gt;&lt;br/&gt;    public void push(Object element) {&lt;br/&gt;        elements.add(element);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public Object pop() {&lt;br/&gt;        return elements.remove(elements.size() -1);&lt;br/&gt;    }&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;On rare occasions I will come across a student that tests the code using main. They write:&lt;br/&gt;&lt;br/&gt;class Stack {&lt;br/&gt;    private ArrayList elements = new ArrayList();&lt;br/&gt;&lt;br/&gt;    public void push(Object element) {&lt;br/&gt;        elements.add(element);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public Object pop() {&lt;br/&gt;        return elements.remove(elements.size() -1);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public static void main(String[] args) {&lt;br/&gt;        push(&quot;cat&quot;);&lt;br/&gt;        System.out.println(pop()):&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;Of course the compiler complains about and they then &quot;fix&quot; the problem by making everything static:&lt;br/&gt;&lt;br/&gt;class Stack {&lt;br/&gt;    private static ArrayList elements = new ArrayList();&lt;br/&gt;&lt;br/&gt;    public static void push(Object element) {&lt;br/&gt;        elements.add(element);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public static Object pop() {&lt;br/&gt;        return elements.remove(elements.size() -1);&lt;br/&gt;    }&lt;br/&gt;&lt;br/&gt;    public static void main(String[] args) {&lt;br/&gt;        push(&quot;cat&quot;);&lt;br/&gt;        System.out.println(pop()):&lt;br/&gt;}&lt;br/&gt;&lt;br/&gt;Hopefully you are shaking your head at this and wondering what the student was thinking. &lt;br/&gt;&lt;br/&gt;More commonly students make all fields and methods static because they:&lt;br/&gt;&lt;br/&gt;Think they only need one instance of the class&lt;br/&gt;Want a easy way to provide global access to that instance&lt;br/&gt;&lt;br/&gt;The students assumptions are frequently wrong. The test cases they use only need one instance at a time of the class but there are times when the program will need multiple instance of the class. The use of the static fields introduces errors into their code, which they are not aware of. If they are lucky I will catch the error and they will lose points on their assignment. They are often wrong about the need for a global access to the one instance of the class. Sometimes here is a way to provide the needed access in the program and they are just being lazy. Other times there are design problems in their code, which they get around using static methods. &lt;br/&gt;&lt;br/&gt;So students when you start to use static method stop and think about what you are doing. Do you really need the global access? If so investigate the singleton pattern. Are you just trying to find a home for a bunch of functions? If so look at your classes and ask yourself why you don't have a class where the functions belong as methods. </description>
      <enclosure url="http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2007/5/21_Static_Abuse_files/iStock_000000939096XSmall.jpg" length="47178" type="image/jpeg"/>
    </item>
    <item>
      <title>HandsOn - A visual programming language for web applications</title>
      <link>http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2006/6/3_HandsOn_-_A_visual_programming_language_for_web_applications.html</link>
      <guid isPermaLink="false">ef7704f4-8a69-42a9-83fc-eba12217d339</guid>
      <pubDate>Sat, 3 Jun 2006 16:04:41 -0700</pubDate>
      <description>&lt;a href=&quot;http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2006/6/3_HandsOn_-_A_visual_programming_language_for_web_applications_files/iStock_000000791468Small.jpg&quot;&gt;&lt;img src=&quot;http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Media/iStock_000000791468Small_1.jpg&quot; style=&quot;float:left; padding-right:10px; padding-bottom:10px; width:206px; height:137px;&quot;/&gt;&lt;/a&gt;Peter Howell, a masters student of mine, has generated some interest in his thesis project: HandsOn. Ian Prince comments about HandsOn in a blog entries &lt;a href=&quot;http://blogs.inextenso.com/seaside/blog/learning/051da810-efb6-11da-a8c7-000d935fad1c&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;http://blogs.inextenso.com/seaside/blog/learning/67b5a972-efda-11da-a8c7-000d935fad1c&quot;&gt;here&lt;/a&gt;. Peter has his &lt;a href=&quot;http://www.u3engage.org/public/thesis/index.php&quot;&gt;thesis online&lt;/a&gt; with two &lt;a href=&quot;http://www.u3engage.org/public/thesis/demo.php&quot;&gt;screencasts&lt;/a&gt;. You can also &lt;a href=&quot;http://www.u3engage.org/public/thesis/download.php&quot;&gt;download&lt;/a&gt; his project. &lt;br/&gt;&lt;br/&gt;This was a very nice project. If you are a graduate student wondering what type of projects my students do for a thesis take a look at Peter's &lt;a href=&quot;http://www.u3engage.org/public/thesis/index.php&quot;&gt;HandsOn&lt;/a&gt;.</description>
      <enclosure url="http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2006/6/3_HandsOn_-_A_visual_programming_language_for_web_applications_files/iStock_000000791468Small.jpg" length="116931" type="image/jpeg"/>
    </item>
    <item>
      <title>The Changing Web - ET Fall 2006</title>
      <link>http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2006/5/24_The_Changing_Web_-_ET_Fall_2006.html</link>
      <guid isPermaLink="false">ca4139d9-53f2-4678-9670-ccf0d4d7245c</guid>
      <pubDate>Tue, 23 May 2006 22:11:30 -0700</pubDate>
      <description>&lt;a href=&quot;http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2006/5/24_The_Changing_Web_-_ET_Fall_2006_files/iStock_000001563649Small.jpg&quot;&gt;&lt;img src=&quot;http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Media/iStock_000001563649Small_1.jpg&quot; style=&quot;float:left; padding-right:10px; padding-bottom:10px; width:206px; height:137px;&quot;/&gt;&lt;/a&gt;I am starting to get inquiries about the course CS 683 Emerging Technologies (ET) to be offered in the Fall 2006 semester so it is time to produce a course description. &lt;br/&gt;&lt;br/&gt;Overview&lt;br/&gt;&lt;br/&gt;The short description is that the course will cover &lt;a href=&quot;http://www.ruby-lang.org/en/&quot;&gt;Ruby&lt;/a&gt;, &lt;a href=&quot;http://www.rubyonrails.org/&quot;&gt;Ruby on Rails&lt;/a&gt;, &lt;a href=&quot;http://www.python.org/&quot;&gt;Python&lt;/a&gt;, &lt;a href=&quot;http://www.djangoproject.com/&quot;&gt;Django&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Cascading_Style_Sheets&quot;&gt;CSS&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Javascript&quot;&gt;Javascript&lt;/a&gt;, &lt;a href=&quot;http://en.wikipedia.org/wiki/Ajax_%252528programming%252529&quot;&gt;AJAX&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Web_services&quot;&gt;Web Services&lt;/a&gt;. For details read on.&lt;br/&gt;&lt;br/&gt;Course Background&lt;br/&gt;&lt;br/&gt;CS 683 is a graduate topics course course covering some new technologies. As a graduate course undergraduate students can only take it if graduate students do not fill up the course. Normally I turn way graduate students in this course. In the six times the course has been offered no undergraduate student has been able to take the course. &lt;br/&gt;&lt;br/&gt;The leading edge of technology is often called the bleeding edge. There has not been time to polish the technology. There are rough edges (bugs, poor or no documentation, incomplete implementations, rapidly changing api, missing features, poor tool support) that make it harder to deal with the technology. This means that the course is a bit more work than normal. Since this will be the first time that I cover these areas and there are no textbooks covering these things the course will also be rougher than normal. This is the trade off one makes dealing with new technology. As a result the course will require a fair amount of work and initiative of the students. The course covers a number of topics, which means we will not cover anyone topic in detail.&lt;br/&gt;&lt;br/&gt;Some Motivation&lt;br/&gt;&lt;br/&gt;While the World Wide Web is always changing it seems to be changing even more these days. Venture capital is flowing into web based companies. One area of change is the development of new frameworks for creating web applications. We will look at two new frameworks that have promise to reduce the time required to develop web applications: Ruby on Rails and Django. What one can do on the web is changing, for example look at &lt;a href=&quot;http://maps.google.com/&quot;&gt;Google Maps&lt;/a&gt; and &lt;a href=&quot;http://mail.google.com/&quot;&gt;Gmail&lt;/a&gt;. AJAX is being used to provide this functionality. There are a number of mashup web sites, that is sites that combine and use other sites and data. A good example is &lt;a href=&quot;http://www.housingmaps.com/%253Fc%253Dsandiego%2526t%253Dapa%2526p%253D1500_2000&quot;&gt;Housing Maps&lt;/a&gt;, which combines Google Maps and &lt;a href=&quot;http://www.craigslist.org/&quot;&gt;Craigslist&lt;/a&gt; showing the location of rentals and housing for sale. Such mashups are possible due to &lt;a href=&quot;http://en.wikipedia.org/wiki/Application_programming_interface&quot;&gt;API&lt;/a&gt;s provided by companies to access their services. Often these APIs are done with Web Services. &lt;br/&gt;&lt;br/&gt;To learn these technologies students will develop programs that use the technologies. If you are looking for a survey course that just talks about technologies or one that talks about the social, economic and technological ramifications this course is not for you. The goal is to give computer science students some experience with these technologies. &lt;br/&gt;&lt;br/&gt;Some Details&lt;br/&gt;&lt;br/&gt;Ruby. Ruby is an interesting and powerful dynamic programming language. Recently interest in the language has grown greatly mainly due to Ruby on Rails, which is why the course will look at Ruby. The standard text on Ruby is &lt;a href=&quot;http://www.amazon.com/gp/product/0974514055/sr%253D8-1/qid%253D1148505132/ref%253Dpd_bbs_1/002-6626074-8267210%253F%25255Fencoding%253DUTF8&quot;&gt;Programming Ruby&lt;/a&gt; 2n’d Edition by Thomas &amp;amp; Hunt. The first edition is available &lt;a href=&quot;http://www.rubycentral.com/book/&quot;&gt;on-line&lt;/a&gt;, but covers a much older version of Ruby. The course will spend about 2 weeks on Ruby. See last years course for the old &lt;a href=&quot;http://www.eli.sdsu.edu/courses/fall05/cs683/notes/index.html&quot;&gt;lecture notes&lt;/a&gt; and &lt;a href=&quot;http://www.eli.sdsu.edu/courses/fall05/cs683/assignments/index.html&quot;&gt;assignments&lt;/a&gt;. There are some on-line tutorials to ruby, here is a &lt;a href=&quot;http://poignantguide.net/ruby/&quot;&gt;popular one&lt;/a&gt;.&lt;br/&gt;&lt;br/&gt;Ruby on Rails. This is a new framework for developing web applications and has a lot of promise and &lt;a href=&quot;http://www.google.com/trends%253Fq%253Druby+on+rails%2526ctab%253D0%2526geo%253Dall%2526date%253Dall&quot;&gt;interest&lt;/a&gt;. The developers paid attention to the difficulties with other web application frameworks. Developers are reporting that they can develop web applications in much less time using Ruby on Rails. Last year a students took one day to redo his semester Java/Struts web project in Ruby on Rails. We will spend about three weeks on Rails. The Ruby on Rails site has a &lt;a href=&quot;http://www.rubyonrails.org/docs&quot;&gt;documentation page&lt;/a&gt; with links and information to books, tutorials and on-line api.&lt;br/&gt;&lt;br/&gt;Python. Python is a popular dynamic programming language. See the main &lt;a href=&quot;http://www.python.org/&quot;&gt;Python web site&lt;/a&gt; for more details. The course will spend about two weeks on Python. The main motivation for covering Python is Django.&lt;br/&gt;&lt;br/&gt;Django. This is a really new framework for developing web applications that uses Python. The current version of Django is 0.91. Hopefully version 1.0 will be out by the fall. Some claim that Django is to Ruby on Rails as Ruby on Rails is to Java/Structs, that is really fast development of web applications. We shall see. The course will spend about three weeks on Django. See the &lt;a href=&quot;http://www.djangoproject.com/&quot;&gt;Django web&lt;/a&gt; site for documentation, there are no books on Django yet.&lt;br/&gt;&lt;br/&gt; AJAX. Ajax uses CSS, Javascript and Xhtml to provide some interesting  client side functionality in web browsers. Some web application frameworks, like Ruby on Rails, generate the needed Javascript. So it is not clear how much time we will need to spend on Javascript. I estimate 2 weeks on CSS, Javascript and Ajax.&lt;br/&gt;&lt;br/&gt;Web Services. Ruby and Python have SOAP implementations. It is  not clear how much detail we will need to add a Web service interface to a web application. Estimate 2 weeks on this topic.&lt;br/&gt;&lt;br/&gt;Prerequisites&lt;br/&gt;&lt;br/&gt;The course changes each time it is taught, so there can not be a fixed list of prerequisites. This is an advanced graduate course at the Masters level. None of the topics in the course are that deep. If I were a manager in industry I would expect anyone with a CS Masters degree to be able to learn any topic in the course by themselves. Past lecture notes and assignments for the course are &lt;a href=&quot;http://www.eli.sdsu.edu/courses/fall05/cs683/index.html&quot;&gt;on-line&lt;/a&gt;. With all this information an advanced graduate student should know if they are capable of taking this course.</description>
      <enclosure url="http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2006/5/24_The_Changing_Web_-_ET_Fall_2006_files/iStock_000001563649Small.jpg" length="190905" type="image/jpeg"/>
    </item>
    <item>
      <title>Future of Books</title>
      <link>http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2006/5/18_Future_of_Books.html</link>
      <guid isPermaLink="false">eb239c83-959e-4763-9b94-14fb7310fe89</guid>
      <pubDate>Thu, 18 May 2006 10:11:35 -0700</pubDate>
      <description>&lt;a href=&quot;http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2006/5/18_Future_of_Books_files/iStock_000000429362Small.jpg&quot;&gt;&lt;img src=&quot;http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Media/iStock_000000429362Small_1.jpg&quot; style=&quot;float:left; padding-right:10px; padding-bottom:10px; width:182px; height:273px;&quot;/&gt;&lt;/a&gt;Kevin Kelly has an &lt;a href=&quot;http://www.nytimes.com/2006/05/14/magazine/14publishing.html%253F_r%253D1%2526oref%253Dslogin%2526pagewanted%253Dall&quot;&gt;excellent article&lt;/a&gt; (registration required) in the New York Times about the efforts to scan all the world’s estimated 25 million books. The current rate is estimated at 1 millions books scanned each year. One company in China claims to have scanned 50% of all books published in China since 1949. Of course he discusses Googles scanning efforts and the issues raised by the project. He also discusses Amazon’s efforts, automated machines that scan 1,000 pages an hour, and China and India’s scanning factories. It is estimated that the USA 15% of the books are in the public domain, 10% are currently in print, with the remaining 75% are out of print but still copyrighted. For a long time a copyright protected a book for 14 years after publication. Now in the USA a copyright protects a book for 70 years after the author’s death.  One result if this long copyright is that most of the books that fall out of print will vanish. The book will still be covered by copyright but it will be impossible to find anyone that owns the copyright. &lt;br/&gt;&lt;br/&gt;Of course the interesting thing is when these millions of scanned books become available on-line. Already libraries can purchase scanned books at about 50 cents per book. The SDSU library contains about 1.2 millions books and bound periodicals. What will happen when students have 1 million books on their laptop or iPod? </description>
      <enclosure url="http://web.me.com/rewhitney/whitneyBlog/In_the_Trenches/Entries/2006/5/18_Future_of_Books_files/iStock_000000429362Small.jpg" length="71692" type="image/jpeg"/>
    </item>
  </channel>
</rss>
