15
Tutorial: 30 LotusScript tips 27 Mar 2007 | SearchDomino.com Among the plethora of sessions to choose from at Lotusphere 2007 , one of the most useful and interesting was "AD505 DevBlast -- 30 LotusScript tips ," a presentation from Bill Buchan , CEO of HADSL , a company that develops best-practice tools for Lotus Notes and Domino. With Bill Buchan's permission, we've repackaged his presentation here for your education and enjoyment. Part 1 introduces 10 basic LotusScript techniques that you should already be using if you've had any previous exposure to LotusScript. These beginner-level tips are also perfect for a Notes/Domino developer just getting started with LotusScript. Part 2 explains LotusScript best practices you should employ as part of your everyday coding. These intermediate-level tips will help you polish your routine coding methods and secure your LotusScript code. Part 3 offers advice to experienced developers who want to take their LotusScript skills to the next level. These advanced-level tips will challenge you to use more complex LotusScript commands to improve the functionality, performance and clarity of your LotusScript code. TUTORIAL: 30 LOTUSSCRIPT TIPS Home: Introduction Part 1: 10 fundamental LotusScript tips Part 2: 10 everyday LotusScript tips Part 3: 10 advanced LotusScript tips Part 4: More LotusScript learning resources

tutorial-30-lotusscript-tips1

Embed Size (px)

DESCRIPTION

LotusScript

Citation preview

Page 1: tutorial-30-lotusscript-tips1

Tutorial: 30 LotusScript tips27 Mar 2007 | SearchDomino.com

Among the plethora of sessions to choose from at Lotusphere 2007, one of the most useful and interesting was "AD505 DevBlast -- 30 LotusScript tips," a presentation from Bill Buchan, CEO of HADSL, a company that develops best-practice tools for Lotus Notes and Domino. With Bill Buchan's permission, we've repackaged his presentation here for your education and enjoyment.

Part 1 introduces 10 basic LotusScript techniques that you should already be using if you've had any previous exposure to LotusScript. These beginner-level tips are also perfect for a Notes/Domino developer just getting started with LotusScript.

Part 2 explains LotusScript best practices you should employ as part of your everyday coding. These intermediate-level tips will help you polish your routine coding methods and secure your LotusScript code.

Part 3 offers advice to experienced developers who want to take their LotusScript skills to the next level. These advanced-level tips will challenge you to use more complex LotusScript commands to improve the functionality, performance and clarity of your LotusScript code.

TUTORIAL: 30 LOTUSSCRIPT TIPS

 Home: Introduction

 Part 1: 10 fundamental LotusScript tips

 Part 2: 10 everyday LotusScript tips

 Part 3: 10 advanced LotusScript tips

 Part 4: More LotusScript learning resources

Page 2: tutorial-30-lotusscript-tips1

LOTUSSCRIPT

10 fundamental LotusScript tips1. Option Declare 2. Templates and versions 3. Application lifecycles 4. How to code 5. "Measure twice, cut once" 6. Extending arrays the easy way 7. Use the list operator 8. Logging agents 9. Code structure 10.Hiding your code

  Fundamental LotusScript Tip #1. Option Declare

Make sure you always use "Option Declare." It sounds obvious, but there are several determining factors as to why you should always use it. Here are some of the reasons:

If you don't use "Option Declare," all variables are created at runtime as variants, and this makes fact checking redundant.

Data conversion will cost your company 10 times your performance. All your errors will be runtime errors. Also, always remember that you should test often and test early. Use the strength

of the compiler to help you.

  Fundamental LotusScript Tip #2. Templates and versions

 

When working with templates and versions in LotusScript in custom code, there are a few things you should always do:

Always create templates with new code, which may include databases with an NTF extension or databases with Master Template Name set.

Make sure you create a separate version for each copy you're working on. And always keep your templates and versions in a central repository.

You might say these all sound like good reasons, but why should I use them? There are three major reasons:

1. Because it makes it much easier to roll back. 2. It helps with version control. 3. It makes it simpler to construct test cases with other versions.

  Fundamental LotusScript Tip #3. Application lifecycles

 

When dealing with the lifecycles of your applications, there are a few best practices

Page 3: tutorial-30-lotusscript-tips1

you should follow:

1. Always develop in a development sandbox -- a non-production environment where each developer keeps his or her working copy of the code base.

2. Always test in a user acceptance environment. 3. Pass the template to your Domino administrator to copy.

Here is why you should adhere to these rules:

It's a basic change-control system. It is you doing your part as a development professional. It shakes out hard-coded bugs, such as hard-coded server names, paths and

replica IDs. It allows you to run extensive testing without affecting your company's production.

  Fundamental LotusScript Tip #4. How to code

Here are the fundamental how's and why's of how to code in LotusScript:

Always code for maintenance. Only code for performance if it is required. Make sure you get your code

working in general, before you get it working for speed.

Here is why you should follow these LotusScript how-to coding guidelines:

The highest cost in development is software maintenance. You make it easier for the person maintaining the application. You could be working on that application!

  Fundamental LotusScript Tip #5. "Measure twice, cut once"

"Measure twice, cut one" may sound a bit cliche, but it is a good analogy when you are writing LotusScript code. Here are a couple ways it applies.

You should always spend more time thinking about what you are coding and less time doing the actual coding.

You should always try to think of two different ways of solving the problem at hand. The best approach is usually a combination of the two, and you should always think about your data model.

This works well because you are spending more time planning and less time doing actual labor.

  Fundamental LotusScript Tip #6. Extending arrays the easy way

You should always try to use "ubound" to establish the size of your array. Below you will find an example of it in use.

Sub initialize() Dim myArray() as String redim my Array(0) call myExtend (myArray, "Hello Sailor"")end sub

Page 4: tutorial-30-lotusscript-tips1

function myExtend(S() as String, ns as String) as integer if (S(ubound(S)) <> "") then redim preserve S(ubound(S)+1) S (ubound(S)) = ns extend = trueend function

If you set up your arrays this way, you won't need to keep a separate index of the array size; it also automatically trims the code. However, there is a minor drawback to implementing this. It will slow down large arrays, so you'll need to define the "empty" value. Otherwise, it works great.

  Fundamental LotusScript Tip #7. Use the list operator

When you use the list operator, it stores a value with a unique lookup key. It's a good idea to use the list operator because:

It's easy and fast It's built right into LotusScript (as long as you're using version 4.5 or higher)

Here is some example code:

Dim WR list as StringWR("Peter") = "Perfect"WR("Penelope") = "Pitstop"

Print "Peter's last name is: " +WR("Peter")if not isElement(WR("Dick")) then print "Dick isn't racing!"forall thisRacer in WR Print listtag(thisracer) + " " + thisRacerend forall

  Fundamental LotusScript Tip #8. Logging agents

Another good tip is to log your LotusScript agents, especially if they are scheduled agents. It's also a good idea if you have a broad range of clients. If you do, you need to log both your client and scheduled agents runtime status.

If you don't log your agents, chances are that your applications will break. Logging your agents will also help to let you know when your LotusScript agents do break. It's also a good timing metric for performance testing.

Show caution when logging your agents though -- you don't want to make the logging so slow that it affects application performance!

  Fundamental LotusScript Tip #9. Code structure

When dealing with the structure of your LotusScript code, it is usually good to keep it as short as possible. Smaller code sequences are easier to deal with and maintain and are easily reusable. A good rule to go by is if your code is more than a screen's worth, you should determine if it is possible to break it up.

Some tips when determining your LotusScript code structure:

Try to keep your functions/procedures/classes at a manageable size. Think before decomposing problems.

Page 5: tutorial-30-lotusscript-tips1

Don't over comment -- explain your "why." Try to use non-intuitive algorithms.

  Fundamental LotusScript Tip #10. Hiding your code

When we say we're "hiding our code," we're basically saying that we're decomposing it so consumers can't see it. You don't want anyone to be able to view it, not even yourself. When you hide your code, you are inferring a logical interface with clear naming. As such, your users and customers can write to the interface but not the code itself. This is good practice because it simplifies the coding experience. You can easily hide your code by using "private/public" methods in your classes, script libraries, etc.

10 everyday LotusScript tips

1. Use error trapping 2. Use defensive coding 3. Protect your code 4. Use NotesDateTime instead of strings 5. Use DXL as Transport 6. Use wizard interface in your Notes client 7. Consuming Web services 8. Use classes 9. Use the Evaluate command 10.Use "trusted servers"

  Everyday LotusScript Tip #1. Use error trapping  

Error trapping tests a particular condition when running a program. If the program runs into an error, it will then execute a corresponding routine to fix the error. This should always be done. Error handling is not a joke -- it should always be handled in a serious manner and should always be mandatory.

There are two ways to go about this:

Use a single error handler at the top of your LotusScript code. It is simple to implement, but at times difficult to keep in context.

Implement your error handler at the function level. It's a little bit more work, but it's also much more granular.

  Everyday LotusScript Tip #2. Use defensive coding  

While it may seem a bit paranoid, you should practice using defensive LotusScript coding -- it will save you time in the long run. Always assume the worst and check all inputs on every function. It doesn't usually affect performance, but it is a good failsafe.

Here is a good example of defensive LotusScript coding in a typical function.

Function mytest (p1as String, p2 as String) as integer mytest = false if p1 = "" then exit function if p2 = "" then exit function . . . ' Now actually do something!

Page 6: tutorial-30-lotusscript-tips1

. . . . mytest = trueend function

  Everyday LotusScript Tip #3. Protect your code  

When creating commercial applications, it's a very good idea to hide your code. But, you may be asking how. There are actually two ways you can go about it:

Create a template and click on "hide design." This is easy to do, but it may end up allowing form customization.

You could also remove your LotusScript source code from your script libraries. Use the NotesNoteCollection command to find your script design document. Then replace the "$ScriptLib" with a String -- "Hello." This is not the easiest way to go about this process, but your other design elements can be modified as well. (Do not do this on your development copy!)

  Everyday LotusScript Tip #4. Use NotesDateTime instead of strings

You should never store date/time values as strings. It is always good practice to use NotesDateTime structures instead and save them.

You might say, sure, but why? Well, you never know how the client will interpret dates. Is it dd/mm/yyyy or mm/dd/yyyy? It also means that views will be able to sort on dates.

Trust me, this is a good tip to practice. This issue comes up more often than you might think.

  Everyday LotusScript Tip #5. Use DXL as Transport  

A good reason to consider using DXL as Transport stems from a situation where a customer wants to easily send back "log" documents. When this happens, you can use a LotusScript agent to:

Pick up all selected documents. Create a memo with a rich-text field. Use DXL to store the documents in the rich-text field.

At the receiving end, this will:

Unpack the mail message to a DXL stream. Construct new documents to store the data.

This way, you are transferring data without replication. Below is a sample code of this being implemented.

Dim sSession As New NotesSessionDim dbThis As notesDatabaseSet dbThis = sSession.CurrentDatabaseDim dc As NotesDocumentCollectionSet dc = dbThis.UnprocessedDocumentsIf (dc Is Nothing) Then exit subIf (dc.count < 1) Then exit subDim doc As NotesDocumentSet doc = dc.GetFirstDocumentWhile (Not doc Is Nothing)

Page 7: tutorial-30-lotusscript-tips1

Dim de As NotesDXLExporterSet de = sSession.CreateDXLExporter()Call de.setInput(doc)Dim dxl As Stringdxl = de.Export' continued overleaf..Dim dbMail As New NotesDatabase("", "")Call dbMail.OpenMail()Dim docM As NotesDocumentSet docM = dbMail.CreateDocumentCall docM.ReplaceItemValue("Form", "Memo")Call docM.ReplaceItemValue("Recipients", "[email protected]")Call docM.ReplaceItemValue("SendTo", "[email protected]")Call docM.ReplaceItemValue("Subject", "Log Documents")Dim rt As New NotesRichTextItem(docM, "Body")Call rt.AppendText(dxl)Call docM.Send(False)Set docM = NothingSet de = NothingSet doc = dc.GetNextDocument(doc)

Wend

  Everyday LotusScript Tip #6. Use a wizard interface in your Notes client

When using a wizard interface with your Lotus Notes client, there are a few steps you should follow:

Create a form with a tabbed table. Set the tabs to "1," "2," "3," etc. Select "Switch Rows Programmatically." Set the "name" field to the name of the table; for example: "RequestTable." Create a variable on the form with $Name; for example: "$RequestTable." Have your "forward" and "back" buttons increment/decrement the variable.

  Everyday LotusScript Tip #7. Consuming Web services

 

There are two different ways you can go about consuming Web services. The first is quick and to accomplish it, you should follow these steps:

Install Microsoft SOAP on client machines. Write LotusScript to create a Microsoft SOAP object. This is a good option

because it is quick and handy when it comes to testing. Unfortunately, it is platform-specific, requires dynamic link libraries on clients, and there is no timeout.

Below is some code that illustrates how to create the Microsoft SOAP object.

Dim Client As VariantSet Client = CreateObject("MSSOAP.SoapClient")'Initialize connection to the Web ServiceCall Client.mssoapinit

Page 8: tutorial-30-lotusscript-tips1

("http://localhost/testWS.nsf/Simple?wsdl")'Call our simple GetEmailAddress function provided by Web serviceDim result As Stringresult = Client.getJoke()'output result to message boxMessagebox result, 48, "Get Joke"

The other approach is a little different. It's big and robust and uses Stubby. Just point it at a Web service and it produces the code for you.

Some good points about it are that it is multi-platform, scalable and there are no dynamic link libraries. However, it does require you to use more than four lines of code.

Everyday LotusScript Tip #8. Use classes

When developing with LotusScript, it is always a good idea to use classes. Here are some reasons why:

Classes help to bundle data and code in one place. They decompose problems into "objects." They help to write smaller, more focused code. They help define and implement the internal data model. They aid reusability.

Classes have a good design methodology, which leads to Java. But everyone is not used to them and it may take time to sink in. Below you will see some code that implements classes.

Class Personprivate nName as NotesNameprivate strUNID as Stringsub new(strNewName as string, strNewUNID asString)me.nnName = new NotesName(strNewName)me.strUNID = strNewUNIDend subpublic function getName as Stringif (me.nnName is nothing) then exit functiongetName = nnName.Canonicalend functionpublic function getUNID as StringgetUNID = strUNIDend function

end class

  Everyday LotusScript Tip #9. Use the Evaluate command

The Evaluate command allows you to run @Functions within LotusScript. It is sometimes quicker and easier, as it allows you to use your favorite function in certain situations. An example of it might be:

evaluate(|@unique|)

Page 9: tutorial-30-lotusscript-tips1

Don't overuse it though. Loads of LotusScript functions mimic @functions.

  Everyday LotusScript Tip #10. Use "trusted servers"  

It is good practice to use trusted servers because scheduled agents cannot normally open databases on other servers.

The "trusted servers" field in a Lotus Domino R6 server document's security section allows servers to trust other servers. By doing this, it allows you to centralize "collection" agents. You also simplify your architecture and limit the number of agents you use. However, it does rely on a fast, reliable network infrastructure.

As a final note, make sure to never trust servers in another domain.

10 advanced LotusScript tips

1. Understand binding 2. Code for performance 3. Use lists and classes 4. Use class inheritance 5. Use platform-specific LotusScript code with classes 6. Use version-specific LotusScript code with classes 7. Use LSI_Info()/GetThreadInfo 8. Use the execute command 9. Use advanced logging 10. Mixing Java and LotusScript

Advanced LotusScript Tip #1. Understand binding

There are two types of binding: early binding and late binding.

Early binding is set by the compiler and works well because it uses type checking, works quickly and is easy to use. An example of early binding might be:

Dim S as String

Late binding is set at runtime. It is very flexible, but doesn't use type checking. Unfortunately, the performance isn't as good as early binding and you might run into some runtime errors.

Dim V as variantDim S as new NotesSessionset V = S.CurrentDatabaseprint V.getTitle()

Advanced LotusScript Tip #2. Code for performance

When you're coding for performance, always remember that expensive operations include opening Lotus Notes databases, and views and documents with lots of fields. So, when you're collecting data, remember to cache views wherever possible and use

Page 10: tutorial-30-lotusscript-tips1

NotesViewEntry instead of opening documents.

As an example, let's say you have a Lotus Notes database with 100,000 documents in it. This would take seven hours to actually open every document in the Lotus Notes database, if you don't code for performance and use views. If you do code for performance, it will only take you 60 minutes to open these using NotesView and only 12 minutes if you use NotesViewEntry!

Advanced LotusScript Tip #3. Use lists and classes

It's good practice to use LotusScript lists and classes because classes bind complex data and operations. Lists can look these up quickly in memory. For a quick example, here's how we might extend our Person class:

dim People list as Persondim PeopleByUNID list as PersonDim P as new Person("Joe Bloggs/ACME", "010101010201020")....set People(P.getName) = Pset PeopleByUNID(P.getUNID) = Pif (isElement(People("Joe Bloggs/ACME"))) then _Print "Joe's UNID is: " + People("Joe Bloggs/ACME").getUNIDif (isElement(PeopleByUNID("010101010201020"))) then _Print "UNID '010101010201020' is: " + _PeopleByUNID("010101010201020").getName

Advanced LotusScript Tip #4. Use class inheritance

Class inheritance allows us to "Extend" classes to add functionality. For example:

class StaffPerson as Personprivate strStaffID as Stringsub new(strNewPerson as String, strNewUNID as String)end subpublic function setStaffNumber(newNo as String)strStaffID = newNoend functionpublic function getStaffNumber as StringgetStaffNumber = me.strStaffIDend function

end class

Advanced LotusScript Tip #5. Use platform-specific code with classes

Dim s as new NotesSessionDim mem as variantselect case s.platformcase "Windows/32"set mem = new getMemW32()case "AIX"set mem = new getMemAIX()case elsePrint "Platform not supported"set mem = nothingend caseif (not mem is nothing) then

Page 11: tutorial-30-lotusscript-tips1

call mem.printMemory()

Class getMemfunction getMem() as longgetMem = 0end functionsub printMemoryprint me.getMem()end sub

end class

Class getMemW32 as getMemfunction getMem() as longgetMem = getWindowsMemory()end functionend class

Class getMemAIX as getMemfunction getMem() as longgetMem = getAIXMemory()end function

end class

Advanced LotusScript Tip #6. Use version-specific code with classes

Dim s as new NotesSessiondim vCU as variantselect case s.version

case 5set vCU = new createUser()case 6set vCU = new createUserv6()case elsePrint "Version not supported"set vCU = nothing

end caseif (not vCU is nothing) then call vCU.CreateUser(....)

Class createUserfunction createUser(...) as integer....end functionend class

Class createUserv6 as createUserfunction createUser(...) as integer....end function

end class

Advanced LotusScript Tip #7. Use LSI_Info()/GetThreadInfo

You can use the LSI_INFO() command to get some runtime information. Be aware though that this information is superceded by the GetThreadInfo command.

If you use GetThreadInfo(11), that will return you the calling class. If you use GetThreadInfo(10), that will return you the function name. And these are just the beginning.

Through error trapping, we can track where we came from. We don't have to pass lists of parameters to error trapping code. It also prevents coding errors through using the copy and paste method. Here is an example of this in use, preceded by the calling

Page 12: tutorial-30-lotusscript-tips1

code:

' calling code...ExitFunction:exit functionerrorhandler:Call RaiseError()resume exitFunctionend functionFunction RaiseError() Dim thisType As String Dim es as String thisType = Typename(Me) ' Not a class, use the calling module instead If (thisType = "") Then thisType = Getthreadinfo(11) es = thisType & "::" & Getthreadinfo(10) & ": " If (Err = 0) Then es = es + "Manually raised an error" Else es = es + "Run time error: (" + Trim(Str(Err)) + ") " + Error$ + " at line: "+ Trim(Str(Erl)) End If Print esend functionAdvanced LotusScript Tip #8. Use the execute command

By using the execute command, you can run LotusScript from a string. Doing this accommodates version/platform differences at runtime. Here's an example:

Dim executeString as StringexecuteString = |print "Hello world"dim s as new NotesSessiondim db as NotesDatabaseset db = s.currentDatabaseprint "Current Database name is: " + db.Title|execute (executeString)

Advanced LotusScript Tip #9. Use advanced logging

By using the OpenNTF "OpenLog" solution, you can make simple LotusScript library additions to your code, provide "called from," "error," and "line number" functionality. Our system now works on error trap and displays all objects in memory.

Advanced LotusScript Tip #10. Mixing Java and LotusScript

By mixing Java and LotusScript together, you can really get the most out of each scripting language. The trick is to use each language to its strengths. For example, Java is good for Web service, network I/O, and multithreaded operations. LotusScript is the traditional Lotus Notes development language and works in the user interface.

Mixing the two languages together is easy -- just call an agent, passing a Lotus Notes document.

You should also know that this works both ways, as you can call Java from LotusScript. This is called LS2J. An example is below:

Page 13: tutorial-30-lotusscript-tips1

// Create a Script Library of type "Java" called xlib// containing the following function:public class calculator {public int add(int a, int b) { return a + b; }public int div(int a, int b) { return a / b; }public int mul(int a, int b) { return a * b; }public int sub(int a, int b) { return a - b; }}Option PublicUse "xlib"Uselsx "*javacon"Sub Initialize

Dim mySession As JavaSessionDim myClass As JavaClass, calculator As JavaObject, a,b,c As IntegerSet mySession = New JavaSession()Set myClass = mySession.GetClass("calculator")Set calculator = myClass.CreateObject()a = 10b = 5c = calculator.mul(a,b)MessageBox "a * b = " & c

End Sub