Supporting free software: TortoiseSVN

It’s a new month, which means it’s time for me to pick a free, open source product to donate to. This month was an easy decision: I picked the product that I use every day to manage my code (and code history): TortoiseSVN.

I’m not the only one who’s ga-ga over TortoiseSVN; they recently were declared the Best Tool or Utility for Developers by the folks at SourceForge. With Subversion being the de-facto source code management standard (even Microsoft is starting to pay attention to it), it’s no surprise that TortoiseSVN is so widely loved.

I’m happy to have joined the list of those who’ve donated to TortoiseSVN!

My donation history to date far is as follows.

Simplify configuration with a generic ConfigurationElementCollection class

I’ve been using Phil Haack‘s Custom Configuration Sections in 3 Easy Steps for some time now, and my configuration file management has never been happier… until I needed to read a collection of configuration elements.

Here’s a sample of the XML I needed to incorporate:

<importer>
	<filespecs>
		<add type="EmployeeCSV" path="d:\import\employees.csv" />
		<add type="OrderCSV" path="d:\import\orders_*.csv" />
	</filespecs>   
</importer>

The typical solution is to write your own collection class (FilespecConfigurationElementCollection), inheriting from ConfigurationElementCollection, and ensuring your Filespec object inherits from ConfigurationElement. I figured there has to be a better way — and there is.

I wrote a generic version of ConfigurationElementCollection, which you can use to avoid writing the custom collection class. The code that follows is the generic class, the Filespec object I used, and the property declaration from my ConfigurationSettings class (as described in Phil’s previously mentioned article).

Note one key part of this implementation: You must override the ToString() method of your custom ConfigurationElement class to return a unique value. The generic ConfigurationElementCollection uses the ToString() method to obtain a unique key for each element in the collection.

// The ConfigurationElementCollection<t> provides a simple generic implementation of ConfigurationElementCollection.
[ConfigurationCollection(typeof(ConfigurationElement))]
public class ConfigurationElementCollection</t><t> : ConfigurationElementCollection where T : ConfigurationElement, new()
{
	protected override ConfigurationElement CreateNewElement()
	{
		return new T();
	}
	protected override object GetElementKey(ConfigurationElement element)
	{
		return ((T)(element)).ToString();
	}
	public T this[int idx]
	{
		get { return (T)BaseGet(idx); }
	}
}
// The Filespec class is an example of a custom configuration element.
// Note that we inherit from ConfigurationElement, and use ConfigurationProperty attributes.
public class Filespec : ConfigurationElement
{
	public Filespec()
	{
	}
	[ConfigurationProperty("path", DefaultValue="", IsKey=true, IsRequired=true)]
	public string Path
	{
		get { return (string)(base["path"]); }
		set { base["path"] = value; }
	}
	[ConfigurationProperty("type", IsKey=false, IsRequired = true)]
	public FilespecType Type
	{
		get { return (FilespecType)(base["type"]); }
		set { base["type"] = value; }
	}

	public override string ToString()
	{
		return this.Path;
	}
}
// Finally, our ConfigurationSettings class (only part of the class is included).
// Note how we use the generic ConfigurationElementCollection.
public class ConfigurationSettings : ConfigurationSection
{
// ...
	[ConfigurationProperty("filespecs", IsRequired=true)]
	public ConfigurationElementCollection<filespec> FileSpecs
	{
		get { return (ConfigurationElementCollection</filespec><filespec>)this["filespecs"]; }
	}
// ...
}

If you’re using a number of ConfigurationElementCollections, this is a great way to simplify your code.

Performance tweaks and bug fixes to WilsonORWrapper

A minor update today (with one breaking change) to WilsonORWrapper:

  • BREAKING CHANGE: Renamed RetrieveTotalRecordCount() to GetObjectCount().
  • Implemented SQL2005 paging support by passing dummy where clause when none specified (they are required with SQL2005 paging); this is a hack, not a fix; you should always specify a sort clause when using any paging operation!
  • Cached value of EntityBase.IsReadOnly on first load; allowed dummy set operator to permit ObjectDataSource usage.
  • Improved IdentityBase.GetHashCode performance with single column keys.
  • Refactored to ensure mapping file stream is disposed.

Thanks to Michael Mepham for help in identifying and resolving these issues. The latest source code is available in ZIP format; no compiled binaries yet.

Wilson.ORMapper subscriber source code repository

Many users of Paul Wilson’s O/R mapper (“WORM”) know that there are a number of community-provided patches which are out there but not incorporated in any official release. Personally, I have maintained a copy of the source code in a private Subversion repository and incorporated a number of these patches for my own use. (Access to the full source code of WORM require you to pay a very reasonable $50 “subscriber fee” to Paul Wilson.)

I contacted Paul Wilson yesterday, asking him if he’d let me grant access to this repository to people who are WORM subscribers. Fortunately for all involved, he said yes!

What does this mean for you? If you are a subscriber to WORM, you can send me your full name and email address and request access to this private repository. I will confirm your subscription with Paul and grant you access.

The following changes have been incorporated into the aforementioned WORM instance:

The purpose of opening up this Subversion repository to subscribers is to give us all a place to share and contribute to a central copy of WORM that includes all the improvements and patches we maintain individually.

If you want to participate, send me your full name and email address.

How to choose: Email, voice mail, or carrier pigeon?

Ayende posted how he has some 80+ unread and starred email messages waiting for him after a busy workweek. Reading this reminded me of a situation I ran into in the mid-1990s, while working in the IT group for a multinational bank. I went away for a little over a week, and I came back to find over 200 unread messages in my inbox. (This was before Blackberries and ubiquitous webmail.)

Reading through some 200 emails would have taken quite some time (even longer considering they used Lotus Notes), so I decided to take an alternate approach: I deleted them all.

Did I commit a grave error, deleting that all-important urgent email from a busy executive who needed to communicate something important to me? No, I did not. If something was that important, it would have been communicated to me via voice mail, or would have been redirected to one of my coworkers.

Granted, this may not be the best approach in all situations, but it illustrates some things we must recognize in a modern world.

  • Do not assume timely response to email. If something is urgent, you should always call someone. Never assume an email will be responded to in any timeframe, even if it has in the past: past performance does not predict future results.
  • Send a voice mail notice when sending important emails. If you have to send an email to communicate important information, call the person (leaving a voice mail message if necessary) notifying the person of the email.
  • Do not assume timely response to voice mail. Not everyone checks their voice mail regularly, so don’t assume your message will be heard any time soon.

Wait a minute — if we can’t rely on voice mail or email for timely communication, what can we do? Nothing, really. There will never be a convenient, reliable replacement for direct person-to-person communication. In my own life, I am trying to reduce my reliance on email and go back to traditional forms of communication (i.e. the spoken word, from my mouth to your ears). Email is convenient, but direct interpersonal communication (even if over the wire) is much more rewarding, interactive, interesting, and effective.

And remember… some people may seem to always be connected to the grid — via their Blackberry, Treo, web mail, text messages, mobile phone, or whatever. Just remember: batteries die, networks go down, service is not available everywhere, people forget to carry devices with them…

New York State highways: underperforming, but safe

imageA report released by the Reason Foundation, Performance of State Highway Systems, 1984-2005, 16th Annual Report, reveals two realities of New York State’s highway system, which you can see for yourself on their interactive map:

  1. It is highly inefficient.
  2. It is safe.

Anyone who lives in New Your State knows how bad our roads can be. In New York City (my home town), road surface anomalies come in many different styles (I never knew the proper name for a hummock until today).

Pothole Phil, courtesy of Staten Island AdvancePotholes in the big city have at times taken on lives of their own, and have created subcultures. Pothole Phil roams Staten Island, sticking his head in the many potholes he finds while smiling for the camera. Yes, this is the stuff of legends.

But what about the safety part? Why is it that New York State highways rank at the bottom in efficiency and quality, but at the top when it comes to safety (6th best in fatalities per 100 million miles)? It’s very simple, actually.

  1. Poor road conditions force drivers to drive slower to avoid a bone-rattling ride.
  2. High traffic conditions in New York force drivers to drive slower than the speed limit.
  3. You are less likely to get in a fatal accident when you’re driving slow.

Sometimes, the law of unintended consequences works out to some benefit.

Supporting Free Software: FileZilla

Last month, I announced that I’ll start donating $5 per month to a free and/or open source project. The first donation went to OpenOffice. This month, the donation goes to FileZilla, the free, open-source FTP client.

FileZilla is one of those utilities that you take for granted. It works so well that you tend to not think about it. There’s barely a day that goes by when I don’t fire up FileZilla at least once. Granted, there are plenty of FTP clients out there, and I’ve used many, but none satisfied me as much as FileZilla.

Thanks to Tim Kosse for starting and maintaining FileZilla over the years.

Supporting free software II: The saga continues

Last month, I posted about how I will start donating $5 per month to a free and/or open source project that I feel is worthy of my $5. (The first recipient was OpenOffice.) Over the past few days, the focus on .Net OSS projects has grown, partially thanks to Jeff Atwood. Ayende talks about putting OSS funds to good use on his projects (notably Castle/MonoRail/ActiveRecord), and a month ago Phil Haack talked about the growing .Net OSS attention.

Speaking of Phil Haack, he wrote today about his push for June 26th being “Contribute to Open Source Day“. To those professionals who use OSS projects regularly, I think $5 a month is hardly a lot of money.

(It’s not July yet, so I won’t announce who will get my next $5, but I assure you they will deserve it.)

Will you join the initiative to give $5 a month to a worthy open source project?

First community patch applied to WilsonORWrapper

Hot on the heals of yesterday’s update, I just received and applied the first community patch to WilsonORWrapper.

The patch, from Wayde Gilliam, adds the following:

  • Added MemberPrefix option to mappings generator, allowing member prefix (private field) customization
  • Added SetProperties method allowing dictionary-based changes
  • Added IncludeList option to mappings generator, allowing selective table inclusion (combines functionality with IgnoreList)

Hats off to Wayde for a well-written patch!

Release 43 (download source code) has the aforementioned changes, as well as an update to the readme file which gives kudos to Wayde and to Gunter Spranz, an early-adopter of this project whose insight and input was invaluable in the development of the product as we see it today.

Thanks to both — and don’t forget to go ahead and send in your own patch!