Skip to main content
    Country/region select      Terms of use
     Home      Products      Services & solutions      Support & downloads      My account     

developerWorks  >  Lotus  >  Forums & community  >  Best Practice Makes Perfect

Best Practice Makes Perfect

A collaboration with Domino developers about how to do it and how to get it right in Domino

I know that in Domino developer training, you were taught to create a dozen temporary variables for the arguments to your @Functions.

years := 0;
months := 0;
days := 30;
hours := 0;
minutes := 0;
seconds := 0;
tmp := @Adjust(SomeDate; years; months; days; hours; minutes; seconds);

If you still do this, don't. Because:

  • It's unnecessary extra typing, using up time that you could be spending on slack.
  • It hurts performance, especially in "hot" code areas such as before a SELECT statement.
  • It makes the formula harder to read because you can't tell what the value of an argument is without looking at two different places in the code -- and if the temporary variable assignments are far from the @Function, a reader must scan all the intervening code to be sure they haven't changed meanwhile.
  • No, you can't make it a rule to always define the temporary variables you need just before you use them, because the syntax doesn't always allow that (maybe the @Function is in the fifth "elseif" clause of an @If). So there will be intervening code, or else you force yourself to use @Do everywhere just so you can do this dumb thing.
  • Person A writing the formula will be lazy and reuse an argument variable name further down in the formula so that they don't have to make up a new name and type the assignment. Person B (or person A later on, having forgotten) will change the value of the argument variable because they want to change it in the first function call, not realizing that they also affect the second function call.
  • Because macro language lets you use an undeclared name anytime, it won't warn you if the spelling of your variable name is different in the two places.
  • It prevents you from noticing otherwise obvious errors in the code as you're looking at it for other reasons, because you don't know the argument values as your eyes scan past them.
You may think you're helping readability by flagging your argument values with useful names, but as we can see from the above the overall effect on readability and maintainability is negative.

Here's another problem:

profilename := "Keywords";
fieldname := "History";
value := "";
uniqueKey := "";
REM {Clear the history entries from the shared profile document.};
@SetProfileField( profilename ; fieldname ; uniqueKey; value )

This works great! Later, someone decides that the proper value for a cleared history is "|" instead of "". So they change the line:

value := "|";

This likely results in a post to the Domino forums that "@SetProfileField doesn't work." Figuring out why it doesn't work is left as an exercise for the reader. It might take you longer when you run across it unexpectedly 'in the field' because I've already hinted where to look. How long might it take someone without the hint, and who also doesn't know formula language as well as you, to catch on?

If you must flag your arguments with a name, take advantage of the fact that := returns the assigned value as its value. E.g.:

tmp := @Adjust(SomeDate; _years:=0; _months:=0; _days:=30; _hours:=0; _minutes:=0; _seconds:=0);

You could still fool yourself as in the above example, but at least you don't have the possibility of spelling them differently in the two places, or of changing their values between where they are set and used, and it doesn't matter if you use the same variable name in two places. I'm not saying you should do it this way; I'm just saying this is a little less dumb than the way you were taught.

Andre Guirard | 25 June 2008 06:09:00 AM ET | Home, Plymouth, MN, USA | Comments (14)


1) Diatribe: Macro formulas, temp variables for each @Function argument
Theo Heselmans | 6/25/2008 6:40:12 AM

The title sounds interesting ;-)

2) Diatribe: Macro formulas, temp variables for each @Function argument
Craig Wiseman | 6/25/2008 7:08:51 AM

I guess it's like looking through a glass window at someone shouting.

Can't hear him, but he's obviously upset....

3) Diatribe: Macro formulas, temp variables for each @Function argument
Patrick Kwinten | 6/25/2008 7:30:39 AM

he's taking his words back?

4) Diatribe: Macro formulas, temp variables for each @Function argument
Colin Macdonald | 6/25/2008 7:40:48 AM

tnemugra noitcnuF@ hcae rof selbairav pmet ,salumrof orcaM :ebirtaiD

5) Diatribe: Macro formulas, temp variables for each @Function argument
Andrew Pollack | 6/25/2008 8:17:59 AM

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nam urna. Ut sed sem. Proin ante. Morbi ac ligula. Proin suscipit, nulla at cursus ullamcorper, dolor elit iaculis justo, rutrum aliquet sem arcu eleifend urna. Fusce tempus, sem et condimentum blandit, nisl diam tempus orci, sit amet vulputate leo libero et elit. Mauris scelerisque dolor ut velit. Nulla orci magna, consectetuer eget, semper vel, egestas non, eros. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Fusce fermentum turpis at odio. Nulla facilisi. Nulla et tortor. In volutpat, nibh auctor vehicula placerat, felis libero bibendum felis, ac egestas libero nibh sed dui. Quisque bibendum adipiscing nisl. Cras pede. Donec nec nulla.

6) Diatribe: Macro formulas, temp variables for each @Function argument
Gabriel Amorim | 6/25/2008 9:08:58 AM


7) Diatribe: Macro formulas, temp variables for each @Function argument
Keith Smillie | 6/25/2008 10:06:26 AM

Hi Andre,

I only partly agree with what you're saying.

All too often I see formulas which are just one big mass of @functions all piled on top of each other like some bizzare macronistic orgy.

A very simple example would be this:

@Adjust( date; @GetProfileField( "keywords"; "years"; @UserName ) ; @GetProfileField( "keywords"; "months"; @UserName ); @GetProfileField( "keywords"; "days"; @UserName ); 0 ; 0; 0 ) ;

Personally I find the following equivalent bit of code simpler to read:

years := @GetProfileField( "keywords"; "years"; @UserName ) ;

months := @GetProfileField( "keywords"; "months"; @UserName ) ;

days := @GetProfileField( "keywords"; "days"; @UserName ) ;

@Adjust( date; years; months; days; 0; 0; 0 ) ;

The above example is very simple but sometimes I've seen formulae which extend over three, four or more lines which would certainly be more understandable and maintainable if they were broken into smaller chunks.

Another benefit of breaking things into smaller chunks is that each chunk can have its own comment. People do put comments in their formulae, don't they? Thought so.


8) Diatribe: Macro formulas, temp variables for each @Function argument
Craig Wiseman | 6/25/2008 10:57:54 AM

The premise is good (this may be showing my personal flaws), but I have also been in situations where I've had to debug masses of nested @formulas and it can be a total nightmare.

I'd much rather try and figure out that 'value' can't be "|" than figure out where the @#$@ I'm missing a closing paren or semi-colon...

The optimization point is very relavent, but we need to strike a balance between undebuggable nested 'fast' code and maintainable 'slow' code.

9) Diatribe: Macro formulas, temp variables for each @Function argument
Andre Guirard | 6/25/2008 11:08:11 AM

Keith, I'm not denying that it's possible to go too far in the other direction. Writing readable code is a skill, and it takes thought to do well. Defining a temporary variable with a constant value can enhance maintainability if, for instance, it's a dialog window title that's used multiple times in the formula. Doing it for every constant is tremendous overkill.

10) Diatribe: Macro formulas, temp variables for each @Function argument
Eric Romo | 6/25/2008 4:20:09 PM

I'm NOT a big fan of any complicated formula language routine(CFLR). Limiting use of variable names is taking a step back to those days of cryptic C code with 1-letter variable names, lack of indentation and every side-effect leveraged to the hilt. Things like nested IF clauses should be discouraged as well, especially with functions that have many parameters.

Those practices create confusing code structures that are further exaggerated by the non-standard (non-existent?) formatting, as well as inconsistent syntax highlighting and error-checking of the IDE.

Formula language is still not ready for prime time. That's fine, but then don't try to overcome those flaws, rather limit their downside by using best practices like keeping the routines simple, limiting the nesting of If clauses, and using meaningful variable names.

11) Diatribe: Macro formulas, temp variables for each @Function argument
Charles Robinson | 6/25/2008 5:29:38 PM

@10 - "Formula language is still not ready for prime time."

I'll be the first in line to set fire to Domino Designer, but the IDE being barely functional doesn't make the language worthless. Formula is very robust, very fast, and relatively simple. Yes you can get yourself in trouble with it in a hurry, and yes, the tools for working with it are atrocious. That's no reason to condemn the language, though.

As Andre has already said, there is a balance between pure performance and readability. If you use 6 variables set to static numbers to feed into an @Adjust it's a waste of time and CPU cycles. Just put the numbers into the formula already. However if you're doing something more complicated, or something you'll use repeatedly, a variable makes sense.

12) Diatribe: Macro formulas, temp variables for each @Function argument
Training? | 6/25/2008 5:57:18 PM

"I know that in Domino developer training, you were taught to create a dozen temporary variables for the arguments to your @Functions."

"developer training?" Are you kidding?

That being said, Andre, there's a basic reason for doing this. If you use the same code pattern over and over again, and you have to copy/paste a lot of references, it's much easier to maintain code that's been structured this way. It's ever-so-slightly harder to DEBUG it, but it's substantially easier to EDIT it.

This, of course, wouldn't be necessary if @functions had a serious editing tool. Perhaps DDE will finally give us the opportunity for that.

13) Sorry... that last post was me
Nathan T. Freeman | 6/25/2008 9:18:40 PM

Got confused between "subject" and "name" :-)

('cause it's all about me, dontchaknow)

14) Diatribe: Macro formulas, temp variables for each @Function argument
Eric Romo | 6/26/2008 11:30:16 AM

@11 I admit "not ready for prime time" was a bit harsh. Maybe I did "throw the baby out with the bath water." But Formula language is tied to the IDE at this point at least.

Sure you can do alot with formula language, but inherently its not well suited for complex programming. Thus keeping routines fairly short/simple, and using variable names are only very rarely a waste of time or cpu cycles.

IMHO, the original recommendations should be limited to when performance needs to be improved.

15) Diatribe: Macro formulas, temp variables for each @Function argument
Andrew Magerman | 6/26/2008 12:27:52 PM

Nathan, hear hear!

I exactly have that. Long ago (this was before the nifty Hello:=0 as arguments), I made a collection of Teamstudio snippets with exactly those pre-formatted entries - no values, paste in whole code, adjust the necessary variable, done. No half-an-hour trying to work out that you got the third and fourth argument wrong. I especially alwayays got the long ones wrong, like @dblookup, @Adjust - impossible to keep those in head.

Andre, I know also that the formula language has been "proceduralized", but I still think in terms of a stack, and I think that still is the best metaphor for really understanding @Formula - and your comments seem to really assume a "start at the top and end at the bottom" logic.

Sorry, not convinced on this one, Andre!


P.S. Apart from that, brillant blog!

 Add a Comment
Comment:  (No HTML - Links will be converted if prefixed http://)
Remember Me?     Cancel

Search this blog 


    About IBM Privacy Contact