Why I use multiple browsers

With Internet Explorer 9.0 on the way, I've been thinking about web browsers. Turns out that I use as many as ten different browsers at work (on Windows), another five browsers at home (on a Mac), and at least two browsers on the road (on an iPhone). Why in the world would I want to use that many different browsers?

Well, platform issues aside, the obvious answer is that I’m a web developer. And, as such, I need to create websites that are compatible with multiple versions of the major browsers. Here are the browsers I have used to do at least some compatibility testing here at Symetra:

  • Microsoft Internet Explorer 8.0, 7.0, and 6.0
  • Mozilla Firefox 3.5 and 2.0
  • Google Chrome 4.1
  • Apple Safari 4.0

But, beyond browser compatibility testing, I also use several different browsers on a daily or near-daily basis. Here’s why:

  • Internet Explorer 8.0 is my default browser. I use it for:
    • Active development, because it is the newest production version of the browser that accounts for the vast majority of our web traffic, both internally and externally. IE has to work!
    • Accessing internal websites, such as SharePoint and the Employee Intranet, because IE does a fantastic job of making security transparent to me. Plus, I can easily extend the search bar in IE to include internal SharePoint sites, like devZone.
    • Accessing external, Symetra-specific websites, such as the ADP Portal and the Learning Site, because IE is our internal standard, and these sites are required to work well with it.
  • I use Mozilla Firefox 3.5 for:
    • Accessing Rally, because Rally renders so much faster/better in Firefox than in any other browser – especially IE.
  • I use the preview browsers in Visual Studio and Windows Live Writer for:
    • Testing code changes before or blog formatting before firing up a web server or posting to my blog to make sure things look mostly correct. (Though, the Visual Studio browser, in particular, is notoriously incompatible with all major browsers, including IE. So, I end up having to test things in the real browsers anyway.)
  • I use the Newsgator FeedDemon 3.1 browser for:
    • Viewing articles linked to one of the RSS feeds I follow, because it is too convenient not to. (Though, technically, FeedDemon uses IE under the hood.)
  • I use Google Chrome 4.1 for virtually everything else, including:
    • Browsing the Internet, especially when I’m starting with a Google search, which accounts for most of my time on the Internet, because Chrome offers one of the fastest rendering engines on the planet, a convenient, combined address/search bar, and a fantastic, tabbed-browsing experience. (Though, I do like the way IE 8.0 will close the current tab, rather than closing the entire browser window when I accidentally click on the wrong X.)

Overall, I’d say I spend the most time in IE and Chrome: IE because I have to, Chrome because I like to.

What browsers do you use? And, why? Which is your default? Which is your favorite? Which browser do you wish would just go away?

Moving past and to the semantic web

In his recent conversation, a coworker mentioned if you’re still using the <table> tag to layout your web pages, “you need to move out of the 90’s.” Of course, I agree. And, I frequently use <div> tags instead of <table> tags.

But, a little digging on the web has shown me I’ve probably been overusing <div> tags. Instead, the recommendations I’m seeing (links at the bottom of this post) are to limit <div> tags to the main layout of your page – things like headers, content, side-bars, and footers. Then, use traditional HTML markup for the content inside each area of your layout.

One such example I ran across used the <fieldset> and <ol> tags to render a form. It looked like this:

<form>
  <fieldset>
    <legend>Please enter your credentials:</legend>
    <ol>
      <li>
        <label for="username">User Name:</label>
        <span class="input"><input type="text" id="username"/></span>
      </li>
      <li>
        <label for="password">Password:</label>
        <span class="input"><input type="text" id="password"/></span>
      </li>
      <li>
        <span class="submit"><input type="button" id="login" value="Login"/></span>
      </li>
    </ol>
  </fieldset>
</form>

Without any CSS, it rendered like this:

image

Of course, that’s not the nicest looking form. But, it does provide some distinct advantages – especially to users who depend on accessibility tools to “view” the web. By enclosing the elements of the form in an ordered list (<ol>), for example, the user can hear how many elements there are in the form.

And, by enclosing all of the fields in a <fieldset>, we give the user additional context that gets repeated with each <label> in the form. This would be particularly useful for a shopping cart, where the Address fields might be repeated in multiple contexts, such as shipping address and billing address. Just enclose each group of fields in a separate <fieldset> and give them an appropriate <legend>.

To get the form to look less like a list and more like a traditionally (<table>) formatted form, I used this CSS:

<style type="text/css">
    fieldset {
        width: 260px;
        border: solid 1px black;
        }
    ol {
        list-style: none;
        margin: 0px 0px 0px -60px ;
        }
    li {
        display: table-row;
        }
    li label {
        width: 100px;
        float: left;
        text-align: right;
        padding: 5px;
        }
    li .input {
        width: 140px;
        float: right;
        text-align: left;
        padding: 5px;
        }
</style>

After which, it rendered like this:

image

Or, after another five minutes, I created this CSS, to render the <label> tags above the <input> tags:

<style type="text/css">
    fieldset {
        width: 200px;
        border: solid 1px black;
        }
    ol {
        list-style: none;
        margin: 0px 0px 0px -30px ;
        }
    li {
        display: table-row;
        }
    li label {
        width: 100px;
        padding: 5px;
        }
    li .input {
        width: 140px;
        float: left;
        text-align: left;
        padding: 5px;
        }
</style>

This rendered the form like this:

image

So, in the end, I learned something today. I hope you do to!

Here are the links I promised:

Enjoy!

On Clarity and Abstraction in Functional Tests

Consider the following tests:

[Test]
public void LoginFailsForUnknownUser1()
{
    string username = "unknown";
    string password = "password";

    bool loginSucceeded = User.Login(username, password);

    Assert.That(loginSucceeded == false);
}
[Test]
public void LoginFailsWithUnknownUser2()
{
    using (var browser = new IE(url))
    {
        browser.TextField(Find.ById(new Regex("UserName"))).Value = "unknown";
        browser.TextField(Find.ById(new Regex("Password"))).Value = "password";

        browser.Button(Find.ById(new Regex("LoginButton"))).Click();
        bool loginSucceeded = browser.Url.Split('?')[0].EndsWith("index.aspx");

        Assert.That(loginSucceeded == false);
    }
}

Note the similarities:

  • Both methods test the same underlying functional code; and,
  • Both tests are written in NUnit.
  • Both tests use the Arrange / Act / Assert structure.

Note the differences:

  • The first is a unit test for a method on a class.
  • The second is a functional test that tests an interaction with a web page.
  • The first is clear. The second is, um, not.

Abstracting away the browser interaction

So, what’s the problem? Aren’t all browser tests going to have to use code to automate the browser?

Well, yes. But, why must that code be so in our face? How might we express the true intention of the test without clouding it in all the arcane incantations required to automate the browser?

WatiN Page Classes

The folks behind WatiN answered that question with something called a Page class. Basically, you hide all the browser.TextField(…) goo inside a class that represents a single page on the web site. Rewriting the second test using the Page class concept results in this code:

[Test]
public void LoginFailsWithUnknownUser3()
{
    using (var browser = new IE(url))
    {
        browser.Page<LoginPage>().UserName.Value = "unknown";
        browser.Page<LoginPage>().Password.Value = "password";

        browser.Page<LoginPage>().LoginButton.Click();
        bool loginSucceeded = browser.Page<IndexPage>().IsCurrentPage;

        Assert.That(loginSucceeded == false);
    }
}
public class LoginPage : Page
{
    public TextField UserName
    {
        get { return Document.TextField(Find.ById(new Regex("UserName"))); }
    }
    public TextField Password
    {
        get { return Document.TextField(Find.ById(new Regex("Password"))); }
    }
    public Button LoginButton
    {
        get { return Document.Button(Find.ById(new Regex("LoginButton"))); }
    }
}

Better? Yes. Now, most of the WatiN magic is tucked away in the LoginPage class. And, you can begin to make out the intention of the test. It’s there at the right hand side of the statements.

But, to me, the Page Class approach falls short. This test still reads more like its primary goal is to automate the browser, not to automate the underlying system. Plus, the reader of this test needs to understand generics in order to fully grasp what the test is doing.

Static Page Classes

An alternative approach I’ve used in the past is to create my own static classes to represent the pages in my web site. It looks like this:

[Test]
public void LoginFailsWithUnknownUser4()
{
    using (var browser = new IE(url))
    {
        LoginPage.UserName(browser).Value = "unknown";
        LoginPage.Password(browser).Value = "password";

        LoginPage.LoginButton(browser).Click();
        bool loginSucceeded = IndexPage.IsCurrentPage(browser);

        Assert.That(loginSucceeded == false);
    }
}
public static class LoginPage
{
    public static TextField UserName(Browser browser)
    {
        return browser.TextField(Find.ById(new Regex("UserName")));
    }
    public static TextField Password(Browser browser)
    {
        return browser.TextField(Find.ById(new Regex("Password")));
    }
    public static Button LoginButton(Browser browser)
    {
        return browser.Button(Find.ById(new Regex("LoginButton")));
    }
}

This is the closest I have come to revealing the intention behind the functional test without clouding it in all the arcane incantations necessary to animate a web browser. Yes, there are still references to the browser. But, at least now the intention behind the test can be inferred by reading each line from left to right. Furthermore, most of the references to the browser are now parenthetical, which our eyes are accustomed to skipping.

What do you think?

I’d like to know what you think. Are your functional tests as clear as they could be? If so, how’d you do it? If not, do you think this approach might be helpful? Drop me a line!

On Logical Layers and Physical Tiers

This post came out of a team design discussion last summer. We were trying to decide how to layer and deploy a new tool for administering part of our system. In order to work through the options, I took a step back and thought about design in the abstract. It helped me a great deal at the time. I hope it helps you, too.

Logical Application Layers

It makes good sense to design applications in logical layers. In most modern business applications, there are (at least) three layers:

  1. A UI layer to display information to the user and handle user input;
  2. A “middle-tier” or business layer to handle data validation and process business rules; and,
  3. A data access layer to handle storage and retrieval of data from some form of repository.

This allows you to keep all of your UI code together in one place, separate from the business rules and data access code (increasing cohesion). And, it makes it easy for you to ensure that the UI code never calls the data access code directly (reducing coupling). These are the hallmarks of good OO design.

Physical Application Tiers

It may also make sense to deploy your logical layers across multiple physical environments (or tiers). For example, you could:

  1. Deploy all three layers to a single physical environment (though not generally recommended), or
  2. Deploy the UI layer to a separate environment in a DMZ, or
  3. Deploy all three layers to separate physical tiers.

This allows you to improve security (through the use of firewalls and service accounts). And, it allows you to improve performance (through the use of load balancers at each tier). These are the hallmarks of a well deployed application. Notice though, that to do this, you need to design logical layers into your application well before you try to deploy it.

Packaging Logical Layers for Deployment to Physical Tiers

Packaging is the process of placing classes into DLLs. In other words, how do I decide where to put a new class when creating it? Obviously, if I plan to deploy the application across multiple physical environments, then it makes sense to create multiple packages (or DLLs). But, if I decide to host two (or more) layers on the same physical tier, I may still want to package those layers separately, and deploy both DLLs. So, packaging decisions can be influenced by deployment decisions, but not the other way around.

Furthermore, how you package your logical layers (in one, two or three DLLs) and where you deploy your logical layers (on one, two or three physical environments) has nothing to do with the logical layers themselves. In other words, no matter how I package and deploy my application, it will still contain the same classes and methods in each logical layer.

Service Layers

If you choose to deploy your logical layers on a single physical environment, each layer can call its subordinate layers directly (regardless of how many DLLs you create). But, if you choose to deploy your logical layers across multiple physical environments, then you’re going to need some glue to allow the layers to communicate across those environments. A common approach to this issue is to introduce a thin service layer between two logical layers to handle the communications, like this:

  • Front-end Tier
    • UI Layer
    • Service Layer Proxy
  • Back-end Tier
    • Service Layer
    • Business Layer
    • Data Access Layer

Notice that the service layer in this case actually spans the two physical environments. A portion of the service layer, called the “proxy” lives on the front-end. And, the remainder of the service layer lives on the back-end. Microsoft does a good job of hiding all this from you in WCF. But, the underlying proxy and service layers are still there.

The important thing to remember about service layers is that they should only handle the communications across physical environments. There should be no UI, business or data access logic in the service layer or its proxy. Again, this goes to increasing cohesion and reducing coupling.

Die, WinDiff! Die!

Have you ever used Microsoft WinDiff to compare two files? If so, I feel for you. The interface is terrible. It "merges" the two files into a single window and color codes any differences - red for the first file, yellow for the second file. If there are a bunch of large differences between the files, you'll feel like you've been teleported to McDonalds!

Fortunately, there are much better options available:

  • Beyond Compare is my favorite full-featured file comparison tool. The user interface is intuitive. Both file and directory comparisons are handled flawlessly. And, it will even synchronize the files in two different folders. The caveat is that Beyond Compare is not free. A "standard" license will set you back $30. A "pro" license costs $50. (The pro version adds three-way merge*, secure FTP support, SCC integration and more.)
  • WinMerge is an open source alternative to Beyond Compare. It, too, handles file and directory comparisons with aplomb. Though, it doesn't provide all the bells and whistles of Beyond Compare, it is absolutely free.

With these options at hand, there is absolutely no reason for anyone to continue using WinDiff!

-----

* A three-way merge is what you do when both you and a coworker change the same file. The merge tool looks at your file, your coworker's file, and the shared ancestor file, then merges the non-conflicting changes automatically. Conflicting changes will need to be resolved manually, but most three-way merge tools proved a simple "this, that, or both" format for selecting which change should be included in the final file.