It's been almost a month since I last made a post. Sorry but I've been busy, mainly with work. I can only spend a few hours a week working on this. I'll make up for it with two posts in one day. The first post is to talk a little more about the asynchronous library I originally created for this blog. It's called SimpleAsynch. I't's been enhanced a bit and I'm now using it on a new application that I'll talk about a later. (Sorry Patrick, I haven't been writing games where things blow up. I promise to do that next.)

1.Construct a request and submit it to the application server through a post action using XMLHttpRequest.
2.On the application server treat the request as any standard post request, parse the parameter list and perform an action, database update, reach out to a web service, etc.
3.When we're ready to return a response, use the asynchronous library to construct a XML document. In the document is a list of action node. Each action node is made up of an action (duh), the action recipient which could be an element id or JavaScript function, and finally a value to either store in the element or pass to a callback.
4.The response is then returned to the browser where the asynchronous library loops through and executes all of the actions.

input - populate an input field, if it doesn't exist create a hidden input field and store the value
div - replace the innerHTML of the div with the value supplied
options - replace all options in a select with the comma delimented option list stored in the value
select - set the selected option in a select to the value supplied
tab - if we use the tabber.js library, we can use this action to activate the tab named in the value parameter
delayCallback - we can use this to execute a callback function on the client, I can't remember why I needed this, I had a reason
callback - use the callback to execute yes a callback, the callback function could build another asynchronous request, we actually do this on the admin piece for the blog and on the project application that I'll talk about later
alert - the alert action will display an alert with the name and value concatenated, useful for reporting errors or for debugging
Now the first version of SimpleAsynch did not construct a XML response, but returned a pipe delimented set of actions, ids, and values. While the delimented response was initially easier to construct and prove out, it was a pain to manage and debug once more complex actions were performed. The project application uses the XML version, while the blog and Salesforce applications use the old delimited version.
The current library accommodates the most important of all browsers, IE6. There are no other browsers. That's wrong. It actually supports all browsers that I have access to IE6, IE7, Firefox 3 on Windows and Linux, Safari 3 on Mac and iPod. I've not downloaded Safari 4 yet nor I have I tried it on Chrome.
Now for some sample code...
The event handler on the browser constructs the request using SimpleAsynch.
function updateProject(){
var request = ""
request = addRequestFunction(request,"updateProject",false);
request = addRequestParameter(request,"projectId",false);
request = addRequestParameter(request,"projectName",false)
request = addRequestParameter(request,"projectStatus",false)
request = addRequestParameter(request,"projectDescription",false)
request = addRequestParameter(request,"projectScheduledStart",false)
request = addRequestParameter(request,"projectScheduledStop",false)
request = addRequestParameter(request,"projectActualStart",false)
request = addRequestParameter(request,"projectActualStop",false)
request = addRequestParameterAndValue(request,"projectAccessList",getAccessList(),false)
request = addCallback(request,"clearProjectForm",true);
postRequest("/updateProject",request);
}
There are a few functions that can be used to add parameters, addRequestFunction, addRequestParameter, addRequestParameterAndValue, and addCallback. The addRequestParameter function will locate the element by the id passed and will populate the value of that element in the parameter list. The addRequestParameterAndValue will let you add parameters to the request for elements that may not exist on the page. The addCallback function will be returned back to the client by the application server in the action list. Finally, postRequest will send the request off to the server.
I won't pull up all of the SimpleAsynch.js code here. You can get it from the site.
On the server you would process the request and build a response. Here's an example where we're trying to populate the screen with the details of a requirement. This example shows the construction of the xml using the SimpleAsynch ResponseXml class. ResponseXml uses a django template to construct the XML for the response.
class LoadRequirement(webapp.RequestHandler):
def post(self):
requirementId = self.request.get('requirementId')
requirements_query = db.GqlQuery("SELECT * FROM Requirement where requirementId = :1",
int(requirementId))
requirements = requirements_query.fetch(1)
rx = ResponseXml()
for requirement in requirements:
rx.addAction("input","requirementIdHidden",str(requirement.requirementId))
rx.addAction("input","requirementNumber",str(requirement.requirementNumber))
rx.addAction("input","listRequirementNumber",str(requirement.requirementNumber))
rx.addAction("input","requirementSubNumber",str(requirement.subNumber))
rx.addAction("input","requirementVersion",str(requirement.version))
rx.addAction("input","requirementMaxVersionHidden",str(requirement.maxVersion))
rx.addAction("input","requirementSummary",requirement.summary)
rx.addAction("input","requirementDescription",requirement.description)
rx.addAction("input","requirementComments",requirement.comments)
rx.addAction("input","requirementStatus",requirement.status)
labelString = ""
for label in requirement.labels:
labelString = label " "
rx.addAction("input","requirementLabels",labelString)
rx.addAction("input","requirementAuthor",str(requirement.requirementAuthor))
rx.addAction("input","requirementEntered",requirement.entered.strftime("%m/%d/%y %H:%M"))
rx.addAction("callback",self.request.get("callback"),"")
if rx.getLength()==0:
rx.addAction("alert","Requirement was not found.","")
self.response.out.write(rx.getXml())
Here's an application that might actually be useful. It's called mamoo project - http://mamooproject.appspot.com/. I've got more work to do on it, but there's enough here to look at. Here's how this all came about. At work, we've been going through a review process of requirements gathering tools. I'm not sure if we'll purchase one, but the vendors are sure nice to talk to. All of the presentations we've seen start off with something like, "Imagine the hell of having to capture requirements in a ginormous Word document. How stupid is that? (giggle...giggle)" However correct they may be, this is not a good way to win over a group of people, especially when everyone in the room has a "ginormous" requirements document back at their desk waiting for them.
So the outcome of all of this? We're still living with our big Word requirements document and we're dragging our feet with the vendors. The fact is, all of the tools we've looked at are good and have pretty much the same functionality and integration points with other applications, our test suite, etc. There are some big differences in cost, but that isn't the issue. I think the biggest barrier for us is maybe a little bit of fear. These are big applications. These things will collect requirements, create use cases, build activity diagrams, create test scenarios and scripts, integrate with development tools, build mockups. It's a bit much for an organization that doesn't have a standard template for the ginormous requirements document. We should probably start smaller. So I began working on mamoo project.

I started off with just the requirements piece. Here's what we have.

There is a large list of fixes and features to be added. I'm working now on a site landing page. This will include security and access lists for all projects. I'm also working on the export of the requirements to google docs. It's a little tricky. You can't just create a new spreadsheet in docs, you have to use an existing one or upload a new one. The problem is that google app engine won't let you just load up a new sheet from the file system. I'll figure it out. The risks and tasks and reports are all just an idea. Along with the challenge of capturing requirements, projects need a good way to manage risk. In the past I've used several tools for this, none have been ideal though one came close, Mercury Test Director - Quality Center - HP QC. The defect section had a nice layout and the defects themselves were customizable. It gave us a good place to store risks, issues, action items, requirements defects, test defects, lessons learned, anything you can thing of. You had good traceability and an okay reporting tool. I'll model the mamoo project tasks and risks section off of Quality Center. It will have much less functionality, but it will still be useful and it won't require a massive applet download to run. Risks and Tasks will also be exportable to docs.