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:

shorter_solution_diagram001.png
#1 - Wanted

shorter_solution_diagram002.png
#2 - Wanted

shorter_solution_diagram003.png
#3 - Wanted

shorter_solution_diagram004.png
#4 - Wanted

shorter_solution_diagram005.png
#5 - Unwanted

shorter_solution_diagram006.png
#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).

1 comment(s)
Filed under:
Aug 21 2008

messenger_nongenuine_logo.png 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.

4 comment(s)
Filed under:
Aug 17 2008

book_dotnet_xml_web_services.jpg

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

2 comment(s)
Filed under:
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.

1 comment(s)
Filed under:
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:

balsamiq_mockups001.jpg

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:

balsamiq_mockups002.jpg 
balsamiq_mockups003.jpg

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.

6 comment(s)
Filed under: