August 2008 - Posts
Aug 26 2008
Sometimes, while we're devloping, we find solutions to problems that work correctly. And sometimes, we think it is the best solution and stop thinking of other possibilities.
I had a recent example few days ago, while I was coding a SQL Server stored procedure that filtered date ranges, returning elements that fit in the first four of this six available outcomes:
#1 - Wanted
#2 - Wanted
#3 - Wanted
#4 - Wanted
#5 - Unwanted
#6 - Unwanted
In order to acomplish the four first situations, this would be the SQL comparisons needed:
B1>=A1 AND B2<=A2
+
B1<=A1 AND B2<=A2
+
B1>=A1 AND B2>=A2
+
B1<=A1 AND B2>=A2
But, there's sometimes a shorter solution... Like this one:
A1<=B2 AND A2>=B1
Beautiful, don't you agree? Just by switching Bs we reduce to just one AND, covering all four desired causistics...
Sometimes we see a narrow passage (play with the lesser/greater operators) when there is more than one solution (playing with the Ax/Bx operands).
Aug 21 2008
This is part three and last on my WLA Testing posts. Read parts one and two if you haven't because we will go into more complex and advanced tests for our testing framework.
In the previous post we built a basic framework containing better summary reports, base error procedures to mark a test as failed, and Assert methods to compare strings and objects.
While all of these are useful, writing tests to test conversational patterns is still a bit difficult, requiring some code for a simple "check if this is the output of that", so we're going to build Asserts to compare arrays, and then use it to build Asserts that compare conversation patterns (with multiple responses) and simple conversation dialogs (example: if user says A then ask B and if says B then answer C).
This are the procedures we will build:
declare procedure TestExErrorIfContainsArray(TESTMETHOD, STRING, REGEXARRAY)
declare procedure TestExErrorIfDoesNotContainArray(TESTMETHOD, STRING, REGEXARRAY)
declare procedure TestExCompareQuery (REGEX, QUERY)
declare procedure TestExCompareQueryNotEqual (REGEX, QUERY)
declare procedure TestExCompareQueryArray (REGEXARRAY, QUERY)
declare procedure TestExCompareQueryArrayNotEqual (REGEXARRAY, QUERY)
declare procedure TestExDialog(EXPECTEDRESULTS,DIALOGRESPONSES,DIALOGQUERY)
We'll start with the Errors:
// Tests if a string contains at least one of the regular expressions in an array
procedure TestExErrorIfContainsArray(TESTMETHOD, STRING, REGEXARRAY)
CONTAINS = false
STRING_NO_NEWLINES = StringSubstitute(STRING, "\n", "X") // This is to make "." match on new lines, since Contains doesn't support the "s" modifier yet
for value REGEX in REGEXARRAY
if (Contains(REGEX, STRING)) && ((STRING_NO_NEWLINES eq STRING) || (Contains(REGEX, STRING_NO_NEWLINES)))
CONTAINS = true
if (CONTAINS)
ERROR_DESC - Expected: \"EscapeHtmlChars(ObjectToString(REGEXARRAY))\"
call TestExError(TESTMETHOD, ERROR_DESC, STRING)
// Tests if a string does not contain at least one of the regular expressions in an array
procedure TestExErrorIfDoesNotContainArray(TESTMETHOD, STRING, REGEXARRAY)
CONTAINS = false
STRING_NO_NEWLINES = StringSubstitute(STRING, "\n", "X") // This is to make "." match on new lines, since Contains doesn't support the "s" modifier yet
for value REGEX in REGEXARRAY
if (Contains(REGEX, STRING)) && ((STRING_NO_NEWLINES eq STRING) || (Contains(REGEX, STRING_NO_NEWLINES)))
CONTAINS = true
if (!CONTAINS)
ERROR_DESC - Expected: \"EscapeHtmlChars(ObjectToString(REGEXARRAY))\"
call TestExError(TESTMETHOD, ERROR_DESC, STRING)
As you can see, we just search for a string but not against a string but an array, with a For-value-in.
Then, the simple query (one question - one answer) Asserts:
// Tests a query against a regular expression for matching
procedure TestExCompareQuery (REGEX, QUERY)
- Test: \"TestExCompareQuery\"
call IncrementTotalTests()
RETURNED = ExecuteQuery(QUERY)
call TestExErrorIfDoesNotContain("TestExCompareQuery", RETURNED, REGEX)
// Tests a query against a regular expression for not matching
procedure TestExCompareQueryNotEqual (REGEX, QUERY)
- Test: \"TestExCompareQueryNotEqual\"
call IncrementTotalTests()
RETURNED = ExecuteQuery(QUERY)
call TestExErrorIfContains("TestExCompareQueryNotEqual", RETURNED, REGEX)
Here the trick is calling ExecuteQuery() and storing it's output. This function works as if a user had typed something, processing it and returning the Agent's response. We catch the response and compare it as we did with a simple string Assert.
But what if we've built an agent rich in answers, that can give different responses to the same pattern? Here's where the array error procedures we've just written come to help:
// Tests a query against a regular expression array to see if contains at least one of its elements
procedure TestExCompareQueryArray (REGEXARRAY, QUERY)
- Test: \"TestExCompareQueryArray\"
call IncrementTotalTests()
if !IsObject(REGEXARRAY)
ERROR_DESC - "REGEXARRAY" not an array
call TestExError("TestExCompareQueryArray", ERROR_DESC, QUERY)
else
RETURNED = ExecuteQuery(QUERY)
call TestExErrorIfDoesNotContainArray("TestExCompareQueryArray", RETURNED, REGEXARRAY)
// Tests a query against a regular expression array to see if does NOT contain any of its elements
procedure TestExCompareQueryArrayNotEqual (REGEXARRAY, QUERY)
- Test: \"TestExCompareQueryArrayNotEqual\"
call IncrementTotalTests()
if !IsObject(REGEXARRAY)
ERROR_DESC - "REGEXARRAY" not an array
call TestExError("TestExCompareQueryArrayNotEqual", ERROR_DESC, QUERY)
else
RETURNED = ExecuteQuery(QUERY)
call TestExErrorIfContainsArray("TestExCompareQueryArrayNotEqual", RETURNED, REGEXARRAY)
What we do is ExecuteQuery() again and check it's value against an array of expected responses.
And finally, here's the code of a simple dialog Assert:
// Tests a menu and all the responses defined in its parameter
// Note: Responses and expected results should be in the same order in the arrys
procedure TestExDialog(EXPECTEDRESULTS,DIALOGRESPONSES,DIALOGQUERY)
- Test: \"TestExDialog\"
call IncrementTotalTests()
RESULTSNUM = SCount(EXPECTEDRESULTS)
if (RESULTSNUM != SCount(DIALOGRESPONSES))
ERROR_DESC - "EXPECTEDRESULTS" and "DIALOGRESPONSES" should have same number of elements
call TestExError("TestDialog", ERROR_DESC, RESULTSNUM)
exit
// Always trigger the dialog, then choose one option each time and check its response
for I in 0 to RESULTSNUM-1
MENURESPONSE = ExecuteQuery(DIALOGQUERY)
ANSWERRESPONSE = ExecuteQuery(DIALOGRESPONSES[I])
call TestExErrorIfDoesNotContain("TestExDialog", ANSWERRESPONSE, EXPECTEDRESULTS[I])
The code is quite self-explanatory, but basically it starts a dialog pattern with DIALOGQUERY, and then loops asking the agent each question (contained in DIALOGRESPONSES array) and each response against the EXPECTEDRESULTS array.
As the code for some examples of this asserts is quite big and I don't want a huge post, I've instead uploaded the full testing framework with a test DDL file so you can directly add them to a buddyscript project and launch the sample tests.
I hope you've learned how to better test your Windows Live Agents with this posts.
I will write just one more post and then leave the legacy to my good friend PedroAfa, who is still working on a daily basis developing WLAs.
Aug 17 2008

I've updated my Books Review section with a new review.
From now on, expect around one monthly review because I'm going to read a lot of books I've bought in the past few years and still haven't even opened. I'm not going to buy more technical books (it's one of my weaknesses, I'm a compulsive tech book buyer) until I've read at least half of them :P
Aug 11 2008
While reading a Gamasutra article about common pitfalls of using Scrum in game development, few of them looked familiar to me (I've worked with "real" and "apparent" Scrum in different projects for more than a year) , so I'll be listing here those which I have something to say about along with my point of view.
No design document needed because the backlog spreadsheet replaces it
I've suffered having no design documentation apart from unit & functional tests documents until the end of the project, and the commercial proposal (which incudes tech specs but not as detailed as developers would want sometimes).
While this can appear to be good, having to "remember" or "ask the customer" for specific features or a requisite can slow development. Also, it is better to do documentation as the project goes on, and not having to remember everything at the end.
Interrupt what people are doing to have them come to the daily 15 min. meeting
Discipline is good, but when developing, sometimes you're in the middle of something, or just came up with the solution to the problem you've been struggling with last four days. In those cases, interrupting can be annoying.
I think that balance is the key: Meeetings should be at a scheduled time, but with the option to delay it a bit if the reason is valid.
Not doing something because it is not in the backlog
I haven't faced this one because we've always added new tasks both to the backlog and to the current sprint if we thought necessary.
Also, as the Gamasutra article mentions, this can make the developers feel like working on peaks: Now I've got work, now I don't. It is better to have a steady rythm of work along all the project.
Start managing stories and sprints before all the people are on the team
This is the worst one. Once, I faced having all the project planned before even knowing what do I was supposed to do. I had to choose tasks I didn't knew what they meaned or what time would take, and even estimate them. As a result, we had to re-arrange tasks in sprints almost every three weeks.
Remember: If you're not going to develop something, ask who is going to develop it at least for advice.
Daily meeting becomes a each person give a status report
I have seen this too. Although the time spent was lowered to near 5 minutes, I see no use on just telling "I've finished this" if you have the scrum spreadsheet and can look at it anytime. Make the meetings useful for the team, or skip them.
Make Scrum mandatory
I'm always a bit "rebel" with rules. They are good while they are useful, but imposing something for everything just because "you must follow it" is nonsense.
In one project we were supposed to follow scrum, and we ended switching to Extreme Programming (with small adaptations too ;) because we were two devs only and it was quite faster to do things like pair programming.
Implement only X weeks of work based on what you currently know about the design
False! "Plan in advance". It is fundamental! For example, if you develop a Windows Live Agent without planning how the agent will interact with the Activity Window, you'll end having to modify code and re-arrange it to adapt to the Activity's asynchronous mechanics.
Start managing the project by prioritizing tasks and asking time estimates before the design document is written
Wrong. As I said before, if you don't know what you're going to do, how can you estimate it correctly?
Spend time writting the design document, then estimate and prioritize.
So, in my oppinion, take Scrum as it is, a methodology. If something doesn't fits with your team's daily work habits, or if something instead of improving the quality/speed/organization will impede it, skip it.
Aug 04 2008
After writing about prototyping GUIs with Powerpoint, I was contacted by Peldi, owner of Balsamiq.com, giving me a free license of his product Balsamic Mockups, to try and if I liked, write a review about it.
I've downloaded the application (made with Adobe AIR), and made a mockup of the Downloads section of the community.
Here is a screenshot of the interface took while I was finishing the mockup:
The app is quite intuitive to use, with toolbars and markers appearing when you select elements. Everything is drag&drop, then customize. All elements come with sample data that explains special tags or characters (for example, using "f " for closed folders and "F " for open ones in a folderview element).
Here it is the final result, and a real screenshot for quick comparison:
As you can see, it is quite similar, and I assure you didn't took more than 5 minutes to build it. Surely I could have played with sizes a bit more, but I wanted a "fast and dirt" prototype.
Prototyping with this tool is really fast and I'm surely going to use it for home projects.