Humble coder

One of the reasons I often dislike Joel Spolsky’s essays is because he makes me feel inferior for not having a Computer Science degree. He doesn’t inspire me to become a better coder; he makes me feel bad that I’m not a better coder in the first place.

Likewise, Paul Graham’s writings often concentrate on startups and the entrepreneurial spirit. Sometimes they’re good; sometimes they have the exact same effect as Spolsky—to make me feel worthless because I haven’t started my own company, and have no intention of doing so.

Rands, on the other hand, writes about management in an interesting and entertaining way, without making me feeling like a failure because I don’t have a team of people working for me. Likewise, I find Jeff Atwood an inspirational writer: in his dedication to coding as a craft, he understands that one of the keys to being a good developer is a fundamental desire to become a better developer. In his latest article, he takes Paul Graham to task for his “you suck” attitude. Thanks, Jeff—I needed that.

I still use this quote from Lois McMaster Bujold as my personal motto:

“There is this, about being the sparring partner of the best swordsman in Caribastos. I always lost. But if I ever meet the third best swordsman in Caribastos, he’s going to be in very deep trouble.”

I don’t know for certain, but I suspect that this attitude would give Paul Graham fits, but it would make Jeff Atwood smile. There’s the difference.

Speed up your laptop with a new hard disk

If you’re feeling dissatisfied with the speed of your laptop, there are a couple of quick and relatively low-cost ways to give it a bit of extra zing. The first option is to add more RAM. Most modern laptops make their memory slots easily accessibly by means of small panel that you can open up with nothing more than a screwdriver. Check with somewhere like Crucial to find out what memory modules you need, slap ’em in, and watch it go.

The second option is less known, but it is definitely the connoisseur’s choice: upgrade the hard disk. The ease with which this can be done varies greatly between manufacturers. With some, there’s a simple panel you unscrew; with others, you might have to consult Google to find a guide to fully opening up the case. And the reason a new hard disk can give you a speed boost is that most present-day laptops are fitted with a 4200 rpm disk, which is slow, slow, slow. The faster a hard disk spins, the faster it can provide your processor with data, and the faster your machine will load programs, read and save files, and even boot and shutdown. In fact, the whole machine will just feel snappier.

As a rough illustration, have a look at these (informal) timings from a WinXP laptop (Dell Inspiron 5150) I just upgraded:

Operation 4200rpm drive 7200rpm drive
From power up to Windows logon screen 46s 29s
Start up Outlook 2003 (cold start) 9s 5s
Start up Firefox 1.5.0.1 (cold start) 13s 7s

Faster disks are more expensive than slower ones, but you can get a sweet little 80GB Hitachi 7K100 Travelstar drive (7200rpm) for around £100. If you’re thinking about buying a new laptop because your own one has lost its zing, you might consider upgrading its disk rather than splashing out many times that price for a new machine.

One thing that always puts me off upgrading my main hard disk is the hassle of reinstalling Windows, applying patches, and configuring the system–and that’s all before I get round to installing all the applications I need for my everyday life. But…there is a BETTER WAY! Oh boy, is it better. Basically, you clone your disk (and its whole Windows installation) using open-source (free) tools.

The key requirements for this solution are a network connection, and access to an FTP server with LOTS OF SPACE (enough to hold your old hard disk). Ideally, this FTP server should be on your local network, because if it’s out on the internet, data transfers are going to take ages.

First of all, go to http://www.feyrer.de/g4u/ and download the g4u ISO image. Burn this image to a blank CD, and then use it for booting up the machine whose hard disk you’re upgrading (with the old hard disk still inside it). By following the instructions on the g4u web site, you can use the uploaddisk tool to upload a bit-for-bit copy of your main hard disk to an FTP server of your choice. (It will upload as a single, gzip-compressed file to save space.) Depending on the speed of the machine and the network, this may take some time (i.e. several hours), but it’s hands-off time. Set it going overnight, and come back the next morning.

Next, replace the old hard disk with the new one. Don’t bother with formatting. (YAY.)

Boot up with the g4u disk again, and now use the slurpdisk tool to download the old hard disk onto the new one. Again, this may take some time, but it will probably be faster than the upload.

Remove the g4u disk, and restart the machine. Assuming it was Windows you were running before, then your machine should boot up as normal without any further changes.

If your new disk is the same size as the old one, you’re done. If the new disk is bigger than the old one, though, (not an unreasonable assumption) there is one further step to take. If you go into the Disk Management tool, you’ll see that your new hard disk has a partition on it of the same size as the old disk, and a bunch of unallocated space. If you’re happy with adding a new drive letter to your machine, you can create a new logical drive in the unallocated space. However, if you want your system drive to make use of the whole disk’s space, you’ll need additional tools, because Windows doesn’t have built-in ability to resize your system partition.

Enter Knoppix. Go to the Knoppix web site and download the iso image for version 4.0.2 (or later), and burn this to a CD. Boot up from this CD into Linux, and use the QTParted tool (already present on the Knoppix disk) to resize your system partition. (Further instructions are available at the ntfsresize page.)

End result: a faster, bigger hard disk, containing an identical clone of your previous system installation. Although the elapsed time may be longer than the time for a complete Windows reinstall, you don’t have to worry about configuration or post-installation tasks. In my book, that’s a BIG win.

The double-padding/nowrap bug: how to make IE6 hit 100% CPU usage with some simple HTML + CSS

I came across an amusing bug in IE6 last week. The existence of a bug in IE is no great surprise, but the way it manifests itself is quite interesting: with just a tiny bit of HTML and CSS, you can cause IE’s CPU usage to spike up to 100% and stay there, slowly leaking away memory. It seems unlikely that this has never been seen before, (especially as it doesn’t occur in the IE7 beta), but I couldn’t find a reference to it anywhere on the web, so I’m posting it here.

It starts off with a simple piece of HTML:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
            "http://www.w3.org/TR/html4/strict.dtd"><html>
<head>
   <title>IE6 100% CPU test page</title>
</head>

<body>
   <table>
      <tr>
         <td>
            <p><span class="test">abcd efgh ijkl mnop</span></p>
         </td>
      </tr>
   </table>
</body>
</html>

Especially in table-based layouts, it’s not unusual to see a span wrapped in a p wrapped in a table cell. The problem kicks in, though, when you apply the following CSS:

<style type="text/css">
   p {
      padding:0.5em;
      position:relative;
      white-space:nowrap;
   }
   span.test {
      padding:1em;
   }
</style>

Setting the position of the p is potentially unusual, and you might wonder why the white-space:nowrap is being applied to the paragraph rather than the span, but at least on the surface, it all looks kosher. Nuh-uh.

I’ve set up a test page with exactly this code in it. Try using IE6 to visit it. Does everything seem to be working as normal? How about if you try resizing your window to narrow it down…and down…until it’s just wide enough to hold the text. Oh no! It’s dead. Poor IE.

Now imagine the text in the cell being wider, or the table having several of those cells in a row, so that even at a normal window size the CPU usage spikes as soon as you load the page. Major bumcraft. This was a pig to track down and debug.

But even having reduced the problem to a simple test case, I’m still not sure why this should go wrong. It looks like IE’s rendering model is unable to resolve a circular reference between the p and the span when the forced width of the nowrap and the added paddings interact. But beyond that…mmmidunno. As always, it pays to be on your guard when dealing with IE and padding.

Update (20 Feb 2006): After playing around with this bug a bit more, I’ve found that it’s even worse than I’d first described. You don’t even need the p to be embedded in a table cell to bring IE down. Using the same CSS as above, the following HTML is sufficient (example 2):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
            "http://www.w3.org/TR/html4/strict.dtd"><html>
<head>
   <title>IE6 100% CPU test page</title>
</head>

<body>
   <p><span class="test">abcd efgh ijkl mnop</span></p>
</body>
</html>

You don’t even have to use a p and a nested span, either. Although I haven’t tested every possible combination, it looks like any inline element nested within a block-level element shows the same behaviour, e.g. an em within a h3 or an a inside a div. If you nest a block-level element inside another block (e.g. a p inside a div, everything’s fine.

What’s even more amusing is if you remove the DTD from the HTML above, and watch what happens (example 3). IE still goes to 100% cpu, but it retains just enough spare capacity to refresh its display. This time, if you narrow the window down, the text disappears, and the window’s vertical scrollbar makes it look like the page has got enormously tall. But if you try scrolling up and down, the content is nowhere to be found. If fact, it looks like IE is still trying to figure out where the content should go, too: if you scroll part-way down the (blank) page, you’ll notice the scroll block jumping up and down like a confused monkey.

But then if you try to widen the window back to its original size, it freezes up completely again.

And yes, it also works if you place the style definitions inline, rather than in a <style> block (example 4):

<html>
<head>
   <title>IE6 100% CPU test page</title>
</head>

<body>
      <p style="padding:0.5em;position:relative;white-space:nowrap"><a style="padding:0.3em" 
href="http://www.example.com">abcd efgh ijkl mnop.</a></p>
</body>
</html>

If you needed another reason why it’s a really bad idea to allow visitors to use HTML in your blog comments section, well, there you go.

Wiggle stereoscopy, follow-up

Almost immediately after putting up my posting about Wiggle stereoscopy with Javascript, I got reports of funny behaviour with Internet Explorer. I can’t say this came as a great surprise.

To recap on the technique, the core idea was to:

  1. replace a composite image with a <div> of a fixed size,
  2. set the background-image of this div to be the same as the replaced image, and
  3. flip the position of the background image every 120ms

Replacing the composite image with a div

Toggling the background image position

You can see the original script in action in Example 1.

The problem lies with the way Internet Explorer handles CSS background images. If IE’s cache settings are at their least forgiving (i.e. check for newer versions of stored pages “Every visit to the page”), changing the background-position of the background image causes IE to requery the web server for the image in question. The answer will generally be “HTTP 304: Not Modified”, so at least it doesn’t re-download the image again, but there’s a good chance that 120ms (the flicker rate) is not long enough for the server round-trip to complete. Result: IE spends all of its time checking for a new version of the image, and no time at all actually displaying anything.

Internet Explorer set to check for a newer version of a page on every visit

This problem is comprehensively documented at FiveSevenSix.com. There is a workaround involving server settings, but that goes against my desire for a keeping the technique nice and simple to implement. Alternatively, I could probably have used a variant of the double-buffering technique to fix it. But upon reflection I wondered if it was worth using background images at all.

Background images are perfect if you want to transform a piece of naked markup (like a <ul> list) into something graphically pleasing. But the wiggle technique is specifically designed to animate an existing in-line image. So: the new version of the script (1.1) does the following:

  1. It wraps a <div> around the <img>,
  2. sets the overflow property of the <div> to hidden, so that the excess parts of the image are masked off, and
  3. changes to position of the <img> itself every 120ms.

Example 2 is running with version 1.1 of the script.

Another problem that the original wiggle script had was that even with IE’s cache settings at a more normal level, it interfered with the mouse hovering over any hyperlinks in the same page: the hand cursor would change immediately back to an arrow, and in some configurations the url of the hovered link would also instantly disappear from the status bar. Version 1.1 fixes this, too.

Dynamically created (or included) Javascript

Dynamically created page elements? No problem. Dynamically created Javascript? As in, using document.createElement() to create a <script> element? Sounds like black magic, and it’s not something I would have tried myself until I saw the article @import voor JavaScript on Naar Voren (in Dutch). Basically, it’s a technique for giving Javascript the ability to include other script files “on demand,” much in the same way as PHP’s include() and include_once() functions.

This technique has actually been around for a while: a quick google showed me the article “Javascript includes – yet another way of RPC-ing”, by Stoyan Stefanov from July of this year, which in turn points back to articles from 2002. In addition to making the whole include() thing possible (a fantastically useful feature), using dynamically generated script also allows you to use make remote calls to other domains–something the HmlHttpRequest object forbids. In fact, Simon Willison was just talking about this the other day, in the context of Yahoo!’s web service APIs now providing output in JSON format as well as traditional XML.

It’s all coming together. A bundle of key techniques that have been around for ages (Unobtrusive javascript, object-oriented javascript, Ajax/remote scripting) have suddenly seen massive adoption and tremendous development. Javascript has matured a great deal over the course of 2005, and is rapidly tuning into one of the cornerstones of modern web development. It’s a very exciting time for the field.

Windows Forms applications: Just Say No

Of all the things I’ve learned this year, the most important is this: in a corporate/enterprise environment, you need to have a damn good reason for building a client-side forms application instead of a web app.

I reached this conclusion after building an in-house stock control system as a Windows forms app. Here’s how the architecture ended up:

Order system architecture: actual implementation

There’s nothing too controversial here, I’m sure you’ll agree. The most unusual thing is perhaps placing the burden of document generation (stock spreadsheets, production orders, invoices, etc.) on the client. The reason for this was cost and (supposed) simplicity: all the client machines using the application are equipped with MS Office, and so I could use Office automation to interact with a set of existing document templates. Buying a server-side component to generate Office documents (such as SoftArtisans OfficeWriter) seemed too expensive given the small size of the app, and creating a new set of templates in order to use a less expensive (or open source) PDF creator seemed too elaborate. (Don’t even get me started on working with WordML.)

In fact, document generation was the deciding factor in building a client-side app. In retrospect, this is probably the worst decision I made in 2005. The downsides were numerous:

Deployments

The obvious one has probably been the least painful. My experiences with .NET zero-touch deployments have been mixed at best. I’ve seen it working, and I’ve had it working myself, but the experience was awkward. Same with application updaters. Distributing a .msi setup package is simple and mostly foolproof, though. Nevertheless, it means the clients have to reinstall whenever a new version is available. If I had to do this again, I would choose one of the hands-off approaches, and work through the pain to get it up and running. Still if this were a web app, I wouldn’t have to deal with any of this.

Asynchronous communication

Easy enough in theory, but a bugger to get right in practice. The main idea is to keep the UI responsive while it is talking to the server by doing all the web service calls on a secondary thread. It was a lot of effort just to get progress bars working properly, and in the end I’m not entirely convinced it was worth it. As a UI specialist I am fully aware of the need for continuous feedback and a snappy feel, but for a small project like this I think it was overkill.

The .NET Datagrid component

Bane. Of. My. Life. Looks fine on paper, or in a demo, but COMPLETELY USELESS in any kind of real-world scenario. The amount of code you have to produce (either by writing it yourself, or by copying it from those who have suffered before you) to get even simple functionality working, like setting row heights, colouring the grid, or adding a drop-down list to a cell is staggering. If you want to do any serious client-side development with grids, you really must buy a third-party component.

In fact, the whole “rich user interface” benefit that has traditionally been the advantage of forms applications needs to be completely re-examined in the light of modern web apps, which draw upon javascript for better and more responsive interaction (Prototype, Script.aculo.us, Rico et al.), and CSS for visual flair. I can see a trend these days (in corporate environments) towards making client-side forms applications look and feel more like web pages, whereas just a few years ago it was the other way round.

Office automation with .NET

Not nearly as good as it should have been. Sure, I was able to re-use the existing templates to produce niceply formatted documents, but the Office API hasn’t improved significantly since 2000. Add to that the painful burning sensation of accessing it through COM Interop, and you get a whole heap of…yuckiness.

So with the benefit of hindsight, what should I have done instead? I’m glad you asked. Here’s the architecture for version 2:

Order system architecture: v2

The Forms UI is going away, and will be replaced by a clean HTML/CSS/JS front-end. The business logic, which was distributed between the client and the server will now be purely server-based. (There will still be a certain amount of client-side validation via the ASP.NET validator controls, but that will be controlled from server-side code.) It might include some Ajax further down the line, but the initial development will be a simple, traditional page-based web app.

And document generation? Version 2 will be using the OpenDocument (OpenOffice.org) format. This is an XML format that is an awful lot easier to get right than WordML, meaning that I can use simple XmlDocument-based code on the server to create documents. The client machines will get OpenOffice 2.0 installed, and upon clicking a “Print” button will receive a response with a Mime type of application/vnd.oasis.opendocument.text. The web browser can then pass it straight to OpenOffice for viewing and printing. OpenOffice has come a long way in the last few years, and version 2.0 is excellent. It happily converts Word templates to its own format, so I don’t even have to do much work in converting all the existing assets.

There is definitely still a need for client-side forms applications. If you want to make use of local hardware features, such as sound (e.g. audio recording), graphics (dynamic graphing and charting), and peripheral devices (barcode scanners), or if you want to have some kind of off-line functionality, you’re going to have to stick closely to the client. But for typical corporate/enterprise applications–staff directory, timesheets, CRM, and every bespoke data-entry package under the sun–I can see no compelling reason to consider a forms application as the default architecture.