Welcome to the third part of this series of articles about how to write better code for the Notes/Domino platform. In part 1 I wrote about creating your forms in a way so you get an instant idea of how they work (what is hidden, computed-for-display fields, etc) and in part 2 the subject had moved to Lotusscript, more specifically variable names and comments.
As already mentioned in that last article (as well as in some of the comments), breaking out code into functions is a great way to make code easier to read as well as dramatically easier to maintain. That is what I will focus on in this article.
In Lotusscript, the functions are declared the same way as in Visual Basic:
Function YourFunctionName(argument As DataType) As ReturnDataType YourFunctionName = ReturnValue End Function
You can have any number of arguments, from none to many. However, it is often suggested to keep the number of arguments to a minimum. I try to not use more than three arguments, unless there is no way around it. If you need to send a lot of information into a function, use an array or a custom data type instead. Then it is easier to change the arguments later, without changing the signature of the function. I have occasionally seen that cause issues in nested script libraries. Also, with many arguments the function declaration will probably not fit on your screen, unless you wrap the line. I try to always keep code visible in the editor, as it is easy to miss things when you have to scroll sideways to view code.
So let’s take a look at one of the code samples in my last article, the one where we call names.nsf to get the email address for the current user. Let’s make this a function (like Kenneth Axi suggests in his comment), but we will make it a more generic function, returning the email address for any user present in address book, not just current user.
Here is the original code:
key = session.CommonUsername Set view = db.GetView("People") Set doc = view.GetDocumentByKey(key) emailaddress = doc.GetItemValue("InternetAddress")
Below is how I would write the function. We will talk more about error handling later, but you want to make sure to always check return values before you use them. The function takes one argument, the name of the user we want the email address for, and returns the email address, or blank if no user/address was found. The username must be in the same format as the names are being displayed in the view we doing the lookup in.
Function getEmailAddress(username As String) As String Dim personname As NotesName Dim nabdb As NotesDatabase Dim nabview As NotesView Dim persondoc As NotesDocument If username = "" Then MsgBox "Username is empty. Exiting.",,"No Value" Exit Function End If '*** Create NotesName object and get CommonName part. '*** We do this so username argument can be in any format. Set personname = New NotesName(username) '*** Use Domino Directory on main server Set nabdb = New NotesDatabase("Domino1/MyDomain","names.nsf") If nabdb Is Nothing Then MsgBox "Could not open names.nsf. Exiting.",,"Error" Exit Function End If Set nabview = nabdb.GetView("PeopleByFirstName") If nabview Is Nothing Then MsgBox "Could not find view 'PeopleByFirstName'. Exiting.",,"Error" Exit Function End If Set persondoc = nabview.GetDocumentByKey(personname.Common) If persondoc Is Nothing Then getEmailAddress = "" ' Did not find person, return blank value End If getEmailAddress = persondoc.GetItemValue("InternetAddress")(0) End Function
You may wonder why I am creating a NotesName object and not just using the name passed as argument directly? That will allow me to get the Common Name of the name, no matter in what format it is passed. You should always check the values of any arguments passed to your functions to make sure you can handle them and that they contain valid data. In this case I make sure the username is not empty, but for a string containing a date I would use the IsDate() function to test that the value is a valid date-time.
Now we can call the function like this:
MsgBox getEmailAddress("Karl-Henry Martinsson") MsgBox getEmailAddress("Karl-Henry Martinsson/MyDomain") MsgBox getEmailAddress("CN=Karl-Henry Martinsson/O=MyDomain")
Beautiful, isn’t it?
How to name functions
This brings us to the naming convention for functions. For functions, I use CamelCase, as that makes it much easier to see what the function does. I have to admit, I am not always consistent with get and set, I sometimes capitalize the first letter, sometimes not. Using CamelCase for functions and lowercase for variables makes it easier for me to read my code later, but you should do what you are comfortable with, and what works for you.
The actual name of the function should describe what it does, without being too long or too short. A well named function will by itself document what it does when you see it in your code later. The function we just created above could have been called getEmail() or getEmailAddressForUserFromCentralServer(). The first is a little too short — you don’t know if it is getting a mail address or an actual email document– while the second is too long.
Consider creating script libraries where you store commonly used functions. I have a number of script libraries, containing different sets of functions, and when I need certain functionality in a new application, I just copy one or more of them into that application. I name the script library in a way so I know what functions are in each one of them:
There are many ways to name your script libraries, and I know some developers who use very
complicated elaborate naming systems, where they can see at a glance if the script library uses back-end or front-end functions/classes, etc. I prefer a slightly simpler approach.
So let’s look at a real life code example, from one of my production applications. This is an agent, called from a browser, that generates some charts and other information, based on the URL parameters passed to the agent.
Thanks to the descriptive function names, hardly any comments are needed. The only comment in this code segment clarifies why we are doing what we do. Obviously the code is much more complex than what you see above, but it will give you an idea of how you can make your code easy to review and maintain.
In the next article I will talk about classes and object oriented Lotusscript.