Archive for November, 2007

The Right Time to Update

Monday, November 26th, 2007

I use subversion for all of my personal and professional source code control. As I've stated before, I highly recommend that you set up an SVN repository for managing and sharing your own projects. My client of choice is Syncro SVN. But like all the other SVN clients that I've tried, it picks the wrong time to update.

When drilling down through the folders of a repository, all SVN clients pause each time a folder is opened to fetch data from the server. Syncro SVN keeps the tree populated while the program is running, so you can collapse and expand folders without penalty. However, once you close the program, it has to fetch folder contents all over again the next time you run it.

This pause for every folder puts a small tax on user navigation. It puts a speed bump on the road that the user takes to get something done. I hold in my head the place that I need to go and the thing that I need to do once I get there. A series of speed bumps, like the so-called "Chinese" water torture, can distract me from that goal and derail my progress.

An even more common example of the wrong time to update can be found in just about any program that downloads new versions of itself. Every once in a while, I start Firefox, Quicken, or iTunes to be asked if I want to install an update. The reason that I started this program was not to install an update. It was to get something accomplished. This question completely puts me off my goal and makes me worry. Is there some serious bug or security problem that I should let them fix? How long will this update take? What's the chance that it will fail and prevent me from accomplishing my goal altogether?

All of these programs let me say no, which I do by default. But then in most cases I'm just asked the question again the next time I try to get something done, so I eventually relent. Firefox is the best of a bad bunch, because it will hold off the update until the end of my session. Of course, it still has to ask, and then it has to tell me that it will update itself. I'd rather it just do that by default.

Here's my solution
I recently implemented automatic self update in a Windows program. I fashioned it after the Firefox model, but just made it work without any pop-ups.

First I created a launcher for the program. This launcher just runs the program, after doing some bookkeeping that I'll describe soon.

Then, when the program starts, it starts a background thread to go to the web site and check for newer versions. If it finds one, it downloads it in the background. If the user closes the program before the download completes, it is canceled. It will try again the next time the program starts.

If the download succeeds, then the new version is put in a sub folder for the launcher to find. This is the bookkeeping I was talking about. The next time the user runs the program, the launcher quickly (and silently) installs the new version before running it.

Update data in the background
The right time to update is when the user isn't looking. This works equally well for data updates as it does for software updates. Syncro SVN could start a background thread to pull down folder contents. This would get that processing off the main thread, and keep the user from experiencing a series of speed bumps.

But background processing isn't enough. If the background process is fired on demand, then the user is still waiting before going to the next step. You also need persistence. Once the folder contents are on the client, they should be accessible no matter what happens. If the user restarts the program, they should still be able to get instant access to folders that they've visited before. That means that those contents should be cached in someplace other than memory.

But wait! The user isn't seeing an up-to-date picture of the data! That's OK. It's fresh enough for the user to move forward toward his goal. Just refresh the data (in the background) when it gets too old. And give the user a manual refresh button if they don't see what they are looking for. Your user is smart. Just keep the speed bumps out of his way.

Definitive behavior patterns

Monday, November 19th, 2007

In a previous post, I described definitive behavior as something that doesn't change during the life of the object. This describes what definitive behavior is, but not how you would use it. Some of the ways to use definitive behavior are:

  • Immutable data types
  • Extenders
  • Views

Immutable data types
Objects in any OO language have properties that can change (dynamic behavior). When you can create an object and pass it into a method, that method can modify the state of the object. The caller might experience different behavior from the object after the method call than before. This is usually desirable, but sometimes it is not.

When it comes to fundamental data types, you don't want dynamic behavior. You don't want the method that you call to change your string or integer variables. In Java, C#, and VB (among others), these data types are immutable.

When you define your own data type, consider whether it will be used as a fundamental value. A complex number, for example, falls into this category. When you add two complex numbers, you want to return a new instance which holds the sum of their real and imaginary parts, respectively. You don't want to modify one of the addends, you want to return the sum.

The alternative to a value is an object with identity. Any number 3 is just the same as any other number 3. They are indistinguishable. But objects that have identity are unique, regardless of any defining characteristic.

Consider a person. You might define a PersonName class that has a first, middle, and last name. You might then define a Person class that has a PersonName property. A Person has identity irrespective of name. Two entirely different people can have the same name. And a person can change his or her name, but that does not change their identity. So while the PersonName class should be immutable, the Person class can change its name by creating a whole new instance of PersonName.

Extenders
How do you add properties to an existing object? One way is to declare a derived class, but then you have to create the object as an instance of that derived class. What if someone else has created the object, and they know nothing of your class?

A great way to do this is to define an extender class. This adds properties to an existing class through aggregation, not inheritance. The extender references the existing object and defines additional properties.

One example that I created long ago is a location model that extends network objects with their locations on a diagram. Routers, servers, and hubs have identity all their own. They know their IP addresses, their routing tables, and their connections to one another. But they know nothing about their representation on a two-dimensional network diagram. To add a point to a Server object, create a new LocatedServer object, having the reference of the Server and a point.

The properties that an extender adds to an object are dynamic. The user can drag the server around the network diagram. But the reference that the extender has to the object it extends is definitive. If you want to add a point to another server, you have to create a new extender for it.

Views
At some point, we want to present our objects to the user. It's best to separate the user interface from the business objects that it represents. Business objects should not know how to paint themselves. This gives you some flexibility in how you present your objects. The same objects can be presented in different ways within different contexts.

But the user interface is itself made up of objects, too. We have forms with text boxes, radio buttons, lists, etc. These are not business objects, so it's OK that they know how to paint themselves.

For the user interface objects to behave correctly, they need to know about the business objects that they represent. The user interface is simply a view into the business objects. The reference that a user interface has to a business object should be definitive. A form is created to edit just one object, and cannot be switched to another.

Some forms have navigators. You can hit a button to advance to the next record. In this case, the form is really tied to the collection of objects, not just the one. The reference to that collection is definitive; the current position within the collection is dynamic.

These are just three of the most common uses for definitive behavior. Other patterns exist, but most of your definitive behavior can be categorized as one of these. Be on the look-out for ways in which these appear in your code.

AiS 37: .NET Generics

Sunday, November 11th, 2007

Listen Now

I recently had the opportunity to speak at the Dallas .NET Users Group. My talk was entitled .NET Generics: more than just containers. You can find slides and code at the topic site.

We had a lot of people in attendance, and many great comments afterward. I was particularly impressed with the diversity of experience represented by the people who wanted to talk after the presentation. I spoke with people completely unfamiliar with generics, as well as some who have already been using the techniques presented.

What most impressed me, though, is that all of these people, regardless of experience level, found something to take away from the discussion. The beginners will be opening angle brackets for the first time for something other than HTML. And the experts will be experimenting with composite algorithms.

It just goes to show that no matter how much we know, there's always more to learn. Enjoy the adventure.

.NET Generics

Wednesday, November 7th, 2007

I've just launched a topic site for my upcoming .NET Generics presentation. I'll post audio and video when it's recorded, but you can get a preview of the slides and material.

If you are in Texas, please come to tomorrow's presentation at the Dallas .NET Users Group. It's at the Microsoft campus in Las Colinas, on November 8 at 6:30.

Generics are a powerful mechanism for code reuse. Most .NET developers have used generic collections, but few have used the language feature to its fullest potential. Generics let us declaratively build algorithms out of smaller components.

I'll present the syntax and some basic patters in both VB.NET and C#. All of the examples are based on practical scenarios. Complete source code is available in both languages.

Effective Dates: an example of degrees of freedom

Friday, November 2nd, 2007

I'm working on a bug in a billing system that underscores the importance of degrees of freedom. The problem is in the effective date calculation.

Prices are effective during a range of dates. The pricing table stores the beginning and end of each range. A query selects prices where the date of business is greater than or equal to the start date, and less than the end date.

The bug is that pricing edits can leave the pricing table in an invalid state. Moving a start date of one range affects the end date of the previous range. If the start date moves earlier or later, the ranges have to switch places. The logic to keep this in sync is complex and fraught with bugs. And the last date range needs to have an open end date, which gets fixed only when a new price is added for a later date.

Here's my solution
The number of unknowns in the system is 2n, a start and end date for each price. Each of these unknowns is being stored directly.

Each adjacent pair of ranges imposes one rule: that the end date of the previous is equal to the start date of the next. That's n-1 adjacent pairs, for n-1 equations.

Then there's one more rule which states that the final range has an open end date. This brings the total number of equations to n-1+1 = n.

The number of degrees of freedom is unknowns minus equations, or 2n-n = n. There is one degree of freedom per price. Therefore, we should only be storing one date for each price, and calculate the other.

This is just another way of getting to a solution that many of you have already jumped to. Only store the start date of each price. This lets us dump all of the complex update code that keeps the end date in sync.

To make this work, we had to change the query that uses end date. The new query selects all prices where the start date is on or before the date of business. Then it orders those prices by decreasing start date and decreasing create date. Finally, it selects only the top 1. This chooses the effective price that has not been superceded by a more recently effective price. In the case of a tie, this favors the price that was created later.

Bringing the storage in line with the degrees of freedom reduces the amount of business logic. Eliminating storage and logic can only eliminate bugs.