A Day In The Lyf

…the lyf so short, the craft so longe to lerne

Archive for April 2007

Beer, Software, and Hypocrisy

I love free software. I love it when it’s free as in speech, and I really love it when it’s free as in beer. The development environment I currently work in lives on an open source infrastructure, and most of the best developers I’ve talked to have contributed in some way to the open source world.

I’ve also spoken to many developers who use Stallman’s notion of free software as nothing more than an excuse to pirate licensed software. The argument, as I understand it, is that society has a moral obligation to make software free, and since they don’t, we’re perfectly justified in using cracked versions of their products. Apparently (the reasons aren’t clear to me), the argument extends to music, movies, and TV shows as well.

I’ll remain mute on the moral argument, and I admit to having used “borrowed” software in my younger and rasher days. What I find absurd, though, is the hypocrisy of using the moral argument of free software to justify pirating software just because you don’t want to pay for it. Most developers, and this certainly includes the ones I’ve spoken with about pirated software, simply aren’t competent enough to deal with the consequences of free software.

Richard Stallman sagely noted that, were software made free (as in speech), there would still be money to be made, but it would not be made by the average developer of today. To be a developer in Stallman’s utopia would require both a passion and competence found only in the upper echelon of today’s developers. Richard Stallman has the skills to back it up. So do many developers. But not most. And for the rest of us, saying that software should be “free as in speech” has too often become a cop-out, when really all we want is a free drink.


Written by Brandon Byars

April 27, 2007 at 9:17 pm

Posted in Ethics

.NET Database Migrations

Pramod Sadalage and Scott Ambler have suggested using a series of numbered change scripts to version your database. Start with a base schema, and every subsequent change gets its own change script, grabbing the next number. That version number is stored in a table in the database, which makes it easy to update—you just run all change scripts, in order, greater than the version stored in your database.

The Ruby on Rails team implemented this technique in their migrations code. It’s quite elegant. This blog uses a Rails application called Typo; here’s one of its migrations:

class AddArticleUserId < ActiveRecord::Migration
  def self.up
    add_column :articles, :user_id, :integer

    puts "Linking article authors to users"
    Article.find(:all).each do |a|

  def self.down
    remove_column :articles, :user_id

That migration is called 3_add_article_user_id.rb, where 3 is the version number. Notice that it’s written in Ruby, not in SQL. It adds a column called user_id to the articles table and updates the data. The data update is particularly interesting—we get to use the ActiveRecord O/RM code instead of having to do it in SQL (although you can use SQL if you need to). The Rails migration code can also rollback changes; that’s what the down method is for.

The problem I’ve always had with this scheme is that we have many database objects that I’d like to version in their own files in our source control system. For example, here’s our directory structure:


We have several files in each directory, and it’s convenient to keep them that way so we can easily check a subversion log and see the history of changes for the database object. For us to use the migrations scheme above, we’d have to create a stored procedure in a migration, and later alter it in a separate migration. Since the two migrations will be in separate files, our source control wouldn’t give us a version history of that stored procedure.

We came up with a hybrid solution. Schema changes to the tables use a migration scheme like Rails. Database objects are versioned in separate files. Both the schema changes and the peripheral database object changes are updated when we update the database.

For this to work, we have to be a little careful with how we create the database objects. We want them to work regardless of whether we’re creating them for the first time or updating them, which means ALTER statements won’t work. The solution is simply to drop the object if it exists, and then create it. This is a fairly common pattern.

I wrote an NAnt and MSBuild task to do the dirty work. It runs both the schema migrations and the database object updates. Both are optional, so if migrations are all you want, that’s all you need to use. It expects all migrations to be in the same directory, and match the pattern 1.comment.sql, where 1 is the version number. It will be stored in a database table whose default name is SchemaVersion, with the following structure:

CREATE TABLE SchemaVersion (
  Version int,
  MigrationDate datetime,
  Comment varchar(255)

I’ve only tested it on SQL Server, but I think the task should work for other DBMS’s as well (it uses OLEDB). Migrations can contain batches (using the SQL Server GO command) and are run transactionally. Unlike the Rails example, the .NET migrations use SQL, and I don’t yet have any rollback functionality.

You can include any extra SQL files you want in the DatabaseObjects property. Both NAnt and MSBuild have convenient ways to recursively add all files matching an extension.

Here’s an NAnt example:

<target name="migrate" description="Update the database">
    <loadtasks assembly="Migrations.dll" />
            <include name="db/functions/**/*.sql"/>
            <include name="db/procedures/**/*.sql"/>
            <include name="db/triggers/**/*.sql"/>
            <include name="db/views/**/*.sql"/>

And here it is using MSBuild:

    <DatabaseObjects Include="db/functions/**/*.sql"/>
    <DatabaseObjects Include="db/procedures/**/*.sql"/>
    <DatabaseObjects Include="db/triggers/**/*.sql"/>
    <DatabaseObjects Include="db/views/**/*.sql"/>

<Target Name="dbMigrate">
        TableName="version_info" />

The source code and binaries can be found here.

Written by Brandon Byars

April 14, 2007 at 10:35 pm