Tutorial: 30 LotusScript tips
Tutorial: 30 LotusScript tips | |
|[pic] |
|27 Mar 2007 | |
|[pic] |
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.
[pic]
[pic]TUTORIAL: 30 LOTUSSCRIPT TIPS
[pic]
[pic] Home: Introduction
[pic] Part 1: 10 fundamental LotusScript tips
[pic] Part 2: 10 everyday LotusScript tips
[pic] Part 3: 10 advanced LotusScript tips
[pic] Part 4: More LotusScript learning resources
LOTUSSCRIPT
10 fundamental LotusScript tips
|[pic][pic]Option Declare |
|Templates and versions |
|Application lifecycles |
|How to code |
|"Measure twice, cut once" |
|Extending arrays the easy way |
|Use the list operator |
|Logging agents |
|Code structure |
|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: |
|Because it makes it much easier to roll back. |
|It helps with version control. |
|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: |
|Always develop in a development sandbox -- a non-production environment where each developer keeps his or her working copy of the code base. |
|Always test in a user acceptance environment. |
|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
[pic]
|Use error trapping |
|Use defensive coding |
|Protect your code |
|Use NotesDateTime instead of strings |
|Use DXL as Transport |
|Use wizard interface in your Notes client |
|Consuming Web services |
|Use classes |
|Use the Evaluate command |
|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@") |
|Call docM.ReplaceItemValue |
|("SendTo", "logs@") |
|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 |
|("") |
|'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
[pic]
|Understand binding |
|Code for performance |
|Use lists and classes |
|Use class inheritance |
|Use platform-specific LotusScript code with classes |
|Use version-specific LotusScript code with classes |
|Use LSI_Info()/GetThreadInfo |
|Use the execute command |
|Use advanced logging |
|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 variant |
|Dim S as new NotesSession |
|set V = S.CurrentDatabase |
|print 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 |
................
................
In order to avoid copyright disputes, this page is only a partial summary.
To fulfill the demand for quickly locating and searching documents.
It is intelligent file search solution for home and business.
Related searches
- free excel tutorial download pdf
- printable excel tutorial in pdf
- microsoft excel tutorial pdf download
- ms excel 2013 tutorial pdf
- free basic excel tutorial pdf
- 30 year fha vs 30 year fixed
- 30 30 ammo ballistics
- 30 30 bullet drop chart
- 30 30 range chart
- 30 30 rifle prices walmart
- 30 30 bullet trajectory chart
- 30 dates in 30 days