July 30, 2006

UI Validation isn't that hard

After filling out an "email" form to contact customer service at our bank, I got the error "The transaction date you have entered is invalid. Please re-enter a valid date in "MM/DD/YY" format.". Sure enough, I had entered the transaction date as "7/25/06", not "07/25/06".

This kind of thing happens all the time on web forms. Another common example is phone number entry fields, which often demand the form of aaa-bbb-cccc or (aaa)bbb-cccc, or some other variant, refusing to accept any other.

This isn't rocket science. Most systems have APIs that can take various formats for date strings and figure out what they really mean. Even if there isn't an API on your web platform of choice, it can't be that hard to parse manually. However long it takes to implement, I would bet any amount of money that it's a fraction of the time spent by users re-entering data that didn't pass the validation.

Posted by Mike at 07:41 PM | Comments (1)

January 19, 2005

Great article on programming and junior engineers

I read this a while back, but kept forgetting to post a link here.

There’s a great article called “Picture Hanging”, all about the challenges in giving tasks to junior engineers. An excerpt:

It's like you're asking them to hang a picture for you, but they've never done it before. You understand what you need done - the trick is getting them to do it. In fact, it's so obvious to you that there are constraints and expectations that you don't even think to explain. So you've got some junior guy working for you, and you say, "Go hang this picture over there. Let me know when you're done." It's obvious, right? How could he screw that up? Truth is, there are a whole lot of things he doesn't know that he'll need to learn before he can hang that picture. There are also a surprising number of things that you can overlook.

It’s a brilliant essay.

Posted by Mike at 10:50 PM

April 07, 2004

Finally hired

We hired someone today! We interviewed him yesterday, gave him the offer today, he accepted today. He starts in 2 1/2 weeks.

One open position down, one more to go.

Posted by Mike at 10:03 PM

February 28, 2004

Yet another reason to love C#

This past week, a co-worker of mine tracked down a memory corruption bug in some C++ code of mine. The bug was that I had allocated memory using one of the numerous ways of allocating memory, but had failed to dispose of it using the matched method. To allocate something, you might use new, malloc, CoTaskMemAlloc, or QueryInterface (to get a COM object). The matched set of dispose operations would be delete, free, CoTaskMemFree, or Release. (I'm sure there are even more pairs -- those are just a few that I can think of off the top of my head.) Use the wrong dispose operation, and if you're lucky, the program will crash right away. In this case, of course, it didn't -- I had allocated a buffer with new, then it got disposed with CoTaskMemFree, and that worked most of the time. But when it did crash, the heap was corrupted for no obvious reason.

The cost of this bug? Days of QA being frustrated that the program crashed occasionally and trying (unsuccessfully) to find a reproducible case. More days for development to try to understand what was happening. More time for PMs fretting over the bug.

The bug was my fault, no doubt about that -- but why do I have to remember how I allocated something? Aren't computers supposed to keep track of this for me?

So, how does this work in C#? Simple: you don't ever even think about this. You allocate objects, and then later on, the garbage collector gets rid of them. How did you allocate the object? Doesn't matter.

And that's great. The computer knows how it was allocated, so it knows how to dispose of it. I don't have to think about it, which means that I can't screw it up. Since I can't screw it up, that's a bug that can't ever happen and won't cause us days of slip six months later in the project when the bug is finally triggered.

Posted by Mike at 12:21 AM | Comments (1)

January 25, 2004

Microsoft dev blogs

A lot of Microsoft developers are blogging now about what they're working on at http://blogs.msdn.com/. There are a lot of devs from the .NET and CLR teams that write there. It's a fantastic resource. If you're into .NET programming at all, check it out.

Posted by Mike at 01:17 PM

October 25, 2003

.NET AsyncCallbacks and completions

I ran into a bug in my code at work the other day that turned out to be because I misunderstood something how .NET Asynchronous Delegates work.

The basic idea behind Asynchronous Delegates is that you can split a function into two calls -- BeginInvoke to start the call asynchronously, and then EndInvoke once it's done in order to clean up the state and to get the return value (if any). There's also a WaitHandle exposed through IAsyncResult (IAsyncResult.AsyncWaitHandle) that you can use to wait for the call to be completed. Async Delegates are useful obviously for any async task, but are especially useful when you start working with .NET remoting, which lets you run code remotely. Since it's going over a network link, there's a huge advantage to being able to invoke the call asynchronously without having to block on the network call.

A C# example of calling an async delegate might look like:

	m_delegate = new DoSomethingDelegate(this.DoSomething);
	m_callback = new AsyncCallback(this.CompletionProc);
...
	IAsyncResult iar = m_delegate.BeginInvoke(m_callback, null);
	iar.AsyncWaitHandle.WaitOne();

My mistake was in thinking that the AsyncWaitHandle would be set (i.e., the call to WaitOne would finish) once the async callback (m_callback) had finished. But this isn't true: it is set as soon as the async call (the call through m_delegate) finishes.

In other words, once the async call finishes, the framework sets the AsyncWaitHandle and starts an async call to the AsyncCallback completion proc. If you really need to block until the AsyncCallback function finishes, you'll need to use something other than IAsyncResult.

You can download some C# sample code to see this in action. DoSomething is the async delegate, which sleeps for 1000 ms and returns. The completion proc also sleeps for 1000 ms and returns. When you run it, you'll see something like this:

About to call DoSomething at 0 ms
Enter DoSomething at 40 ms
Exit DoSomething at 1041 ms
WaitOne finished at 1041 ms
Enter CompletionProc at 1041 ms
Exit CompletionProc at 2042 ms

You can clearly see that IAsyncResult.AsyncWaitHandle was set ("WaitOne finished") at the same time as the async callback was called -- not when the async callback finished.

As a final note, you might wonder why there's a 40 ms delay between calling DoSomething asynchronously and having it actually start. This is true only the first time you use that asynchronous delegate -- subsequent calls have virtually no delay.

Posted by Mike at 10:54 AM

June 17, 2003

C# / COM interop and scarce resources

Recently, I had to write some C# code to call a specialized device driver. The driver manufacturer had supplied a COM object that support dual interfaces, complete with Typelib. So calling it from C# was easy -- add a reference to the COM object from your C# project file in Visual Studio .NET, and start using it. C# does a really good job with interoperability with COM. The typelib importer even converts COM 'connection points' (which never completely made sense to me) into .NET events (which make perfect sense to me).

The problem I was having had to do with releasing the COM object. Normally, in C#, you don't ever worry about releasing anything -- eventually, the garbage collector will run, and things will magically disappear. Microsoft has done a lot of work on the performance of .NET and the garbage collector in particular, so I've never really noticed the performance hit from this. However, one of the COM objects I received from the driver represented a scarce resource. For a driver, this is fairly common -- drivers have to hand out pointers to hardware resources all the time (for example, video card memory, which is often pretty limited). I couldn't wait for the garbage collector to run; by the time it did, the driver would have completely run out of the scarce resource.

Someone else at Microsoft on the .NET team finally pointed me to the obvious answer -- Marshal.ReleaseComObject does the trick. Despite the name, this isn't quite the same as just calling IUnknown->Release() on an object, because of the way the CLR handles ref counting of COM objects. For (lots) more information, check out this blog entry from a .NET engineer.

Posted by Mike at 11:42 PM

June 14, 2003

XML and C#

At work, we've been trying to use XML for our configuration files. Writing the XML files, and even the XML schema, has been pretty easy. Writing the pages of code to call MSXML from C++ to parse the files has been relatively simple, but still tedious. It is, after all, still pages of code to get all the properties you want out of a reasonably complex XML document.

Then I found out how to do it with C# and .NET. It's incredibly easy. Visual Studio .NET includes a command-line tool (xsd.exe) to convert an XML schema file to a C# data structure. The data structure is tagged with all sorts of attributes so that .NET can later know how to map the XML into that structure. So, from a schema file foo.xsd, you run:

   xsd /c foo.xsd

which creates foo.cs, containing the data structures defined by your schema.

Then, to fill in the data structure, you call the XMLSerializer to 'deserialize' the XML into your data structure:

TextReader myStreamReader = new StreamReader(@"c:\dev\foo.xml");

XmlSerializer serializer = new XmlSerializer(typeof(ConfigType));
ConfigType config;
try
{
   config = (ConfigType)serializer.Deserialize(myStreamReader);
}
catch(XmlException xe)
{
   MessageBox.Show (xe.Message, "XML Parse Error",
      MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch(InvalidOperationException ioe)
{
   MessageBox.Show (ioe.InnerException.Message, "XML Serialization Error",
      MessageBoxButtons.OK, MessageBoxIcon.Error);
}

And that's it. The exception handling is just so that you can figure out what the problem is should the XML file not parse. Assuming you didn't get an exception, your data structure (config) is completely filled in. To see what was set in the XML file, you just look at the fields in the data structure.

Posted by Mike at 10:26 AM

March 10, 2003

MakeWebPictures (C# code)

I finally posted a program I wrote a while back to generate web pages with thumbnails of and links to pictures. I've been using for a while now to generate most of the recently-posted picture pages (e.g., the London pictures). It's written in C#, mostly because it was a good excuse for me to learn something about C# and the .NET framework. If you're interested in such things, check it out. Full source code is included.

Posted by Mike at 03:49 PM | Comments (1)