Friday, January 06, 2012

New Year, New Resolutions

よいお年をお迎えください。

In other words, happy new year!

As far as making and keeping new resolutions go, I’d already failed miserably by January 2nd, probably setting a new low. The resolution was to take a photograph everyday and upload it to Flickr/Facebook, but that just didn’t happen. In fact, I haven’t picked up my camera for a week or two, and only used the camera in my phone to play around with Photosynth, which looks completely out of place on an iPhone, having been built for a Windows-based phone with no effort made to translate the UI design, but nevertheless, works very well.

However, the new year does afford me the chance to indulge in some spring cleaning, even if we are in the early throes of summer here in the Lucky Country. In particular, now that I am back at work, it means opening up the computer case, and having some fun with a rather large air compressor to remove all the dust that has accumulated since the PC was assembled. It also means that I can finally give it a good formatting and install everything afresh, something which every PC user should do at least annually.

Clean ALL the things!This of course reminds me just how many applications I have downloaded and installed in the past year. Just installing Windows 7 with all the layers upon layers of patches takes about half a day, and our internet connection at work feels much slower than my home internet connection.

To give you an idea of just how much stuff your typical Windows developer needs to make it through the day, here’s an approximate list. So far it’s taken me a whole day to download and install this lot, and I’m still finding those useful little apps that you forget aren’t included out-of-the-box.

System

  • 7-Zip – beats WinZip for compression any day;
  • DropBox – file synchronisation across almost any device;
  • Google Chrome – the choice of most developers;
  • Mozilla Firefox – the chose of most other developers;
  • Skype – for keeping in touch with our other offices around the world;
  • Virtual CloneDrive – for mounting all those application installation ISOs;
  • Windows Live Essentials – Mail, Messenger, and of course, Writer (which no self-respecting blogger should be without – definitely one of the most useful products to come out of Redmond);

Business Applications

Developer Tools

  • Beyond Compare – the best diff tool that I’ve tried (WinMerge is free and also very good, but I just prefer BC);
  • CruiseControl.NET – nothing inspires confidence in your day’s work like a row of green lights confirming that it compiles, the tests ran successfully, and the installation package is ready to be shipped;
  • Fiddler – if you have to send data across the network, you need this tool;
  • Notepad++ – syntax highlighting for almost every language out there, and tabbed windows too;
  • Smtp4Dev - for testing the sending of emails;
  • SQL Server Compact – for when the application you are developing will not need a full-blown database server;
  • SQL Server Express – for when application you are developing will need a full-blown database server;
  • Subversion (command-line, GUI, and IDE integration) – who wants to be a tightrope walker without a safety net?
  • Visual Studio – where I spend 95% of my time:
  • Windows 7 SDK – essential developer tools;
  • Silverlight – for rich web client development;
  • Silverlight Toolkit – the bits that Microsoft forgot in Silverlight
  • Expression Blend SDK – another set of bits that Microsoft forgot in Silverlight

Friday, March 25, 2011

A craftsman knows his tools

Those who have worked with me for any length of time will know that I’m always looking for ways to improve my ability as a programmer. It may be in researching the latest available tool libraries (my current new favourite is StoryQ, which is great for developing BDD-style tests, and NSubstitute, which is as easy to use as Moq, but without those annoying calls to .Object), or how to write better, more reliable, build scripts. Either way, learning new skills and refining existing skills is an essential part of any craft (I’m deliberately steering clear of the ongoing “software development isn’t a craft”/“oh yes it is” argument – this still applies to trades and scientific disciplines).

This week I have been focusing on knowing my tools, and being a developer who works with Microsoft technologies, those tools inevitably centre around Visual Studio. One way to increase your productivity is to reduce the time you spend doing pointless activities, or rather, when faced with two ways of achieving something, to choose the quicker way. The most obvious form for a programmer is to learn to let go of the mouse; a little strange maybe, especially in an operating system that defines itself around the use of the mouse, but it really does act as a great big brake on your productivity. When I first started playing guitar, it would take me several seconds to visualise the necessary finger patterns in my head, and then position my fingers on the fret board. Now after much practising, I can see an F# minor chord written down and play it without having to even think about it.

The first step was to get rid of all the toolbars and icons. If there are no icons on screen, there’s not much point using the mouse to click them! The commands are still all there, and they can be accessed via the menu bar if I get really stuck. As a bonus, suddenly I have much more viewable area to concentrate on what really matters – the code.

So my first shortcut to learn was how to stop a debug session. I knew F5 to launch the debugger, but I always clicked on the Stop icon to stop it; well, it turns out that Shift-F5 was my new best friend. So far, so easy, and not too much time saved.

The next useful one was the Surround-with snippet; this is part of the excellent Resharper which really takes the heavy lifting out of Windows programming). I was working with code which was throwing exceptions, and there was no exception handler. Before, I would have used the mouse to click just above the offending line of code, then typed in the standard try/catch blocks, then selected the offending line of code and cut’n’paste it into the try {} block, then clicked into the catch {} and add the exception handling. That’s a lot of pointless mouse and keyboard work. Now, using the keyboard, I would select the line of text (Shift-End to select to the end of the line), then Ctrl-K,S to bring up the Surround-with snippets, then type try and press Enter to surround my code with a try/catch block and automatically position the cursor in the catch {} block ready to select my exception type. Intellisense camel-case matching helped, so I only had to type in CE to match the ConstraintException I was trying to catch, hit Enter, and job done.

There are only so many hours in the day - reclaim yours by learning how to use the tools you have to get more done in less time.

Thursday, March 24, 2011

Synchronicity Part 2

Last year, it was Flash crashing Safari while I was trying to read an article about the problems with Flash. This time, it’s Google Chrome crashing while I’m trying to read about why the newly-released Firefox 4 is the new hotness.

image

Coincidence or conspiracy?

Tuesday, March 22, 2011

Unity and log4net

In my current project at TouchStar, I’ve had the opportunity to play with Unity, Microsoft’s Inversion-of-Control container. Previously I’ve used StructureMap, which is very popular, but I wanted to broaden my experience of different containers, and given that my project involved a WPF client, Unity seemed to be a good choice.

One of the first problems was how to configure log4net using Unity. Usually, log4net is called from within a class thusly:

   1: public class MyClassWithLogger()
   2: {
   3:     private static readonly ILog Logger = LogManager.GetLogger(typeof(this));
   4:  
   5:     public void DoAction()
   6:     {
   7:         Logger.Debug("Hello world");
   8:         DoSomeOtherAction();
   9:     }
  10:  
  11:     private void DoSomeOtherAction()
  12:     {
  13:         Logger.Debug("Still here");
  14:     }
  15: }

Which, depending on how you’ve configured your appenders, would produce an output something like this:

   1: MyClassWithLogger [DEBUG] - Hello world
   2: MyClassWithLogger [DEBUG] - Still here

So far, so vanilla, and the sort of code that anyone whose used log4net will have written thousands of times; but what happens if we want to apply good SOLID design principles and inject the log4net dependency into the class, rather than have the class create the instance itself. I prefer constructor injection for this, as it makes it very explicit what the dependencies are, and you can’t accidentally forget to set one without getting a compile-time error. The class would then become:

   1: public class MyClassWithLoggerDependency()
   2: {
   3:     private static readonly ILog Logger;
   4:  
   5:     public MyClassWithLoggerDependency(ILog logger)
   6:     {
   7:         Logger = logger;
   8:     }
   9:  
  10:     public void DoAction()
  11:     {
  12:         Logger.Debug("Hello world");
  13:         DoSomeOtherAction();
  14:     }
  15:  
  16:     private void DoSomeOtherAction()
  17:     {
  18:         Logger.Debug("Still here");
  19:     }
  20: }

We’re now ready to apply some IoC magic with Unity to create the instance of ILog that our class will use. Since log4net uses its own factory class to instantiate itself, we have to jump through a hoop or two to get Unity to set things up properly:

   1: public class Program
   2: {
   3:     public static void Main(string[] args)
   4:     {
   5:         var container = new UnityContainer()
   6:             .Register<ILog>(new InjectionFactory(x => LogManager.GetLogger(typeof(this))));
   7:             .Register<MyClassWithLoggerDependency>()
   8:  
   9:         var myClass = new container.Resolve<MyClassWithLoggerDependency>();
  10:         myClass.DoStuff();
  11:     }
  12: }

Which produces an output like this:

   1: Program [DEBUG] - Hello world
   2: Program [DEBUG] - Still here

See the problem? Now the logger is using the context of the code where Unity was configured to log from, rather than the context that the logger is being called from. I’ve seen plenty of questions asked about this, but it was only today that I stumbled upon the answer to this problem, hidden in a discussion on the Unity forums. A developer named Marco posted his solution, which was to create two extensions – the first being a BuildTracking extension, and the second being a LogCreation extension. The build tracking extension keeps tabs on what types are being built up, and then calls out to the log creation extension to create the logger component in the context of the class which is asking for it. Another developer, Scott, then posted his amendments that took care of some breaking API changes from the earlier version of Unity that Marco was using, together with an enhancement to improve detection of the calling class name when log4net is not being used with dependency injection.

My small contribution to the discussion was to provide the actual implementation code, which is as follows:

   1: public class Program
   2: {
   3:     public static void Main(string[] args)
   4:     {
   5:         var container = new UnityContainer()
   6:             .AddNewExtension<BuildTracking>()
   7:             .AddNewExtension<LogCreation>()
   8:             .Register<MyClassWithLoggerDependency>()
   9:  
  10:         var myClass = new container.Resolve<MyClassWithLoggerDependency>();
  11:         myClass.DoStuff();
  12:     }
  13: }
Now that in my eyes is a much tidier piece of code. Gone is the explicit registration of the ILog type with its rather ungainly use of the InjectionFactory to create the appropriate implementation, and instead we have the two new extensions registered.

This is a great little bit of code, and big thanks go to Marco and Scott for sharing their contributions with us. I’m sure that many other developers will find this useful.

Monday, March 21, 2011

Watching Ideas Take Flight

In my last entry, I mentioned an idea I’d had before on how to make it easier to package .NET applications when run as part of an automated build. It solved a problem for me, and I thought it worth sharing, firstly as an aide mémoire for myself, and secondly because it seems the sort of thing that other people would find useful.

Rob Reynolds came across my post, and he obviously found it useful. In fact, he liked it so much that he has put together a NuGet package to make the set-up of _PublishedApplications even easier, together with a demo of how easy it is to use.

Demo of _PublishedApplications at work

I’m thrilled to see this getting out there – a big thanks to Rob for really getting this off the ground, as well as giving it more exposure.

Thursday, March 10, 2011

Publishing .NET Applications

This is a problem I came across in my previous job at Fairfax Digital, when setting up automated builds; now that I am working at TouchStar, I’m facing the same problem, but couldn’t remember what I did the first time round.

The problem is this: when building ASP.NET web applications using TFS or some other continuous integration solution (I’m using UppercuT at TouchStar), the MSBuild engine very conveniently creates a _PublishedWebsites folder in your output folder, and then creates a subfolder in that folder for each website that you are creating. So far, so good. However, when building executable applications, such as console apps, WPF applications or Windows services (and I’m building all three at TouchStar) then it just throws everything into one directory, and leaves it to you to pick out the bits you need. “If only you could export your build results to a _PublishedApplications folder!”, I hear you cry.

Well, that’s essentially my solution. I took a copy of the Microsoft.WebApplication.targets file that is referenced in the ASP.NET project file, renamed it to Microsoft.Application.targets and saved it to C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0\Applications. I then tweaked it, renaming variables and such to match the type of content, and removing any references to /bin folders. I then reference the new file in the Visual Studio project file by adding the following line:

  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\Applications\Microsoft.Application.targets" />

And voila! I now have one folder per application in the _PublishedApplications folder when run as part of an automated build. If I build from within Visual Studio, outputs are still sent to their usual location (e.g. /bin/Debug/). I’ve included a link to the file below.

[Download Microsoft.Application.targets]

Thursday, August 12, 2010

Mixing TFS 2008 and VS 2010

At work, we’re in the early phases of migrating our TFS 2008 setup to TFS 2010. However, since some teams have already started work on the new hotness that is VS 2010 and .NET 4, there was a need for us to get their automated builds up and running immediately. We “requisitioned” a desktop that was already running builds for another semi-defunct project using CruiseControl.NET, and installed Team Build on it.

It took a few tweaks to get the code compiling, but something was wrong with the testing phase – the tests would run, but the test runner would then report a failure, resulting in a yellow warning lights rather than nice green success lights. The error message was:

MSBUILD : warning MSB6003: The specified task executable "MSTest.exe" could not be run. The system cannot find the file specified [D:\Source\CommonPlatform\Common Platform Development CI Build\BuildType\TFSBuild.proj]

So the tests all passed, but then Team Build couldn’t find the testrunner that it had just used! We tracked down another user with the same complaint on StackOverflow, but they were shouting in the dark, with no response to their question.

After much head-scratching alternated with banging our heads against the wall and wondering why Microsoft products are sometimes to great and sometimes so plain awful (often in the space of just five minutes), we eventually found the solution to our problem tucked away in forum on MSDN. The TeamBuild targets file which imports the TestToolsTask has an invalid path reference:

<UsingTask TaskName="TestToolsTask" AssemblyFile="$(MSTestRefPath)\Microsoft.VisualStudio.QualityTools.MSBuildTasks.dll" 
Condition="'$(ProjectFileVersion)' == '2'" />

since MSTestRefPath doesn’t appear to be defined in VS 2010. By changing it to the correct path, the test runner can be found again, and the error disappeared.

Quite why Microsoft implemented it so that the tests would run but then fail afterwards I don’t know, but at least our builds are all happy, and the developers are happy. Hopefully we can now get back to migrating TFS 2008 to 2010, and we can see the back of this problem.

Wednesday, May 12, 2010

Synchronicity

Apple and Adobe seem to be having a bit of a dummy spit over Flash at the moment, which is polarising the developer community. Well, I opened up Google Reader to read Richard Banks’s latest thoughts on the subject, and as I do that, bam! Safari crashes with a Flash error.

Flash Irony

(the Flash app was running in a different tab, not as part of Google Reader).

Wednesday, May 05, 2010

Baseless suggestion

I’ve been spending the past few days cleaning up a messy situation at work, where one of our source control branches in TFS 2008 has not been properly merged back into trunk for several months. In trying to tidy things up, I kept getting the following error:

TF14087: Cannot undelete '$/MyCareer/Trunk/build/NightlyBuild/TFSBuild.rsp' because not all of the deletion is being undeleted.

The problem was that the folder NightlyBuild had been renamed in both the source and destination branch, but there was still a reference to it in this old changeset. Using tf merge /discard reported that there were no changes to make, which left me stuck for a bit, until one quick application of Google-fu, and I found the solution to my problem. By performing a baseless merge, the offending file is accepted:

tf merge /discard /baseless /version:C13494~C13494 $/MyCareer/Branches/Maintenance $/MyCareer
/Trunk /recursive
Resolved D:\Source\MyCareer\Trunk\build\DailyBuild\TFSBuild.rsp as AcceptYours

Hope that helps!

Thursday, February 25, 2010

Lightroom and CS3

I recently upgraded my camera from an ageing Canon EOS 30D to the newly-released EOS 7D. Jumping from 8 megapixels to 18, and adding HD video recording, as well as niceties such as Auto ISO, are real plusses for me.

However, I soon found an annoying problem: I use Adobe Lightroom 2 to manage my rapidly-growing photo collection (just a handful shy of 10000 now) and Adobe Photoshop CS3 to do clever stuff like panorama stitching. However, CS3 doesn’t recognise the RAW format that Canon uses in the 7D, although Lightroom 2 does, so I can’t load photos taken with the 7D in Photoshop. Bummer.

Adobe’s ideal solution is that I upgrade to Photoshop CS4, which will be several hundred dollars. However, the solution I came across was to use Adobe’s own tools to work around the limitation. Lightroom can convert RAW images to its preferred DNG format, and that format can be opened in CS3. Usually I convert my RAW images to DNG as the last step in my development process, but this is a neat little workaround, saving me a big chunk of cash at the same time.

Thursday, November 05, 2009

Working with bugs

No, this is not a post on entymology; rather, it’s a bit of a lament on the lost art of filing bug reports. Though they may bestride the programming world like a colossus, even the best programmers will eventually leave bugs in their code. Sooner or later, some poor user will fall foul of it.

You then have a number of solutions, depending on where the product came from. For a commercial product, you can:

  1. ignore it and hope it goes away;
  2. file a bug report, and hope that the provider will fix it;
  3. find some sort of workaround, or just learn to live with it;
  4. vote with your wallet, and switch to a competitor’s product

For an open-source product,, you have an extra option:

  1. download the source code, and fix it yourself, and preferably submitting your fix back to the community.

In my case, it was a bug in a Microsoft development tool, the succinctly named Microsoft Visual Studio Team System 2008 Database Edition GDR R2. As an aside, let me say that I’ve been using it for all of 2 days, and I absolutely love its functionality. It finally makes versioning and deploying databases a delight rather than a painful chore. There is now no excuse for organisations not to have their databases under version control, or for having painful manual deployment processes.

Anyway, it has a bug in it which is holding up a particular project at work. I searched for a solution, and found someone who had reported the same issue some 9 months ago. Unfortunately the bug report that they filed was so lacking of information that Microsoft promptly closed the bug as Not Reproducible. In fact, it’s not 100% certain that the bug relates to my issue because it is so light on details – it just reports the same error message.

As it happens, the steps required to reproduce the bug were incredibly trivial, so I opened a new bug, and gave the sort of details that a developer trying to fix a bug needs to see – in other words, I described what I was doing, what I expected to see happening, and what actually was happening. More to the point, I list the steps that the developer should take to make the same thing happen for them.

The first step to being able to resolve a bug is to be able to reproduce it. If you can’t reproduce it, how can you work out what is going wrong, and how can you prove that you’ve fixed the bug? And if the bug reporter doesn’t tell you how to reproduce the bug, what chance do you have of being able to fix it?

So please – if you want your bug to be fixed, consider the poor developer who has to fix it, and tell them what they need to know to get the job done. Anything less, and you’ll have a 9 month wait before someone else with the same problem files the same issue again.

Wednesday, September 23, 2009

Weird Sydney morning weather

The joys of parenthood include many early mornings. This is what awaited me this morning when Samuel woke us up. Most freaky! Any ideas what's causing this?
Update : apparently it's a dust storm. Western Australia is missing several hundred tonnes of dust and topsoil.

Monday, June 29, 2009

iPhone on 3

When the iPhone 3G was originally released in Australia, I and many others complained that 3, who provide some of the best 3G data plans in the country, did not sell it. There were ways around it,which kind of suggest that it was a problem at Apple's end rather than 3's, but it seems that with the release of the updated iPhone 3GS, users of the 3 network are finally getting some Apple love. And of course, it's at this point that I notice that my elderly Nokia N95 8Gb is finally fully supported by OS X, including syncing from iTunes and iPhoto. Now where was that a year ago when I really needed it? Never mind; just as soon as I can sell a kidney on Ebay, I'll have his'n'hers iPhone 3GS's, and the Nokia can go in the phone recycling bin.

Wednesday, May 20, 2009

SvnRevisionLabeller makes its v2 release

Recently Thoughtworks started to make available release candidates for version 1.4.4 of CruiseControl.NET. Tucked away inside there though are some changes to some of the core components, that break compatibility with SvnRevisionLabeller.

This gave me the proper motivation to find some time to finish off the packaging of a fairly major change to the way the labeller constructs build labels. The real work was actually done by another developer, fezguy - I just had to integrate his patch, tweak it to the way I like things (hey, it is my project after all!), and finally start work on some automated tests. I like automated tests.

Since the two changes combined do break backwards compatibility, it's good to take a step back and see where we are now.

Before, SvnRevisionLabeller was quite opinionated about how it thought build labels should be structured. With version 1.1, it was {major}.{minor}.{svnRevision}.{build} - {build} would start at 0, then if you forced another build without another commit having taken place, it would be incremented by one. A commit would then reset {build} back to 0, so you had a good idea how often the build was being forced. I later added the ability to specify prefix and suffix text for the label.

Version 1.3 saw me rethink things a bit, with the label now defaulting to {major}.{minor}.{build}.{svnRevision}; now, successive forced builds made no difference to the label. What it did give me was that when I deployed a hotfix to production (usually designated by the incremented {build} number), I could tell immediately which Subversion revision it was built with.

So it obviously works the way I wanted it to - but what about other people? Version 2.0 makes the label scheme very flexible - some tokens are defined, and you just position the tokens wherever you want them in a string pattern. So for instance, if I set my configuration thusly:

<labeller type="svnRevisionLabeller">
<major>1</major>
<minor>4</minor>
<build>2</build>
<pattern>Release v{major}.{minor}.{build} from {revision}</pattern>
</labeller>

then when revision 42 is committed, the build label will become Release v1.4.2 from 42. At work, I use the {build} number to represent the sprint number since we began working on the {minor} release.

Finally, I noticed that my project was not the only one to be caught out by CC.NET's upgrade - Codeplex's CC.NET Community Plugins are also broken by the change; unfortunately, they have a little more work to do, as it's not just a question of updating their external libraries and recompiling. I'm rather underwhelmed by the amount of activity on the site: I raised an issue earlier this month, and then submitted a patch to fix the issue, and it still hasn't been acknowledged yet, let alone added to the repository. For the time being, I won't be upgrading to v1.4.4 at work, since we need that library for our deployments.

Tuesday, April 14, 2009

An afternoon at Lake Parramatta

The Easter weekend was a good opportunity to get out of the house for a while and enjoy some of what Sydney has to offer. Several friends have recommended Lake Parramatta, a small dam and reservoir less than 10 minutes from our house, but we've never been there before. It was built in the late 19th century to provide drinking water for Parramatta, but these days it's a recreation area. It's sometimes swimmable, I think they're still working on the general cleanliness of the water (lots of stormwater drains etc empty into the catchment area).

The reservoir of Lake Parramatta

There's plenty of parking etc at the entrance, barbecue areas, covered seating, even a playground for the little 'uns. It was quite busy considering sunset was less than an hour away, lots of families having picnics and so on.

The dam wall of Lake Parramatta

We took a brief walk round the easy part of the reservoir, down to the dam wall itself. There's a small creek at the base of the dam, with some pretty lush vegetation from the water that trickles down from the dam (although the picture above doesn't explicitly show it, the wall is constantly damp, as the water finds its way through and down).

Stepping stones

The creek at the bottom is crossed with a line of stepping stones. There's a lot of brown algae in the water, so it doesn't look very pleasant, but I think I got enough of an angle above so that it doesn't show. The full circuit around the reservoir is about 4.2km (I did say it was a little reservoir!), and although some of it is paved and flat, some of it requires a bit of a scramble. We'll have to save that for another time, because we got there not long before sunshot, and also because Emily is a bit too pregnant to be climbing anything at the moment.

Tuesday, March 31, 2009

MassTransit

Earlier this month, I mentioned the MassTransit project, an open-source .NET Enterprise Service Bus implementation, a topic sure to break the ice at a many a party.

We've been getting stuck into MassTransit at work for a major project, and had all sorts of problems along the way, mainly due to the youth of the project and the general lack of documentation. Where there were code samples, sometimes the code just plain didn't work.

Blog postings need images, apparently; so here's one that's distantly related to the topic under discussion - it's a restaurant tram in MelbourneThe two main developers, Dru and Chris, have been a fountain of knowledge and general helpfulness, responding quickly to my sometimes continuous barrage of questions, not helped of course by our being on opposite sides of the planet. I've been able to chip in with the occasional patch, nothing to fancy at this stage, but at least enough for me to feel like it's not a completely one-way street.

Anyway, congratulations to MassTransit for shipping their v0.6 release candidate. I've been running it for a few days now, although without using some of the cooler pieces of new technology, such as the saga state machines. Hopefully with their help, I'll be able to get our project back on track and heading in the right direction.

Thursday, March 19, 2009

Topshelf

At work, I'm currently working on a project which requires the integration of several different systems, some of them hosted on the internet, and some on different sides of the corporate firewalls. This means that we can expect to lose connections between systems, which naturally pointed us in the direction of message queues, which are designed for such scenarios. A chat with a former colleague pointed me in the direction of enterprise service buses as the core technology to take care of all the plumbing; and after comparing feature sets with our requirements, I downloaded MassTransit.

What interested me was a spin-off from the MassTransit project, called Topshelf, which has a single and simple aim - to get rid of all the cruft associated with actually launching .NET programs, especially all the boilerplate code you have to come up with to run services.

I ran into a few issues though: the first was that before, I had been using the WiX's ServiceInstall code to handle all the service registration, such as setting the service name, description and credentials. However, Topshelf provides its own code to do that, and the two aren't compatible. In the end, the solution I came up with was to remove the WiX code and use Topshelf's, which would be invoked by a custom action in the WiX script:

<CustomAction Id="InstallService" FileKey="ServiceExe" ExeCommand="/install" />
<InstallExecuteSequence>
    <Custom Action="InstallService" After="InstallFinalize" />
</InstallExecuteSequence>

FileKey is just a reference to the Id of the executable for the service, and ExeCommand contains the parameter(s) to pass to it.

All well and good, but unfortunately, Topshelf's implementation currently launches the same dialog box that installutil does, and if you're trying to produce an unattended install file, a dialog box is the last thing you want. I've had a little play around with the source code and came up with something which would technically work, but was nowhere near as elegant as the rest of the code, so I'm not planning on submitting it.

I did add a few refactorings and documentation into the codebase, nothing clever or anything; I then submitted the changes as a patch to Dru, and within the hour, they had been committed to trunk. This really reminds me why I love open-source programming so much - if the application doesn't do quite what you want it to do, you can download the source code and modify it, and if it works well, you can contribute that change back to the community. Talk about a win-win situation. Non-open source companies have to think about every way that people will use their software, and then program all that functionality in, thus proving the 80-20 rule - 80% of your users are only using 20% of your application's functionality. Did you know that Microsoft Word has a Japanese Greeting dialog box, which allows you to select a greeting specific to the month of the year?! I wonder even how many Japanese people know it exists?

Japanese Greeting dialog box from Microsoft Word 2003

Speaking of contributing to open source, I've accepted a couple of patches to my SvnRevisionLabeller project, and should be releasing a new build soon, once I've figured how to get some good tests in there. You are testing your software, right?!

Thursday, March 12, 2009

This stuff is supposed to be fun

So blogged Jeff Attwood some 18 months ago, and as far as my own experience goes, he is absolutely right. When I went to university, it was to study Electronics and Communications Engineering, but by mid-way through the second year, I really wanted to on Computer Science, but really it was just too late to be changing courses, so I stuck it out to the end. To show willing, I applied to some of the major electronics companies like Philips and Marconi, but nothing came of that, so I managed to convert my summer job at the Foreign & Commonwealth Office into a more permanent job, doing typical admin stuff in the library. A healthy dose of luck and good timing saw me slide into an IT helpdesk/sysadmin role, and from there, I never looked back.

I was then able to leverage (how I hate that word) my IT skills to get into development, and there I knew that I had found my real métier. Like no doubt thousands of my technical colleagues, I have found the perfect union between my favourite pastime and my job. My wife still marvels that I spend eight or more hours a day at the office working with computers, and then when I come home, I'm happy to spend the rest of the evening, or most of the weekend, doing exactly the same thing (and not getting paid for it!).

In fact, I enjoy being a developer so much that I will do everything in my power to avoid promotion to a position where I can't sit down and write code every day. For some, it may be just a step on the ladder to management, and that's OK; but for me, the day I stop coding and using computers is the day they prise the keyboard from my cold, dead hands.

In short, I know what colour my parachute is; and being a self-professed geek, it's black.

So are there any other categories of people out there whose private life seems to be just an extension of their working life? Or perhaps even better, they see it as the other way round, where they're getting paid to do something they could spend every day doing? Musicians? Sportsmen? Accountants, anyone?!

Friday, February 27, 2009

One hour of heavy petting

I wonder if there's any chance of something like this taking off in Sydney. Maybe there's just something so incredibly Japanese about it that it wouldn't work, but I just love the idea.

Either way, it seems Sarah Marchildon has struck a bit of a chord with her blog posting, generating all sorts of interest.

Perhaps I should buy a fancy espresso machine and add a dozen cats to the household, and set myself up as the Sydney branch of 猫の時間 (Neko no Jikan, or "Cat Time").

It's a hard life being a cat. All that sleeping...

Wednesday, February 18, 2009

Cuuuurses!

Oh well, so much for my earlier optimism - it turns out, that for the time being at least, Sandcastle can't easily be used on a build server.

The problem is the Help 2.0 Compiler, which in a previous life as the Help 1.x Compiler, was shipped as a standalone product. However, Microsoft, in its infinite wisdom, decided to bundle the 2.0 version into the Visual Studio SDK; and of course, to install the Visual Studio SDK, you need to first have an installation of Visual Studio, which rather defies the point of a build server. Especially for small operations on a budget, having to acquire an extra VS license just to automate the creation of documentation is more than a pain in the neck, it's downright unsociable.

There are some guides on working round this, but they only cover up to VS2005 and its SDK, whereas we're using VS2008 SP1.

I'm going to have a play around with exporting chunks of my registry which has references to the 2.0 compiler, in the hope that that fixes things. I don't hold out much hope.