Yesterday on twitter I had the start of an interesting conversation with Steve Harmann and Scott Bellware, but then I had to do work, so I had to stop just when it was getting interesting.

One of the things I have found useful in writing unit tests for an application I work on is mbunit’s CombinatorialTest. If you are familiar with RowTests in mbunit, CombinatorialTests are similar, but allow you to use a factory method to generate the parameters for the test.

By way of example, below is a dumbed down version of a real test I have. Note that this was developed before I really knew anything about BDD.

The system under test needs to find the next best move as a number. There are two candidate moves. If the candidates are on both sides of the number we’re on now (mixed signals), we don’t move. If they are both on the same side, we move that direction, but to the number with the smallest change from our current number. I received these specs from our product owner in the form of an Excel spreadsheet with a formula, mixed with a crap-load of test data.

I have found that it’s useful to define a class for the parameter to the test, and that it’s really useful to have that class have lambdas for the actual test, and that it’s really, really useful to use Expression<> for the lambdas, so you can print the result. I am going to call this class a “Specification Class” for lack of a better term. Here’s the one for the stories described above:

public class PositionSpec
{
    public decimal Candidate1 { get; set; }
    public decimal Candidate2 { get; set; }
    public decimal Current { get; set; }
    public Expression<Predicate<ModelPosition,decimal>> Test { get; set; }
    public override string ToString()
    {
        return String.Format("c1={0:p} ^ c2={1:p} ^ current={2:p} -> {3}", 
            Candidate1, Candidate2, Current, Test.Body.ToString());
    }
}

Notice that the Test property is an Expression. If you are not familiar, this is like a lambda - Expression<Predicate<ModelPosition, decimal>> can do everything Predicate<ModelPosition, decimal> can do – but you can examine the body of the expression. I think this is really cool and a gateway to functional+dynamic programming. In this case though, I just want to use that so I can print the expression in ToString – mbunit will call this when printing the name of the test in the results, so we can see which expression we are testing.

Here’s the factory function that produces instances for tests (specifications):

public IEnumerable<PositionSpec> TestPositions()
{
    yield return new PositionSpec() { Candidate1 = .15M, Candidate2 = .20M, Current = .17M, 
        Test = (pos, w) => w == .17M };
    yield return new PositionSpec() { Candidate1 = .15M, Candidate2 = .20M, Current = .10M, 
        Test = (pos, w) => w == .15M };
    yield return new PositionSpec() { Candidate1 = .15M, Candidate2 = .10M, Current = .20M, 
        Test = (pos, w) => w == .15M };
    yield return new PositionSpec() { Candidate1 = .15M, Candidate2 = .13M, Current = .10M, 
        Test = (pos, w) => w == .13M };
    yield return new PositionSpec() { Candidate1 = .15M, Candidate2 = .17M, Current = .20M, 
        Test = (pos, w) => w == .17M };
    yield return new PositionSpec() { Candidate1 = .15M, Candidate2 = .20M, Current = .17M,
        Test = (pos, w) => pos.IsNoActionRequired == true };
    yield return new PositionSpec() { Candidate1 = .15M, Candidate2 = 0M, Current = .14M,
        Test = (pos, w) => pos.IsNoActionRequired == true };
    yield return new PositionSpec() { Candidate1 = .15M, Candidate2 = 0M, Current = .14M,
        Test = (pos, w) => w == .14M};
    yield return new PositionSpec() { Candidate1 = .15M, Candidate2 = 0M, Current = .20M,
        Test = (pos, w) => w == .15M};
    yield return new PositionSpec() { Candidate1 = 0M, Candidate2 = .15M, Current = .14M,
        Test = (pos, w) => pos.IsNoActionRequired == true };
    yield return new PositionSpec() { Candidate1 = 0M, Candidate2 = .15M, Current = .14M,
        Test = (pos, w) => w == .14M};
    yield return new PositionSpec() { Candidate1 = 0M, Candidate2 = .15M, Current = .20M,
        Test = (pos, w) => w == .15M};
    yield return new PositionSpec() { Candidate1 = 0M, Candidate2 = 0M, Current = .20M,
        Test = (pos, w) => w == 0M};
}

And finally the test that consumes them:

[CombinatorialTest]
public void should_result_in_smallest_delta_from_current_with_netting(
    [UsingFactories("TestPositions")] PositionSpec spec)
{
    Mocks.ReplayAll();
 
    ModelPosition candidate1 = new ModelPosition(){ Weight = spec.Candidate1 };
    ModelPosition candidate2 = new ModelPosition()
    {
        Weight = spec.Candidate2,
        HeldPositionWeight = spec.Current
    };
 
    decimal result = _methodology.GetNetPositionWeight(candidate2, candidate1);
    Assert.IsTrue(spec.Test.Compile().Invoke(candidate2, result));
}

The result has the expression bodies printed out, so looks like:

------ Test started: Assembly: XXX.Tests.dll ------
 
Starting the MbUnit Test Execution
Exploring XXX.Tests, Version=1.0.0.2, Culture=neutral, PublicKeyToken=null
MbUnit 2.41.232.0 Addin
Found 13 tests
[assembly-setup] success
[success] NettingMethodologyTests.BaseSetup.should_result_in_smallest_delta_from_current_with_netting(TestPositions(c1=15.00 % ^ c2=20.00 % ^ current=17.00 % -> (w = 0.17)))
[success] NettingMethodologyTests.BaseSetup.should_result_in_smallest_delta_from_current_with_netting(TestPositions(c1=15.00 % ^ c2=20.00 % ^ current=10.00 % -> (w = 0.15)))
[success] NettingMethodologyTests.BaseSetup.should_result_in_smallest_delta_from_current_with_netting(TestPositions(c1=15.00 % ^ c2=10.00 % ^ current=20.00 % -> (w = 0.15)))
[success] NettingMethodologyTests.BaseSetup.should_result_in_smallest_delta_from_current_with_netting(TestPositions(c1=15.00 % ^ c2=13.00 % ^ current=10.00 % -> (w = 0.13)))
[success] NettingMethodologyTests.BaseSetup.should_result_in_smallest_delta_from_current_with_netting(TestPositions(c1=15.00 % ^ c2=17.00 % ^ current=20.00 % -> (w = 0.17)))
[success] NettingMethodologyTests.BaseSetup.should_result_in_smallest_delta_from_current_with_netting(TestPositions(c1=15.00 % ^ c2=20.00 % ^ current=17.00 % -> (pos.IsNoActionRequired = True)))
[success] NettingMethodologyTests.BaseSetup.should_result_in_smallest_delta_from_current_with_netting(TestPositions(c1=15.00 % ^ c2=0.00 % ^ current=14.00 % -> (pos.IsNoActionRequired = True)))
[success] NettingMethodologyTests.BaseSetup.should_result_in_smallest_delta_from_current_with_netting(TestPositions(c1=15.00 % ^ c2=0.00 % ^ current=14.00 % -> (w = 0.14)))
[success] NettingMethodologyTests.BaseSetup.should_result_in_smallest_delta_from_current_with_netting(TestPositions(c1=15.00 % ^ c2=0.00 % ^ current=20.00 % -> (w = 0.15)))
[success] NettingMethodologyTests.BaseSetup.should_result_in_smallest_delta_from_current_with_netting(TestPositions(c1=0.00 % ^ c2=15.00 % ^ current=14.00 % -> (pos.IsNoActionRequired = True)))
[success] NettingMethodologyTests.BaseSetup.should_result_in_smallest_delta_from_current_with_netting(TestPositions(c1=0.00 % ^ c2=15.00 % ^ current=14.00 % -> (w = 0.14)))
[success] NettingMethodologyTests.BaseSetup.should_result_in_smallest_delta_from_current_with_netting(TestPositions(c1=0.00 % ^ c2=15.00 % ^ current=20.00 % -> (w = 0.15)))
[success] NettingMethodologyTests.BaseSetup.should_result_in_smallest_delta_from_current_with_netting(TestPositions(c1=0.00 % ^ c2=0.00 % ^ current=20.00 % -> (w = 0)))
[reports] generating HTML report
TestResults: file:///C:/Users/cbilson/AppData/Roaming/MbUnit/Reports/XXX.Tests.Tests.html
 
13 passed, 0 failed, 0 skipped, took 3.30 seconds.
 

So that’s one example. I had a lot of little tiny contexts. I wanted to apply the same basic proto-spec to each one. I could have done this with a base context class and a bunch of subclasses, which seems to be the BDD way to do this, but using combinatorial tests seems more concise and readable to me.

There’s one other really powerful thing you can do with combinatorial tests. Since you can use these to separate context from spec, you could apply a set of specs to a set of contexts. Your actual tests would be the cross product of the two, without having to specify each product.

For example, say you had a really complicated data entry screen. Your user stories indicated that everyone needed to be able to edit data in some subset of the fields on the screen, only admins another subset, and only under certain conditions everyone could edit all fields.

There are lots of ways to tackle this, but one way would be to define the two different subsets using two factories. Then your specifications could be really simple and readable, like “everyone_should_be_able_to_edit_the_everyone_fields”, “only_admins_can_edit_the_admin_fields”, and “everyone_can_edit_the_admin_fields_in_some_special_case".”

For admin vs. normal user fields, it would probably be better to just tag the fields somehow, but what if there were way more conditionals, like “for gold card members with the super-duper price-protection plan, normal customer service reps should be able to edit the discount field.” I have a couple of cases like this where the user interface changes a lot based on a couple of different special conditions and I have found combinatorial tests really good for this.

Now that I am getting into BDD, I think I could do a better job of separating the context from the specification. It seems like the “specification” class I had above should really be the “context” and I should remove the Test property, since that’s the core of the specification. I could then use this technique when I have a specification that applies to a large number of contexts.


 
Categories: bdd | tdd

So let’s say I have a user story like:

As a Portfolio Analyst

I need to be able to change an account’s market value, overriding what was reported by the custodian

So I can reflect cash flows I know are going to hit the account.

So we talk with them and know that we are going to make the Market Value field on some screen editable. When they don’t do anything, we will just use the market value reported by the custodian (which is what we already do now) but when they enter a manual plug, we will use that value instead.

So the developers talk about it an decide we first want to introduce properties ReportedMarketValue and EstimatedMarketValue. Here is the original Account class

public class Account
{
  public virtual string AccountNumber { get; set; }
  public virtual decimal MarketValue { get; set; }
}

Which we change to:

public class Account
{
  public virtual string AccountNumber { get; set; }
  public virtual decimal MarketValue { get; set; }
  public virtual decimal ReportedMarketValue { get; set; }
  public virtual decimal? EstimatedMarketValue { get; set; }
}

Next we want to make MarketValue read-only, have it either be EstimatedMarketValue if there is one, or ReportedMarketValue. All the places that don’t compile anymore (where someone said “account.MarketValue = “) will be changed to use the ReportedMarketValue mutator.

…but before that, let’s get our specs in place.

MSpec makes heavy use of lambdas, fluent interface, and a custom nunit test runner to take away a lot of the curly braces. Again, read Aaron’s blog for the introduction, but basically, we are going to declare a base class class to establish all the actors in a series of specs around this story:

public abstract class account_spec
{
  protected static Account Account { get; private set; }
 
  Establish context = () => {
    Account = new Account();
    Account.ReportedMarketValue = 100M;
  };
}

Establish is just a delegate and we’re setting it to an anonymous method to just create a new Account. Notice that the Account property is static? Yeah, that sucks. You can’t reference non static members from inside an initializer for a delegate:

image

I think the driving design choice is to limit the amount of alien noise in the spec. Here the tradeoff is adding “static” vs. doing the initialization inside of a constructor or something. Tough call. Whatever, this works, so let’ just go with it.

Next we want to specify what happens when there is no plugged market value:

[Concerning(typeof(Account), "Market Value")]
public class with_no_plugged_market_value : account_spec
{
  Because the_account_has_no_plugged_market_value = () => Account.EstimatedMarketValue = null;
  It should_give_the_reported_market_value_as_the_market_value = () => 
    Account.MarketValue.ShouldEqual(Account.ReportedMarketValue);
}

There is more decoration here. Let’s go over that:

  • The Concerning Attribute: Is used to format the output of the test run and to introduce a “test fixture”.
  • Because: is just another anonymous delegate. I think in one of my experiments I tried having two because’s (I was thinking it be like “because of this and because of that”) but only one got executed. This makes sense. Just put all your because stuff in the same block.
  • It: is…yep, just another anonymous delegate. You can have multiple It’s.
  • ShouldEqual: is a nice extension method that comes with mspec. Thanks!

When run, this spec fails:

------ Test started: Assembly: Specs.dll ------ 
 
Account Market Value, with no plugged market value
!!» should give the reported market value as the market value !! 
 
TestCase 'should give the reported market value as the market value' failed: 
    NUnit.Framework.AssertionException:   Expected: 100m
      But was:  0m
    at NUnit.Framework.Assert.That(Object actual, Constraint constraint, String message, Object[] args)
    at NUnit.Framework.Assert.AreEqual(Object expected, Object actual)
    C:\projects\machine\Source\Specifications\Machine.Specifications\ExtensionMethods.cs(25,0): at Machine.Specifications.ShouldExtensionMethods.ShouldEqual(Object actual, Object expected)
    C:\Users\cbilson\Documents\Visual Studio 2008\Projects\ClassLibrary2\Specs\Class1.cs(24,0): at Specs.with_no_plugged_market_value.<.ctor>b__1() 
 
0 passed, 1 failed, 0 skipped, took 0.54 seconds.

So we implement it (Spec First Development!):

public virtual decimal MarketValue { 
  get { return ReportedMarketValue; }
  set { throw new NotImplementedException(); }
}

(don’t worry, we’ll get rid of set later in another refactoring – or forget about it and find a zillion other tests broke.)

Now we pass:

------ Test started: Assembly: Specs.dll ------
 
Account Market Value, with no plugged market value
  » should give the reported market value as the market value
 
 
1 passed, 0 failed, 0 skipped, took 0.46 seconds.
 
 

Note the nice Product-Owner-friendly output. This was one of my bullets from Part 1. Check.

Remember MTEGOTAG? It turns out that this increases my MTEGOTAG number to about 5 minutes. After that the product owner’s eyes glaze over and their “thinking about leaving early for a round of golf” program pegs their CPU. They can still search this output though if they have a question about something. But from a mean of around 13 seconds to 5 minutes is an amazing feat!

The other spec:

[Concerning(typeof(Account), "Market Value")]
public class with_plugged_market_value : account_spec
{
  Because the_account_has_plugged_market_value_of_200 = () => Account.EstimatedMarketValue = 200M;
  It should_give_the_estimated_market_value_as_the_market_value = () =>
    Account.MarketValue.ShouldEqual(Account.EstimatedMarketValue);
}

Which fails until we implement it:

public virtual decimal MarketValue { 
  get { return EstimatedMarketValue ?? ReportedMarketValue; }
  set { throw new NotImplementedException(); }
}

And all our specs run together look like:

------ Test started: Assembly: Specs.dll ------

Account Market Value, with no plugged market value
» should give the reported market value as the market value

Account Market Value, with plugged market value
» should give the estimated market value as the market value


2 passed, 0 failed, 0 skipped, took 0.46 seconds.

This can almost go straight into our trac wiki. Maybe someone I work with will read this and fix our build scripts to update trac.

One quick note: When you run the spec project in TD.NET, it doesn’t show the output of all the specs, just how many failed/succeeded. I could probably fix this and submit a patch. Hopefully I will.

Final things to note: There are a lot of conventions in play here – ex.: the concern’s name and the spec’s name and how they get formatted in the end. I like conventions because it means there’s less to explain to get going. I can see new developers being able to easily learn write specs like this, but I bet they are going to run into a lot of bizarre compiler errors along the way. Good way for them to learn about lambdas and c#!

So, apologies for the lame - yet long - and simplistic example. This is almost like something we did on a real project at work, just way simpler. Now that we have a simple example to start with, in my next post, I want to go over a more complicated example – one in which I felt a little bit more pain and confusion. That’s going to take me longer to type up though. In the meantime, please comment. Thanks!


 
Categories: bdd

Fellow Seattle ALT.NETter Aaron Jensen and his friends at Eleutian released a really interesting library of functionality several months ago called “Machine.” There are several things in here I can use every day. Not all of it is perfect, but it’s very innovative, clean, and easy to work with.

Today, I want to talk about Machine.Specifications, or MSpec as I will refer to it going forward. If you haven’t read Aaron’s introduction post, read it now, then come back and read this.

I am still learning BDD but I am already enjoying some benefits of it in my tests. For the most part, I have just been adopting BDD style naming of my fixtures/tests (or rather, contexts/specifications), using my existing testing framework (mbunit), and using really detailed versions of the stories our Product Owners come up with. I get two main benefits:

  • Product Owners would know what a test was covering.
  • My tests are coupled to the user stories, not the code.

The advantages are offset by:

  • Product Owners don’t look at the code. It’s a psychological barrier, but it’s there.
  • I am still new to BDD so keep running into things that I find hard to express in BDD terms.

One thing almost all BDD frameworks offer that hits one of those bullets is functionality to format a bullet point list of the specs that are implemented from tests following a naming convention. That alone is enough reason for me to try some of these frameworks.

Concept: MTEGOTAG (pronounced “Em Teg-O-Tag”): Mean Time to (Product Owner) Eyes Glazing Over Thinking About Golf. When I write my specs in c#, this number is very low, approaching zero. I can keep a Product Owners interest for 10, maybe 20 seconds if I am showing specs in c#. The number gets even lower for each repeated application per session.

So that’s kind of my motivation. I recently had some time to sit down and actually do real work in mspec, my next post will be about the results.

P.S.: If you are in the seattle area and don’t already know this, a bunch of us are meeting to talk about BDD this Thursday.


 
Categories: bdd

Foundations of Programming Ebook - Karl Seguin I just finished reading this book this morning. It's:
  • Packed with excellent information
  • Concise
  • Free
I would recommend any .net developer read this and will ask anybody I interview if they have read it from now on.
 
Categories: 411

July 1, 2008
@ 06:39 AM
I was happy to see that NHibernate 2.0 Beta has been released. Over the past few weeks, in talking to various people, I have been suprised at the number of people who haven't looked at 2.0 alpha. I've actually been using it for several months and haven't yet run into any problems, other than some API changes which was a one time simple change.

Here's to hoping that a new greek letter = more people using newer NHibernate.


 
Categories: nhibernate

May 15, 2008
@ 07:07 PM

When I was a younger programmer I had the privilege of working in a few places where we had really tight development processes: Daily Builds (before CI was widely known), test suites (like perl make test type stuff - before TDD became popular) and tools to help do common things in our process.

One example of a tool like this I remember was working at a company where we were using CVS and had developed shell scripts to do the work of testing, checking in, sending a notification, and whatever else it was we did, so you could just type something like "re-up" and get all in sync and checked in.

When I started using subversion, for some reason I stopped using things like this. In subversion, I think you are encouraged to hook these things up as hooks on the server, so clients don't need to have any special scripts or know anything special to invoke the pre/post-checkin process.

This sounds like a better solution, but it's interesting that I have never once written a subversion hook script. I don't know why, but it just seems...I don't know...less visible...harder to test...harder to try out.

Since I started using git, I notice I am building little patterns I do through the day, like:

git add .; git ci; git co master; git merge NewNettingStrategy; git svn dcommit; git svn co NewNettingStrategy; git merge master

I do this whenever I want to cause a build to happen with whatever I am doing in a feature branch, then come back to the feature branch.

I usually just keep these things in my history and up-down arrow to invoke them from powershell, but more and more, I see how these could easily grow into little scripts to make it real easy to "do things my way." A script could interact with git to determine things like the current branch, where to merge into, etc. I just finished one to push my days work to a repo I can get at from home.

Git isn't really any better than subversion in this respect, except for maybe having more granular control over it, but the mindset lends itself to customization and fitting to your process, which I really enjoy.


 
Categories:

I am sick and tired of trying to find a really good podcast client. iTunes has the best "reach" but itunes sucks in every other respect (I love it when I shift click a bunch of things while iTunes is thinking real hard about something for 30 seconds, then I release shift, and iTunes thinks I have selected just the last thing  - "he's not holding down shift now!")

I've tried maybe a dozen other podcast clients and none were worth remembering their names so I could run them again. A couple of days ago I noticed winamp had podcast client functionality. After using it for three days and having winamp crash regularly while trying to manage my podcasts, I gave up and tossed it in the pile with the others.

So, I thought, how fracking hard can this be? A podcast client: it reads rss, looks at the url of enclosures, and downloads them. What do I know that is really good at letting me work with XML and is really simple...hmmm....

So I quickly threw together this powershell script (I actually prototyped the whole thing as a single command line pipeline). Nothing special, but way better than any of the other podcast clients, and I can make it work exactly how I like:

$rootPodcastFolder = 'E:\Downloads\Podcasts'
$feeds = @(
	'http://leoville.tv/podcasts/twit.xml',
	'http://feeds.feedburner.com/rubiverse',
	'http://feeds.feedburner.com/netRocksWmadirect',
	'http://feeds.feedburner.com/altnetpodcast',
	'http://channel9.msdn.com/rss.aspx?threadID=312315&format=wma',
	'http://feeds.feedburner.com/Hanselminutes',
	'http://www.npr.org/rss/podcast.php?id=13',
	'http://www.npr.org/rss/podcast.php?id=5',
	'http://blog.stackoverflow.com/?feed=podcast',
	'http://feeds.thisamericanlife.org/talpodcast',
	'http://podcast.thoughtworks.com/itmatters/it_matters.xml'
)
$agent = new-object net.WebClient

foreach ($feed in $feeds) {
	$document = [xml] $agent.DownloadString($feed)
	$title = $document.rss.channel.title.Replace(':', '-')
	$feedFolder = [io.Path]::Combine($rootPodcastFolder, $title)
	if (![io.Directory]::Exists($feedFolder)) {
		[io.Directory]::CreateDirectory($feedFolder)
	}
	Write-Output "Checking $title ($feedFolder)..." 
	
	foreach ($item in $document.rss.channel.item) {
		$fileName = [io.Path]::GetFileName($item.enclosure.url)
		$fileName = [io.Path]::Combine($feedFolder, $fileName)
		if (![io.File]::Exists($fileName)) {
			"`tDownloading {0}..." -f $item.enclosure.url
			$agent.DownloadFile($item.enclosure.url, $fileName)
		}
	}
}

Now, if only powershell could help me copy these files to my windows mobile phone in less than the decade I've been waiting so far...


 
Categories:

Git is a great distributed version control system that I am getting to like more and more everyday. We don't use git where I work, but for me, git works just as well as a super-powered subversion client.

I like to have git integrated with the rest of my (cmd) shell, so I use the MSysGit found here. This is as close as you can get to native git on windows. Using this, I am able to use git in powershell, cmd scripts, build scripts, or in lots of other places, without having to invoke it through something like the bash.exe that comes with cygwin.

Unfortunately, as of this writing, msysgit does not include git-send-mail (here's the issue). As I wrote before, I sometimes need to manually push patches around between the various computers I work on, and e-mail would work great for this.

Fortunately, powershell community extensions has a Send-SmtpMail cmdlet that can do the same things git-send-mail did - even more actually.

I use pobox.com for my e-mail and their smtp relay will relay mail for me, but only if I authenticate properly. As far as I know (I haven't actually tried this) git-send-mail isn't able to authenticate with my e-mail provider.

Anyway, here is what I do, in powershell, to e-mail my patches:

git format-patch -M origin

Then, to send it off:

mail -To cbilson@whereheworks.com `
     -From cbilson@pobox.com `
     -SmtpHost sasl.smtp.pobox.com `
     -Credential (get-credential) `
     -AttachmentPath *.path `
     -Bcc cbilson@pobox.com `
     -Body "Please apply this patch. KTHXBY"
     

I get the patches as attachments, save them to a folder somewhere, and just use git-am to apply them at work.

The kind of weird thing about this is that all the patches are in my gmail account and I have a folder for them. Given the baseline I started using git from, I could re-apply all those patches and get back to HEAD (I would likely want to use powershell to automate that!) So Gmail is my repo.


 
Categories:

Due to various network obstacles between my work and personal machines, I often find it necessary and convenient, when using git, to use skydrive, thumbdrives, or some other low-tech means to pass around patch files. Git has really nice integration with common unix mail utilities that make it really sweet to do this on unix.

But I am using windows.

I had to overcome a couple of annoying but obvious hurdles to get this to work. Here's my current process for cloning a project in an svn repo at work, then passing patches around:

1. clone the svn repo. Let's call this clone':

git svn clone -s http://svn-server/MyProject

Actually, I am lying. I use this command because our projects are not in the canonical git layout in our repository:

git svn clone http://svn-server/svn --trunk=trunk/MyProject --branches=branches/MyProject --tags=tags/MyProject

2. Make sure your repo has core.fileMode false (this takes care of many of the other problems I had with git too):

git repo-config core.fileMode false

3. For some reason my life is easier with core.autocrlf false. Or maybe that's why I always have to --whitespace nowarn when I apply patches. I don't know. This is just the way I am doing it and it works.

git config --global core.autocrlf false

4. Clone that repo to take home or wherever. Call this clone''. Remember that the real magic in cloning is that it creates tracking branches:

git clone --no-checkout C:\Projects\MyProject.git E:\ToTakeCome\MyProject.git

5. Say I am home on clone''. I branch, work, commit. Do the dance, now I want to takes these changes back to the mother ship. Machines aren't connected. Don't want to bring laptop to work:

git format-patch -M origin; cp *.patch E:\TakeToWork

6. At work, in clone':

git am -3 --whitespace nowarn E:\FromHome\*.patch

That's basically how I am doing it, after many blind alleys and false starts. My process is a work in progress, so I will update when it changes.


 
Categories:

We use Wix to build installers at my work. I've blogged about this before.

Wix comes with custom actions to create IIS App Pools and Virtual Directories. Up until today, my wix scripts all WebVirtualDirs and WebAppPools in the same component:

	<Component Id='WebApp_WithAppPool' 
		   Guid='$(var.IIsWithAppPoolSettingsComponentId)'>
        	<Condition>Not IISMAJORVERSION="#5"</Condition>
                <WebAppPool Id='MyAppPool'
                            Name='$(var.AppPool)' />
                <WebVirtualDir Id='MyVDirWithAppPool'
                               Alias='IMR/$(var.InstallDirectory)'
                               Directory='INSTALLDIR'
                               WebSite='Default'
                               DirProperties='AppDirProps'>
                    <WebApplication Id="MyAppWithAppPool" 
				    Name='[ProductName]' 
				    WebAppPool='MyAppPool'>

We recently changed the security model of this application to use a service account, but the above installer would uninstall the app pool when the application was uninstalled. When they went to install an upgraded version they would have to find someone that knew the password for the service account to enter it in the app pool settings after installing.

A little searching led me to this mailing list thread, where they recommend adding a Permanent='yes' attribute (which I didn't realize existed.)

This worked, but then my vdir doesn't get uninstalled, so I just created a new component for the app pool, made it permanent, and voila:

  • When installing
    • If the app pool doesn't exist it's created
    • If it exists we leave it alone but still put the app in it.
  • When uninstalling
    • The vdir is deleted, but the app pool is left alone.
	<Component Id="WebApp_AppPool"
		   Guid="$(var.IIsAppPoolComponentId)"
		   Permanent="yes">
       		<Condition>Not IISMAJORVERSION="#5"</Condition>
                <WebAppPool Id='MyAppPool'
                            Name='$(var.AppPool)' />
	</Component>
	<Component Id='WebApp_WithAppPool' 
		   Guid='$(var.IIsWithAppPoolSettingsComponentId)'>
        	<Condition>Not IISMAJORVERSION="#5"</Condition>
                <WebVirtualDir Id='MyVDirWithAppPool'
                               Alias='IMR/$(var.InstallDirectory)'
                               Directory='INSTALLDIR'
                               WebSite='Default'
                               DirProperties='AppDirProps'>
                    <WebApplication Id="MyAppWithAppPool" 
				    Name='[ProductName]' 
				    WebAppPool='MyAppPool'>

 

It actually took me a little while to find out about Permanent='yes', hence this blog post.


 
Categories: installer | tool | wix

April 26, 2008
@ 08:27 AM
  • It takes me around 30-90 minutes to prepare a blog post - I'm not a good writer and kind of shy and afraid of looking stupid, so I usually got through lots of revisions. (update: even this short post took me 30 minutes, between editing, answering 5y old questions, and moving baby to new less boring place to sit.)
  • We've got a new baby in the house. Every two hours while I'm awake and not at work, I have a little 15 - 20 minute process I need to do. This is enough time to obliterate whatever concentration I had. I'd really forgotten how much there is to do with a baby - it's not so hard (especially after having already done it once) but it's just kind of...a lot. My concentration is always on the edge of a huge gaping void, ready to fall in.
  • Battlestar Gallactica is back on. A few other good shows I've gotten turned onto: New Amsterdam, Breaking Bad. Time sinks all.
  • Twitter. Before I'm even done thinking a thought, it's on the internet.
    • Works really well with having a baby.
    • Works on phone
    • Can do it while my mind is otherwise unoccupied, like during boring meetings at work.

 
Categories: bs

April 19, 2008
@ 07:20 AM

Last night at the opening of #altdotnet seattle, we had a fishbowl about polyglot programming. I felt several times I wanted to run up and grab a chair but...well...when Martin Fowler, Scott Hanselman, Scott Bellware, Ted Neward and other "celebrity programmers" are all jockeying for the one open chair, what I want to say seems a little less important, relatively.

Not so here on my blog, the desert of the real!

So I have been doing polyglot programming for a while: first basic+assembly (atari 800, apple //), then clipper + c, vb + c++, javascript+c++ (MFC app with embedded web browser control), perl + anything (perl's a slut), vb classic + javascript + c++, c#+javascript, vb.net + javascript...oh, and SQL with all those.

One combination notably missing is c#+vb. Why? There is 99.9% overlap between what I would do in c# and vb. For the vast majority of .net applications in the world, it's either in c# or it's in vb. There are a very few edge cases where it makes sense to have both c# and vb in the same application (using vb for office interop, where methods have craploads of optional parameters comes to mind.) So there is basically no/little value mixing c# and vb. It's like mixing sugar with equal. Just pick one, use it, and be happy.

One combination that's in there several times is <<something>> + javascript. Why? Javascript+DHTML is for a totally different purpose than the other languages. It's specially designed for working with browsers. When I am in browserland, I like to talk browser-ese. I find I have to use fewer words to accurately communicate what I want to say.

Being a polyglot is a big investment. You need to get familiar with the languages. You need to keep up on them and use them, lest they atrophy. Some people don't want to do that. In the web programming space, there are lots and lots of tools that let you use one language and generate another. Some of the helpers in monorail come to mind. Most of ASP.NET, and especially, all of asp.net ajax comes to mind. Commercial tools like Iron Speed definately come to mind. These tools and libraries are like machine translation. whazattchickendrive

I really, really want to know what this web page about some funky USB thing that looks like a chicken foot says. Problem is, it's in japanese. No problem, just use translate.live.com or translate.google.com. This will help me kind of understand what the idea is, but it's no where near as informative as the source page, provided you can understand and read Japanese.

I think a lot of tools that hide/generate/translate from a high level language to javascript/html are like machine translation. It's best if you can just learn the language where you are working - javascript for the web, for example - and tools that translate for you are a cheap substitute.

When deciding to watch a Jackie Chan movie, here in the states, I can chose to watch it in dubbed english sans subtitles, or in Chinese. Jackie Chan's movies often have lots of little puns and side jokes going on. Most of this gets lost when the translate/dub it. To really get a Jackie Chan movie, you've really got to understand Chinese (not just the language, but the culture too.) The translated version sounds like the javascript that GWT generates looks.

Source code is, number one, a tool for programmers to express ideas. Working in the right language for the domain you are in improves your ability to accurately and succinctly express your intent to other programmer and the computer. Treat source code as generate-only gobbleygook, and that's what you'll get.


 
Categories:

This isn't terrible earth shaking but since I had to futz with this a little, I thought I would write it down.

Goal: We moved to a new subversion server, and while we were at it, wanted to stop using joke passwords in a file called passwd, start using our windows credentials, and also install trac, on a windows 2003 x64 server.

Ingredients:

First, we installed subversion and restored a backup of our repository...and waited...and waited.

The next day, we installed apache. We set apache to run on port 8080 and verified that it worked (http://localhost:8080) We then copied mod_authz_svn.so, mod_dav_svn.so, libdb44.dll, and mod_auth_sspi.so to the apache modules folder. We enabled these things:

LoadModule asis_module modules/mod_asis.so
LoadModule sspi_auth_module modules/mod_auth_sspi.so
LoadModule auth_basic_module modules/mod_auth_basic.so