Personal Names

I’m lucky because most software is designed for me. I never have a decision to make when I run across a form:

First name
Last name

But not every name follows the “FirstName LastName” convention. Some names are written family-name-first (China), some people have multiple family names (Hispanic cultures), and others have more complicated rules.

This article from the W3C is an excellent primer on how personal names differ across cultures.

The gist is that, if you’ve written this code:

Console.WriteLine($"Hello {firstName} {lastName}!");

then you might have called some people by the wrong name. If you can, it could be better to use “full name” and “nickname” fields:

Full name
What should we call you?

For a more humorous description of cultural differences in names: Falsehoods Programmers Believe About Names.

Learning Async #2: Controlling the Context

The main purpose of async/await is to handle the bookkeeping work when you make asynchronous calls.

When you do asynchronous work, there’s often some context you have to be aware of. For example, you can’t touch the UI from any thread but the special “UI thread”. There are two rules about this:

  1. Only the UI thread may update the UI.
  2. Don’t block the UI thread with long-running work.

If you have a long computation, you can spawn a thread so the UI thread isn’t blocked, but you must remember to get back onto the UI thread before you touch any controls:

void ButtonPressed(sender s, EventArgs e)
{
    // Start some calculation on a background thread
    new Thread(new ThreadStart(() =>
    {
        var answer = Factorial(1000000);
        // Get back onto the UI thread before continuing
        Invoke(() =>
        {
            answerTextBox.Text = answer.ToString();
        });
    }));
}

In WinForms, the UI thread is your “context” you have to get back after doing some asynchronous work. You use Invoke(action) to do that.

Before C# 5, this could be painful, but async and await make it a piece of cake. They make that mess as simple as:

async void ButtonPressed(sender s, EventArgs e)
{
    var answer = await FactorialOnThreadPoolThreadAsync(1000000);

    // The await got us back onto the UI thread automatically
    answerTextBox.Text = answer.ToString();
}

(I cheated a little by assuming somebody wrote FactorialOnThreadPoolThreadAsync(int) for me).

That little await keyword did all of this for you:

  1. Save the task returned by FactorialOnThreadPoolThreadAsync()

  2. Capture the current “SynchronizationContext”

  3. Schedule the rest of ButtonPressed() to run with the current SynchronizationContext when the task completes. Since this is a WinForms app, that means it gets us back onto the thread we started on.

Notice that await captures a SynchronizationContext, not a thread. In a WinForms app, these pretty much mean the same thing, but in an ASP.NET app, they don’t. In ASP.NET, the SynchronizationContext contains the request context: Who is authenticated, what session state is available, etc., almost none of which is specific to the thread.

The details of all this aren’t usually important to understand. The important thing to remember is “using await gets me back where I was before the asynchronous call”.

Learning Async #1: Basic Lessons

So I’ve been building Turbocharged.Beanstalk, a .NET client library for using Beanstalkd. This project has been a way to start using the async/await feature of C# 5.0.

I’m writing a few articles about what I’ve learned from this exercise.

Tasks are not just about multithreading

A Task is not necessarily “work running on a background thread”. It often is, but not always.

Here are two method calls that block the thread:

// CPU-bound
Factorial(1000000);

// Not CPU-bound
socket.Receive(buffer, 0, 1, SocketFlags.None);

Both of these methods take a really long time to return. The first one takes a long time because calculating the factorial of one million requires a lot of work.

The socket read takes a long time because the network is soo slooowww compared to the CPU. But the thread isn’t doing anything, it’s just standing around. Couldn’t it be doing other work, something that actually requires the CPU?

Yes. Tasks help you avoid blocking a thread when really you’re just waiting for a system interrupt.

It’s like cooking

If you’re the only cook in the kitchen, then you can only be doing one thing at a time. You are a single-threaded cook.

If you’re going to whip up some eggs, one of the tasks you must perform is heating the skillet. Do you put the skillet on the stove, then stand around until it’s hot enough?

Of course not. Heating a pan doesn’t require any work from you. You put the skillet on the stove, then while it’s heating up you do other work:

  1. Crack some eggs and scramble them
  2. Get the toaster out and put the toast in
  3. etc.

By the time the pan is hot, you’ve completed a bunch of work, none of which depended on the pan being hot.

Back to code

Let’s read a byte from the network:

await networkStream.ReadAsync(buffer, 0, 1);

While this task is awaiting, no thread is blocked waiting for the read to complete. Waiting for a byte to be received from the network does not require a thread. Instead of wasting a thread until a byte is received, the thread goes off and does useful work. Eventually, the operating system notifies your app that the read task has completed. A thread resumes at the await and continues where it left off.

Putting some work in a Task does not mean a background thread is blocked waiting for the Task to complete.

The await isn’t doing any threading magic for us. Here’s another example:

public static void Main()
{
    var tcs = new TaskCompletionSource<string>();
    Task task = tcs.Task;

    int countdown = 3;
    while (!task.IsCompleted)
    {
        Console.WriteLine("{0}...", countdown);
        if (--countdown == 0)
            tcs.SetResult("Done!");
    }

    Console.WriteLine("Task completed with result: {0}", task.Result);
    Console.ReadKey();
    
    // Prints:
    //   3...
    //   2...
    //   1...
    //   Task completed with result: Done!
}

There’s only one thread here. There are no awaits. Instead of representing code running on a background thread, the Task returned by TaskCompletionSource<T>.Task represents “waiting for somebody to call SetResult(T)”.

Improving our builds with Psake and Rake

I believe these are good things:

For these reasons, our team has been using Continua CI to build our Windows projects and TeamCity for our iOS projects. I have more experience with Continua so that’s what I’ll discuss here, but the same ideas apply to TeamCity.

Continua CI lets you design a build process with a web-based tool that has first-class support for running MSBuild scripts, creating NuGet packages, running various testing tools, or just executing programs and scripts.

Until now, our build process has been written in this tool. This gave us a graphical way of editing the build process without mucking around in a batch file or other scripting language. Continua was reponsible for remembering how to build and deploy our projects, and we could deploy anything by signing into Continua and starting a build.

Unfortunately, we’ve realized this comes with several problems:

To fix this, we are putting the build logic in a Psake build script. Psake is a build automatation tool written in PowerShell. You define the steps of your build as “tasks”, then choose which task you want to execute.

## default.ps1 (the build script)

Task Build {
    echo "Building the solution"
    & msbuild $solutionFile
}

Task Deploy {
    echo "Deploying to the devepment environment"
}

Then invoke the build script with the Invoke-psake function:

PS C:\> Invoke-psake Build

---------------[Build]---------------
Building the solution
... msbuild output ...

---------------[Deploy]---------------
Deploying to the development environment
... output ...

Build Succeeded!

--------------------------------------
Build Time Report
--------------------------------------
Name            Duration
----            --------
Build           00:00:09.4624557
Deploy          00:00:12.2191711
Total:          00:00:21.6816268

You can do more than just execute commands from Psake. The build script is just PowerShell, so anything you can do from PowerShell can be done during a build. This is great for us because we make heavy use of Microsoft’s development ecosystem, and all of Microsoft’s System Center products and Windows Azure have PowerShell modules to do almost anything we could want, including creating VMs and deploying software do them.

Our build script in Continua has been reduced from this:

to this:

Continua is still invaluable, but as the tool to automatically kick off our builds whenever we push changes and notify us when something bad happens. It no longer knows how to build the projects, only how to call Psake.

For our iOS projects, we’re using Rake, which is equally awesome, but build scripts are written in Ruby instead of PowerShell. Rakefiles have the same basic structure as Psake build files:

task :build do
    # Build with Xcode
    sh "xcodebuild ..."
end

task :testflight => [:build] do
    # Upload to TestFlight
end

and invoked with rake testflight.

Global settings files in WiX

Global settings files have several requirements:

  1. On install, create the file if it does not exist.

  2. Configure certain settings during installation/upgrade, and leave all other settings alone.

  3. Never delete the settings file during installation, upgrade, or uninstallation.

With these requirements, we have the following fragment:

<Component Id="settings.config" NeverOverwrite="yes" Permanent="yes">
    <File Source="path/to/default/settings.config" KeyPath="yes" />
</Component>

<Component Id="settings.config.Configure" KeyPath="yes" Guid="...">
    <util:XmlConfig File="[#settings.config]" .... Value="[PROPERTY1]" />
    <util:XmlConfig File="[#settings.config]" .... Value="[PROPERTY2]" />
</Component>

Here’s how this meets all the requirements:

  1. The settings.config component creates the file if the component isn’t installed when we start the installation.

  2. During installation and upgrade, the second component will modify the existing settings.config that’s on disk. The setting Component/@NeverOverwrite prevents us from overwriting the existing file on upgrade.

  3. During uninstallation, the file is left in place with Component/@Permanent. This attribute also prevents the file from being removed even if MajorUpgrade/@Schedule='afterInstallValidate'.

  4. The XmlConfig actions are in a separate component so they will run on upgrades even though settings.config isn’t being updated.