A Day In The Lyf

The lyf so short, the craft so longe to lerne

Managing Config Files

Posted by Brandon Byars Fri, 11 Jan 2008 03:39:00 GMT

There's a discussion on the altdotnet Yahoo group about managing configuration files. How do you manage updating multiple configuration files to change the appropriate values when deploying to a different environment?

The solution I hit on was to create a custom MSBuild task (yeah, I screwed up and used MSBuild instead of NAnt). When called from our build script, it looks something like this:

<ItemGroup>

    <ConfigFiles Include="$(DeployDir)/**/*.exe.config"/>

    <ConfigFiles Include="$(DeployDir)/**/*.dll.config"/>

    <ConfigFiles Include="$(DeployDir)/**/web.config"/>

</ItemGroup>

 

<ItemGroup>

    <HibernateFiles Include="$(DeployDir)/**/hibernate.cfg.xml"/>

</ItemGroup>

 

<ItemGroup>

    <Log4NetFiles Include="$(DeployDir)/**/log4net.config"/>

</ItemGroup>

<Target Name="UpdateConfig">

      <UpdateConfig

          ConfigFiles="@(ConfigFiles)"

          ConfigMappingFile="$(MSBuildProjectDirectory)\config\config.xml"

          Environment="$(Environment)"

      />

      <UpdateConfig

        ConfigFiles="@(HibernateFiles)"

        ConfigMappingFile="$(MSBuildProjectDirectory)\config\hibernate_config.xml"

        Environment="$(Environment)"

        NamespaceUri="urn:nhibernate-configuration-2.2"

        NamespacePrefix="hbm"

  />

      <UpdateConfig

        ConfigFiles="@(Log4NetFiles)"

        ConfigMappingFile="$(MSBuildProjectDirectory)\config\log4net_config.xml"

        Environment="$(Environment)"

  />

  </Target>

Notice that each call to UpdateConfig takes the list of config files that will be changed and a config mapping file. That mapping file is what is read to update the config files given the environment. Here's an example of what the mapping file looks like:

<configOptions>

    <add xpath="configuration/appSettings/add[@key='dbserver']">

        <staging>

            <add key="dbserver" value="stagingServer"/>

        </staging>

        <production>

            <add key="dbserver" value="productionServer"/>

        </production>

    </add>

</configOptions>

Each config file is scanned looking for each XPath expression in the mapping file. On each match, the entire node (and all its child nodes) of the original config file are replaced with the node under the appropriate environment tag in the mapping file. It's a bit verbose, but simple enough, and it supports as many environments as you want to have.

The MSBuild task itself is fairly simple, delegating most of its work to a separate object called XmlMerger:

private void MergeChanges()

{

    foreach (ITaskItem item in ConfigFiles)

    {

        string configFile = item.ItemSpec;

        XmlDocument configFileDoc = LoadXmlDocument(configFile);

        XmlDocument configMappingDoc = LoadXmlDocument(configMappingFile);

 

        XmlMerger merger = new XmlMerger(configFileDoc, configMappingDoc);

        if (!string.IsNullOrEmpty(NamespaceUri) && !string.IsNullOrEmpty(NamespacePrefix))

            merger.AddNamespace(NamespacePrefix, NamespaceUri);

 

        merger.Merge(environment.ToLower());

        configFileDoc.Save(configFile);

    }

}

XmlMerger just finds the nodes that need updating and replaces them from the mapping file. Notice that it also accepts namespace information (see the NHibernate example in the build script snippet above), which is occasionally needed:

public class XmlMerger

{

    private readonly XmlDocument configFile;

    private readonly XmlDocument configMapping;

    private readonly XmlNamespaceManager namespaces;

 

    public XmlMerger(XmlDocument configFile, XmlDocument configMapping)

    {

        this.configFile = configFile;

        this.configMapping = configMapping;

        namespaces = new XmlNamespaceManager(configFile.NameTable);

    }

 

    public void AddNamespace(string prefix, string uri)

    {

        namespaces.AddNamespace(prefix, uri);

    }

 

    public void Merge(string environment)

    {

        foreach (XmlNode mappingNode in configMapping.SelectNodes("/configOptions/add"))

        {

            string xpath = mappingNode.Attributes["xpath"].Value;

            XmlNode replacementNode = FindNode(mappingNode, environment).FirstChild;

            XmlNode nodeToReplace = configFile.SelectSingleNode(xpath, namespaces);

            if (nodeToReplace != null)

            {

                ReplaceNode(nodeToReplace, replacementNode);

            }

        }

    }

 

    private void ReplaceNode(XmlNode nodeToReplace, XmlNode replacementNode)

    {

        nodeToReplace.InnerXml = replacementNode.InnerXml;

 

        // Remove attributes not in nodeToReplace.  There's probably a cleaner solution,

        // but I didn't see it.

        for (int i = nodeToReplace.Attributes.Count - 1; i >= 0; i--)

        {

            if (replacementNode.Attributes[nodeToReplace.Attributes[i].Name] == null)

                nodeToReplace.Attributes.RemoveAt(i);

        }

        foreach (XmlAttribute attribute in replacementNode.Attributes)

        {

            if (nodeToReplace.Attributes[attribute.Name] == null)

            {

                nodeToReplace.Attributes.Append(configFile.CreateAttribute(attribute.Name));

            }

 

            nodeToReplace.Attributes[attribute.Name].Value = attribute.Value;

        }

    }

 

    private XmlNode FindNode(XmlNode node, string xpath)

    {

        XmlNode result = node.SelectSingleNode(xpath);

        if (result == null)

            throw new ApplicationException("Missing node for " + xpath);

        return result;

    }

}

That's it. Now the whole process is hands-free, so long as you remember to update the mapping file when needed. The config files we put into subversion are set to work in the development environment (everything is localhost), so anybody can checkout our code and start working without having to tweak a bunch of settings first. The deployment process calls our build script, which ensures that the appropriate config values get changed.

Posted in , | no comments |

Using Closures to Implement Undo

Posted by Brandon Byars Tue, 06 Nov 2007 05:26:00 GMT

While it seems to be fairly common knowledge in the functional programming world, I don’t think most object-oriented developers realize that closures and objects can be used to implement each other. Ken Dickey showed how it can be done rather easily in Scheme, complete with multiple inheritance and dynamic dispatch.

That’s not to say, of course, that all OO programmers should drop their object hats and run over to the world of functional programming. There is room for multiple paradigms.

Take the well-known Command pattern, often advertised as having two advantages over a more traditional API:

  1. Commands can be easily decorated, giving you some measure of aspect-oriented programming. CruiseControl.NET uses a Command-pattern dispatch for the web interface, and decorates each command with error-handling, etc, providing a nice separation of concerns.
  2. Commands can give you easy undo functionality. Rails migrations are a good example.

Recently, I had to retrofit Undo onto an existing legacy (and ugly) codebase, and I was able to do it quite elegantly with closures instead of commands.

What are closures?

Briefly (since better descriptions lie elsewhere), a closure is a procedure that “remembers” its bindings to free variables, where free variables are those variables that lie outside the procedure itself. The name come from LISP, where the procedure (or “lambda”, as LISPers call them) was said to “close over” its lexical environment. In C# terms, a closure is simply an anonymous delegate with a reference to a free variable, as in:

string mark = “i wuz here”;

DoSomething(delegate { Console.WriteLine(mark); });


Notice that the anonymous delegate references the variable mark. When the delegate is actually called, it will be within a lexical scope that does not include mark. To make that work, the compiler wraps the closure in a class that remembers both the code to execute and any variable bindings (remember – objects and closures can be interchanged).

As always, Wikipedia has a nice write-up. A C#-specific description can be found here.

What does a closure-based Undo look like?

The legacy code I needed to update maintained the entire object state serialized in XML. This was terrible for a number of reasons, but it did have the advantage of making undo easy in principle; just swap out the new XML with the XML before making the previous API call. I wanted something like this:

public delegate void Action();

 

public void AddItem(OrderItemStruct itemInfo)

{

    string originalXml = orderXml;

 

    Action todo = delegate

    {

        OrderApi.AddOrderItem(currentSession, ref itemInfo,

            ref orderXml, out errorCode, out errorMessage);

    };

 

    Action undo = delegate { orderXml = originalXml; };

 

    processor.Do(todo, undo);

}

In actual practice, the undo part of that could be wrapped up in some boilerplate code:

public void AddItem(OrderItemStruct itemInfo)

{

    CallApiMethod(delegate

    {

        OrderApi.AddOrderItem(currentSession, ref itemInfo,

            ref orderXml, out errorCode, out errorMessage);

    });

}

 

private void CallApiMethod(Action method)

{

    string originalXml = orderXml;

    processor.Do(method, delegate { orderXml = originalXml; });

    // error handling, etc…

}

Notice that the undo procedure is referencing originalXml. That variable will be saved with the closure, making for a rather lightweight syntax, even with the static typing.

Getting Started

Implementing a single undo is really quite easy. Here’s a simple test fixture for it:

public class CommandProcessorTest

{

    private const int CAPACITY = 5;

 

    private int testValue;

    private CommandProcessor processor;

 

    [SetUp]

    public void SetUp()

    {

        testValue = 0;

        processor = new CommandProcessor(CAPACITY);

    }

 

    [Test]

    public void SingleUndo()

    {

        int originalValue = testValue;

        processor.Do(delegate { testValue++; },

            delegate { testValue = originalValue; });

 

        processor.Undo();

        Assert.AreEqual(originalValue, testValue);

    }

}

...and the code to make it work:

public delegate void Action();

 

public class CommandProcessor

{

    private CircularBuffer<Action> undoBuffer;

 

    public CommandProcessor(int capacity)

    {

        undoBuffer = new CircularBuffer<Action>(capacity);

    }

 

    public void Do(Action doAction, Action undoAction)

    {

        doAction();

        undoBuffer.Add(undoAction);

    }

 

    public void Undo()

    {

        if (!undoBuffer.IsEmpty)

        {

            Action action = undoBuffer.Pop();

            action();

        }

    } 

}

I won’t go into how CircularBuffer works, but it’s such a simple data structure that you can figure it out.

Naturally, with undo, we’ll want redo:

[Test]

public void SingleRedo()

{

    int originalValue = testValue;

    processor.Do(delegate { testValue++; }, delegate { testValue = originalValue; });

 

    int changedValue = testValue;

 

    processor.Undo();

    processor.Redo();

    Assert.AreEqual(changedValue, testValue);

}

Conceptually, this should be fairly easy:

public void Undo()

{

    PopAndDo(undoBuffer);

}

 

public void Redo()

{

    PopAndDo(redoBuffer);

}

 

private void PopAndDo(CircularBuffer<Action> buffer)

{

    if (!buffer.IsEmpty)

    {

        Action action = buffer.Pop();

        action();

    }

}

However, we’re not actually adding anything to the redo buffer yet. What we need to do is rather interesting—we don’t want to add to the redo buffer until Undo is called. Closures to the rescue:

public void Do(Action doAction, Action undoAction)

{

    doAction();

    undoBuffer.Add(delegate

    {

        undoAction();

        redoBuffer.Add(doAction);

    });

}

But let’s say I undo, redo, and then want to undo and redo again. That won’t work as written, and making it work is starting to get pretty ugly:

public void Do(Action doAction, Action undoAction)

{

    doAction();

    undoBuffer.Add(delegate

    {

        undoAction();

        redoBuffer.Add(delegate

        {

            doAction();

            undoBuffer.Add(delegate

            {

                undoAction();

                redoBuffer.Add(doAction);

            });

        });

    });

}

It’s becoming apparent that what we really want is infinite recursion, lazily-evaluated. How ‘bout a closure?

public void Do(Action doAction, Action undoAction)

{

    doAction();

    undoBuffer.Add(DecoratedAction(undoAction, undoBuffer, doAction, redoBuffer));

}

 

private Action DecoratedAction(Action undoAction, CircularBuffer<Action> undoBuffer,

        Action redoAction, CircularBuffer<Action> redoBuffer)

{

    return delegate

    {

        undoAction();

        redoBuffer.Add(DecoratedAction(redoAction, redoBuffer, undoAction, undoBuffer));

    };

}

Now we see how easy it is to decorate closures—remember that the ability to decorate commands is an oft-quoted advantage of them. However, closures provide a more lightweight approach to programming than commands.

The elegance of this approach is hard to deny. All it takes is getting over the conceptual hump that functions are just data. Think about it—we just added a function that took two functions as arguments and returned another function.

What also was apparent to me is how much TDD helped me get to this point. It may not be obvious from the few snippets I’ve shown here, but building up to the DecoratedAction abstraction was a very satisfying experience.

For reference, here’s the full CommandProcessor class. The bit I haven’t shown, CanUndo and CanRedo, along with an event that fires when either one change, is there so that we know when to enable or disable a menu option in a UI.

public class CommandProcessor

{

    public event EventHandler UndoAbilityChanged;

 

    private CircularBuffer<Action> undoBuffer;

    private CircularBuffer<Action> redoBuffer;

 

    public CommandProcessor(int capacity)

    {

        undoBuffer = new CircularBuffer<Action>(capacity);

        redoBuffer = new CircularBuffer<Action>(capacity);

    }

 

    public void Do(Action doAction, Action undoAction)

    {

        FireEventIfChanged(delegate

        {

            doAction();

 

            // Redo only makes sense if we’re redoing a clean undo stack.

            // Once they do something else, redo would corrupt the state.

            redoBuffer.Clear();

 

            undoBuffer.Add(DecoratedAction(undoAction, undoBuffer, doAction, redoBuffer));

        });

    }

 

    private Action DecoratedAction(Action undoAction, CircularBuffer<Action> undoBuffer,

        Action redoAction, CircularBuffer<Action> redoBuffer)

    {

        return delegate

        {

            undoAction();

            redoBuffer.Add(DecoratedAction(redoAction, redoBuffer, undoAction, undoBuffer));

        };

    }

 

    public void Undo()

    {

        FireEventIfChanged(delegate { PopAndDo(undoBuffer); });

    }

 

    public void Redo()

    {

        FireEventIfChanged(delegate { PopAndDo(redoBuffer); });

    }

 

    public void Clear()

    {

        undoBuffer.Clear();

        redoBuffer.Clear();

    }

 

    public bool CanUndo

    {

        get { return !undoBuffer.IsEmpty; }

    }

 

    public bool CanRedo

    {

        get { return !redoBuffer.IsEmpty; }

    }

 

    private void PopAndDo(CircularBuffer<Action> buffer)

    {

        if (!buffer.IsEmpty)

        {

            Action action = buffer.Pop();

            action();

        }

    }

 

    private void FireEventIfChanged(Action action)

    {

        bool originalCanUndo = CanUndo;

        bool originalCanRedo = CanRedo;

 

        action();

 

        if (originalCanUndo != CanUndo || originalCanRedo != CanRedo)

            OnUndoAbilityChanged(EventArgs.Empty);

    }

 

    protected void OnUndoAbilityChanged(EventArgs e)

    {

        EventUtils.FireEvent(this, e, UndoAbilityChanged);

    }

}

Posted in , , , | no comments |

Configuring ActiveRecord to work with SQL Server 2005

Posted by Brandon Byars Wed, 24 Oct 2007 00:13:00 GMT

As much as possible, I like a zero-install configuration. In other words, I want to simply checkout a codebase, run an automated build process, and start working. Ideally, I’d like to be able to do that on a clean machine.

It doesn’t always work, of course. For instance, even though most of our production code is written in .NET, we use Ruby extensively for automation. Installing Ruby is one of those dependencies that we live with. But installing Ruby isn’t enough; we also need Rails (or at least ActiveRecord) for some data management scripts we have, Watir, and some fixes for ActiveRecord to work with SQL Server.

All of that can be done fairly easily by somebody who knows what they’re doing, but new developers often don’t know what they’re doing, and I strive to be dispensable. We wrote a script that configured Ruby and the necessary libraries to work for our development environment.

First, we needed to install the necessary gems. This is quite easy to do on the command line, but it took me a little digging before I figured out how to do it in code:

needed_gems = ["rails", "watir"]

require "rubygems"
Gem.manage_gems

needed_gems.each do |gem|
  puts "Installing gem #{gem}..."
  Gem::GemRunner.new.run ["install", gem, "--include-dependencies"]
end

SQL Server requires an ADO adapter that doesn’t ship with Ruby. You can read about it here. All that’s needed is to download the ADO.rb file (which we have versioned next to our setup script) and copy it to the right place, creating the directory if needed:

setup_dir = File.dirname(__FILE__)
ruby_dir = "C:/ruby/lib/ruby"
ruby_version = 1.8

# The ADO adapter needed for using dbi (the standard db access)
# with SQL Server, which does not come with ruby by default.
# See http://wiki.rubyonrails.org/rails/pages/HowtoConnectToMicrosoftSQLServer.

puts "creating ADO adapter..."
ado_dir = "#{ruby_dir}/site_ruby/#{ruby_version}/DBD/ADO"
system "if not exist #{ado_dir} mkdir #{ado_dir}"
system "copy /Y #{setup_dir}/ADO.rb #{ado_dir}"

Finally, we use SQL Server 2005, and we want to use Windows Authentication for all of our Ruby scripts. Neither SQL Server 2005 nor Windows Authentication is supported by rails out of the box. The problem, described on the SQL Server wiki for rails, is the connection string rails builds. At first, we were taking the suggestions of some of the comments on the wiki and changing the sqlserver_adapter.rb file that ships with rails. This obviously isn’t ideal, so now we monkey-patch it in our code that accesses the database:

module DBI
  # We have to monkey patch this because the SQL Server adapter that comes
  # with rails (active_record\connection_adapters\sqlserver_adapter.rb)
  # doesn't work with SQL Server 2005 or with Integrated Security yet.
  class << self
    alias_method :original_connect, :connect

    def connect(driver_url, username, password)
      # Change to SQL 2005
      driver_url.sub! "SQLOLEDB", "SQLNCLI"

      # Change to Windows Authentication
      driver_url.sub! /User Id=[^;]*;Password=[^;]*;/, "Integrated Security=SSPI;"

      original_connect(driver_url, username, password)
    end
  end
end

And that’s it. You still can’t checkout the codebase and start working on a clean machine, but it’s not bad. Install Ruby, run setup.rb. All database code has been patched to deal with our environment.

Posted in , | no comments |

Auto-merging fixes

Posted by Brandon Byars Tue, 23 Oct 2007 01:06:00 GMT

Paul Gross recently blogged about a rake task to automatically merge changes to the trunk if the change was made in a branch. This seemed like a useful feature, even though we don’t use rake.

Fixing productions bugs and merging is no fun, but why not take some of the pain out of the process? Depending on the developer and their mood, we either fix the bug in the trunk and merge to the branch, or fix it it the branch and merge to the trunk. Where it really gets ugly is when we have to merge two release branches back, because we make our release branch a few days before actually pushing it to production. Any urgent bug fix requiring a merge during that time has to be merged both to the new release branch as well as to the release branch currently in production.

Using Paul’s code as a base, I wrote automerge.rb, which, by default, either merges to the trunk (if you’re in a branch), or merges to the latest release branch (if you’re in the trunk). Alternatively, you can pass a release number, and automerge.rb will merge to that release branch. In all cases, you have to have the working copy checked out on your machine, and, if you’re on Windows, you need to make sure to put patch in your path.

The script assumes that your directory structure looks something like the following:

/trunk /branches /Release-2.8 /Release-2.9

The Release-major-minor format is just our branch naming standard; it’s easy to change.

if !ARGV[0].nil? dest_dir = "branches/Release-#{ARGV[0]}" replace_pattern = /(trunk|branches).*$/i elsif %x[svn info].include? "branches" dest_dir = "trunk" replace_pattern = /branches.*$/i elsif %x[svn info].include? "trunk" pattern = /^Release-(\d+).(\d+)\/$/ branches = %x[svn list http://devtools01:8080/svn/lazarus/branches] releases = branches.split.find_all {|branch| branch =~ pattern} # sort them in reverse order by major, minor releases.sort! do |first, second| first_major, first_minor = pattern.match(first)[1..2] second_major, second_minor = pattern.match(second)[1..2] if first_major != second_major second_major.to_i <=> first_major.to_i else second_minor.to_i <=> first_minor.to_i end end dest_dir = "branches/#{releases[0]}" replace_pattern = /trunk/ end puts "Merging changes into #{dest_dir}. Don't forget to check these in." dest_path = Dir.pwd.gsub(replace_pattern, dest_dir) puts dest_path system "svn diff | patch -p0 -d #{dest_path}"

The only tricky part here is figuring out the latest release branch, which is done by using the svn list command followed by a custom sort.

Posted in , | no comments |

C# Enum Generation

Posted by Brandon Byars Mon, 22 Oct 2007 02:54:00 GMT

Ayende recently asked on the ALT.NET mailing list about the various methods developers use to provide lookup values, with the question framed as one between lookup tables and enums. My own preference is to use both, but keep it DRY with code generation.

To demonstrate the idea, I wrote a Ruby script that generates a C# enum file from some metadata. I much prefer Ruby to pure .NET solutions like CodeSmith—I find it easier and more powerful (I do think CodeSmith is excellent if there is no Ruby expertise on the team, however). The full source for this example can be grabbed here.

The idea is simple. I want a straightforward and extensible way to provide metadata for lookup values, following the Ruby Way of convention over configuration. XML is very popular in the .NET world, but the Ruby world views it as overly verbose, and prefers lighter markup languages like YAML. For my purposes, I decided not to mess with markup at all (although I’m still considering switching to YAML—the hash of hashes approach describes what I want well). Here’s some example metadata:

enums = {
  'OrderType' => {},
  'MethodOfPayment' => {:table => 'PaymentMethod',},
  'StateProvince' => {:table => 'StateProvinces',
                      :name_column => 'Abbreviation',
                      :id_column => 'StateProvinceId',
                      :transformer => lambda {|value| value.upcase},
                      :filter => lambda {|value| !value.empty?}}
}

That list, which is valid Ruby code, describes three enums, which will be named ‘OrderType’, ‘MethodOfPayment, and ‘StateProvince.’ The intention is that, where you followed your database standards, you should usually be able to get by without adding any extra metadata, as shown in the ‘OrderType’ example. The code generator will get the ids and enum names from the OrderType table (expecting the columns to be named OrderTypeId and Description) and create the enum from those values. As ‘StateProvince’ shows, the table name and two column names can be overridden.

More interestingly, you can both transform and filter the enum names by passing lambdas (which are like anonymous delegates in C#). The ‘StateProvince’ example above will filter out any states that, after cleaning up any illegal characters, equal an empty string, and then it will upper case the name.

We use a pre-build event in our project to build the enum file. However, if you simply overwrite the file every time you build, you may slow down the build process considerably. MSBuild (used by Visual Studio) evidently sees that the timestamp has been updated, so it rebuilds the project, forcing a rebuild of all downstream dependent projects. A better solution is to only overwrite the file if there are changes:

require File.dirname(__FILE__) + '/enum_generator'

gen = EnumGenerator.new('localhost',database-name’)
source = gen.generate_all(‘Namespace', enums)

filename = File.join(File.dirname(__FILE__), 'Enums.cs')
if Dir[filename].empty? || source != IO.read(filename)
  File.open(filename, 'w') {|file| file << source}
end

I define the basic templates straight in the EnumGenerator class, but allow them to be swapped out. In theory, the default name column and the default lambda for generating the id column name given the table name (or enum name) could be handled the same way. Below is the EnumGenerator code:

class EnumGenerator
  FILE_TEMPLATE = <<EOT
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool from <%= catalog %> on <%= server %>.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace <%= namespace %>
{
    <%= enums %>
}
EOT

  ENUM_TEMPLATE = <<EOT
public enum <%= enum_name %>
{
<% values.keys.sort.each_with_index do |id, i| -%>
    <%= values[id] %> = <%= id %><%= ',' unless i == values.length - 1 %>
<% end -%>
}

EOT

  # Change the templates by calling these setters
  attr_accessor :enum_template, :file_template

  attr_reader :server, :catalog

  def initialize(server, catalog)
    @server, @catalog = server, catalog
    @enum_template, @file_template = ENUM_TEMPLATE, FILE_TEMPLATE
  end
end

The code generation uses erb, the standard Ruby templating language:

  def transform(template, template_binding)
    erb = ERB.new(template, nil, '-')
    erb.result template_binding
  end

template_binding describes the variables available to use in the template in much the same way that Castle Monorail’s PropertyBag describes the variables available to the views. The difference is that, because Ruby is dynamic, you don’t have to explictly add values to the binding. The rest of the code is shown below:

  def generate(enum_name, attributes)
    table = attributes[:table] || enum_name
    filter = attributes[:filter] || lambda {|value| true}
    values = enum_values(table, attributes)
    values.delete_if {|key, value| !filter.call(value)}
    transform enum_template, binding
  end

  def generate_all(namespace, metadata)
    enums = ''
    metadata.keys.sort.each {|enum_name| enums << generate(enum_name, metadata[enum_name])}
    enums = enums.gsub(/\n/m, "\n\t").strip
    transform file_template, binding
  end

  private
    def enum_values(table, attributes)
      sql = get_sql table, attributes
      @dbh ||= DBI.connect("DBI:ADO:Provider=SQLNCLI;server=#{server};database=#{catalog};Integrated Security=SSPI")
      sth = @dbh.execute sql
      values = {}
      sth.each {|row| values[row['Id']] = clean(row['Name'], attributes[:transformer])}
      sth.finish

      values
    end

    def get_sql(table, attributes)
      id_column = attributes[:id_column] || "#{table}Id"
      name_column = attributes[:name_column] || "Description"
      "SELECT #{id_column} AS Id, #{name_column} AS Name FROM #{table} ORDER BY Id"
    end

    def clean(enum_value, transformer=nil)
      enum_value = '_' + enum_value if enum_value =~ /^\d/
      enum_value = enum_value.gsub /[^\w]/, ''
      transformer ||= lambda {|value| value}
      transformer.call enum_value
    end

Caveat Emptor: I wrote this code from scratch today; it is not the same code we currently use in production. I think it’s better, but if you find a problem with it please let me know.

Posted in , , | no comments |

On Being Dispensable

Posted by Brandon Byars Mon, 17 Sep 2007 00:25:00 GMT

A question I like to give when interviewing prospective developers is, “what separates good software developers from bad ones?” I’ve heard different answers, ranging from “passion” to “experience.” I actually consider “experience” to be a pretty poor answer, as experience seems to correlate pretty weakly with skill.

I’ve worked with many bad developers, and I’ve been a bad developer. When I started out, I was just another Mort itching for the next Big Thing from Redmond. However, the one quality I did pick up very early was a sense of modesty about development. In my first job, I said “it’s impossible”—once. Thirty seconds later, I was shown that “it” was, in fact, not impossible, and oh, by the way, here’s how you do it. I haven’t said anything in software development is impossible since; it’s just that some things are harder than others.

I also make a habit of not saying “that makes no sense” when troubleshooting, as I’ve found out all too often that it really does make sense, once you change your way of thinking about the problem. “I don’t understand” is a much more accurate way of describing such problems. Ron Jeffries occasionally quotes Mary Doria Russell in his email signatures, and while I don’t know who Mary Doria Russell is, I certainly agree with her observation: Wisdom begins when we discover the difference between “That makes no sense” and “I don’t understand.”

But by itself, modesty does not a good developer make. And I can’t look back over my career and say that, the better I’ve gotten, the more modest I’ve become. I’ve been thinking about that quite a bit lately—what can I correlate to skill in my own development?

Dispensability

It was thinking about that question that reminded me of a quote by Jerry Weinburg in a book I read a few years back: “If a programmer is indispensable, get rid of him as quickly as possible.”

No better quote represents the distinction I’ve seen between the good programmers I’ve worked with and the bad ones. Simply put, the bad ones all seem absolutely indispensable. And the more skilled I have become, the more dispensable I have become. A few years ago, I was considered indispensable by my supervisor and peers. Now, I’m interviewing with other companies, and my company and I are considering the ramifications of me leaving soon. What we’re realizing is that the IT department should be fine without me.

Correlating dispensability with skill will likely come across as paradoxical (or just plain wrong) to people who don’t develop software, and to people who do develop software but aren’t very good at it. I say this because, when I first read the aforementioned Weinburg book, I thought it paradoxical, and wrong. After all, I was indispensable. That I also wasn’t any good didn’t occur to me until later.

No, any good developer is a dispensable developer. “That makes no sense,” you ask? Of course it does. What makes a developer dispensable?

Dispensable developers write simple, easy-to-read code. The code is cohesive and reads based on its intent. Bad developers write code that belies the fact that the only thing their interested in is getting something to work. The code therefore lacks cohesion and is a procedural ball of mud as the use case gets more and more involved. Bad code is written from the standpoint of “how can I make the computer do this?” Good code is written from the standpoint of “how can I make this understandable to a person?” It should be no surprise that, were the bad programmer to leave, nobody else would know what the hell to do with their code, whereas when a good programmer leaves, anybody should be able to maintain their code.

Good developers write tests for their code. Not the kind of tests that are written down as a series of steps in an Excel spreadsheet (“open the Doodle form, enter ‘blurf’ in the textbox, click the ‘Snarf’ button, and make sure that 2 appears in the status bar). The kind of tests where, at the press of a button, you can find out whether your changes have broken anything. Automated tests, and for those good developers who are test-infected, there will be no shortage of automated tests to help you out when the good developer leaves.

Good developers get bored doing the same tasks over and over, so they automate them. We have some code we purchased from a vendor. It is not good code. It’s terrible to read, has no tests, and we still can’t really figure out how to deploy it. On the other hand, our code has automated builds and automated deployments. We have automated database creations and automated database migrations. We’re developers, and good developers don’t like doing things that the computer can do better. That makes it much nicer when good developers leave.

Good developers make sure that other people understand their code. At my current job, in the dark days of A Few Years Ago, we all “owned” pieces of the system and worked in separate offices with little communication. Predictably, the system sucked, but we could console ourselves that it sucked because the other person sucked, and besides, we all had nice big offices and felt important. When I became manager, I started introducing the idea of collective code ownership. Then we started meeting face-to-face each day for stand-up meetings to decide who was to do what. Then we started pair programming. Then we gave up our offices and moved into a shared war room environment to do all of our work. With one exception, our developers took the changes well. That one exception was our worst developer, and he’d do anything he could to keep people out of code he had written. He’s been gone for a while now, and we still have trouble working with “his” code. In many cases, we’re seeing it for the first time. The code sucks, it’s untested, and he made sure that nobody else ever understood it.

Another developer moved on last year, but he did everything he could to make sure we knew how to handle what he had worked on. He paired with others often and worked well with the team. Before he left, he gave a presentation with a projector on everything he could think of that we might need to know. While I hated to lose him much more than I hated to lose the bad developer, I have to admit that it’s been much easier to live without him than it has been to live without the bad developer.

Nowadays, we have a very good team. We all work together well, and everybody gets to see everybody’s code. We model our environment on XP, and it’s somewhat enlightening to reflect how XP tends to make team members dispensable over time. Frequent releases? Gotta have automation. Pair programming and collective code ownership? Gotta let others see your code. Simplicity and shared standards? Gotta make sure others can read what you’ve written. Test-driven development and customer tests? Gotta make sure others know if they’ve broken code you’ve written without having to read it.

Good developers are hard to find. But it’s much easier to lose a good developer than it is to lose a bad developer.

Posted in | 1 comment |

log4net Connection String Blues

Posted by Brandon Byars Mon, 10 Sep 2007 03:01:00 GMT

We use log4net as our production logger, which has proven to be tremendously flexible. However, one problem I ran into was configuring the AdoNetAppender that logs to the database. It expects the connection string to be defined in the configuration file, which I didn’t want to do since it was already defined in our NHibernate config file.

This proved to be a relatively easy fix (found here):

private void SetConnectionStrings()

{

    Hierarchy hierarchy = LogManager.GetRepository() as Hierarchy;

 

    if (hierarchy == null)

        return;

 

    using (UnitOfWork unitOfWork = new UnitOfWork())

    {

        foreach (IAppender appender in hierarchy.GetAppenders())

        {

            AdoNetAppender dbAppender = appender as AdoNetAppender;

            if (dbAppender != null)

            {

                dbAppender.ConnectionString = unitOfWork.ConnectionString;

                dbAppender.ActivateOptions();

            }

        }

    }

}

However, the problem is that log4net whined to standard error about not having the connection string defined. The result was that any console application had its output garbled (including our tests, since some of them used the production logger).

The solution turned out to be going ahead and putting a connection string in the config file, but making it obviously invalid (e.g., “<ignore>”). Then, when the logger is configured, temporarily redirect standard error:

public void ConfigureLogger()

{

    FileInfo file = new FileInfo(ConfigUtils.GetFilePath(“log4net.config”));

 

    TextWriter stdErr = Console.Error;

    Console.SetError(new StreamWriter(new MemoryStream()));

 

    XmlConfigurator.ConfigureAndWatch(file);

    ServiceRegistry.Logger = new Log4NetLogger();

 

    Console.SetError(stdErr);

}

Voila.

Posted in | no comments |

Throw Out Those Utility Classes

Posted by Brandon Byars Wed, 29 Aug 2007 04:40:00 GMT

How many times have you written an xxxUtils class, where xxx is some framework supplied class that you can’t extend or subclass? I always seem to end up with several in any decent sized project, StringUtils, DateUtils, DictionaryUtils, etc. In most cases, these classes are the result of language limitations. In Ruby and Smalltalk, for example, what would be the point of a StringUtils class when you could simply add methods to the String class directly? But C# and Java make String sealed (final) so you can’t even subclass it.

Utility classes like these tend to suffer from logical cohesion. In spite of the friendly-sounding name, logical cohesion is actually a fairly weak form of cohesion; it’s just a loose jumble of functions that have something in common. It can in no way be considered object-oriented.

Our DictionaryUtils makes an interesting case study because it was small. It only did two things: compared two dictionaries key-by-key for equality (useful in testing), and converting the entries to a Ruby-esque string. That last method made me a little jealous of how convenient Hashes are in Ruby:

middlestate:~ bhbyars$ irb >> {'a' => 1, 'b' => 2, 'c' => 3} => {"a"=>1, "b"=>2, "c"=>3}

For the non-Ruby readers, I just created a 3-element Hash in one line. The command-line interpreter spit out a string representation. Our DictionaryUtils.ConvertToText could manage that last bit, but I wanted to be able to create hashtables as easily in C# as I could in Ruby. Naturally, that meant a third method on DictionaryUtils. Or did it?

C# on Hash

DictionaryUtils.Create seemed bloviated and ugly as soon as I first wrote it, so I quickly scratched it out and started a new class:

public class Hash

{

    public static Hashtable New(params object[] keysAndValues)

    {

        if (keysAndValues.Length % 2 != 0)

            throw new ArgumentException(“Hash.New requires an even number of parameters”);

 

        Hashtable hash = new Hashtable();

        for (int i = 0; i < keysAndValues.Length; i += 2)

        {

            hash[keysAndValues[i]] = keysAndValues[i + 1];

        }

        return hash;

    }

}

This allowed me to create small loaded Hashtables in one line, which was convenient, especially for test methods (although the syntax isn’t as explicit as Ruby’s). I then decided to merge the static DictionaryUtils methods into Hash, as instance methods. First, of course, I had to make Hash an actual dictionary implementation. This was trivial:

private IDictionary proxiedHash;

 

public Hash(IDictionary dictionary)

{

    proxiedHash = dictionary;

}

 

public bool Contains(object key)

{

    return proxiedHash.Contains(key);

}

 

public void Add(object key, object value)

{

    proxiedHash.Add(key, value);

}

 

public void Clear()

{

    proxiedHash.Clear();

}

 

// etc…

Then I changed the return value of Hash.New to a Hash instead of a Hashtable. The last line became return new Hash(hash) instead of return hash.

Next I moved the ConvertToText method, which, as an instance method, conveniently mapped to ToString.

public override string ToString()

{

    SeparatedStringBuilder builder = new SeparatedStringBuilder(”, “);

    ICollection keys = CollectionUtils.TryToSort(Keys);

    foreach (object key in keys)

    {

        builder.AppendFormat(“{0} => {1}”, Encode(key), Encode(this[key]));

    }

    return “{“ + builder.ToString() + “}”;

}

 

private object Encode(object value)

{

    if (value == null)

        return ”<NULL>”;

 

    IDictionary dictionary = value as IDictionary;

    if (dictionary != null)

    {

        return new Hash(dictionary).ToString();

    }

 

    if (value is string)

        return ”\”“ + value + ”\”“;

 

    return value;

}

The SeparatedStringBuilder class is a StringBuilder that adds a custom separator between each string. It’s very convenient whenever you’re a building a comma-separated list, as above. It’s proven to be handy in a variety of situations. For example, I’ve used it to build a SQL WHERE clause by making “ AND “ the separator. It’s included with the code download at the bottom of this article.

Notice, also, that we’re still using a CollectionUtils class. Ah, well. I’ve got to have something to look forward to fixing tomorrow…

The DictionaryUtils.AreEqual method conveniently maps to an instance level Equals method:

public override bool Equals(object obj)

{

    IDictionary other = obj as IDictionary;

    if (other == null) return false;

 

    Hash hash = new Hash(other);

    return hash.ToString() == ToString();

}

 

public override int GetHashCode()

{

    return proxiedHash.GetHashCode();

}

The syntax is much cleaner than the old DictionaryUtils class. It’s nicely encapsulated, fits conveniently into the framework overrides, and is object-oriented, allowing us to add other utility methods to the Hash class easily. It’s especially nice for testing, since the Equals method will work against any dictionary implementation, not just Hashes:

Assert.AreEqual(Hash.New(“address”, customer.Address), propertyBag);


The approach was simple, relying on proxying for fulfilling the IDictionary implementation (I’m probably abusing the word “proxying,” since we’re not doing anything with the interception. Really, this is nothing more than the Decorator design pattern). That was easy only because the framework actually provided an interface to subtype; the same isn’t true of String and Date. However, it isn’t true of StringBuilder either; if you look at the code, SeparatedStringBuilder looks like a StringBuilder, it talks like a StringBuilder, and it quacks like a StringBuilder, but there is no syntactic relationship between them since StringBuilder is sealed and doesn’t implement an interface. While the need for SeparatedStringBuilder may represent a special case, I think I’d prefer creating similar-looking objects rather than relying on a framework-provided xxx and a custom built xxxUtils class. Proxying, as used by Hash, generally makes such implementations trivial and clean, leaving you to spend your time developing what you really want without making the API unnecessarily ugly.

All the code needed to compile and test the Hash class can be found here.

Posted in | no comments |

Dealing with Exceptions

Posted by Brandon Byars Tue, 28 Aug 2007 02:35:00 GMT

We had an interesting discussion on the XP news group this past week about dealing with exceptions. The discussion seemed to focus on functions that return something rather than functions called for their side effects. Four general approaches were mentioned:

Return a special value (null or an error code)

This was generally seen as the weakest approach. Returning a null forces a null-check on each client of your method, which has the unfortunate effect of distributing complexity instead of localizing it. The canonical example is with lists—it is much better to return an empty list than a null one. Client code can work without any changes with an empty list. The same principle applies to error codes.

Throw an exception

This was the most controversial option. Several developers argued that exception handling is prone to the same weakness as the special return value, that it spreads complexity around. As Ron Jeffries’ said: “Throwing an exception doesn’t solve the problem any more than throwing up in the morning solves one’s drinking problem.”

Nevertheless, throwing an exception has proven to be the mainstream choice in modern languages, and the way exceptions bubble up the call stack can come in handy when used judiciously. Anthony Williams advocated using them, noting that they clearly signal an abortive operation (rather than relying on clients to check a return value), and allow application developers to write a global exception handler that catches any uncaught exceptions throughout the application.

The discussion intrigued me largely because I continue to use exceptions when convenient, although I’m interested in learning alternative approaches. I think that at least some of the hostility towards exceptions can be traced to the ugliness of checked exceptions (as in Java), which force clients to write try/catch blocks even if they’d prefer the exception bubble up.

Return a polymorphic value

This is probably the purest object-oriented solution, but I’m skeptical that it can work as a general case. Woolf’s Null Object Pattern is a special case—the empty list mentioned above being a simple example. We use a more sophisticated example in the content management system we developed for our website at work. When you go to ”/Content/AboutUs,” for example, the application knows “AboutUs” is supposed to be a content-managed page, and requests the content from the database. If the page doesn’t exist, rather than return null or throw an exception, it returns a new web page whose content matches our 404 page content.

If a page is content-managed, then users can edit it directly on the page in a fairly typical way. The content-managed portion is outlined with an ‘edit’ link at the top that puts the content in a WYSIWYG editor. However-this is the crucial point-the web page returned when it doesn’t exist in the database is a content-managed page. Yes, it has the 404 content, and anybody visiting that URL without content editing privileges sees what they are supposed to see. But if you do have content editing privileges, you see the familiar border with the edit link, and you can use the exact same procedure that you use to update other pages to create new pages.

The advantage to this approach is obvious—clients do not need to behave any differently regardless of whether the method call succeeded or failed. It was suggested that perhaps the same approach could be used even if some other exception occurred. I think in some cases it may be possible. I looked over some of our code for an example only to discover that the large majority of methods we use that throw exceptions have a void return type, but found an example of an exception-throwing method in our credit card processing code. The code simply sends an XML document to the company we use to process credit cards and returns a value representing the result of that transaction. It looks something like this:

public CreditCardResponse Send(string xml)

{

    IServerXMLHTTPRequest server = GetServer();

    try

    {

        server.send(message);

    }

    catch (Exception ex)

    {

        throw new ApplicationException(“The connection to the credit card server failed”);

    }

    return Parse(server.responseText);

}

This code clearly could benefit from removing the thrown exception and enhancing or subclassing CreditCardResponse. That return type is already responsible for reporting errors given in the return XML by the credit card processor; why would clients want to treat failing to connect to the credit card processor any differently than one of those errors?

Callbacks

At first glance, I don’t see why a callback would be any easier than an exception handler for dealing with errors, other than perhaps making it easier to localize handling certain exceptions in one place. They have the unwanted effect of cluttering up the API by adding exception handling callback parameters.

Posted in | no comments |

Using Higher Order Functions in Windows Forms Applications

Posted by Brandon Byars Tue, 17 Jul 2007 05:22:00 GMT

My wife is in the middle of a research project comparing diet to the age of reproduction in African house snakes. She has to collect quite a bit of data, and when I finally looked at the spreadsheets she was maintaining, I was ashamed that I had not written something for her earlier.

This was really the first Windows Forms application that I’ve had the opportunity to do in years (my UI’s aren’t very inspiring). However, I have to maintain a couple at work that were primarily written by former colleagues, and I’ve always been a bit dismayed at the enormous amount of duplication that the standard event-driven application generates.

Despite the fact that the application I wrote for my wife was nothing more than a one-off application, one which you don’t expect to have to maintain, I focused on eliminating the duplication I see in the Windows applications at work. The result isn’t something that I would even begin to consider done for a corporate application, but I found the duplication removal techniques worth writing about. The code can be found here.

The biggest gains in removing duplication, and the ones most readers are likely to be least familiar with, are the use of higher order functions. My impression is that most C# developers aren’t very comfortable with higher order functions. Actually, I think that’s probably true for most developers working within mainstream commercially developed (Microsoft, Borland, Sun) languages. They’re simply not emphasized enough.

For example, all the forms had a ListView to display the data. All of them had to define the column header names and the data that goes in each row. It looked something like this:

protected override void AddHeaders()

{

    AddHeader(“Weight”);

    AddHeader(“Length”);

    AddHeader(“HL”);

    AddHeader(“HW”);

}

 

protected override void AddCells()

{

    AddCell(Weight);

    AddCell(Length);

    AddCell(HeadLength);

    AddCell(HeadWidth);

}

Having the subclass define the column header names and the data that goes in each row didn’t bother me. What did bother me was having to specify the order that the headers and data needed to be shown in two different place. However, while the header names were static, the data would be different for each invocation. The result was to specify the order only once, in an associative array (I used .NET 2.0’s generic Dictionary, which seemed to maintain the order I entered the items). The key would be the column name, and the value would be a function to retrieve the data value.

// The superclass for all Forms…

public class SnakeForm : Form

{

    protected delegate object GetterDelegate(object value);

 

    private IDictionary<string, GetterDelegate> associations;

 

    protected virtual void AddListViewAssociations(IDictionary<string, GetterDelegate> associations)

    {

        throw new NotImplementedException(“Override…”);

    }

 

    protected virtual IEnumerable ListViewHeaders

    {

        get

        {

            foreach (string header in associations.Keys)

            {

                yield return header;

            }

        }

    }

 

    protected virtual IEnumerable ListViewValues(object value)

    {

        foreach (GetterDelegate getter in associations.Values)

        {

            yield return getter(value);

        }

    }

 

    protected virtual void AddCells(object source)

    {

        foreach (object value in ListViewValues(source))

        {

            AddCell(value);

        }

    }

 

    private void SnakeForm_Load(object sender, EventArgs e)

    {

        associations = new Dictionary<string, GetterDelegate>();

        AddListViewAssociations(associations);

        AddHeaders();

    }

 

    private void AddHeaders()

    {

        foreach (string header in ListViewHeaders)

        {

            AddHeader(header);

        }

    }

 

    private void AddHeader(string name)

    {

        ColumnHeader header = new ColumnHeader();

        header.Text = name;

        lvData.Columns.Add(header);

    }

The important things to note are that the subclass is passed, in a template method, a collecting parameter, associations, each entry of which represents a column name along with a way of retrieving the value for a row in that column. The delegate used to retrieve the value can be passed a single state parameter, which is needed by the report forms that need to pass in the source object for each row. Given that information, the superclass can manage most of the work. (AddListViewAssociations would have been abstract, except for the fact that Visual Studio’s designer doesn’t much care for abstract classes.)

For example, here is the information for the measurement form that was first given to show the problem:

protected override void AddListViewAssociations(IDictionary<string, GetterDelegate> associations)

{

    associations.Add(“Weight”, delegate { return Snake; });

    associations.Add(“Length”, delegate { return Length; });

    associations.Add(“HL”, delegate { return HeadLength; });

    associations.Add(“HW”, delegate { return HeadWidth; });

}

One of the benefits of removing the ordering duplication is that the column names now sit beside the functions for retrieving the values, making it easier to understand. Notice that the GetterDelegate definition actually accepts an object parameter. C#’s anonymous delegate syntax lets you ignore unused parameters, making for a somewhat more readable line.

One of the forms shows the information about feedings per snake, and needed that parameter. Below is the entire implementation of the form (aside from the designer-generated code).

// ReportForm is a subclass of SnakeForm

public partial class FeedingBySnakeReport : ReportForm

{

    public FeedingBySnakeReport()

    {

        InitializeComponent();

    }

 

    protected override void AddListViewAssociations(IDictionary<string, GetterDelegate> associations)

    {

        associations.Add(“Snake”, delegate(object obj) { return ((FeedingReportDto)obj).Snake; });

        associations.Add(“Diet”, delegate(object obj) { return ((FeedingReportDto)obj).Diet; });

        associations.Add(“Date”, delegate(object obj) { return ((FeedingReportDto)obj).Date; });

        associations.Add(“Weight”, delegate(object obj) { return ((FeedingReportDto)obj).Weight; });

        associations.Add(“Food Weight”, delegate(object obj) { return ((FeedingReportDto)obj).FoodWeight; });

        associations.Add(“Ate?”, delegate(object obj) { return ((FeedingReportDto)obj).Ate; });

        associations.Add(“%BM”, delegate(object obj) { return ((FeedingReportDto)obj).PercentBodyMass; });

        associations.Add(“Comments”, delegate(object obj) { return ((FeedingReportDto)obj).Comments; });

    }

 

    protected IEnumerable GetReportValues()

    {

        FeedRepository repository = new FeedRepository();

        return repository.FeedingsBySnake(Snake);

    }

}

In case you’re wondering what this form does, it allows you to select a snake, or all snakes, and see the feeding information in the ListView. It also lets you export all the data to a CSV file. Not bad for 30 lines of code.

Another thing that bothered me about all the event handlers was how similar they looked. The workflow was abstracted in the superclass into a HandleEvent method:

protected delegate void EventHandlerDelegate();

 

protected virtual void HandleEvent(EventHandlerDelegate handler)

{

    Cursor = Cursors.WaitCursor;

    try

    {

        handler();

    }

    catch (Exception ex)

    {

        ShowError(ex.Message);

    }

    finally

    {

        Cursor = Cursors.Default;

    }

}

HandleEvent takes a function that handles the meat of the event handler and wraps it within the code that’s common to all event handlers. Here’s a couple examples:

// In DataEntryForm, an abstract superclass, and subclass of SnakeForm

private void btnSave_Click(object sender, EventArgs)

{

    HandleEvent(delegate

    {

        if (!IsOkToSave())

            return;

 

        Save();

        AddRow(null);

        FinishListViewUpdate();

        Reset();

    });

}

 

// In ReportForm, an abstract superclass, and subclass of SnakeForm

private void btnShow_Click(object sender, EventArgs e)

{

    HandleEvent(delegate

    {

        lvData.Items.Clear();

 

        // GetReportValues() is a template method defined in the subclasses.

        IEnumerable reportValues = GetReportValues();

        foreach (object record in reportValues)

        {

            AddRow(record);

        }

    });

}

Managing the ListView proved to be fertile territory for removing duplication through higher order functions. For example, I used the first row’s data to set the column alignments automatically—if it looked like a number or date, right-align the data; otherwise left-align it.

private void SetAlignments(object record)

{

    int i = 0;

 

    // A bit hackish, but the report dtos currently provide strings only…

    foreach (object value in ListViewValues(record))

    {

        if (IsNumber(value) || IsDate(value))

            lvData.Columns[i].TextAlign = HorizontalAlignment.Right;

        else

            lvData.Columns[i].TextAlign = HorizontalAlignment.Left;

 

        i += 1;

    }

}

 

private bool IsNumber(object value)

{

    try

    {

        double.Parse(value.ToString().Replace(”%”, ””));

        return true;

    }

    catch

    {

        return false;

    }

}

 

private bool IsDate(object value)

{

    try

    {

        DateTime.Parse(value.ToString());

        return true;

    }

    catch

    {

        return false;

    }

}

Look how alike IsNumber and IsDate look. We can simplify:

private delegate void ParseDelegate(string text);

 

private bool IsNumber(object value)

{

    return CanParse(value, delegate(string text) { double.Parse(text.Replace(”%”, ””)); });

}

 

private bool IsDate(object value)

{

    return CanParse(value, delegate(string text) { DateTime.Parse(text); });

}

 

private bool CanParse(object value, ParseDelegate parser)

{

    try

    {

        parser(value.ToString());

        return true;

    }

    catch

    {

        return false;

    }

}

I used a similar trick to auto-size the column widths in the ListView based on the width of the largest item. Here’s the refactored code:

private delegate string GetTextDelegate(int index);

 

private void AutoSizeListView()

{

    int[] widths = new int[lvData.Columns.Count];

    FillSizes(widths, delegate(int i) { return lvData.Columns[i].Text; });

 

    foreach (ListViewItem item in lvData.Items)

    {

        FillSizes(widths, delegate(int i) { return item.SubItems[i].Text; });

    }

 

    for (int i = 0; i < lvData.Columns.Count; i++)

    {

        if (!IsHidden(lvData.Columns[i]))

        {

            lvData.Columns[i].Width = widths[i] + 12;

        }

    }

}

 

private void FillSizes(int[] widths, GetTextDelegate text)

{

    using (Graphics graphics = CreateGraphics())

    {

        for (int i = 0; i < lvData.Columns.Count; i++)

        {

            SizeF size = graphics.MeasureString(text(i), lvData.Font);

            if (size.Width > widths[i])

                widths[i] = (int)size.Width;

        }

    }

}

 

private bool IsHidden(ColumnHeader header)

{

    return header.Width == 0;

}

If this were a more long-lived application, I really should have bit the bullet and created my own ListView subclass. The methods above reek of Feature Envy.

Being able to treat functions as first-class objects is extremely useful. For some reason, it doesn’t get the attention it deserves in most development books. And it’s often somewhat obscured by intimidating sounding names like “lambda expressions” thanks to its roots in lambda calculus. However, much of what I was able to do in this application was possible only because I was able treat functions as data and pass them as parameters. And it was helped by the fact that I didn’t have to explicitly define each function as a method; I could create them anonymously like any other data object (although C#’s anonymous delegate syntax is somewhat obscured by the static typing).

Posted in , , | no comments |

Older posts: 1 2 3 4