Why Are We Still Using Internet Explorer 6? – Part Two

Nearly a year and a half ago I wrote this post about why many large organizations are still using Internet Explorer 6. Every now and again, the post is re-discovered and is re-circulated and I get some great feedback about it. I’ve decided that it is time for a bit of an update on the subject, so here goes.

I’m going to assume that you’ve read my original post, but in one line, the reason many large organizations still use Internet Explorer 6 is application compatibility. My employer (a large government department) has recently experienced this first-hand, having had to postpone deployment of Internet Explorer 8 after discovering compatibility issues (mid-deployment) with some important business applications. I have no idea how come they only discovered the issues after starting to deploy. Either someone didn’t do due diligence and test before-hand, or worse, they were completely clueless about the risks of incompatibilities. Either way, as a fellow IT employee in the same organization, it’s down right embarrassing.

One of the most frequent comments I receive as feedback on my original post is that folks get the compatibility issues, but they believe that we wouldn’t be in this situation if these incompatible applications had been written using web standards. It’s the fault of the application developers that their applications only work properly with Internet Explorer 6.

Continue reading

Why Are We Still Using Internet Explorer 6?

There has been some discussion online recently between public servants about how the public service is still overwhelmingly using Microsoft Internet Explorer 6. I got involved when someone tweeted a link to this site: http://hey-it.com/download.html. The site provides cute posters asking the IT folks to basically get off their arses and give us a newer web browser. I responded back that there are other issues involved when upgrading web browsers, such as legacy application compatibility, and that things aren’t as clear cut as it may seem from the perspective of someone outside IT.

Well, responses to that included “don’t punish users for your deployment issues” and “are you afraid of losing your job if I upgrade my own browser”? Oh, and the term “visionless IT geeks” was tossed around. My response to this was a flurry of tweets quoting other folks rhyming off reasons why large organizations all over still use Internet Explorer 6. I then signed off Twitter and did not log back in for two days.

I essentially had a hissy-fit.

Continue reading

Working from Home

In case you weren’t aware, we are on day 8 of a transit strike here in Ottawa. I don’t drive (at all) so I normally rely heavily on the bus system here (which, in my mind, is top notch, when it’s running). Fortunately the nature of my work (and my manager) has allowed me to work from home on most of the strike days so far.

I was a little worried about working from home. I wasn’t sure how productive I’d be. But as it turns out, I am more productive at home than I am in the office. Here is a quick pro and con list of my experience working from home so far:

Pros:

  • I control the work environment (temperature, lighting, etc.)
  • Quiet! I am all by myself all day (heaven for an introvert like me)
  • More screen real-estate. At the office I have dual 17″ monitors (both @ 1280×1024). At home I am using a laptop (@ 1600×1050), plus the laptop is hooked into my 2nd monitor via the KVM (@ 1280×1024) PLUS I have my 24″ monitor (@ 1920×1200) connected to my home PC, which I can use for web browsing, media, etc). That’s over 5 million pixels in all!
  • Quiet! I can get focused and stay focused (again, for an introvert, getting focused, or getting back into focus, can be difficult)
  • Lunch and snacks are closer, and cheaper.
  • I have full access to the office network (via VPN) and my office PC’s hard drive.
  • Better chair than the one in my office.
  • I can play my music as loud as I want!

Cons (both relatively easy to resolve):

  • The laptop only has 1 GB of RAM!
  • I haven’t been able to get the laptop to share my mouse and keyboard (the mouse works, but it’s laggy. No wonder though: USB Mouse -> USB to PS/2 adapter -> KVM -> KVM Cable -> PS/2 to USB adapter -> laptop). Update: Resolved via laptop docking station borrowed from the office.

Here’s my home office setup:

IMG_2150 IMG_2151

Investigating a .Net Web Application’s Performance Issues

Yesterday my boss and I meet with a group that has been having some significant performance issues with one of their web applications.

It’s a basic .Net web forms application (in C#). Their issue was that they had one page that was taking upwards of 75 seconds to load! Seriously. 75 seconds! They said they were using NHibernate and they had tracked the issue down to one method that was taking up the majority of those 75 seconds. They also said they had tried some direct database (Oracle) queries that returned MUCH faster than the NHibernate.

We suggested that they look at caching the results of the database queries and that they confirm exactly what queries NHibernate is making on their behalf (I think they assumed it would execute the same query they had tested directly, which may or may not be the case).

Now I am a fan of NHibernate, and I have done some things with it that resulted in less than stellar performance, but I’ve always found tweak things to near direct database performance levels without much effort by changing/correcting some basic assumptions I had about the data and model. So when I left the meeting I felt that NHibernate had unfairly been labelled as the source of the performance issues, so I decided to have a look at the code for myself.

After grabbing a local copy of the code from their source control repository, I ran the code in debug mode and quickly came to the conclusion that the method they had identified as taking a long time to execute was in fact really taking a long time to execute. So I had a closer look at that method, and here (essentially) is what I saw:

/* ... */
IQuery query = CreateQuery("SELECT ...");

for (i = 0; i < query.List().Count; i++)
{
    if ((!((object[])(new ArrayList(query.List())[i]))[0] == null) 
       && (!((object[])(new ArrayList(query.List())[i]))[2] == null))
    {
        String value = (((object[])(new ArrayList(query.List())))[2]).ToString();
    }
}
/* ... */

I am “paraphrasing” a bit (the real code was worse).

The query.List() call returns an IList instance containing all the results of the SQL query. I don’t know if each call to query.List() actually executes the database query again (there may be some caching involved somewhere) but each call to query.List() did involve some database activity (according to my network sniffer). You notice that query.List is being called 3 times per loop (in the real code it was more like 6 times per loop)!

Changing this code to make one call to query.List, storing the results in a local IList variable and subsequently re-using that local variable shaved nearly 50 seconds of the response time.

On top of that there would also be improvements by removing the code that creates 3 ArrayLists per loop (again in the real code, 6 ArrayLists per loop), copies the IList of database results into each ArrayList, uses each of those ArrayLists to access only one single item and them discards the ArrayLists (only to recreate them again on the next loop).

NHibernate wasn’t the source of their problem…

A Day Spent Refactoring Code

I spent a good part of today refactoring some code I’ve inherited. It’s a VB.Net wrapper around some commercial address verification software. Two examples of the type of functionality the software provides are address correction and address formatting.

Here is a simplified version of three of the classes I was given to work with: Address, CorrectedAddress and FormattedAddress. An Address is what you would provide to the verification software and the other two classes would be returned from either the address correction or address formatting functionality.

Public Class Address
    Public AddressLine As String
    Public City As String
    Public Province As String
    Public PostalCode As String
    Public Country As String
End Class
Public Class CorrectedAddress : Inherits Address
    Public Status As CorrectedAddress.Status
    Public Message As String

    Public Enum Status
        Valid
        Invalid
        Corrected
        [Error]
    End Enum
End Class
Public Class FormattedAddress
    Public AddressLineOne As String
    Public AddressLineTwo As String
    Public AddressLineThree As String

    Public Status As FormattedAddress.Status
    Public Message As String

    Public Enum Status
        Valid
        Invalid
        [Error]
    End Enum
End Class

Note that CorrectedAddress inherits from Address, but FormattedAddress does not. Both CorrectedAddress and FormattedAddress have a Status and Message properties (implemented as public fields above only for brevity). The Status properties both return similar, but not identical enumerations. In the actual code there were six classes like these two, but I am focusing only on these two for simplicity.

The whole thing didn’t seem quite right to me, and I struggled a bit to put my finger on how this should have been implemented. But then it hit me. CorrectedAddress isn’t really an Address. It’s a result of an address correction (that happens to have an address). “Is A” versus “Has A”. Remember the oft quoted Object-Oriented design principle:

Favour Composition over Inheritance

So I pulled the Address class out of the inheritance hierarchy, renamed CorrectedAddress and FormattedAddress to CorrectedResult and FormattedResult respectively and even threw in some Generics stuff to deal with the similar but different Status enumerations.

The result (the Address class was left as-is):

Public MustInherit Class Result(Of T As Structure)
    Public Status As T
    Public Message As String
End Class
Public Class CorrectedResult : Inherits Result(Of CorrectedResultStatus)
    Public Address As Address

    Public Enum CorrectedResultStatus
        Valid
        Invalid
        Corrected
        [Error]
    End Enum
End Class
Public Class FormattedResult : Inherits Result(Of FormattedResultStatus
    Public AddressLineOne As String
    Public AddressLineTwo As String
    Public AddressLineThree As String

    Public Enum FormattedResultStatus
        Valid
        Invalid
        [Error]
    End Enum
End Class

Much better!