Principal, Asia/Pacific Computer Services
The Intractability of Domino Web Agents
I've been programming since the mid 1960s, and never cease to be surprised how tricky debugging can be on some platforms, or in some environments on a particular platform. One such environment is the debugging of Web agents running on a Domino server. I know this is a sore point for most Domino developers.
Debugging of LotusScript for the Notes Client is pretty easy, since there's a nice debugger available (although the same can't be said for the Formula Language and Java environments, which is a shame.)
You put lots of loving care into developing your slick Web agent, then confidently launch it for the first time, and what do you see? Maybe nothing at all seems to happen. If you're lucky, you get a message or two in the Domino console log, but typically is so obscure as to be of no real use to you or on the surface seems to have no relationship to what your agent was trying to achieve!
I was in this situation a year or two ago, when extending NotesTracker, a database usage reporting toolkit (described at http://notestracker.com or http://asiapac.com.au ) from its originhal Notes-Client-only environment to embrace the Web browser environment.
The NotesTracker LotusScript code was quite intricate, and I had a few challenges to modify parts of it to get it working via WebQueryOpen and WebQuerySave agents. Additionally, this was some years ago, under Notes R4 and R5 so could only use the tools available at that time. The Remote Debugger capability didn't come along until Domino 6 (and even when it did become available, I found ND6 remote debugging too fiddly for my liking, not all that easy to set up and use).
Naturally enough, not wanting to "reinvent the wheel" I did the right thing by carrying out exhaustive research to see how others had gone about debugging Domino Web agents. I searched articles, forums and knowledge bases on the Lotus Web site, as well as quite a range of non-Lotus sites (nearly all of which latter you'll find conveniently listed at http://notestracker.com/Links/NotesDomino.htm ).
Firstly, refer to the following IBM developerWorks articles for some excellent general guidance about debugging Domino agents:
- http://www-10.lotus.com/ldd/today.nsf/lookup/DebuggingLotusScript_1
- http://www-10.lotus.com/ldd/today.nsf/lookup/DebugLS2
- http://www-10.lotus.com/ldd/today.nsf/lookup/ND6NewAgentFeatures
Prior to ND6, typical debugging methods suggested were to Include strategically-placed Print or MessageBox statements to display debugging information, or the more elegant use of the AgentLog class to write out the debug info into a log database.
But I was seeking a more direct method. So here's what I came up with. (I generally use it insteaad of the other techniques like inserting Print statements).
A brief outline of my technique follows. I suggest that you also watch the screencam demonstration at http://notestracker.com/tips/debug_web_agent.htm that I hope to make available soon.
Note that while I'm talking LotusScript in this article, the technique should also work for Domino Java Web agents and maybe even for Formula Language Web agents (although I haven't tested either of these). In fact, it might work in just about any release of any programming language on any platform (a wild claim, but we Aussies are not averse to making such assertions).
The Debugging Technique
Key steps in locating the coding problem in your Web agent:
- Develop a single, simple LotusScript statement that will cause the agent to throw a specific, easily-recognized error message at the Domino console. (This, as usual, will incorporate your Web agent’s name, which will distinguish your agent from all the other console message sources.)
It helps if you have handy access to the Domino console. In fact I find it most convenient if you can run the Domino server, Domino Designer, Web browser (and Notes Client, for that matter) all on a single machine -- nothing could be handier than that. - Place the debug statement at a strategic point in the agent’s code stream, then trigger the agent and
watch for a specific termination error message at the console. You now know that the Web agent has successfully reached exactly that particular point in the code stream before strinking your deliberate error trap. - Now cut-and-paste (not copy-and-paste) the debug statement to another strategic point further on
in the agent’s code stream. Then go back to Step 2, running the Web agent again. - Iterate through the above two steps until eventually a point is reached in your agent’s code stream where either
(a) there is an error message sent to the Domino console that is caused by something in the agent's code stream that is other than your deliberate debug statement, or
(b) the agent terminates without that error message. In the latter case you know that the faulty code must lie between that statement and the end of the code stream.
What do I mean by “strategic points” in the code stream? Each such point is simply a statement that represents a major logical step in either the agent's mainstream or in one of its underlying subroutines and functions.
I strongly suggest that you utilise a binary search approach to decide where such points are in the agent's code stream. (I don't want to teach you to "suck eggs" -- but if you're not familiar with this approach you can find out about it at a site like http://www.nist.gov/dads/HTML/binarySearch.html or by doing a Google search on "binary search".)
Focus first on the agent's mainline because the error might lie in the mainline itself. If you don't locate the error in the mainline, place the debug statement one-at-a-time at the very start of each successive subroutine (or function), and move on in the “binary search” fashion within the subroutine until you’re sure that the fault does not lie in
that subroutine, then move on to the next subroutine. This methodical approach is far more efficient than randomly picking points to place the statement.
My choice was to deliberately force a Zerodivide error to generate the Domino Console errors.
Naturally, in a mathematical operation, there cannot be an attempt to divide by zero, and the LotusScript compiler is smart enough to disallow statements that it is able to predict will cause division by zero, such as:
z% = 1 / 0 or z% = 1 / ( 1 – 1 )
To get around this issue, I use a statement of this general form:
zerodivide% = 1 / ( zerodivide% - zerodivide% )
The % character forces the field to be an integer, Leave it off, then the field becomes a LotusScript variant and the zerodivide technique fails.
In practise, I use this terse form:
zd% = 1 / (zd% - zd% )
or simply: z% = 1 / ( z% - z% )
And in all but simple agents I use the following variation:
z% = 1 / ( z% - z% ) ‘ ###########################
where the string of hash symbols (#) is added to be an "eye-catcher". This helps to make your debug statement stand out in your agent's code stream, enabling you to locate the statement much more easily when you want to cut-and-paste it elsewhere. Likewise it also helps you not to overlook it (and so leave it in the agent's code stream) when you've finished debugging and need to remove it entirely.
As mentioned earlier, I try to run the Domino test server on the same workstation that I'm using for the Domino Designer and Web browser (nice, but not always achievable). This way, I can see the Zerodivide error message the very instant that it appears on the Domino Console, a fraction of a second after opening the affected page in the Web browser. (You definitely should view the screencam to see what I mean by this.) The next best thing is
to run a remote Domino Console on your workstation, or to have the Domino server system very close by. This arrangement can significantly improve your debugging turnaround time, compared with not having to use a remote Domino test server.
Summing Up
I'm not pretending that the above technique is "rocket science" but that was precisely my objective: to describe a straightforward and painless technique which enables you to quickly hone in on the whereabouts of that elusive coding problem in your Domino Web agent. Try it out and see if it works well for you too. Otherwise, if you have an even simpler approach, send us your feedback.