Worth Reading: Automate, else Enforce otherwise Path of Least Resistance

A friend and colleague, Matthew Rowan, has just spent some time formalising some of the knowledge that many developers will have grasped intuitively with respect to process management – but that many won’t have.

Automate, else Enforce otherwise Path of Least Resistance.

This is well worth a read as far too many companies get burdened with process documentation over actual workable process.

Automatically rejecting appointments in Microsoft Outlook 2007

There’s a nice feature in Outlook that allows users to automatically accept appointments, and even decline conflicting appointments. Unfortunately, what it can’t do is allow you to specify specific reasons for rejecting meeting invitations.

image

A particular pet hate of mine is when people send a meeting invitation entitled “Foo Discussions” or some such, and fail to specify a location or any content. It’s even more irritating when I’m trying to be a good little corporate citizen and have my calendar auto-accept appointments, but they send it ten minutes before the thing actually starts. They’re going to receive an acceptance notice (of course) but my phone’s not going to synch for a good half-hour, and there’s just no way I’m going to be there. Funnily enough, I’m not just sitting around on my backside, waiting for someone to invite me to a meeting.

Oh, a meeting! How exciting! I’ve been waiting for one of these all day!

Of course, if you simply decline offending appointments manually, people tend to get offended. (Which may or may not be a good thing, depending on who it is.) A better way, however, is to automate the process.

Nothing personal, old chap – my calendar just has automation rules that apply to everyone.

The rules for getting into my calendar are simple:

  1. Tell me everything I need to know about the meeting. This includes, specifically, its location. Outlook enforces pretty much everything else, but fails to enforce this one.
  2. Please do me the courtesy of checking my free/busy information and do not attempt to trump something that’s already been organised. It shows a complete and utter disregard for my time and that of anyone with whom I’ve already agreed to meet.
  3. Do me the courtesy of giving me at least 24 hours’ notice. Don’t send me a meeting request at 7pm on Monday evening for 7:30am on Tuesday morning. I’m not going to read it, and I’m not going to be there.

I finally snapped today, after another imbecilic meeting request, and wrote these two quick methods. They enforce the three rules above, automatically accept the request if it passes and automatically decline otherwise. They appear to work for me; your mileage may vary. No warranties, express or implied, etc.

Sub AutoProcessMeetingRequest(oRequest As MeetingItem)

    ' bail if this isn't a meeting request
    If oRequest.MessageClass <> "IPM.Schedule.Meeting.Request" Then Exit Sub

    Dim oAppt As AppointmentItem
    Set oAppt = oRequest.GetAssociatedAppointment(True)

    Dim declinedReasons As String
    declinedReasons = ""

    If (oAppt.Location = "") Then
        declinedReasons = declinedReasons & " * No location specified." & vbCrLf
    End If

    If (HasConflicts(oAppt)) Then
        declinedReasons = declinedReasons & " * It conflicts with an existing appointment." & vbCrLf
    End If

    If (DateTime.DateDiff("h", DateTime.Now, oAppt.Start) < 24) Then
        declinedReasons = declinedReasons & " * The meeting's start time is too close to the current time. " & vbCrLf
    End If

    Dim oResponse As MeetingItem
    If (declinedReasons = "") Then
        Set oResponse = oAppt.Respond(olMeetingAccepted, True)
    Else
        Set oResponse = oAppt.Respond(olMeetingDeclined, True)
        oResponse.Body = _
            "This meeting request has been automatically declined for the following reasons:" & vbCrLf & _
            declinedReasons

    End If

    oResponse.Send
    oRequest.Delete

End Sub

Function HasConflicts(oAppt As AppointmentItem) As Boolean
    Dim oCalendarFolder As Folder
    Set oCalendarFolder = ThisOutlookSession.Session.GetDefaultFolder(olFolderCalendar)

    Dim apptItem As AppointmentItem

    For Each apptItem In oCalendarFolder.Items
        If ((apptItem.BusyStatus <> olFree) And (oAppt <> apptItem)) Then
            If (apptItem.Start < oAppt.End) Then
                ' if this item starts before the given item ends, it must end before the given item starts
                If (apptItem.End > oAppt.Start) Then
                    HasConflicts = True
                    Exit Function
                End If
            End If
        End If
    Next

    HasConflicts = False
End Function

Just open the VBA editor from within Outlook (Alt-F11) and paste the subroutines into the ThisOutlookSession project.

image

Then go and create an Outlook rule that calls the AutoProcessMeetingRequest subroutine for every meeting request you receive:

image

Those of your colleagues who persistently refuse to learn how to use email (an essential business tool!) will receive responses along the following lines:

image

Don’t be spamming me, Windows Live

image

New features are all very nice, guys, but:

a) that feature’s been around for ages;

b) I hate it, as does everyone I know;

c) I’ve already told Messenger not to pop up the today box when I launch it, and this looks remarkably like you’re ignoring your users’ wishes for your own marketing purposes.

Back to Pidgin, methinks.

What’s wrong with this sequence? A message to the VSTS guys:

Stupid Question #1: What actually constitutes a conflict?

Is a conflict when two people have changed a file, or is it when two people have changed the same part of a file and VSTS needs assistance to resolve it? Every other (sane) version control system in the world interprets a conflict as the latter.

image

Stupid Question #2: How is it “Auto Merge” when I have to tell VSTS to merge?

image

Stupid Question #3: If VSTS could not-quite-auto-but-with-the-press-of-a-button merge, and it managed to resolve everything all by itself, why on earth does it pester me about non-existent conflicts all the time?!?!?

image

Perhaps these questions are stupid, but I most respectfully submit that the answers are stupider.

Microsoft on why a memory leak isn’t really a leak

The genesis of this rant is that a colleague and I have just spent a couple of days diagnosing and fixing memory leaks (sorry, “pseudo-leaks”,” according to Microsoft, which presumably means that the memory explosion we were seeing wasn’t actually real) caused by awful, awful garbage collection in Internet Explorer.

The icing on the cake was finding this article: Understanding and Solving Internet Explorer Leak Patterns. The markworthy text is this:

Pseudo-leaks almost always appear on the same page during dynamic scripting operations and should rarely be visible after navigation away from the page to a blank page.

In other words, Microsoft Word doesn’t leak memory either. All you have to do is close it, open it again and miraculously all the memory that it allocated and failed to release (but that somehow fails to meet the definition of “leaked”) is released.

The whole point of Internet Exploder 8 was to build an AJAX-friendly browser. The subtext went along the lines of, “Well, all those AJAX-heavy sites like GMail, Google Maps, Hotmail etc don’t perform well under IE7 and we’re losing browser market share, so let’s make a browser that is AJAX-friendly. But, at the same time, let’s make developers require people to navigate away from that application before any of its memory is released.”

We’ve just spent days diagnosing as many of the various ways that IE leaks memory (ways, incidentally, with which none of the other browsers seem to have problems), patching the jQuery core to cope with its idiocy and writing our own DOM garbage collection handlers to deal with it. The jQuery and GWT discussion forums reveal that these guys are having just as much pain, and for similar reasons.

To the IE development team: Please, please, please, guys, fix your sodding .removeChild method and everything that has anything to do with it. And don’t talk to me about setting .innerHTML properties either until you have a browser that doesn’t seg-fault when I do that to a table element, or when I manually break the relationship between a node and its parent. Finally, at least have the courage to confess that your browser does leak memory in these scenarios rather than some pathetic attempt at explaining why a leak isn’t a leak. Grr!!

If you want to cringe, grab the sIEve tool (see Memory leak detector for Internet Explorer for a link) and point it at http://msdn.microsoft.com. Navigate around a bit and then have a look at the number of orphan DOM nodes. Consider how many full-page reloads MSDN causes, and compare this to your own AJAX application. Weep.

Memory leak detector for Internet Explorer

I’ve been playing with Drip and sIEve in order to find some memory leaks that we’ve been encountering under Internet Exploder.

Drip / IESieve, Memory leak detector for IE Internet Explorer .

If you haven’t looked at your application with sIEve, you really should.

console.log() Equivalent for Internet Explorer

There are a bunch of people out there who are fed up with the lack of a console.log() equivalent in Internet Explorer. It shouldn’t come as any surprise that I’m one of them.

For anyone who’s ever tried to debug a whole bunch of JavaScript code and ended up with myriad alert(‘here’) and alert(‘here2’) calls just so they could see what was happening, console.log() became our friend very, very quickly. No surprise, however, that IE didn’t have it.

It becomes significantly more painful, however, when you’re trying to clean up JS code for the sake of performance. The usefulness of any metrics collected goes out the window once there’s user activity involved. (Besides, clicking “OK” for all those alert boxes is a royal pain.)

(Hint to the IE8 team: Your product is still in beta. You must have a logging call somewhere. Publish it, please. Please. All the other browsers of note do.)

There are quite a few good console.log() equivalents out there, not the least of which are Faux Console and the Yahoo User Interface Logger Widget. For extremely light-weight applications, though, there was nothing that did just what I wanted, so I wrote one. You’ll be depressed at how simple it is, and how easy it would have been for the IE team to have included this functionality at almost any point in IE’s development cycle.

 

The JavaScript code:

// rudimentary javascript logging to emulate console.log(). If there already exists
// an object named "console" (defined by most *useful* browsers :p) then we
// won't do anything here at all.
if (typeof (console) === 'undefined') {

    // define "console" namespace
    console = new function() {
        // this is the Id of the console div. It doesn't actually need to be a div,
        // as long as it has an innerHTML property.
        this.ConsoleDivId = "JavaScriptConsole";

        // maintains a reference to the console output div, so that we don't have to
        // call document.getElementById a bunch of times.
        this.ConsoleDiv = null;

        // allows us to cache whether or not the console div exists, so that we can
        // just do an early exit from the console.log method and similar if we're not
        // going to put any useful output anywhere.
        this.ConsoleDivExists = null;
    };

    // this is an expensive (really quite expensive) string padding function. Don't use
    // it for large strings.  -andrewh 11/3/09
    console.padString = function(s, padToLength, padCharacter) {
        var response = "" + s;
        while (response.length < padToLength) {
            response = padCharacter + response;
        }

        return response;
    }

    console.log = function(message) {

        // this will be executed once, on first method invocation, to get a reference to the
        // output div if it exists
        if (console.ConsoleDivExists == null) {
            console.ConsoleDiv = document.getElementById(console.ConsoleDivId);
            console.ConsoleDivExists = (console.ConsoleDiv != null);
        }

        // only do any logging if we actually have an output div.  (Check using the cached
        // variable so that we don't end up with a bunch of failed calls to
        // document.getElementById).
        if (console.ConsoleDivExists) {
            var date = new Date();
            var entireMessage =
                console.padString(date.getHours(), 2, "0") + ":" +
                console.padString(date.getMinutes(), 2, "0") + ":" +
                console.padString(date.getSeconds(), 2, "0") + "." +
                console.padString(date.getMilliseconds(), 3, "0") + " " + message;
            delete date;

            // append the message
            console.ConsoleDiv.innerHTML = console.ConsoleDiv.innerHTML + "<br />" + entireMessage;

            // scroll the div to the bottom
            console.ConsoleDiv.scrollTop = console.ConsoleDiv.scrollHeight;
        }
    }
}

Ideally you’d drop this into an included script file, but it’s more likely that you’ll paste it into a <script> tag in the header of your HTML document.

 

The HTML that creates the DIV to contain the output:

<!--
 This is here for JavaScript debugging. Please use calls to console.log(message) to log to this console, as
 we're emulating the console.log() function that real browsers provide.  -andrewh 11/3/09
 -->
 <div id="JavaScriptConsole" style="position: absolute; bottom: 30px; left: 30px; width: 600px; height: 200px; overflow: scroll; background-color: Yellow; color: Red;">
     <a href="javascript:document.getElementById('JavascriptConsole').style.visibility = 'hidden';" style="float: right;">Close</a> <span style="font-weight: bold;">JavaScript Console</span><br />
 </div>

Note that this div also contains a hyperlink with JavaScript code in it to hide it.

 

A simple hello world script to log to it:

<script type="text/javascript">
   1: console.log("Hello, world!");

</script>

 

… and finally, the output:

image

Microsoft’s Azure Services Platform

… and why you really should care.

I’m sitting in a Microsoft user group meeting right now, and I am, to be honest, pretty unimpressed. Not with the presenters – they’re doing a good job – or with the presentation, which is on what should be a fascinating topic, but with the people. Sorry, Microsoft, but the greatest problem you face right now is not your technology; it’s pretty damn good[1]. It’s the people who are afraid of using it – who, sadly, aren’t very.

OK, I’m home now, so I can type properly.

The presentation topic was the Azure Services Platform, which is Microsoft’s  answer to the Google cloud. Azure is a fascinating topic, both technically and strategically. The technical merits I’ll discuss in a minute. Strategically, however, this platform shows that Microsoft is quaking in its boots over what Google’s been doing with cloud computing, and is now trying to play catch-up. The degree of success a) remains to be seen; and b) depends upon the aforementioned people who are going to have to want to learn to use and exploit its strengths.

This platform gives immeasurable advantages to whomever wants them: almost infinite scalability, massive parallelism and redundancy, no more worries about server provisioning or downtime… the list goes on.

One of the reasons I’m so irritated is that instead of asking intelligent questions like, “How much can we scale a single computational task?” or even “How does this compare to the Google cloud in terms of speed, flexibility and response time?” people asked questions around keeping their own servers (“Can I still be woken up at 3am when a server falls over, please?”) and security (“Can I host my own database and have the platform talk to it?” or, in other words, “Can I still trust Microsoft with my unencrypted data, but nonetheless re-introduce my own single point of failure into an otherwise-well-designed system?”). Honestly.

I don’t want to rant, so suffice it to say this:

Learn about your craft. Go and sign up for the Azure CTP. Go and get your Google App Engine key. Read about the Google file-system and Amazon’s S3. And, while you’re at it, go and re-read some Knuth and some Fowler[2], just because you should, and probably haven’t.

Get some enthusiasm about what you’re seeing, people. It’s brilliant. Go and learn about it. For what it’s worth, if you haven’t been hanging out for a cloud computing solution from Microsoft for a very long time, I most respectfully suggest that you might be in the wrong profession.

 

[1] Except for Live Writer. What were you thinking, guys? Writing this post has been painful. I tried to screenshot the crash messages and embed them into another blog post (also in Live Writer) and it crashed, too. Fail.

[2] Who are they? Shame on you.

#if DEBUG Considered Harmful

I know, I know. Lots of people have written about this one, but nonetheless it still gets used and I feel I should add my $0.02. (That’s Australian money, by the way, so it probably works out at not very much in your own currency.)

This post is specific to C#, as .NET has the very nice feature of code attributes, specifically the ConditionalAttribute class which allows methods to be compiled and invoked by the JIT compiler only if there’s a particular compilation variable set.

Consider the code below:

private static void Hello()
{
    Console.WriteLine("Hello, world!");
}

private static void Goodbye()
{
    Console.WriteLine("Goodbye, cruel world!");
}

public static void GreetTheWorld()
{
    #if DEBUG
    Hello();
    #endif

    Goodbye();
}

Let’s say that we compile this in Debug mode with code analysis turned on and warnings set to errors. (We all compile with warnings == errors, right?) All is well.

We go to run our unit tests again in Release mode prior to check-in, so we recompile in Release mode. (Or, if we’re lazy, we just check in from our Debug build and let our build server compile and run the tests in Release mode.)

Oops. CA1811 violation: you have uncalled private methods in your code. Please call them if you meant to call them, or remove them if not. The FxCop engine will never notice that our #if DEBUG directive has compiled out the call to our Hello() method, so code analysis throws an error.

Use this one instead:

[Conditional("DEBUG")]
private static void Hello()
{
    Console.WriteLine("Hello, world!");
}

private static void Goodbye()
{
    Console.WriteLine("Goodbye, cruel world!");
}

public static void GreetTheWorld()
{
    Hello();
    Goodbye();
}

This makes the compiler much happier.

Let’s consider the first piece of code again, though, and edit it in Release mode. Perhaps we’d like to rename our methods to something more descriptive of what they do: PrintHello() and PrintGoodbye(). So, we whip out our trusty refactoring tool (^R ^R in Visual Studio) and tell it to rename our methods.

Here’s what we end up with (remembering that we’re in Release mode):

private static void PrintHello()
{
    Console.WriteLine("Hello, world!");
}

private static void PrintGoodbye()
{
    Console.WriteLine("Goodbye, cruel world!");
}

public static void GreetTheWorld()
{
    #if DEBUG
    Hello();
    #endif

    PrintGoodbye();
}

Oh, sod. We’ve introduced a compilation error because the refactor/rename operation uses the compiled version of the code to check for symbol usage, and our call to the former Hello() method doesn’t appear in the compiled assembly because the #if DEBUG check caused it to not be compiled. We’ve left the old call to Hello() unchanged.

If we’d performed the same operation on the second piece of code instead, we’d be laughing.

Brisbane Alt.Net User Group Launched

The Brisbane Alt.Net User Group has launched. Check it out at Brisbane Alt.Net or, even better, turn up to the first meeting in February.

Next Page »