Skip navigation.

CSS Challenge: Styling Definition ListsAll recent postsSilent Force by Within Temptation

Refactoring Web User Interface

When developing a web application you create a design roadmap first and then write code. A good system always evolves, a bad one get shelved. As you add more and more code you inevitably deviate from the original design guidelines and practices. You, as a team or a solo developer, introduce that unhealthy build-up which had better be removed at some point. That’s the circle of life, and it’s ok that it happens as long as you come back and refactor your code.

According to venerable Martin Fowler,

Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure. It is a disciplined way to clean up code that minimizes the chances of introducing bugs. In essence when you refactor you are improving the design of the code after it has been written.

[…] With refactoring you find the balance of work changes. You find that design, rather than occurring all up front, occurs continuously during development. You learn from building the system how to improve the design. The resulting interaction leads to a program with a design that stays good as development continues.

Microsoft has been diligently expanding its library of patterns and practices. Over the past couple of years I’ve seen a lot of sound guidance appear at their Patterns and Practices portal. I think we’ve become very comfortable with n-tier designs, Business Logic, Data Layers, Service Layers, and other notions.

One aspect of design I see lacking in the Microsoft camp is that of User Interface. I think the closest we’ve come is outlined in Design and Implementation Guidelines for Web Clients. These guides don’t really address the presentation, the “looks”, of web applications per se.

As of the time of me writing this, I haven’t seen anything on accessibility, usability and even cross-browser design as if we’re not even talking about web applications. It’s easy enough to throw sever controls and get a hodge-podge of HTML that breaks once you switch to an Mozilla, Opera or Safari.

Maybe instead of the greasy DataGrid control a Repeater or a DataList would’ve worked better in some particular situation. Or maybe it makes more sense to use an HtmlGenericControl to represent a paragraph of text rather than the ubiquitous Label control. Speaking of which, use of Label is often inappropriate because it renders as a <span>, i.e. an inline element, where you might need a block-level one (see (X)HTML Specs Made Easy). I’ll discuss appropriate choice of server controls in greater depth in another post.

Back To The Drawing Board

Just recently we’ve gone through an extensive UI refactoring of our product at work. I’ll share my approach here, so take it with a bit of proverbial grain of salt.

It’s a sobering experience to pull up a page in a browser, save it along with HTML, CSS, JavaScript, image files, etc, and then open it up in Macromedia Dreamweaver. Why Dreamweaver? Because it allows you to nicely format your HTML (which is almost never formatted perfectly in production), with everything properly indented and highlighted. This is where you actually see what’s being produced by all those server controls.

Believe it or not, but it’s easier to align server controls with the desired look once you know exactly where they fit on a page and what kind of markup they should produce.

You’re probably better off saving this page from Internet Explorer because ASP.NET regards other browsers as down-level and doesn’t emit some HTML. Validators are a good example. You don’t want to miss out on markup.

This is exactly what I did during my Microsoft.com Redesign exercise. I divided up parts of their home page into “building blocks” and had everything grouped into a masthead, content, footer block and so forth. With our own product it was a little easier because we’re more organized in this regard, even though we’re running a portal kind of application whose markup is assembled by various server controls.

This is a good opportunity to verify if your choice of this or that server control was correct. Need a nicely looking unordered list (<ul>)? Maybe a Repeater would fit the bill. Or you can build an HtmlGenericControl instead.

I’m not offering definitive advice on control choice because each project is unique and you have to assess on your own. It worked great for us. We’ve managed to cut down on page size considerably by ditching some markup-heavy Web server controls and using lighter HTML server controls. In some cases we had to go with sophisticated custom repeaters to have ultimate control over the rendering logic.

It also helps to see how you’re doing on styling. You immediately spot if you have excessive CSS rules. I call this CSS refactoring because over time you introduce ids and classes which can and should be combined, applied to a parent element, or removed altogether.

Just a quick example, lifted from MSNBC.com:

<td>
 <div class="boxBI_3032045"> 
  <div class="textHang"> 
    <div style="padding-bottom:3px">
       <span class="textSmall"><a href="...">Corrections</a></span>
    </div> 
    <div style="padding-bottom:3px">
        <span class="textSmall"><a href="...">Letters</a></span>
    </div> 
    <div style="padding-bottom:3px"><span class="textSmall">
        <a href="...">Newsletters</a></span>
    </div>
  </div> 
 </div>
</td> 

This can easily be refactored into:

<td>
 <div class="boxBI_3032045"> 
    <div>
       <span><a href="...">Corrections</a></span>
    </div> 
    <div>
        <span><a href="...">Letters</a></span>
    </div> 
    <div><span><a href="...">Newsletters</a></span>
    </div>
  </div> 
 </td>

<div class="textHang"> seems to be excessive here, so both classes, boxBI_3032045 and textHang can be combined with the 3px bottom padding accounted for as well. Also, spans around hyperlinks are dead weight because you can style hyperlinks directly.

Perhaps having divs inside divs for a sidebar is the wrong choice of markup here, when a list would do better:

<td>
 <ul class="boxBI_3032045">
    <li><a href="...">Corrections</a></li>
    <li><a href="...">Letters</a></li>
    <li><a href="...">Newsletters</a></li>
 </ul> 
</td>

The bottom line is it’s hard to see these optimization when you look at a bunch of server controls in the Visual Studio.NET Designer. Looking at the markup they all produce helps assess how you’re doing on the UI architecture itself and whether you need to revisit the choice of server controls to get what you’re after.

Rationale

This is not a petty exercise in code purity. We’re talking turkey here. This is about

  1. Consistency. You can’t expect your web app to provide the same experience to users of different browsers when you have an HTML hodge-podge on your hands.
  2. Performance. Allow me to quote the January issue of the MSDN Magazine: When you consider the user’s experience when downloading large amounts of view state data, you realize that the user’s pain threshold is really the limiting factor and that it’s crossed before the server has problems.

    This is not only about view state, but the payload in general.

  3. Good design. I began this post with Martin Fowler’s definition of refactoring. We want the design to stay good as development continues.

There are other benefits, such as improved usability, cross-browser compatibility, etc. They go along with the mantra that markup shouldn’t control you. You should control markup.

Comments

Comment permalink 1 Joe |
One thing that I have found to be helpfull in creating a common light-weight markup for the site I am working on now, is to isolate the developers from even knowing that css exists for the site, instead of creating markup and litering it with class="myCoolClass" or tons of style attributes everywhere, the developers use controls that when they are first writen are usualy not much more than a shortcut to something like div class="specialClass"... but then as the need for aditional functionality come in we expand the capabilities of that control.

This has worked pretty well, as not all the developers are focused on creating standard markup, but if there is a control for almost everything that they need, they tend to use them. And then one person can be put in charge of the markup for the site, to a certain extent.
Comment permalink 2 Rick Mason |
You can force ASP.net to emit the same HTML for other browsers as it does for IE by modifying the [browserCaps] element in machine.config. See http://aspnet.4guysfromrolla.com/articles/050504-1.aspx for the code.

We now do this for all our ASP.net servers.
Comment permalink 3 Milan Negovan |
Rick, what about validator controls? They won't work because the validation logic is written in JScript with Microsoft's proprietary plugs. You can fool the HTML writer, but the client-side script won't work.

That's why I prefer to leave things as they are right now. i.e. allow client-side validation in IE and always call Page.IsValid regardless.
Comment permalink 4 Rick Mason |
We use the validation controls but we turn off client scripting, so invalid JScript isn't a problem for us.
Comment permalink 5 Matthias Orgler |
Are there any testing frameworks especially designed for HTML/CSS? I know that the refactoring process is very painful, if you don't have a proper test suite. General GUI test frameworks don't seem to fit. Any ideas?

Matthias
Comment permalink 6 Milan Negovan |
Unfortunately, I don't know of any HTML/CSS refactoring tools. If you're looking for unit testing an ASP.NET app, take a look at NUnitAsp.

Emails and Notifications

Would you like to be notified when somebody responds to this post?  Would you like to have these comments emailed to you?

Submit your comment

Please enter only text since all HTML tags except hyperlinks will be stripped. Hyperlinks will become live links. Any comments with flaming or offensive language will be deleted. Be courteous to other posters. Thank you.

Your name (required):
Your email (optional):
Your site's URL (optional):
Enter this number
Type in the number above:
Comment (required):