December 2007 - Posts

OT: Merry Christmas and Blog Stats 2007 Edition

Merry Christmas to all my reader(s). I hope you have a great Christmas and New Year, and I’ll see you in January!

I thought it would be fitting to wrap up 2007 with a quick summary of my blog statistics, below.

Number of posts for the year: 31 (plus this one, equals 32)

3 Most Viewed Posts According to Web and Aggregate View Stats - probably because they're the oldest

3 Most Commented Posts

Book Reviews

My Favorite 4 Posts - I had something to say, or I put a lot of effort in and was happy with the results, or something impacted me

Examples of Code I Wrote - my feeble contribution :-)

Tags: christmas, statistics, blog

Featuritis - Adding Features Causes Pain

BugTracker.NET's Corey Trager posts about "featuritis" - one simple definition is where continually adding features to software eventually pushes users beyond happiness. Corey references Kathy Sierra's original post which explains it a lot better than I can here (and has a nice graph too).

I have two counter-arguments to the simple definition of "featuritis": discoverability, and user personas (to be fair, Kathy goes into a lot more detail and her post is well worth reading).

If an application adds new features but makes them hard to discover, or does the opposite by adding new features and making the older ones harder to discover, then users will be frustrated. Microsoft Office is a classic example of an application that keeps adding features, attracting derogatory terms like "bloatware". However, Office 2007 has addressed the discoverability issue by better grouping of commands via the ribbon (yes, you may not agree with me, but I only said addressed the issue, not necessarily solved it).

My second objection to Kathy's original graph is that it lumps all users on the one scale. I reckon that for different types of users (e.g. personas), more features would actually be a good thing. Here's my take on it:

For a "power user" (you know who you are), I reckon more features make an application more attractive, although there will be a point where the "where the heck did they put that feature?" syndrome kicks in (let alone the problem of adding features at the expense of fixing existing features).

With this post I'm just making the point that adding more features does not necessarily frustrate users, especially when you take into account discoverability and different types of users. "Featuritis" is a problem; Kathy has still got the last word on it when she says that developers should "give users what they actually want, not what they say they want. And whatever you do, don't give them new features just because your competitors have them!"

Tags: featuritis, user, features

Still on SQL Server 2000 with SP4?

If so, then it's worth knowing that mainstream support ends April 2008 (via Andy Leonard, who asks "What's that ticking sound?")

Tags: sql server, support, microsoft

Don't Show 'Time Taken: 456.6 seconds' to Users

Instead, use this basic "natural language" elapsed time function in VB.NET.

I use this simple function to show elapsed time in the user interface. It came about because although I believe it's useful to provide some feedback at the end of long-running processes, I was getting sick of strings like "Time taken: 456.6 seconds" which is indecipherable to real people.

This VB.NET function returns a string like "less than 10 seconds", "under 1 minute", "around 4 minutes" which, as you can see, changes the unit of measure depending on how long the elapsed time is:

    ''' 
    ''' Returns an approximate, rounded string of the difference in seconds, minutes or hours between the passed 
    ''' start and end DateTimes (depending on how long the difference is), to return feedback to the user 
    ''' on how long a process takes to run.
    ''' 
    ''' The starting or commencement time.
    ''' The end or finish time.
    ''' A natural-sounding sentence fragment that can be used after an opening like "The process finished 
    ''' in ". The return value will not have leading or trailing spaces, or a full stop or other punctuation, and 
    ''' may possibly be empty if either  or  is Nothing.
    ''' I wrote this to replace the over-exact and hard to understand "456.75 seconds"-type strings 
    ''' that I had previously used to return elapsed time for long-running processes. This function has special cases 
    ''' for under 30 seconds, under a minute, under half an hour, etc. which means that the information provided is 
    ''' exact enough, but not too precise.
    ''' Debug.Write("The process finished in " + GetFriendlyTimeElapsed(Now, DateAdd(DateInterval.Minute, 74, Now)))
    ''' Debug.Write("The process finished in " + GetFriendlyTimeElapsed(dat1, dat2))
    ''' 
    
Friend Function GetFriendlyTimeElapsedString(ByVal StartTime As System.Nullable(Of DateTime), _
                                                 
ByVal EndTime As System.Nullable(Of DateTime)) As String

        
' if we didn't get two dates, leave
        
If Not (StartTime.HasValueOrElse Not (EndTime.HasValueThen Return String.Empty

        
' get the timespan between the two times
        
Dim tsElapsed As TimeSpan EndTime.Value StartTime.Value

        
' check that the start date is less than the end date
        'Debug.Assert(StartTime.Value < EndTime.Value, "The start time should be less than the end time.")

        ' take action depending on number of seconds for small figures (up to about 3600 seconds or 1 hour), 
        ' or if longer than an hour return exact hours and minutes. Up to 1 hour, the return is intentionally 
        ' rough or inexact to return more natural language. Note that the CASE statements have to be in ascending
        ' order, because once the criteria is met we exit the SELECT construct.
        
Select Case tsElapsed.TotalSeconds
            
Case Is <= 1
                
' special case for 1 or 0 seconds, or if the start time is *after* the end time (resulting in a 
                ' negative number of seconds)
                
Return "less than 1 second"
            
Case Is 31
                
' return "less than x seconds", rounded to nearest 5 seconds
                
Return "less than " & ((Int(tsElapsed.TotalSeconds 5) * 5) + 5).ToString("F0") & " seconds"
            
Case Is 61
                
' if more than 30 seconds but less than a minute, special case - return "less than 1 minute"
                
Return "less than 1 minute"
            
Case Is 91
                
' around 1 minute
                
Return "around 1 minute"
            
Case Is 1620
                
' if less than 27 minutes, return "around x minutes", rounded to nearest minute
                
Return "around " & (tsElapsed.TotalSeconds 60).ToString("F0") & " minutes"
            
Case Is 1800
                
' if time is between 27 minutes and 30 minutes, return "under 1/2 an hour"
                
Return "under 1/2 an hour"
            
Case Is 1980
                
' up to 33 minutes, return "around 1/2 an hour"
                
Return "around 1/2 an hour"
            
Case Is 2520
                
' less than 42 minutes, return nearest minutes
                
Return "approximately " & (tsElapsed.TotalSecondss 60).ToString("F0") & " minutes"
            
Case Is 2700
                
' under 45 minutes (between 42 and 45)
                
Return "under 45 minutes"
            
Case Is 2880
                
' just over 45 minutes (up to 48 minutes)
                
Return "just over 45 minutes"
            
Case Is 3420
                
' if under 57 minutes, return "approximately x minutes", rounded to nearest minute
                
Return "approximately " & (tsElapsed.TotalSeconds 60).ToString("F0") & " minutes"
            
Case Is 3900
                
' approximately 1 hour (from 57 up to 65 minutes)
                
Return "about 1 hour"
            
Case Else
                
' catch all case, after 65 minutes: return number of hours and minutes
                ' we need special formatting in case we hit 1 minute or 1 hour to leave the "s" off the end
                
Return tsElapsed.Hours.ToString("F0") & " hour" CStr(IIf(tsElapsed.Hours 1"s"String.Empty)) & _
                    
" and " tsElapsed.Minutes.ToString("F0") & " minute" CStr(IIf(tsElapsed.Minutes 1"s"String.Empty))
        
End Select

    End Function

I'm also trying out the Simple-Talk Code Prettifier (via Mladen Prajdić) which this version of Community Server does not like (how old is the version DNJ is running anyway?).

For recommendations as to where you might display the elapsed time to users, see SSW's Rule To Better Windows Forms.

Tags: time, code, vb.net, natural, development

Reporting Services Matrix Techniques

I haven't posted anything on Reporting Services recently.

So, I have two links for the infamous matrix control:

Because I feel I need to compensate :-)

Tags: sql server, database, reporting services, matrix