# Monday, October 29, 2007

I opened up another tab to Udi Dahan's blog, at which point my PC came to a screeching halt.  After finally getting the task manager open I noticed FireFox was using 1.5GB of RAM.  Wow!  IE never uses that much memory - in fact IE usually crashes well before it ever gets that much memory consumed.  Here's a look at my memory usage after I killed FireFox, note the huge drop in the Physical Memory Usage History (blue line).

FireFoxMemUsage

WTF
Monday, October 29, 2007 5:44:12 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Friday, October 26, 2007

I just checked off my last item (fast PC) from the "Programmer's Bill or Rights."  Compared to my last job that's a 66% improvement.

Friday, October 26, 2007 5:25:22 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

Setting up a new Windows development machine is a pain.  In fact it's more work than setting up a Linux development machine.  In Linux the package manager for the OS, the Rails package manager, and/or the Eclipse update manager handles most of this for me.  In Windows I'm forced to install things individually using separate installers.  Here's the minimum I had to install on my brand new Windows Vista box to get a decent development environment:

  • Visual Studio 2005
  • VS 2005 SP1
  • VS 2005 SP1 patch for Vista
  • Windows Vista SDK
  • WCF for VS 2005
  • .NET 1.1 Runtime (yes, I still have a project that compiles .NET 1.1)
  • ReSharper 3 for C#
  • SVN
  • TortoiseSVN
  • VisualSVN

That's just to get my machine compiling our code, that doesn't even include the numerous other tools I need to be productive like Paint.NET or MS Office.  All in all, I had to install around 30 applications yesterday!  No wonder I've been dragging my feet on getting a new system for the past month.  The good news is, I'm now done and this new 3GHz dual core system with 3GB or RAM freakin' rocks compared to my old Dell Dimension 4600.

Friday, October 26, 2007 5:17:09 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Sunday, October 21, 2007

Scott Bellware brought up SmartBear Code Collaborator code review tool as a way to annotate code on the ALT.NET mailing list today.  It looks really interesting to me since my entire team works remotely and facilitating code review is pretty difficult.  We've used NetMeeting in the past, but I would like something that promotes a more organic code review which naturally happens when co-located.

The really neat thing is that integrates tightly with source control systems such as Perforce's Windows client so that you can initiate a code review of a particular changelist before checkin.  I didn't see any mention about SVN integration...

Sunday, October 21, 2007 6:17:41 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, October 18, 2007

It seems I keep running into situations where I want to mock or stub a class that is responsible for saving something out to disk.  The problem is that using a StreamWriter (or similar) is the lifetime of the writer object is shorter than the containing class, which makes it impossible to mock effectively.

Often the way around this is to implement an interface with three method calls: Open, Write, Close - so you can reuse the writer instance for multiple files thus changing the lifetime of the writer to the same as the containing class thus allowing you to mock the writer.

I've never liked this solution, it always has felt like a workaround for testability.  Instead, how about splitting the two parameters (contents and file path) into separate fluent method calls and having the Write auto-close the file like this example:

keyWriter.Write(exportKeys).To(destinationFolder);

 

...

 

public interface IExportKeyWriter

{

    IExportKeyWriter Write(ImageExportKeys keys);

    void To(string destinationFolder);

}

 

I like it because its very readable and more importantly its mockable.  I can inject a single instance of the IExportKeyWriter into my class under test.  When Write is called, the object is queued for writing to disk, and when To is called the destination file is opened, written to (using the queued object), and finally closed.

The only Problem I can think of is that it may not be obvious that you need to call the To method to have the file actually written out.

I'm hoping for some feedback on this, so I ask dear reader, what do you think?

Thursday, October 18, 2007 1:29:09 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, October 17, 2007

This isn't something I have had to deal with a lot, but this PDF looks likes its useful for coming up with a XML versioning scheme.  So far I've just chosen to go down the path of least resistance and add a schemaVersion to my XSD along with a schema version attribute in my XML instance docs.

XML
Wednesday, October 17, 2007 5:20:38 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Tuesday, October 16, 2007

The following code snippet causes a stack overflow exception.  Can you spot it?  I almost didn't catch the case difference.  See it now?  I'm surprised the compiler didn't complain - at all, however ReSharper found the recursive call and squiggled it.  Yet another reason to get Re#.

 

public string CreatedDate

{

    get { return createdDate; }

    set { CreatedData = value; }

}

Tuesday, October 16, 2007 7:33:42 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Sunday, October 14, 2007

I needed the ability to kill a process and any of its child processes, but System.Process.Kill() does not kill any child processes. 

I tried using the JobObjectWrapper library, but unfortunately it doesn't work when running from an existing job, which is exactly the scenario I needed since Visual Studio 2005 on Windows Vista is already running under a job.

The solution I opted for was to use the WindowsXP Pro/Windows Vista taskkill.exe utility since it supports kill a task tree.

/// <summary>

/// Will kill a process and all its child processes.  This class requires

/// taskkill.exe present in the WINDIR\System32 directory.

/// </summary>

public class TaskKill

{

    private readonly int pid;

    private readonly string imageName;

 

    public TaskKill(string imageName)

    {

        this.imageName = imageName;

    }

 

    public TaskKill(int pid)

    {

        this.pid = pid;

    }

 

    /// <summary>

    /// Kills the process associated with this TaskKill instance.

    /// </summary>

    public void KillAssociatedProcess()

    {

        if (!string.IsNullOrEmpty(imageName))

            KillProcessByName();

        else

            KillProcessById();

    }

 

    protected void KillProcessById()

    {

        string killArgs = string.Format("/F /PID {0} /T", pid);

        ExecuteKill(killArgs);

    }

 

    protected void KillProcessByName()

    {

        string killArgs = string.Format("/F /IM {0} /T", imageName);

        ExecuteKill(killArgs);

    }

 

    protected string GetTaskKillExePath()

    {

        string taskKillPath = Path.Combine(Environment.SystemDirectory, "taskkill.exe");

        if (!File.Exists(taskKillPath))

            throw new FileNotFoundException(

                "Cannot find taskkill.exe in the Windows Sytem32 directory.  Are you running WindowsXP Home which doesn't include this utility?");

 

        return taskKillPath;

    }

 

    private void ExecuteKill(string processShellArgs)

    {

        ProcessStartInfo info = new ProcessStartInfo(GetTaskKillExePath(), processShellArgs);

        info.CreateNoWindow = true;

 

        Process process = new Process();

        process.StartInfo = info;

        process.Start();

        process.WaitForExit(5000);

    }

}

 

The code that uses the TaskKill class looks like this:

[Test]

public void Test1()

{

    ProcessStartInfo info = new ProcessStartInfo("notepad.exe");

    Process process = new Process();

    process.StartInfo = info;

    process.Start();

 

    Assert.That(!process.HasExited, "Process exited early");

 

    TaskKill taskKill = new TaskKill(process.Id);

    taskKill.KillAssociatedProcess();

 

    Assert.That(process.HasExited, "TaskKill failed to kill the process");

}

Sunday, October 14, 2007 6:07:44 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Saturday, October 13, 2007

Today our product manager was trying mocking up some new UI elements in Visual Studio 2005 when he came to me with this error, "one or more errors encountered while loading the designer."  This is something that probably doesn't come up very often, or at least I hope not - especially in this specific case.

In our WinForms application we have a custom resource manager that the main form uses.  This custom resource manager makes use of a MarketSegment class which is created based off a setting in the app.config via the MarketSegmentManager class.  This market segment object is used to conditionally load resources depending on the current market segment selected in the app.config.  This way we can display different text and graphics depending on the current customer's segment.

Apparently when the Visual Studio designer builds and then runs, it doesn't give your code access to the app.config - at least when its loading resources.  I ended up having to change our MarketSegmentManager class to return a default MarketSegment object when the app.config setting was read in as null - like when its running under the VS designer.  I don't really like this because it is anything but fail fast, but its better than not having the VS winform designer.

Saturday, October 13, 2007 6:39:55 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Friday, October 12, 2007

If you look at all OSS projects out there (the good one's anyway), they don't even check in their AssemblyInfo.cs files, as these are auto generated when you run a build and the version # is just an MSBuild or NAnt property.  CC.NET should track the version number in its local project state file and pass that into the build script, or the version should be deduced from source control meta data.  Here are some typical responses from developers why they like keep version numbers in a text file checked into source control:

  1. But what if we need to do a local build which needs to be versioned with something besides 0.0.0.0?  Why on earth would you ever need to do that?  Local dev builds should never be official, thus should never be deployed.  The continuous integration server is the integration point, not your local desktop.
  2. But I need to use a specific version because my assembly is strong name signed to a specific version and I want to hot swap a DLL for testing purposes (or something more sinister).  If you really, really want a local versioned build, override the script's version property, but really you should be using a binding redirect in your app.config.
  3. What happens if the build server dies and we lose the state file?  That's why you label source control with the version # every build, which you can use to build a new state file on the new CC.NET server.
  4. We don't label source control, so now what happens if the autobuild server dies? You do output versioned builds somewhere don't you?  Look at your last build and rebuild your state file.
  5. But, but, but...  That's how I've always done it.  Why? Sure its nice to keep everything in source control, but in this case there's no need.  Really you should be using the meta data of your source control system to manage build version increments, not some text file in source control.

While your removing your version.txt from your source control system, consider switching to SVN while your at it.  ;-)

Friday, October 12, 2007 5:43:03 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

Its no wonder many programmers shy away from web programming, specifically HTML and CSS.  Most senior developers consider HTML programming, and UI programming in general, beneath their station.  I think they're hiding from the truth. 

Making an easy to use and pleasant looking user interface is much harder than consuming a web service or writing some highly concurrent middle tier layer, especially when that environment is the Internet where you have any number of browsers and operating systems to interact with.  Sure you think MAC, Windows, Linux, IE, Firefox, and mobile devices, but lets throw in another element most people don't think about - web browsing from a TV. 

Sure HDTVs have enough resolution from 2 feet away, but the issue is, people use their TVs from 10feet away or more, which effectively reduces your resolution because all of your fonts and images need to be double what they are on the PC.  Additionally the input device has changed from a mouse, to a remote control which also means you need to tab between buttons and hyperlinks, not mouseover - your fancy CSS rollover buttons don't work anymore.

Now try to get a page to look consistent across all these platforms and browsers!?  Good luck, its hard enough to get things to look consistent between FireFox 2.0 and IE7 on Windows.  What works in one browser for positioning and alignment falls flat on its face in another.  This leads to a lot of trial and error when coding up some HTML and CSS. 

I think this is why so many ASP.NET programmers hide behind ASP.NET server controls.  To touch the HTML and CSS is like assembly programming for a non-specific platform.  It hurts.  Building a nice UI for a TV doesn't fall into the realm of pre-built user controls, so I find I spend a lot of my time in "web assembly language."

At least when you're dealing with a complicated middle tier things are consistent, they either work or they don't.  Add in concurrency, threading, and scalability to your middle tier and you might have an argument that its as hard as UI programming.

Yeah, UI development is that kind of hard, especially when you throw in the subjective aspect of it.  Maybe that's why Mr. Coding Horror has so many blog posts about UI development.

Thursday, October 11, 2007 11:32:51 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [2]  | 
# Friday, October 05, 2007

I just bought an external Western Digitial 500GB MyBook hard drive that is capable of connecting through either eSATA or USB 2.0.  The drive only comes with a USB cable so I'm stuck using that until I got back to the store tomorrow to purchase a new eSATA cable.  I initially tried copying my source folder over to the drive (~1,8GB), but it was copying slower than I could check it out from SVN over the Internet.  Obviously something was wrong.  The culprit as it turns out was that the drive comes preformatted using FAT32 and I just tried using it as is.  Big mistake!  One NTFS reformat later and my drive is copying like a champ.

Friday, October 05, 2007 5:51:29 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, October 03, 2007

Don't include Windows.h -  I had to say it.  ;)

Always have a blank line at the bottom of each source or header file.  You get g++ compiler warnings if files don't have an extra carriage return at the bottom.

Compiler pragma warning disable statements should be ifdef'd for WIN32 only.

#include statements must match the case of the header file name.

#include "gpireader.h" // won't compile on g++, but

#include "GPIReader.h" // will compile on g++

 

Don't forget to use virtual destructors where appropriate, g++ will complain if they're missing.

Don't memset STL strings (std::string) to zeros.  Strange and odd memory corruption will occur if you do.

Don't memset structs which contain STL strings, see point above.

Don't include enum names. 

if (res == ResourceType::AccessBlock) // won't compile on g++, but

if (res == AccessBlock) // will compile on g++

 

Don't include the class prefix in header files for method declarations.

std::string GPIReader::GetXMLStringResource(ResourceType type);  // won't compile on g++, but

std::string GetXMLStringResource(ResourceType type); // will compile on g++

 

stricmp (case insensitive strcmp) function is not available on Linux, you must toUpper then compare or something.

C++ | Linux
Wednesday, October 03, 2007 6:07:53 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

Being the only one at work with any Linux experience, I was elected by default to port our C++ API over to Linux.  Luckily we had some CxxTests already being utilized on Windows, and good thing we did because as I found out, just getting our API to compile on Linux didn't mean it would run on Linux.  These unit tests saved me around 2 days of work (it only took me about 12 hours to port).

The Linux environment I chose to use was Ubuntu running Eclipse CDT.  After some Googling I found that there's an Eclipse plugin for CxxTest that is similar to the Eclipse JUnit runner.  That sounded very appealing; I sure wish there was Visual Studio CxxTest runner.  Unfortunately all of the instructions for the plugin are about getting it to work with Windows and Cygwin, which wasn't much help in my scenario.  To get the pluging to work I found I needed to:

  1. Install the BFD dev library onto my Ubuntu system using apt-get.
  2. Remove the -libintl flag from the test project's additional libraries section.

After making those changes I was able to get the CxxTest runner building and running just fine.  The one thing I did notice is that the tests run only after 2 rebuilds of the test project.  I'm not sure why that is, or if I was doing something wrong - it was getting annoying having to edit my test file, compile, edit it again, and then recompile a second time to get the tests to run.  There must be a manual way to force the tests to build...

Wednesday, October 03, 2007 5:19:55 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [2]  |