Usability - Productivity - Business - The web - Singapore & Twins

By Date: September 2007

20 Easy Steps to Screw Up a Domino Upgrade

Domino upgrades are comparable easy and can be quite fast. Of course you need to know what you are doing. There might be times when you don't want to have a smooth ride. Like when you are paid by the hour or when you want to move to a different platform. In this case this post is for you. Follow the following easy to implement steps and your upgrade will be an utter failure. But be aware, you have to set the stage before the upgrade, voicing concerns, so you can blame it on IBM when things start to fail --- and they will.
  1. Do not upgrade the admin's workstation. Using the latest version of Domino administrator would actually give you access to the latest feature, avoid this
  2. Make sure, that you don't have access to all servers and that you are not a system administrator of the domain
  3. Make sure, that you can't reach all the servers from the admin workstation
  4. Start upgrading the most critical application server first, and the hubs and the administrative server last
  5. Make sure you have enough time so the design task on an old server can undo all design changes the upgrade process might have applied
  6. Make sure you have touched and customized all system templates, so their change date is younger than the new version. Also make sure the templates don't replicate everywhere. A mess in the system template will give you weeks of (billable) fun
  7. Make sure, that your system databases don't replicate or replicate outside the deletion stub life cycle interval
  8. Never ever upgrade the design of the Domino Directory or other system databases. If you do so the upgraded server actually could use other settings than defaults.
  9. Try to make sure that your ODS is at least one version behind. This keeps the indexer busy.
  10. Yes a full hard disk is also a good idea: if the available space is less than your biggest database and less than 20% that is good
  11. Enable disk compression. Having the OS scream when it needs to uncompress notes databases on access
  12. Use a desktop virus scanner on your server. Make sure it scans every file on access
  13. Don't uninstall any 3rd party extensions (like the virus scanner or compliance plug-ins). It is more fun to search for such issues. And while you are on it: don't use the latest version of 3rd party apps, they actually might be compatible with the new version of Domino.
  14. Enable transaction logging with either the OS or the data drive as destination. Hard disks should spin hard.
  15. Make sure you don't apply your OS level service packs or patches. This is especially important on W2K3 and W2K3/64.
  16. Do not apply the latest version of your source version. (LIke 5.0.13a when you come from R5, or 6.5.6 when you come from R6.x) This is especially fun when skipping a version
  17. Make sure that the messaging people don't talk to the apps people vice versa. Also don't give notice to the apps people that you do the upgrade
  18. Do not maintain documentation which applications use which system template for lookup. Anyway documentation is for whimps.
  19. Be creative. Look for best practices in Redbooks, on the IBM site and other online locations. Put a "not" or "don't" in front of every recommendation.
  20. Don't use fixup or compact before or after the upgrade.

This list is by far not complete. So if you know another way to screw your upgrade, let me know.

Posted by on 27 September 2007 | Comments (3) | categories: Show-N-Tell Thursday

Customizing system templates

Everything in Notes can be customized by tweaking with the design. I highly recommend never to tweak design in a database itself, but use Domino's template capability. You can have multiple databases using the same layout. Even if you build a specialized custom application you will have at least 3 databases sharing the same design: development sample data, UAT sample data and production data. So use template, and NO hiding the design is not a nice thing to do and actually not a security feature (it's rather an obscurity feature).
In a lot of installations I came across system databases have been altered: the Domino directory, the log, the mail template etc. IBM's support always has a hard time helping in this environments. There is a rather strict policy to insist on original IBM templates. Following a few easy steps however you can eat your cake and have it too. The secret is to use the template system wisely. Following the steps has quite some advantages:
  • Your customizations are protected from being overwritten since they are sitting in their own database
  • Your customizations are visible since they are sitting in their own database
  • Since the original templates are untouched future fixes are easily included in your actual database
  • You can switch back and forth between the IBM template and your customized template using "replace design". This is extremely useful when troubleshooting issues: switch to the original IBM template, if the problem is gone you know where to look. If the problem persists you don't need to argue with support about customization having an impact

These are the steps:

Read more

Posted by on 26 September 2007 | Comments (4) | categories: Show-N-Tell Thursday

Syncing documents in 2 views

I got quite some requests on the details of the syncing documents in views pattern/anti-pattern.So this is what you need to do:
  1. Have 2 views with identical keys, sorted by the key
  2. Julian's OpenLog database
  3. The main function SyncAllDocument
  4. 3 auxiliary functions: getCompareKeySource, getCompareKeyTarget and updateSourceDoc
In my example code I made the assumption, that the documents contain the same fields and have a single key. You might have different requirements like computing things and/or only coying part of the items or do a computewithform before saving. Nevertheless you don't need to touch the main routine for that. You get the idea.

Read more

Posted by on 21 September 2007 | Comments (3) | categories: Show-N-Tell Thursday

Domino Anti-Pattern: Delete and Recreate

When reviewing agents or trouble shooting mis-behaving databases I come across a popular anti-pattern for Domino: delete and recreate. Anti-pattern are well known failures for common known problems. "Delete and Recreate" can be found in report generating applications or databases that pull values from other sources like RDBMS or flat files. Mostly you can find that pattern when developers came from a RDMBS background where deleting equals the total removal of information. In Domino things are a little different. When you delete a document something remains back: a deletion stub. A deletion stub is the DocumentUniqueId plus a flag that says "I'm a deletion stub". The stub is then replicated to other servers or clients to also remove this document in the replica. The default life span of a deletion stub is 30 days.
In a recent analysis I was looking at a database with just 400 documents, that was big, slow and prone to crashes. On closer examination I found an agent performing this pattern on the 400 documents every 30 minutes. Do your math: 400 x 48 x 30 = 576000. Quite some baggage for just 400 entries.
So what are the alternatives?
Requirements like this are often solved with another anti-pattern: "Loop through a big loop and do a dbLookup (or getDocumentByKey) for each iteration". But there is an easier way: Typically there is a sorted key (customer number, part number, record id etc.) that would be available in source and target. Create a collection for source and target and use what I call "The Tango" or "The Wiggle". The pseudo code looks like this:
  1. Read first source key and first target key
  2. Do until you run out of keys
  3.  if source key is equal target key: call sub routine comparing the two records how they have to be compared and update and save target if it has changed (but not otherwise)
  4. if source key is bigger than target key: get next target key and delete current target
  5. if target key is bigger than source key: insert source document into target view and read next source document
  6. End of the do loop

Of course your production code needs to handle the case that you run out of source keys (= delete all remaining target documents) or target keys (=insert all remaining source documents).
This way you don't create unnecessary zombie deletion stubs.

Posted by on 20 September 2007 | Comments (4) | categories: Show-N-Tell Thursday

Michael Vizard on Microsoft Exchange

Michael Vizard writes on Microsoft Exchange (emphasize mine)

" Within the land of IT, nothing is a bigger pain to own, manage and run than Microsoft Exchange. Everywhere you go customers have horror stories about the installation, maintenance and, above all, uptime of their Microsoft Exchange implementations. And worse yet, they will all tell you they are paying top dollar for the privilege because the expertise needed to successfully run a Microsoft Exchange server is some of the most expensive in the IT labor pool."

Posted by on 07 September 2007 | Comments (0) | categories: Software

A CRUD webservice - Part 2

In Part 1 of this Show-N-Tell Thursday I showed how to generate a WSDL definition out of a Notes form. While this is nice, it leaves quite a bit of work to actually implement the service. In this installment we take the opposite route. Instead of generating a WSDL definition, LotusScript code will be generated out of a Form definition. Unfortunately DXL doesn't support Web services very well (at least up to R8.0), so I will generate a text file that contains pure LotusScript code. This text file needs to be manually imported into an empty Web service (Copy and paste will do).

I generate a few classes including a custom class which you can overwrite to implement your specific additions to the code. You might want to put that into a different library, so you keep your customization. Nota bene: the generated code is not real production quality. I haven't implemented good logging or error handling ( OpenLog anybody). Once you see the code you get the idea and can complete that easily (feedback would be nice).

A web service requires a LotusScript class with public members, properties and/or functions. Domino Designer will then generate a WSDL file for us. One path to travel would be implementing generic code, that takes fields as name/value pairs. While tempting this has the clear disadvantage, that the web service becomes rather unspecific and we can't take advantage of a strong validation using XML schema. So my approach is to analyze the form and generate 2 XML structures: one for all input fields, used to create and update a document and one for all fields used to read a document. I don't take hide-when formulas into account.

There are a few challenges to overcome. First we need to deal with multi-value fields. In WSDL these are expressed as Arrays. Secondly we need to map the Domino data types to WSDL data types. Luckily half of the work is done since Domino includes "lsxds.lss" It translates WSDL data types into LotusScript. From LotusScript to NotesItems is a path well travelled.

Let's have a look at the XSLT stylesheet (if you don't know how to translate DXL using XSLT use this plug-in -- you are using FireFox are you?)

To instruct the XSLT processor to output plain text rather than XML or HTML we use this statement:
<xsl:output indent= "yes" method= "text" omit-xml-declaration= "yes" media-type= "text/lotuscript" xml:space= "preserve" />

Then inside the root tag the LotusScript Code is written as you would write in Domino Designer.
  <xsl:template match= "/" >
        <!-- We use the build-in data type mapping for LotusScript agents -->
        %INCLUDE "lsxsd.lss"
        '  Autogenerated code to be embedded into a Domino Web Service
        Public Class form <xsl:value-of select= "$formName" />

We have 2 levels of comments here. XSLT Comments looking like this: <!-- ... --> and regular LotusScript comments starting with '.
Whenever we need to get specific we can use <xsl:value-of to pick a value from the DXL form.

The class we will expose into the webservice is, other than its name and the content of the parameters pretty standard and (IMHO) self explaining:

Public Class form <xsl:value-of select= "$formName" />
            '* createData takes in the custom form data and creates a new document.
            '* the data given as parameter matches all input fields of the form
            Public Function createData(formData as <xsl:value-of select= "$formName" /> InputData) as ResultCode
                    Dim curData as new <xsl:value-of select= "$formName" /> CustomData
                    Set createData = curData.createData(formData)
            End Function

        Public Function createAndReadData(formData as <xsl:value-of select= "$formName" /> InputData) as ExtendedResult
                Set createAndReadData = new ExtendedResult
                Set createAndReadData.Data = new <xsl:value-of select= "$formName" /> CustomData
                Set createAndReadData.Result = createAndReadData.Data.createData(formData)
        End Function

        Public Function readData(key as String) as <xsl:value-of select= "$formName" /> CustomData
                    Dim tmpResult as new <xsl:value-of select= "$formName" /> CustomData
                    Call tmpResult.readData(key)
                    Set readData = tmpResult
            End Function
            Public Function updateData(key as String, formData as <xsl:value-of select= "$formName" /> InputData) as ResultCode
                    Dim curData as new <xsl:value-of select= "$formName" /> CustomData
                    Set updateData = curData.updateData(key, formData)        
            End Function
            Public Function updateAndReadData(key as String, formData as <xsl:value-of select= "$formName" /> InputData) as ExtendedResult
                    Set updateAndReadData = new ExtendedResult
                    Set updateAndReadData.Data = new <xsl:value-of select= "$formName" /> CustomData
                    Set updateAndReadData.Result = updateAndReadData.Data.updateData(key,formData)
            End Function
            Public Function deleteData(key as String) as ResultCode
                Dim curData as new <xsl:value-of select= "$formName" /> CustomData
                Set deleteData = curData.deleteData(key)
            End Function
        End Class
        Public Class ResultCode
            Public Value as Integer 'We use HTTP values
            Public DBid as String 'Database and document we try our luck with
            Public DocID as String
        End Class
        Public Class ExtendedResult
            Public Result as ResultCode
            Public Data as <xsl:value-of select= "$formName" /> CustomData
        End Class

Read more

Posted by on 05 September 2007 | Comments (1) | categories: Show-N-Tell Thursday

Software Pricing and Software Risk

Most of software created today is bespoke software. Code that runs in one organisation and is never resold or passed on (and sadly hardly reused). This entry is about pricing the creation of bespoke software. It is not about pricing of standard software. That is a topic others have to fight over. So what pricing models are out there? We make the simplifying assumption, that you have an idea what effort is required and that we can ignore market forces (like: "this is the price we pay for this service here").
At the two ends of the models are "time and material (TM)" and "turn key projects (TKP)". TM is the delivery model corporate developers typically work with (yes there are cost centers, so it might be different in your company), while TKP is the sole model used when software projects are tendered out.
In a TM model finding the price is pretty easy: effort + profit margin = price (remember we exclude the market forces in this examples).
Time and Material Pricing
The calculation is simple, since any change in requirement, any unforeseen complication just leads to more billable hours. Everyone loves this model... except the customer. In this model 100% of the risk is on the shoulders of the project sponsor. Naturally project sponsors or customer want to limit the risk. So they push for fixed deliverables and turn key pricing. This seems to be a sensible approach. However the way a contractor is calculating the price of the software becomes very different. First: the internal pricing is always TM since you pay your staff a monthly salary. So when accepting a TKP there is a substantial added risk that the contractor has to bear. Risk translates to money. So the calculation suddenly looks like this:
Price with risk
While it looks like that the profit margin took a dent, typically the risk margin is added to the project costing (especially when it is an internal cost center). So the real picture looks more like this:
Software Pricing and Risk
Since Risks can be expensive both sponsor and customer try to minimize the risk. The usual approach is to flesh out detailed specifications what needs to be done, what is included and what is out. These specification then are the ultimate benchmark to decide if the contractor has fulfilled the obligations and gets paid. In other words: the system is completely specified before work commences. With some notable exceptions it is consensus, that big up-front design doesn't work. This insight hasn't reached the teams that design tender specifications. In my personal experience: the systems users appreciated most when delivered where the ones that had the least in common with the original design specifications (but that might have been just my dumb luck ).

Update: Jesse Davidson from Madberry.com notified me about the demise of stsc.hill.af.mil and shared the Background story. Interesting read!

Read more

Posted by on 01 September 2007 | Comments (1) | categories: Software