Your SlideShare is downloading. ×
Ad505 dev blast
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Ad505 dev blast

130
views

Published on

Published in: Technology, Business

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
130
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. ®AD505 DevBlast – 30 LotusScript TipsBill Buchan - HADSL
  • 2. AgendaIntroductionNursery SlopesEveryday TipsAdvanced TipsConclusion
  • 3. IntroductionWhat is this about?This talk aims to run through 30 different LotusScript tips10 of these tips (Nursery Slopes) are fundamental10 of these tips (Everyday Tips) are less well known10 of these tips (Advanced Tips) are there toprovoke thought
  • 4. Introduction (cont.)Why 30 tips?“The Lazy Programmer” methodologyExperience and understandingPush your comfort zone and provoke thoughtWho am I?Bill BuchanDual PCLP in v3, v4, v5, v6, v710+ years senior development consultancy forEnterprise customersLearn from my pain!5+ years code auditingCEO – HADSL – developing best-practice tools
  • 5. AgendaIntroductionNursery SlopesEveryday TipsAdvanced TipsConclusion
  • 6. NS #1: Option DeclareYou should always use “Option Declare”Yes, but why?If not, all variables are created at runtime as variantsThis makes type-checking redundantData conversion costs 10x performance!And means all errors will be runtime errorsRemember: Test lots, test earlyUse the strengths of the compiler to help you
  • 7. NS #2: Templates and VersionsIn terms of custom code, you should alwaysCreate templates with new codeDatabases with “ntf” extensionOr databases with Master Template Name setCreate a separate copy for each versionKeep them in a central repositoryWhy?It makes it far easier to roll backVersion controlEasier to construct test cases with “other” versions
  • 8. NS #3: Application LifecycleYou should always:Develop in a development “sandbox”Test in a user acceptance environmentPass the template to your administrator to applyWhy?It’s a basic change control systemProfessionalismIt shakes out “hardcoded” bugsHardcoded server names, paths, replica IDsIt allows you to run extensive testing withoutaffecting production
  • 9. NS #4: How to CodeHow to code?Code for maintenanceOnly code for performance if requiredGet it working before you get it working for speedWhy?The highest cost in development is software maintenanceMake it easier for the person maintaining the applicationIt could be YOU
  • 10. NS #5: “Measure Twice, Cut Once”Spend more time thinking and less time codingTry to think of at least TWO methods of solvinga problemThe best approach is usually a blend of the twoThink about the data model!Why?More planning, less work“You know it’s been a rough night when you wake up next to somecode you don’t recognize”- Bob Balaban
  • 11. NS #6: Extending Arrays the Easy WayUse “ubound” to establish the size of the array.Pros:No need to keep separate index of array size, Automatically “trims”Cons:Slow with large arrays, Need to define some “empty” valueSub initialize()Dim myArray() as Stringredim myArray(0)call myExtend (myArray, “Hello Sailor”)end subfunction myExtend(S() as String, ns as String) as integerif (S(ubound(S)) <> “”) then redim preserve S(ubound(S)+1)S(ubound(S)) = nsextend = trueend function
  • 12. NS #7: The List OperatorList stores a value with a unique lookup keyPros:It’s easy and it’s fastIt’s built right into LotusScript, since v4.5Cons:You can’t directly read and write a list froma document item– Convert to an array firstDim 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 WRPrint listtag(thisracer) + “ “ + thisRacerend forall
  • 13. NS #8: LoggingIf you have applications with scheduled AgentsOr if you have a diverse range of clientsThen you need to log your Agent (both client and scheduled) runtime statusWhy?Applications will breakYou need to know when they breakTiming metrics for performance testingBeware!Don’t make the logging so slow that it affects application performance!
  • 14. NS #9: Code StructureProblem Decomposition:Smaller code sequences are easier to:Maintain – the majority of the costReuse – if kept simpleRule of thumb: If it’s more than a screenful – can it be broken up?But – don’t be prescriptiveIt’s all aboutProblem decompositionMaintainabilityCode re-useGet the data model right to start with!
  • 15. NS #9: Code Structure (cont.)Tips:Keep functions/procedures/classes at a manageable sizeBut don’t be prescriptiveThink before decomposing problemsDiscussion“Declare at the top” or “Declare in the code”I prefer to declare variables in the codeCommentsDon’t over comment – explain the “Why”!I usually only comment non-intuitive algorithms“This isn’t what you think … ”Comment pseudocode to start with
  • 16. NS #10: Code HidingCode hidingMeans decomposing your code so that consumers don’t see your codeIncluding yourselfInfers a logical interface (with clear naming!)Customers/peers now write to the “interface”Not the code itselfIt simplifies the coding experienceHow?“Private/Public” methods in classes, script libraries, etc.
  • 17. AgendaIntroductionNursery SlopesEveryday TipsAdvanced TipsConclusion
  • 18. ED #1: Error TrappingIf I hear “I write perfect code. I don’t need error trapping,” I think oftwo things“Yeah, right”“Fire this guy”Error handling is mandatory. Seriously.Now, how? Two routes:Single error handler at the top, bubble errors upSimple, but difficult keeping contextError handler implemented at function levelMore work, but much more granular
  • 19. ED #2: Defensive CodingDefensive coding is:Assume the worst, check all inputOn every functionDoes this affect performance? Not usuallyA typical function looks like:Function mytest(p1 as String, p2 as String) as integermytest = falseif p1=”” then exit functionif p2=”” then exit function... Now actually do something!....mytest = trueend function
  • 20. ED #3: Protecting CodeCommercial applications need to hide their code. How?Create a template and “hide design”Pro: EasyCon: You may allow form customization, etc.Or remove LotusScript source code from script librariesUse NotesNoteCollection to find script design documentReplace item “$ScriptLib” with a String – “Hello”– Con: Not so simple– Pro: Other design elements can be modifiedDon’t do this on your development copy …
  • 21. ED #4: Use NotesDateTime Instead of Strings!Don’t store date/time values as StringsUse NotesDateTime structures, and save themWhy?You don’t know how the client will interpret dates …Is it dd/mm/yyyy or mm/dd/yyyy?It means that views will be able to sort on datesThis happens more often than you think!
  • 22. ED #5: DXL as TransportConsider the situation where your customer wants to send back“log” documents easilyUse a LotusScript Agent to:Pick up all selected documentsCreate a Memo with a Rich Text FieldUse DXL to store the documents in the RT fieldAt the receiving end:Unpack the mail message to a DXL StreamConstruct new documents to store the dataThis is data transfer without replication
  • 23. ED #5: DXL as Transport Example Code – SendDim 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)Dim de As NotesDXLExporterSet de = sSession.CreateDXLExporter()Call de.setInput(doc)Dim dxl As Stringdxl = de.Export continued overleaf..Actual Work
  • 24. ED #5: DXL as Transport Example Code – SendDim dbMail As New NotesDatabase("", "")Call dbMail.OpenMail()Dim docM As NotesDocumentSet docM = dbMail.CreateDocumentCall 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 = NothingSet de = NothingSet doc = dc.GetNextDocument(doc)Wend
  • 25. ED #6: WizardsA Wizard interface in Notes Client:Create a form with a tabbed tableSet the tabs to “1”, “2”, “3”, etc.Select “Switch Rows Programmatically”Set the “name” field to the name of the tablee.g., “RequestTable”Create a variable on the form with $Namee.g., “$RequestTable”Have “forward” and “back” buttons increment/decrementthe variable
  • 26. ED #7: Consuming Web ServicesTwo approachesQuick and dirtyInstall MS Soap on client machinesWrite LotusScript to create an MS Soap Object– Pro: Very quick, handy for testing– Con: Platform specific, requires DLLon clients, no timeoutDim Client As VariantSet Client = CreateObject("MSSOAP.SoapClient")Initialize connection to the Web ServiceCall Client.mssoapinit ("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"
  • 27. Second ApproachBig and robustUse “Stubby”http://www.openNtf.orgPoint it at a web serviceIt produces the code for you!Pro:Multi-platform, scalableNo DLL’sConIts more than 4 lines of code.ED #7: Consuming Web Services (cont.)
  • 28. What are Classes?Classes help to:Bundle data and code in one placeDecompose problems into “objects”Write smaller, more focused codeDefine and implement the internal data modelClasses aid reusabilityPros: Good design methodology, leads to JavaCons: “Different,” and takes time to sink inED #8: Classes
  • 29. ED #8: Classes (cont.)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 functionend class
  • 30. ED #9: EvaluateEvaluate allows you to run @Functions within LotusScriptSometimes faster, easierExample:evaluate(|@unique|)DON’T:Overuse it. Lots of LotusScript functions mimic @functions.“strRight” == @StrRight
  • 31. ED #10: “Trusted Servers”Scheduled Agents cannot normally open databases on other servers“Trusted Servers” field in R6 server document, security section, allows servers to“trust” other serversThis allows you to centralize “collection” AgentsCaveat: Don’t trust servers in another domain!Pros:Simplifies architectureFewer AgentsCon:Relies on fast, reliable network infrastructure …
  • 32. AgendaIntroductionNursery SlopesEveryday TipsAdvanced TipsConclusion
  • 33. Advanced #1: Understanding BindingThere are two types of bindingEarly: Set by the compilerPros: Type checking, speed, and ease of useExample: “Dim S as String”Late: Set at runtimePros: Flexibility, NO type checkingCons: Performance, runtime errorsDim V as variantDim S as new NotesSessionset V = S.CurrentDatabaseprint V.getTitle()
  • 34. Advanced #2: Coding for PerformanceRemember – Expensive operations include:Opening databases and viewsDocuments with lots of fieldsWhen collecting data:Cache views where possibleUse NotesViewEntry instead of opening documentsExample:100,000 document database7 hours for “open every document in database”Not using views60 minutes using NotesView and opening documents12 minutes for “notesviewEntry”
  • 35. Advanced #3: Lists and ClassesClasses bind complex data and operations - List looks these upquickly in memoryExample – Let’s 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 “Joes UNID is: “ + People(“Joe Bloggs/ACME”).getUNIDif (isElement(PeopleByUNID(“010101010201020”))) then _Print “UNID 010101010201020 is: “ + _PeopleByUNID(“010101010201020”).getName
  • 36. Advanced #4: Class InheritanceClass inheritance allows us to “Extend” classes toadd functionalityclass 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 functionend class
  • 37. Advanced #5: Platform-Specific Code With ClassesClass getMemfunction getMem() as longgetMem = 0end functionsub printMemoryprint me.getMem()end subend classClass getMemW32 as getMemfunction getMem() as longgetMem = getWindowsMemory()end functionend classClass getMemAIX as getMemfunction getMem() as longgetMem = getAIXMemory()end functionend classDim 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) thencall mem.printMemory()
  • 38. Advanced #6: Version-Specific Code With ClassesClass createUserfunction createUser(...) as integer....end functionend classClass createUserv6 as createUserfunction createUser(...) as integer....end functionend classDim s as new NotesSessiondim vCU as variantselect case s.versioncase 5set vCU = new createUser()case 6set vCU = new createUserv6()case elsePrint “Version not supported”set vCU = nothingend caseif (not vCU is nothing) then _call vCU.CreateUser(....)
  • 39. Advanced #7: LSI_Info()/GetThreadInfoLSI_INFO() gives some runtime informationSuperceded by GetThreadInfoGetThreadInfo(11) gives calling classGetThreadInfo(10) gives function nameand lots more …Why?Error trapping: We can track where we came fromWe don’t have to pass lists of parameters to errortrapping codePrevents “cut-n-paste coding” errors ...
  • 40. Advanced #7: LSI_Info()/GetThreadInfo (cont.)Function RaiseError()Dim thisType As StringDim es as StringthisType = Typename(Me) Not a class, use the calling module insteadIf (thisType = "") Then thisType = Getthreadinfo(11)es = thisType & "::" & Getthreadinfo(10) & ": "If (Err = 0) Thenes = es + "Manually raised an error"Elsees = es + "Run time error: (" + Trim(Str(Err)) + ") " + _Error$ + " at line: "+ Trim(Str(Erl))End IfPrint esend function calling code......ExitFunction:exit functionerrorhandler:Call RaiseError()resume exitFunctionend function
  • 41. Advanced #8: ExecuteExecute runs LotusScript code from a String• Example:• Why?Accomodates version/platform differences at runtimeDim 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)
  • 42. Advanced #9: Advanced LoggingOpenNtf “OpenLog” solution:Simple script library addition to your codeProvides “called from”, “error”, and “Line number” functionalitySimple to implementExample of our “NSD” system:On error trapDisplays all objects in memory
  • 43. Advanced #10: Mixing Java and LotusScriptUse each language to its strengthsJava – good for Web services, network I/O, multithreaded operationsLotusScript – traditional Notes development language, works in UIHow to mix:Simple: Call an Agent, passing a Notes documentFast. I didn’t say you had to save the document!Works both waysLS2JCall Java from LotusScriptExample on the next slide ...
  • 44. Advanced #10: Mixing Java and LotusScript …Option PublicUse "xlib"Uselsx "*javacon"Sub InitializeDim 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 = " & cEnd Sub// 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; }}
  • 45. AgendaIntroductionNursery SlopesEveryday TipsAdvanced TipsConclusion
  • 46. ResourcesHomework:Classes – My OO presentationhttp://www.billbuchan.com/web.nsf/htdocs/BBUN6MQECQ.htmSteve McConnell, Code Complete 2 (MS Press, 2004).www.amazon.com/gp/product/0735619670Duffbert’s presentation on Javahttp://hostit1.connectria.com/twduff/home.nsf/htdocs/TDUF5VAQSY.htmBob Balaban, Programming Domino 4.6 with Java(M&T Books, 1998).www.amazon.com/gp/product/1558515836
  • 47. Resources (cont.)LS 2004/AD104 – LotusScript Tips & Trickswww-10.lotus.com/ldd/sandbox.nsfSearchDomino.com – LotusScript Learning Guidehttp://searchdomino.techtarget.com/originalContent/0,289142,sid4_gci1001826,00.htmlNSFTools – Notes Tipswww.nsftools.com/tips/NotesTips.htmThe Notes FAQ !www.keysolutions.com/NotesFAQ/
  • 48. Resources (cont.)Brian Benz and Rocky Oliver, Lotus Notes and Domino 6Programming Bible (Wiley 2003).www.amazon.com/gp/product/0764526111Notes.Net (of course)www.notes.netAll my presentations and materials are available on my blog:http://www.billbuchan.comThe View magazinehttp://www.eView.comLotus Advisorhttp://www.lotusAdvisor.com
  • 49. Questions and AnswersLimited Time for QuestionsI’m available in the speaker room immediately after this session.Remember to fill in your Evaluations.This is how YOU influence Lotusphere 2008!