For the purposes of this discussion, I'm temporarily stepping out of my typical role of " code monkey" and switching to my alternate (but equally important) role as system administrator. Having seen several different approaches to provisioning server connections in Notes, I'm curious how you approach it. Here are a couple examples of what I've seen in different environments:
- During workstation setup, the DNS address of the user's home/mail server is entered, establishing a connection to that server. From then on, attempts to access other servers rely on the ability of Notes to automatically request the destination server's address from the user's home server; as long as that server is accessible, the user doesn't need connections to any other servers, because their home server will tell them how to get there. NOTE: this only works if the home server can determine the destination server's address... if the user needs to get to servers not listed in the primary Domino directory (for example, servers in isolated test or development environments), this feature does them no good.
- During workstation setup, whoever is configuring Notes (or walking the user or a delegate through the process) manually defines connection documents to every server the user could ever possibly need to access. This precludes the need for the home server to be contacted to request an address the first time (per session) a new server is accessed, but if any server's network address changes, in addition to updating it in the Domino directory, the change must also somehow be pushed to all the users.
- When a user needs to access a server they don't have a connection for, an administrator sends them an email that includes a button that, when clicked by the user, programmatically creates the connection document. Typically, then, the admin doesn't know the user doesn't already have a connection until the user has already tried to connect and failed.
- When a user needs to access a server they don't have a connection for, they are instructed to enter the server's network address - instead of its name - in the "Open Application" ("Open Database", in versions prior to 8) dialog and click "Open", which automatically creates a connection document if they don't already have one. Hence, users don't need to be sent a new button each time they identify a new server they need to connect to; they just need to know its network address.
- Domino servers that are only used behind a firewall are named such that internal DNS (or WINS, or another equivalent) allows the Notes client to locate the server by its CN without even requiring a connection document. While this might lead to either Domino servers with ridiculous names the users have little hope of remembering (i.e. TNGATLDM37 might be the 37th Lotus Domino mail server added to a facility in Gatlinburg, Tennessee) in order to conform to an existing DNS naming convention, or require a compromise from the network staff (perhaps in the form of an alias mapping a "friendly" Domino name to a conforming name), this is my personal favorite. The users don't get the impression that Domino - or the network - is unreliable because they can't get to a server that they've never told Notes how to find, Notes doesn't have to query their mail server for a destination address every time they want to open an application on a server that they access infrequently, and neither admin nor user has to spend time configuring connection documents unless they're a remote user... and, while remote and offline access has long been a key strength of Notes/Domino, in the majority of organizations (in my experience, at least), the majority of users need neither.
What's your take on this? Are there other approaches you take to ensuring your users can find Domino servers? Are there specific reasons why you prefer one approach over another?
|
How do you provide connection documents to your us...
|
Yahoo! has done extensive research on how to optimize web site performance, and for some time now has maintained a list of best practices that summarize the results of that research, along with detailed descriptions of why each guideline enhances site performance. Two of their guidelines that go hand in hand are as follows:
- Put stylesheets at the top: the closer to the top of the HEAD your stylesheets are, the more progressively the page will render. Strictly speaking, this doesn't allow the page to load more rapidly, but the progressive rendering speeds up the display of the page once it has loaded.
- Put scripts at the bottom: this may seem counter-intuitive, especially if you're used to cramming all of your script into the JSHeader object in a Domino design element (.....please don't) instead of defining it in libraries or file resources that are then loaded via script tags, but script should be as close to the bottom of the BODY as possible.
Check out Yahoo!'s list for more detail on why they recommend these (and other practices) for maximizing site performance. Thus far I haven't experienced anything in my own development that contradicts their recommendations.
|
Quick performance reminder: style at the top, scri...
|
|
|
yellow all day long
|
How many times (this week) have you needed an object representing a past or future date in LotusScript? Pretty standard stuff... you instantiate a NotesDateTime with Now, then call an adjustment method to correct the date: Dim datTomorrow As New NotesDateTime(Cstr(Now))
Call datTomorrow.AdjustDay(1) And it's only two lines of code... but there's a way to do it in one by performing the adjustment immediately in the instantiation. LotusScript actually treats each date as a Double. The integer portion
is the date (the number of days since 12/30/1899) and the fraction
indicates the percentage of the day. Hence, if you convert Now to a
Double instead of a String it'll return something like 39665.7083333333
( Cdat that and Cstr it, and you'll get "8/5/2008 5:00:00 PM" ). As a result, you can add/substract the number of days you want to adjust, convert the result to a scalar date, and then a String... then pass that into the NotesDateTime constructor and by the time the object is initialized it already has the desired value:
Dim datTomorrow As New NotesDateTime(Cstr(Cdat(Cdbl(Now) + 1)))
Dim datOneWeekLater As New NotesDateTime(Cstr(Cdat(Cdbl(Now) + 7)))
Dim datLaterToday As New NotesDateTime(Cstr(Cdat(Cdbl(Now) + (1/24)))) Enjoy.
|
Quick tip: shorthand date adjustment in LotusScrip...
|
Thanks for all the feedback on my recent ramblings regarding LotusScript event binding. Just one more post on this and I'll leave it alone for a while. Both Thomas Bahn and Devin Olson chimed in on the last article in this series, and Peter Presnell posted a great article about compensating for weaknesses in LotusScript's OOP model, all of which prompted some useful mods to the framework. If you've already downloaded it, you may want to snag a fresh copy.
Thomas suggested that, instead of calling each bound Sub recursively with stack trace checking to prevent infinite recursion in cases where the event handler has not been overridden in the derived class... just bind the event to a delegate function that, in turn, calls the actual event handler. This results in a bit more code within the framework classes, but since the structure is such that you won't need to modify those classes again until new events are added in future versions of Notes, I'm perfectly fine with that as a tradeoff for avoiding recursion altogether. Don't worry, we'll find another excuse to use Nathan's code locking approach.
Devin's comments and Peter's article both provided insight into forcing (at runtime, at least) methods and classes to be treated as abstract, and, as such, overridden and derived, respectively. That was a bit of a mouthful, so perhaps it would be simpler to just show you the most basic of the EventBinder child classes in its current form:
Public Class TimerEventBinder As EventBinder
Public Sub New (Source As NotesTimer)
Dim classname As String
Let className = Typename(Me)
If (className = "TIMEREVENTBINDER") Then
Error ERR_ABSTRACT_INSTANTIATION, MSG_ABSTRACT_INSTANTIATION & classname
Exit Sub
End If
Set Me.context = Source
End Sub
Private Function bindEvent (Byval eventName As String, Source As Variant)
Select Case Lcase(eventName)
Case "alarm":
On Event Alarm From Source Call delegate_Alarm
Case Else:
Error ERR_UNSUPPORTED_EVENT, MSG_UNSUPPORTED_EVENT & Ucase(eventName) & " in class " & Typename(Me)
|