Vous êtes sur la page 1sur 13

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

LOTUSSCRIPT

10 fundamental LotusScript tips


1. 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 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 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 = true end 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 String WR("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) + " " + thisRacer end 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. 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! . . . . mytest = true end 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 NotesSession Dim dbThis As notesDatabase Set dbThis = sSession.CurrentDatabase Dim dc As NotesDocumentCollection Set dc = dbThis.UnprocessedDocuments If (dc Is Nothing) Then exit sub If (dc.count < 1) Then exit sub Dim doc As NotesDocument Set doc = dc.GetFirstDocument While (Not doc Is Nothing) Dim de As NotesDXLExporter Set de = sSession.CreateDXLExporter() Call de.setInput(doc) Dim dxl As String dxl = de.Export ' continued overleaf.. Dim dbMail As New NotesDatabase("", "")

Call dbMail.OpenMail() Dim docM As NotesDocument Set docM = dbMail.CreateDocument Call docM.ReplaceItemValue ("Form", "Memo") Call docM.ReplaceItemValue ("Recipients", "logs@hadsl.com") Call docM.ReplaceItemValue ("SendTo", "logs@hadsl.com") Call docM.ReplaceItemValue ("Subject", "Log Documents") Dim rt As New NotesRichTextItem (docM, "Body") Call rt.AppendText(dxl) Call docM.Send(False) Set docM = Nothing Set de = Nothing Set 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 Variant Set Client = CreateObject("MSSOAP.SoapClient") 'Initialize connection to the Web Service Call Client.mssoapinit ("http://localhost/testWS.nsf/Simple?wsdl") 'Call our simple GetEmailAddress function provided by Web service Dim result As String result = Client.getJoke() 'output result to message box Messagebox 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 Person private nName as NotesName private strUNID as String sub new(strNewName as string, strNewUNID asString) me.nnName = new NotesName(strNewName) me.strUNID = strNewUNID end sub public function getName as String if (me.nnName is nothing) then exit function getName = nnName.Canonical end function public function getUNID as String getUNID = strUNID end 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|)

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 Dim S set V print as variant as new NotesSession = S.CurrentDatabase 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 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 Person dim PeopleByUNID list as Person Dim P as new Person ("Joe Bloggs/ACME", "010101010201020") .... set People(P.getName) = P set PeopleByUNID(P.getUNID) = P if (isElement(People("Joe Bloggs/ACME"))) then _ Print "Joe's UNID is: " + People("Joe Bloggs/ACME").getUNID if (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 Person private strStaffID as String sub new(strNewPerson as String, strNewUNID as String) end sub public function setStaffNumber(newNo as String) strStaffID = newNo end function public function getStaffNumber as String getStaffNumber = me.strStaffID end function end class

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


Dim s as new NotesSession Dim mem as variant select case s.platform case "Windows/32" set mem = new getMemW32() case "AIX" set mem = new getMemAIX() case else Print "Platform not supported" set mem = nothing end case if (not mem is nothing) then call mem.printMemory() Class getMem function getMem() as long getMem = 0 end function sub printMemory print me.getMem() end sub end class Class getMemW32 as getMem function getMem() as long getMem = getWindowsMemory()

end function end class Class getMemAIX as getMem function getMem() as long getMem = getAIXMemory() end function end class

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


Dim s as new NotesSession dim vCU as variant select case s.version case 5 set vCU = new createUser() case 6 set vCU = new createUserv6() case else Print "Version not supported" set vCU = nothing end case if (not vCU is nothing) then call vCU.CreateUser(....) Class createUser function createUser(...) as integer .... end function end class Class createUserv6 as createUser function 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 code:
' calling code... ExitFunction: exit function errorhandler: Call RaiseError() resume exitFunction end function Function 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 es end function

Advanced 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 String executeString = | print "Hello world" dim s as new NotesSession dim db as NotesDatabase set db = s.currentDatabase print "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:
// 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 Public Use "xlib" Uselsx "*javacon" Sub Initialize Dim mySession As JavaSession Dim myClass As JavaClass, calculator As JavaObject, a,b,c As Integer Set mySession = New JavaSession() Set myClass = mySession.GetClass("calculator")

Set calculator = myClass.CreateObject() a = 10 b = 5 c = calculator.mul(a,b) MessageBox "a * b = " & c End Sub

Vous aimerez peut-être aussi