Friday 31 October 2008

Rethinking Syncing

I have been doing a lot of synchronization work recently, trying to get multiple video and audio streams to play back together as best synchronized as possible. This is not a trivial task, especially if those streams are only partially downloaded and the user can reposition anywhere they like during playback.

In the past I have tended to use locks for synchronization. So you have a renderer thread, that is writing video frames or audio samples to an output device, and when it needs to read some more data, it takes a lock, reads what it needs and releases that lock. Meanwhile, over in another thread, quite probably controlled by a slider of some description on the GUI, the user makes repositioning requests. When one of these requests comes in, the various audio and video streams take a lock on the same object that the renderer wants, reposition their streams to the new position, and then release the lock. Hey presto, the renderer will now read from the correct place on its next read call and is in no danger of reading corrupt data packets because we are midway through repositioning.

However, I am beginning to think that there is a better approach. When the user attempts to reposition the playback cursor, this simply posts a repositioning request into a queue. Then when the renderer threads want to read more data, they first check to see if a reposition request needs to be serviced. I think this approach will perform just as well as the first, (if not better because we can throw away repositioning requests if they are not serviced quickly enough). It also means that locks do not need to be held for significant periods of time (just a quick one to govern the read/write from the reposition queue). I am thinking I might trial this new sync model in a future version of NAudio. Let me know in the comments if you think this is a better approach or not.

There are a couple of interesting implications of this approach that need to be considered. First, when you ask a stream to reposition, you won't find out whether the reposition was successful immediately. You can query the current position just after setting the position and its value will not be up to date. Second, if the renderer thread is processing the repositioning requests, then when playback is stopped, repositioning requests may not get serviced. It very much depends on your application as to whether this is a problem or not.

Thursday 30 October 2008

MIDI In for BabySmash

I watched Scott Hanselman's presentation at the PDC on BabySmash this afternoon, and was very impressed both with the quality of his presentation skills as well as the sheer coolness of all the new technologies he was using.

As I watched it, I thought to myself how easy it would be to add MIDI in to this application using the NAudio open source .NET audio toolkit I have written. I downloaded the BabySmash source code from CodePlex and it only took about 10 minutes for me to add MIDI in support.

The first thing to do was to listen for MIDI in events on the default device. Thanks to NAudio, this is just a couple of lines of code, called after InitializeComponent.

private void StartMonitoringMidi()
{
    midiIn = new MidiIn(0); // default device
    midiIn.MessageReceived += midiIn_MessageReceived;
    midiIn.Start();
}

Next we needed to handle the MIDI in messages. I only care about NoteOn messages, and need to switch to the despatcher thread before interacting with the GUI:

void midiIn_MessageReceived(object sender, MidiInMessageEventArgs e)
{
    if (this.Dispatcher.Thread == Thread.CurrentThread)
    {
        NoteOnEvent noteOnEvent = e.MidiEvent as NoteOnEvent;
        if (noteOnEvent != null)
        {
            controller.ProcessMidiNoteOn(this, noteOnEvent);
        }
    }
    else
    {
        Dispatcher.BeginInvoke(new EventHandler<MidiInMessageEventArgs>
            (midiIn_MessageReceived), sender, e);
    }
}

The final step is for the new Controller method to somehow convert the note on event into something to be displayed. Obviously we could have lots of fun here, but for this initial demo I wanted to keep it really simple.

public void ProcessMidiNoteOn(FrameworkElement uie, NoteOnEvent noteOn)
{
    AddFigure(uie, new string((char)('A' + noteOn.NoteNumber - 30), 1));
}

And that's all there is to it. Less than 20 lines of code. Here's a brief video of me demonstrating it:

Some notes:

  • The existing audio playback in BabySmash seems problematic and caused hanging on my laptop. I might see if I can replace it with the audio playback mechanism from NAudio. This would allow me to put some drum / musical sounds in and manage the number of concurrent sounds.
  • I didn't change the graphics at all. I had hoped that the MEF plugin architecture demoed in the PDC talk would be there for me to create my own "SmashPack", but it looks like that code hasn't made it onto CodePlex just yet. One advantage of MIDI in is that each input has a velocity (how hard you smashed it) as well as what note you hit. I would like to try out using colour or initial size to indicate velocity.
  • BabySmash seemed to cope very well with the speed of new notes coming at it. It probably would feel a bit more responsive if the shapes appeared instantaneously rather than animating in.
  • Apologies for the very poor sound quality on the video. I sound like I am speaking with a lisp, and the piano sounds dreadful. As for the drums, well the less said the better. I am not a drummer and there is something badly wrong when you can hear the sticks louder than the drum sounds themselves.
  • Earlier this week two keys on my piano actually got "smashed" for real by one of my children, which means I have an expensive repair bill coming my way. There's no way I'm going to let any of them have a go at smashing on my laptop!
  • Also apologies for the difficulty of seeing what's on the screen in the video. My laptop screen viewing angles aren't that great (and my cheap camera isn't exactly the greatest either, having suffered yet another "baby smash" incident of its own).

Sunday 26 October 2008

NAudio and the PDC

Every time a new version of the .NET framework is due to be announced I always get my hopes up that this will be the year that we are finally given a low-level audio API for .NET. Looking at the sessions for this year's PDC, it sadly seems that audio has been overlooked once more. In fact, the only audio related session is one from Larry Ostermann, which seems like it will announce some new Windows 7 API's for writing apps with real-time audio communications (presumably chat / phone apps).

But there is one piece of news that might prove very useful for NAudio, which is that there are some upcoming changes in the .NET type system that promise to make COM interop a lot easier. I'm not getting my hopes up too high, but anything that makes COM and P/Invoke code easier in .NET would be a huge benefit to NAudio. I have been looking at adding a managed wrapper round the Windows Media Format SDK, and the sheer amount of interop code that is required is daunting. Anyway, I'll be watching the PDC sessions with interest this week, and will post back here if there turns out to be anything relevant to NAudio.

Monday 20 October 2008

Volume Metering and Audio Waveform Display in NAudio

I spent a couple of hours this evening adding two features to NAudio that I have been meaning to add for a long time. They are two Windows Forms controls, one to display volume levels, and the other to display audio waveforms. They are still in a very raw state, and I will probably make some enhancements to their appearance as well as how they calculate their volume levels in the future, but they work pretty well for basic visualisation purposes. I'm also looking forward to creating their equivalents in WPF.

winforms-waveform

I've made a very short screencast to show them in action. Watch it here: http://screencast.com/t/m13tSFGAG

Find Orphaned Source Files Using LINQ

On a project I am working on there is a growing number of files that are in Source Control but are not actually referenced by any .csproj files. I decided to write a quick and dirty command line program to find these files, and at the same time learn a bit of LINQ to XML.

During the course of my development, I ran into a couple of tricky issues. First was how to combine some foreach loops into a LINQ statement, and second was to construct the regex for source file matching. Both I guess I could have solved myself with a bit of time reading books, but I decided to throw them out onto Stack Overflow. Both were answered within a couple of minutes of asking. I have to say this site is incredible, and rather than treating it as a last resort for questions I have reached the end of my resources on, I am now thinking of it more like a super-knowledgeable co-worker who you can just ask a quick question and get a pointer in the right direction.

Here's the final code. I'm sure it could easily be turned into one nested LINQ query and improved on a little, but it does what I need. Feel free to suggest refactorings and enhancements in the comments.

using System.Text;
using System.IO;
using System.Xml.Linq;
using System.Text.RegularExpressions;

namespace SolutionChecker
{
    public class Program
    {
        public const string SourceFilePattern = @"(?<!\.g)\.cs$";

        static void Main(string[] args)
        {
            string path = (args.Length > 0) ? args[0] : GetWorkingFolder();
            Regex regex = new Regex(SourceFilePattern);
            var allSourceFiles = from file in Directory.GetFiles(path, "*.cs", SearchOption.AllDirectories)
                                 where regex.IsMatch(file)
                                 select file;
            var projects = Directory.GetFiles(path, "*.csproj", SearchOption.AllDirectories);
            var activeSourceFiles = FindCSharpFiles(projects);
            var orphans = from sourceFile in allSourceFiles                          
                          where !activeSourceFiles.Contains(sourceFile)
                          select sourceFile;
            int count = 0;
            foreach (var orphan in orphans)
            {
                Console.WriteLine(orphan);
                count++;
            }
            Console.WriteLine("Found {0} orphans",count);
        }

        static string GetWorkingFolder()
        {
            return Path.GetDirectoryName(typeof(Program).Assembly.CodeBase.Replace("file:///", String.Empty));
        }

        static IEnumerable<string> FindCSharpFiles(IEnumerable<string> projectPaths)
        {
            string xmlNamespace = "{http://schemas.microsoft.com/developer/msbuild/2003}";
            
            return from projectPath in projectPaths
                   let xml = XDocument.Load(projectPath)
                   let dir = Path.GetDirectoryName(projectPath)
                   from c in xml.Descendants(xmlNamespace + "Compile")
                   let inc = c.Attribute("Include").Value
                   where inc.EndsWith(".cs")
                   select Path.Combine(dir, c.Attribute("Include").Value);
        }
    }
}

Tuesday 14 October 2008

Styling a ListBox in Silverlight 2

Back in April, I started a series of posts here on how to completely customise the style of a ListBox in Silverlight 2 beta 1, including the scroll-bar styles. That was followed by a rather painful update to Silverlight 2 beta 2 (see Part 1, Part 2, Part 3). Now that Silverlight 2 has officially shipped, the code required one last update. Thankfully the changes were not so great this time. A few deprecated properties needed to be removed from the XAML, and some Duration attributes needed to be changed to GeneratedDuration, but that was about it.

There is some good news. From initial inspection it looks like the scroll-bar bug, where you saw a stretched horizontal scroll-bar behind your vertical scroll-bar has finally been fixed. And first impressions of the XAML preview in Visual Studio are good - you can actually see what it looks like without having to run the project.

What it hasn't fixed is my appalling colour selections and graphical design skills. I might take the time to work a bit more on the appearance of this thing now that I can be sure the syntax isn't going to change yet again.

Fully Styled Listbox in Silverlight 2

I've uploaded my example project which can be opened in Visual Studio 2008 (with Silverlight Tools) or in Expression Blend 2 SP1. Download it here.

Friday 10 October 2008

Refactoring to Reduce Method Complexity

I gave a seminar to the developers at my work this week on the subject of how we can keep the overall complexity of our projects down by refactoring methods. Here's some of my key points...

Measure the Complexity of Your Source Code

I have been experimenting recently with the excellent freeware application SourceMonitor. This can scan your source code folder (it supports several languages including C#, C++, VB.NET, Java), and give you a report that will help you quickly identify classes with the most methods, methods with the most lines of code, methods with the deepest level of indentation, and methods with the greatest "complexity" rating (which I think is related to how many possible routes through the code there are). You will be surprised at how good this simple tool is at identifying the areas of your code that have the most problems.

SourceMonitor output

SourceMonitor output

Measuring complexity allows you to identify whether new code you have written is over-complicated. It also alerts you to the fact that you may have increased the complexity of the existing code you have modified. If developers make it a goal to leave the code they work on less complex than it was when they started, gradually an overcomplicated codebase can be brought under control.

Complexity Grows Gradually

A competent developer writing new code knows not to make functions that are hugely long and convoluted. But complexity sneaks in gradually, most commonly because of bug fixes or special cases come up. Often these 5-10 line additions are considered so trivial that the method in question does not need to be refactored. But before long, you have gigantic methods that cause headaches for anyone who needs to debug, modify or reuse them.

Consider this simple line of code:

string filename = Path.Combine(folderBrowserDialog.SelectedPath,
    String.Format("RecordedItem {0}-{1}-{2}-{3}-{4}-{5} Channel {6}.xml", 
        recordedItem.StartTime.Year,
        recordedItem.StartTime.Month,
        recordedItem.StartTime.Day,
        recordedItem.StartTime.Hour,
        recordedItem.StartTime.Minute,
        recordedItem.StartTime.Second,
        recordedItem.Channel));

All it is doing is creating a filename. Many developers would not consider putting this into a function of its own (even though it is taking up 9 lines of vertical space). What happens next is a bug report is filed, and suddenly, the code to create a filename gets even longer...

string filename = Path.Combine(folderBrowserDialog.SelectedPath,
    String.Format("RecordedItem {0}-{1}-{2}-{3}-{4}-{5} Channel {6}.xml", 
        recordedItem.StartTime.Year,
        recordedItem.StartTime.Month,
        recordedItem.StartTime.Day,
        recordedItem.StartTime.Hour,
        recordedItem.StartTime.Minute,
        recordedItem.StartTime.Second,
        recordedItem.Channel));
int attempts = 0;
while (File.Exists(filename))
{
    attempts++;
    if (attempts > 20)
    {
        log.Error("Could not create a filename for {0}", recordedItem);
        throw new InvalidOperationException("Error creating filename");
    }
    filename = Path.Combine(folderBrowserDialog.SelectedPath,
        String.Format("RecordedItem {0}-{1}-{2}-{3}-{4}-{5} Channel {6} {7}.xml", 
            recordedItem.StartTime.Year,
            recordedItem.StartTime.Month,
            recordedItem.StartTime.Day,
            recordedItem.StartTime.Hour,
            recordedItem.StartTime.Minute,
            recordedItem.StartTime.Second,
            recordedItem.Channel,
            attempts));
}

Now we have thirty lines of code all devoted to the relatively simple task of creating a unique filename. Most developers who will work on our code do not need or want to know the details. This code therefore is an ideal candidate for breaking out into a single method:

string filename = GetFilenameForRecordedItem(folderBrowserDialog.Path, recordedItem);

Now developers can skip over this code and only look within the function if they actually need to know how the filename is generated.

Break Long Methods into Individual Tasks

The most common reason for a method being very long, or deeply nested is simply that it is performing more than one task. If a method doesn't fit onto one screen in an IDE, the chances are it does too much.

Methods are not just for code that needs to be reused. It is fine to have private methods that only have one caller. If creating a method makes overall comprehension easier, then that is reason enough to create it.

Let's take another simple example. It is common to see functions that have a comment followed by several lines of code, and then another comment, and then more code, as follows:

private void buttonSearch_Click(object sender, EventArgs args)
{
    // validate the user input
    ... several lines of code
    // do the search
    ... several lines of code
}

When presented like this, it is pretty obvious that the search button click handler performs two discrete tasks, one after the other. The code can therefore be made much more simple to read if it is refactored into...

private void buttonSearch_Click(object sender, EventArgs e)
{
    if (IsUserInputValid())
    {
        PerformSearch();
    }
}

Now a developer can quickly see what is going on, and can easily choose which of the two functions to delve deeper into depending on what part of the functionality needs to be changed. It is also interesting to note that we don't need the comments any more. Comments are added when the code isn't self-explanatory. So clear code requires less comments.

Refactor Similar Code, Not Just Duplicated Code

Most developers know not to reuse by cutting and pasting large blocks of code. If exactly the same code is needed in two places, they will move it into a common function. But often the code isn't an exact duplicate, it is simply similar.

Consider this example

XmlNode childNode = xmlDoc.CreateElement("StartTime");
XmlText textNode = xmlDoc.CreateTextNode(recordedItem.StartTime.ToString());
childNode.AppendChild(textNode);
recItemNode.AppendChild(childNode);

childNode = xmlDoc.CreateElement("Duration");
textNode = xmlDoc.CreateTextNode(recordedItem.Duration.ToString());
childNode.AppendChild(textNode);
recItemNode.AppendChild(childNode);

Here we have two very similar blocks of code, but they are not identical. This should not be seen as a barrier to reuse. Without too much effort this duplicated code can be extracted into a helper method. The end result is less complexity and much easier to see the intent.

AddTextNode(recItemNode,"StartTime", recordedItem.StartTime.ToString());
AddTextNode(recItemNode,"Duration", recordedItem.Duration.ToString());

Extract Reusable Functionality into Static Helper Methods

The AddTextNode method in the previous example actually could be used by any class that needed to add a child node to an XML node. So rather than staying buried inside the class that uses it, only for the wheel to be reinvented by the next coder who needs to do a similar task, move it out into a static method in a utility class. In this case, we could create an XmlUtils class. Obviously there is no guarantee that other developers will notice it and use it, but they stand a greater chance of finding it if it resides in a common utilities location rather than hidden away in the code behind of a Windows form.

Use Delegates To Enable Reuse Of Common Surrounding Code

There is one type of cut and paste code that can seem too hard to effectively refactor. Consider the following two functions. They are virtually identical, with the exception that the line of code inside the try block is different.

private void buttonSaveAsXml_Click(object sender, EventArgs args)
{
    FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
    folderBrowserDialog.Description = "Select folder to save search results to";
    if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
    {
        try
        {
            SaveAsXml(folderBrowserDialog.SelectedPath);
        }
        catch (Exception e)
        {
            log.Error(e, "Error exporting to XML");
            MessageBox.Show(this, e.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
    }
}

private void buttonSaveAsCsv_Click(object sender, EventArgs args)
{
    FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
    folderBrowserDialog.Description = "Select folder to save search results to";
    if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
    {
        try
        {
            SaveAsCsv(folderBrowserDialog.SelectedPath);
        }
        catch (Exception e)
        {
            log.Error(e, "Error exporting to CSV");
            MessageBox.Show(this, e.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
    }
}

The answer is to make use of delegates. We can take all the common code and put it into a SelectSaveFolder function, and pass in the action to do once the folder has been selected as a delegate. I've used the new C#3 lambda syntax, but ordinary or anonymous delegates work just as well:

delegate void PerformSave(string path);

void SelectSaveFolder(PerformSave performSaveFunction)
{
    FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
    folderBrowserDialog.Description = "Select folder to save search results to";
    if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
    {
        try
        {
            performSaveFunction(folderBrowser.SelectedPath);
        }
        catch (Exception e)
        {
            log.Error(e, "Error exporting");
            MessageBox.Show(this, e.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
    }
}

private void buttonSaveAsXml_Click(object sender, EventArgs args)
{
    SelectSaveFolder(path => SaveAsXml(path));
}

private void buttonSaveAsCsv_Click(object sender, EventArgs args)
{
    SelectSaveFolder(path => SaveAsCsv(path));
}

The benefit here is that the two button click handlers which previously had a lot of duplicated code now show very simply what they will do. And that is the point of refactoring your methods. Make them show the intent, not the implementation details.

Use IDE Refactoring Support

Finally, remember to use the Visual Studio Refactor | Extract Method command wherever possible. It can't always work out exactly what you would like it to do, but it can save you a lot of time and avoid a lot of silly mistakes if you make a habit of using it. (If you have a tool like Resharper then I'm sure that's even better).

Tuesday 7 October 2008

The Cost of Complexity and Coupling

Five weeks ago I was given a task to add some custom video playback to a large C# application. The video format in question is a proprietary codec wrapped in a custom file format and can only be played back using a third party ActiveX control. There was no documentation for the codec, the file format or the ActiveX control. We did, however, have a working application that could play back these video. All I needed to do was extract the bits we needed as a reusable component.

Sounds simple, right? The problem was that the working application was huge and did far more than simply playing back video. There were dependencies on over 100 .NET assemblies plus a few COM objects thrown in for good measure. The Visual Studio solution itself contained 20 projects. My task was to understand how it all worked, so I could reuse the bits we needed.

Approach 1 - Assembly Reuse

My first approach was to identify the classes that we could reuse and copy their assemblies to my test application and use them as dependencies. This seemed a good idea, until I found that tight coupling resulted in me copying the majority of the 100 dependent assemblies, and required me to construct instances of classes that really were not closely related to what I was trying to do. I spent a long time (probably too long) trying to persevere with this approach until I finally admitted defeat.

Approach 2 - Refactor

My second approach was to take a copy of the source for the entire application and gradually delete all the stuff that wasn't needed. Eventually I would end up with just the bits that were necessary for my needs. This approach was a dead end. First there was far too much to delete, and second, the tight coupling meant that removal of one class would cause all kinds of others to break, with cascading side-effects until I inadvertently broke the core functionality.

Approach 3 - Code Reuse

My third approach was to simply copy the source code of the classes that seemed to be needed over to my test project. That way, I could edit the code and comment out properties or methods that introduced unnecessary dependencies. Even so, the tight coupling still caused a lot of junk to be moved across as well. In the end my test application contained about 200 classes in total. And when I finally finished putting all the pieces together, it didn't work. Four weeks gone, and no closer to my reusable component.

Approach 4 - DIY

My final approach was to go to the lowest level possible. I would use a hex editor and really understand how the file format worked. And I would examine the interface of the ActiveX control and call it directly rather than through several layers of wrapper classes. This meant I would need to re-implement a lot of low-level features myself, including the complex task of synchronization and seeking. The existing application, which I was getting to know quite well by this point, would simply act as a reference. It was another week of work before I got the breakthrough I was looking for. Finally, five weeks after starting, I could display video in a window in my test application.

Technical Debt

Why am I telling this story? I think it demonstrates the concept of technical debt. The working application did what it was supposed to and was bug-free (at least in terms of the feature I was interested in). But its complexity and coupling meant that I spent weeks trying to understand it and found it almost impossible to extract reusable components from it.

And this is exactly the meaning of technical debt. Sure you can do stuff the "quick way" rather than the right way, and it may allow you to meet project deadlines. But if the application is going to be developed further, sooner or later, you will have to pay for your shortcuts. And the way that usually plays out is that a future feature was supposed to take a couple of weeks to implement ends up taking several months.

What happens next is that the managers will hold an inquest. How on earth did this feature overrun by so much? Was the developer stupid or just lazy? Or is he useless at estimating timescales? And it sounds like passing the buck to blame architectural mistakes made by previous developers. After all, we're programmers. We're supposed to be able to understand complicated things and find a way to get new features in.

How Big is Your Debt?

Technical debt is real, it really costs companies lots of wasted time, and both developers and managers need to take it very seriously. But how can it be measured? If we could find some way of quantifying it, we could then observe whether we are accumulating debt, or slowly but surely paying it off.

For most of my development career there were only two metrics that counted: number of open bugs, and number of support cases raised. But these measure existing problems. Technical debt is a problem waiting to happen. Fortunately, there has been an increase in the number of tools that can put some numbers against the quality of source code and its overall design. I'll list a few of the ones I have tried or want to try here...

I would be very interested to hear of any other suggestions or tools for measuring "technical debt".