Your SlideShare is downloading. ×
  • Like
  • Save
Dev buchan 30 proven tips
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Now you can save presentations on your phone or tablet

Available for both IPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Dev buchan 30 proven tips

  • 259 views
Published

 

Published in Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
259
On SlideShare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
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. © 2007 Wellesley Information Services. All rights reserved.30 Proven Tips toOptimize YourLotusScriptDevelopmentBill BuchanHADSL
  • 2. 2What We’ll Cover …• Introduction• Theory• Practice• Advanced• Wrap-up
  • 3. 3Introduction• Who is the target audience? Lotus Notes Developers• What is this about? This talk aims to run through 30 different LotusScript tips 10 of these tips (“Theory”) are fundamental 10 of these tips (“Practice”) are what you should be doing 10 of these tips (“Advanced”) are there to provoke thought
  • 4. 4Introduction (cont.)• Why 30 tips? “The Lazy Programmer” methodology Experience and understanding Push your comfort zone and provoke thought• Who am I? Bill Buchan Dual PCLP in v3, v4, v5, v6, v7 10+ years senior development for Enterprise customers Learn from my pain! 5+ years code auditing CEO – HADSL – developing best-practice tools
  • 5. 5What We’ll Cover …• Introduction• Theory• Practice• Advanced• Wrap-up
  • 6. 6Theory #1: Option Declare• You should always use “Option Declare”• Yes, but why? If not, all variables are created at run-time as variants This makes type-checking redundant Data conversion costs ten times more performance! And means all errors will be run-time errors Remember: Test lots, test early Use the strengths of the compiler to help you
  • 7. 7Theory #2: Templates and Versions• In terms of custom code, you should always: Create templates with new code Databases with “ntf” extension OR databases with Master Template Name set Create a separate copy for each version Keep them in a central repository• Why? It makes it far easier to roll back Version control Easier to construct test cases with “other” versions
  • 8. 8Theory #3: Application Lifecycle• You should always: Develop in a development “sandbox” Test in a user acceptance environment Pass the template to your administrator to apply• Why? It’s a basic change control system Professionalism It shakes out “hardcoded” bugs Hardcoded server names, paths, replica IDs It allows you to run extensive testing without affectingproduction
  • 9. 9Theory #3: Application Lifecycle (cont.)managerDevDeveloper managerAdministratorUATProductionmanagereditoruser
  • 10. 10Theory #4: “Measure Twice, Cut Once”• Spend more time thinking and less time coding• Think of at least TWO methods of solving a problem The best approach is usually a blend of the two Think about the data model!• Why? More planning, less work• “You know it’s been a rough nightwhen you wake up next to somecode you don’t recognize.”– Bob Balaban
  • 11. 11Theory #5: Code Structure• Problem decomposition: Smaller code sequences are easier to: Maintain – the majority of the cost Reuse – if kept simple Rule of thumb: If its more than a screenful – can it bebroken up? But – don’t be prescriptive• It’s all about: Problem decomposition Maintainability Code reuse Get the data model right to start with!
  • 12. 12Theory #5: Code Structure (cont.)• Tips: Keep functions/procedures/classes at a manageable size But don’t be prescriptive Think before decomposing problems• Discussion “Declare at the top” or “Declare in the code” I prefer to declare variables in the code
  • 13. 13Theory #6: How to Code• How to code Code for maintenance Code updates cost more than new code Architect well. Get the data model right to start with.• Only code for performance, if required Get it working before getting it working for speed• Why? The highest cost in development is software maintenance Make it easier for the person maintaining the app It could be YOU
  • 14. 14Theory #7: How to Test• Test soon, test often, test completely Look at test-driven development Write the specification Write the structure Write the tests Write the code Automatic testing means: Far easier to regression test all the time Minimize run-time errors by: Always assuming that data operations outside the currentdatabase may fail Trapping all run-time errors and providing an executionpath that fails safely
  • 15. 15Theory #7: How to Test (cont.)• Why test early? Costs rise as the tests fail further away from development Cheapest to most expensive are: Unit tests — by the developer User acceptance tests (UATs) — by the tester End-user failure — by the user The more tests you perform in unit testing: The cheaper your development will be The more professional your colleagues will think you are The more your boss will like you
  • 16. 16Theory #8: “Attitude”• The first rule of Best Practices is: There is no Best Practice!• Seriously: Don’t use Best Practices in a prescriptive manner Examine each one and decide whether it makes sense inthis context Be open to new ideas• Attitude is better than prescriptive coding No “Not invented here” syndrome Collaborate “The Lazy Programmer”
  • 17. 17Theory #9: Comments• Comments Don’t over-comment – explain the “Why!” I usually only comment non-intuitive algorithms “This isn’t what you think … ”• A good use of comments is to write meta-code For instance, when first writing a function, write the code-branches as a series of comments Leave them in once the code is completeFunction test (param1 as String, param2 as String) as integer check the parameters and bail out if incorrect. Add Param 1 to param 2 Check it’s valid. If so – update... Errorhandlerend function
  • 18. 18Theory #9: Comments (cont.)• Remember: Comments consume code space in LotusScript There’s a 64k — about 1,400 line — limit for each codesequence This should not normally be an issue Classes, of course, are all declared in Declarations In terms of classes, you can “subclass” to break up largeclass declarations• Check out LotusScript.doc: www.lsdoc.org It’s a “JavaDoc for LotusScript” You can annotate code to make the comments clearer
  • 19. 19Theory #10: Error Handling• An Error is thrown at run-time when: A resource is unavailable: Database, server, memory File I/O breaks Etc., etc.• Execution stops at the point of error• Sets error information: Error$ — a textual description Err — a numeric error code Erl — the line number of the error• Jumps to the error handling routine If there is no error handling routine in the current codesequence, jumps to calling function If top-level function has no error handler, then default errorhandling is used
  • 20. 20Theory #10: Error Handling (cont.)• If an error occurs in the middle of a critical sequence ofupdates, possibly some updates will happen, and somewill not Serious data consistency errors Get all your validation done before committing transactions Perform all the transaction “commits” at the same time In our case, all the “saves” Defensive coding minimizes this effect Do not use “on error goto next”• You must deal with errors
  • 21. 21Theory #10: Error Handling (cont.)• Two approaches: Error trap in almost every routine Very granular, lots of information Minimal chance of breaking transactions However, lots of code Error trap at the top Very simple, minimal code You will lose context — you might not be able to get validdata on how the error happened You might break transactions — and therefore compromisedata integrity• I recommend: Error trap in most routines!
  • 22. 22What We’ll Cover …• Introduction• Theory• Practice• Advanced• Wrap-up
  • 23. 23Practice #1: The List Operator• List stores a value with a unique lookup key Pros: It’s easy and it’s fast It’s built right into LotusScript, since v4.5 Cons: You can’t directly read and write a list from a documentitem – convert to an array firstDim Pres list as StringPres(“George”) = “Bush”Pres(“Bill”) = “Clinton”Print “Georges’s last name is: “ + Pres(“George”)if not isElement(Pres(“Chad”)) then print “Chad wasn’tfound”forall thisPres in PresPrint listtag(thisPres) + “ “ + thisPresend forall
  • 24. 24Practice #2: Defensive Coding• Defensive coding is: Assume the worst, check all input On every function Does this affect performance? Not usually. A typical function looks like:Function mytest(p1 as String, p2 as String) asintegermytest = falseif p1=”” then exit functionif p2=”” then exit function... Now actually do something!....mytest = trueend function
  • 25. 25Practice #3: Extending Arrays the Easy Way• 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
  • 26. 26Practice #4: Logging• If you have applications with scheduled Agents• Or, if you have a diverse range of clients Then, you need to log your Agent (both client and scheduled)run-time status• Why? Applications will break You need to know when they break Timing metrics for performance testing• Beware! Don’t make the loggingso slow that it affectsapplication performance!
  • 27. 27Practice #4: Logging (cont.)• OpenLog is an OpenNTF Project: www.openntf.org• It provides a framework for collecting error logging To use in your database: Copy the script libraries from the OpenLog database Update the code:Function test(param1 as String) as integerTest = falseon error goto errorhandler ...Test = trueexitFunction:exit functionerrorhandler:call logError()resume exitfunctionend function
  • 28. 28Practice #4: Logging (cont.)• Example OpenLog output:
  • 29. 29Practice #5: Code Hiding• Code hiding Means decomposing your code so that consumers don’t seeyour code Including yourself Infers a logical interface (with clear naming!) Customers/peers now write to the “interface” Not the code itself It simplifies the coding experience How? “Private/Public” methods in classes, script libraries, etc.
  • 30. 30Practice #6: Use NotesDateTime Instead of Strings!• Don’t store date/time values as Strings• Use NotesDateTime structures, and save them• Why? 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 dates• This happens more often than you think! And things always break on the 13th of the month
  • 31. 31Practice #7: Wizards• A Wizard interface in Notes Client: 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: e.g., “RequestTable” Create a variable on the form with $Name: e.g., “$RequestTable” Have “forward” and “back” buttons increment/decrementthe variable
  • 32. 32Practice #8: Consuming Web Services• Two approaches: First, quick and dirty Install MS Soap on client machines Write 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"
  • 33. 33Practice #8: Consuming Web Services (cont.)• Two approaches: Second, big and robust Create a Java Agent that you pass a Notes document to – withall your setup information Read the document in your Java Agent, and consume theWeb service Write the results back to your Notes document Once the Java Agent returns, read the document forthe results Pro: Multi-platform, scalable Con: Quite a lot of work
  • 34. 34Practice #9: Evaluate• Evaluate allows you to run @Functions withinLotusScript• Sometimes faster, easier• Example:evaluate(|@unique|)• DON’T: Overuse it. Lots of LotusScript functions mimic @functions strRight == @StrRight
  • 35. 35Practice #10: “Trusted Servers”• Scheduled Agents cannot normally open databases onother servers “Trusted Servers” field in R6 server document, securitysection allows servers to “trust” other servers This allows you to centralize “collection” Agents Caveat: Don’t trust servers in another domain!• Pros: Simplifies architecture Fewer Agents• Con: Relies on fast, reliable network infrastructure …
  • 36. 36What We’ll Cover …• Introduction• Theory• Practice• Advanced• Wrap-up
  • 37. 37Advanced #1: Custom Classes• What are Custom Classes? Custom Classes help to: Bundle data and code in one place Decompose problems into “objects” Write smaller, more focused code Define and implement the internal data model Custom Classes aid reusability Pros: Good design methodology, leads to Java Cons: “Different,” and takes time to sink in
  • 38. 38Advanced #1: Custom 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
  • 39. 39Advanced #2: Understanding Binding• There are two types of binding: Early: Set by the compiler Pros: Type checking, speed, and ease of use Example: “Dim S as String” Late: Set at run-time Pros: Flexibility, NO type checking Cons: Performance, run-time errorsDim V as variantDim S as new NotesSessionset V = S.CurrentDatabaseprint V.getTitle()
  • 40. 40Advanced #2: Understanding Binding (cont.)Function ListCollection(p as variant) as integertest = falseif (typeName(p) = “NOTESVIEW”) or _(typeName(p) = “NOTESDOCUMENTCOLLECTION”) then decompose this collection into a number of single document calls to myselfdim doc as NotesDocumentset doc = P.getFirstDocumentwhile (not doc is nothing)call listCollection(doc)set doc = p.getNextDocument(doc)wendelse Weve been passed a single document. Process it.Print “I have been passed doc: “ + doc.Title(0)test = trueend ifend function
  • 41. 41Advanced #3: Coding for Performance• Remember: Expensive operations include: Opening databases and views Documents with lots of fields• When collecting data: Cache views where possible Use NotesViewEntry instead of opening documents
  • 42. 42Advanced #3: Coding for Performance (cont.)• Performance example: 100,000 document database 7 hours for “open every document in Database” Not using views 60 minutes using NotesView and opening documents 12 minutes for “NotesViewEntry”See also:Application Performance Techniques for Notes and Web Clients(Jamie Magee)
  • 43. 43Advanced #4: Lists and Custom Classes• Custom Classes bind complex data and operations• Lists look these up quickly in memory Example: 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
  • 44. 44Advanced #5: Class Inheritance• Class inheritance allows us to “Extend” classes to addfunctionality: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 functionend class
  • 45. 45Advanced #6: Encapsulation• Encapsulation allows us to include other complex typesin our classes: Allows you to collect different types ofcomplex informationclass Departmentprivate headOfDepartment as Personprivate members list as Person as Stringprivate departmentname as Stringprivate Locations list as String…end class
  • 46. 46Advanced #7: Version-Specific Code with ClassesClass createUserfunction createUser(...) as integer....end function….end 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(....)
  • 47. 47Advanced #8: LSI_Info()/GetThreadInfo• LSI_INFO() gives some run-time information• Superceded by GetThreadInfo GetThreadInfo(11) gives calling class GetThreadInfo(10) gives function name And lots more• Why? Error trapping: We can track where we came from We don’t have to pass lists of parameters to errortrapping code Prevents “cut-n-paste coding” errors ...
  • 48. 48Advanced #8: 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
  • 49. 49Advanced #9: Execute• Execute runs LotusScript code from a String: Example: Why? Accommodates version/platform differences at run-timeDim 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)
  • 50. 50Advanced #10: Mixing Java and LotusScript• Use each language to its strengths: Java – good for Web services, network I/O, multi-threadedoperations LotusScript – traditional Notes development language, worksin UI• How to mix: Simple: Call an Agent, passing a Notes Document Fast. I didn’t say you had to save the document! Works both ways LS2J Call Java from LotusScript Example on the next slide ...
  • 51. 51Advanced #10: Mixing Java and LotusScript …// 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 InitializeDim mySession As JavaSessionDim myClass As JavaClassDim calculator As JavaObjectDim 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
  • 52. 52What We’ll Cover …• Introduction• Theory• Practice• Advanced Tips• Wrap-up
  • 53. 53Resources• Homework: Classes – my OO presentation www.billbuchan.com/web.nsf/htdocs/BBUN6MQECQ.htm Steve McConnell, “Code Complete, SecondEdition” (Microsoft Press, 2004) www.amazon.com/gp/product/0735619670 Duffbert’s presentation on Java http://hostit1.connectria.com/twduff/home.nsf/htdocs/TDUF5VAQSY.htm Bob Balaban, “Programming Domino 4.6 with Java” (M&TBooks, 1998) http://www.amazon.com/gp/product/1558515836
  • 54. 54Resources (cont.)• LS 2004/AD104 – LotusScript Tips & Tricks http://www-10.lotus.com/ldd/sandbox.nsf/ecc552f1ab6e46e4852568a90055c4cd/68797abc4efa809a85256e51006a2c8a?OpenDocument&Highlight=0,AD104• nsftools – Notes Tips www.nsftools.com/tips/NotesTips.htm• The Notes FAQ! www.keysolutions.com/NotesFAQ/
  • 55. 55Resources (cont.)• Brian Benz and Rocky Oliver, “Lotus Notes and Domino6 Programming Bible” (Wiley, 2003) www.amazon.com/gp/product/0764526111• Notes.net (of course) www.notes.net• Articles in THE VIEW André Guirard, “Speed up view development — A LotusScriptagent to automatically create a view with fields from anyform” (THE VIEW, July/August 2006) Mikkel Heisterberg, “Self-documenting LotusScriptcode” (THE VIEW, January/February 2006)
  • 56. 567 Key Points to Take Home• You never stop learning good development techniques• Develop your code for maintenance• Good architecture is the best starting point• Understand the problem area before proposingsolutions• Spend a little time each day reading blogs, “THE VIEW,”and the support database Even though specific articles may not be of immediateinterest, they may pay off in the future• A problem shared/discussed is a problem better defined• Have fun and enjoy your work
  • 57. 57Your Turn!How to contact me:Bill BuchanBill@hadsl.com