Damon Payne: Hand waving software architect

103db signal to noise ratio at < .03% total harmonic distortion
Solution Architect, software developer, geek
Damon Payne at Blogged
2009 Microsoft MVP - Client App Dev
2007 Microsoft MVP - Solution Architecture
 Tuesday, June 05, 2007

According to the DasBlog stats engine, loyal Damon readers are surpassed by Googlers looking for a specific answer to a specific design or code question by an order of magnitude.  I suppose I could apply political spin to this and state that I am Very Useful, but not too popular.  At any rate, Googlers should utilize the Ctrl+F chord about now, since this article contains various loosely related but hard won observations.

I wrote about  a program I gave to my support people that did something simple and gave me an excuse to dig around in WPF.  Since I am always looking for ways to lessen the burden of our support department (so I can tap them for more dedicated testing, which is in their rational self interest anyway) I try to identify commonalities in support calls and do something about it.  Sometimes “doing something” means new features or bug fixes disguised as new features.  Yep, I said that out loud.  Sometimes these are knowledge base articles; sometimes they are internal only Software Tools.

My company has a special camera that uses a barcode scanner (not TTL) to embed data within images.  Sometimes our illustrious employees and customers make innocent mistakes like “accidentally doing a days’ work with their daughter’s Fisher Price camera and not our ultrahighend special camera” and end up with 1000 photos with no data in them.  This is a conundrum.  Luckily the massively parallel nature of the human brain makes us very good at pattern recognition tasks such as “These 20 photos go with that 1999 dodge”, and rather than the ultra painful manual process our support crew does now to assign these, I thought I’d just spend an hour and write a tool that allowed them to right-click on a group of photos in Explorer and assign some scan data to them using Exif.  It took slightly more than an hour.

File Types in a Setup Project

Like a mathematician who cannot be bothered to determine the sum of the square root of four with itself, I generally find it to be a better use of my time to talk to Tools and APIs than to learn the guts of HKEY_CLASSES_ROOT.  In my last WPF example I used VS2005 and an MSI project’s “View File Types” designer to assign all JPG files to a custom shell verb that runs my program.  Oddly enough it seems to be impossible to find information related to making more than one program a windows shell command for a single file type.  I’m free to add “Output from program one” and “Output from program two” as actions, however Windows is nice enough to employ a WIWO (whichever in, whichever out) technique to randomly choose which program is actually run  out of the two JPG associated programs via the installer.  Looking up the meaning of the “Verb” option on MSDN it would appear that the Verb gives me further command information (which menu item the user clicked) on the JPG and therefore will allow my program to determine what to do with the command line argument of the file path.  Of course I wrote completely separate programs before finding this.  This lack of foresight aside, the “verb” is not passed as a command line argument nor is it set as an environment variable or passed to my program in any way that I can see as useful.

To use multiple custom programs from the windows shell for the same file type, alter the arguments to contain the verb and use a launcher program:

If you want to “run program A for JPG files” and also “run program B for JPG files”, create two commands, two main executables, and a launcher executable.  In some cases the two executables may not make sense but in my case I already had two entirely separate solutions built in Expression Blend and I wasn’t about to look into merging them.  My launcher program is of project type Windows Application yet does not run a Form; this prevents users from seeing the black flash of a console window.

Inter process communication between Windows programs is harder than it needs to be in managed code:

So, as I said in the intro I want to right click on the 30 photos taken of the 1995 Dodge Minivan and work with them all at once inside one program instance. I found that the Windows shell, by default, will open up one instance of the associated program per file selected when dragging the mouse.  Do this with enough files and Windows is nice enough to warn me that “Edit Exif Data for this many files may be slow, continue?”  I would have assumed that each file would be passed as a separate command line argument to a single instance.  Without the ole Init() vs. InitInstance() from win32, I had to find another way to communicate quickly between multiple running Windows applications, WPF applications in this case.

My first attempt was using SendMessage() through P/Invoke and sending a message containing all the command line arguments to the first running instance.  WPF is an entirely new model, obviously, so I had to determine how to get a hold of the wndproc and filter messages.  On WPF this is done like so:

            System.Windows.Interop.WindowInteropHelper helper = new System.Windows.Interop.WindowInteropHelper(this);

            System.Windows.Interop.HwndSource hwndSource = System.Windows.Interop.HwndSource.FromHwnd(helper.Handle);

            hwndSource.AddHook(new System.Windows.Interop.HwndSourceHook(MessageHook));

Where the HwndSourceHook delegate looks like:

protected IntPtr MessageHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)

The problem here was that although I could P/Invoke SendMessage to a window after obtaining its main Window handle using System.Diagnostics.Process, and even though I could convince it to marshal wParam or lParam as type LPTSTR, the string in the received message was unconvertible by any means back to a string.  After trying every  Marshal.PtrToStringXXX(IntPtr) method I had to assume something was fundamentally wrong with this method.  Windows pointers are relative to the base memory space of the process.  If a string is marshaled as something like TCHAR* then all the second process is getting is a pointer to a memory address that is only valid in the calling address space. Either more P/Invoke or Marshal calls to do something to memory are needed or this won’t work.  I found a potentially cleaner method anyway.

Remoting

Some people are afraid of Remoting in the same way they are afraid of Threads and probably say things like “We should never use threads or Remoting on this project.”  I have to admit I’ve done almost zero Remoting outside of studying for MCXX tests but I was convinced by my favorite Iron Man/Software Architect/Short Order Cook that Remoting was a fine way to implement trivial inter process communication between applications on the same machine.  Fine, it’s easy enough.  

    public class InterprocessListener : IDisposable

    {

        public const int PORT = 5785;

        private TcpChannel _channel;

 

        public InterprocessListener()

        {

            _channel = new TcpChannel(PORT);

            ChannelServices.RegisterChannel(_channel,false);

            RemotingConfiguration.RegisterWellKnownServiceType(typeof(ArgServer), "ExifEditor", WellKnownObjectMode.Singleton);

        }

 

        public void Dispose()

        {

            if (null != _channel)

            {               

                _channel.StopListening(null);

                ChannelServices.UnregisterChannel(_channel);

            }

        }

 

    }

So, let’s assume we right click on 30 JPG images and choose to run “Edit Exif Data”.  The first instance up would instantiate this simple InterprocessListener on my favorite port, 5785.  The ArgServer implementation is equally trivial:

    public class ArgServer : MarshalByRefObject

    {

        /// <summary>

        /// Delegate to let listeners in this process know we got a message

        /// </summary>

        /// <param name="newArg"></param>

        public delegate void ArgAddedCallback(string newArg);

 

        public static event ArgAddedCallback ArgAdded;

 

        /// <summary>

        /// Pass an arbitrary string out of process

        /// </summary>

        /// <param name="argument"></param>

        public void PassArg(string argument)

        {

            OnArgAdded(argument);

        }

 

        protected void OnArgAdded(string arg)

        {

            if (null != ArgAdded)

            {

                ArgAdded(arg);

            }

        }

    }

Now, as our WPF programs are starting up we can execute some simple logic:

If(this is the first ExifEditor instance to start)

{

Start Interprocess listener

 add ourselves to the static arg passed event
} else {

Get a remote reference and pass our own arguments

Exit as we are no longer needed
}

The SendArgs() method shows the simple Remoting client code used to contact the primary instance.

        /// <summary>

        /// Find a local server and try to send it my arguments

        /// </summary>

        private void SendArguments()

        {

            TcpChannel chan = new TcpChannel();

            ChannelServices.RegisterChannel(chan, false);

            ArgServer argServer = (ArgServer)Activator.GetObject(typeof(ExifEditor.ArgServer), "tcp://localhost:5785/ExifEditor");

            if (null != argServer && Environment.GetCommandLineArgs().Length > 1)

            {

                argServer.PassArg(Environment.GetCommandLineArgs()[1]);

            }

 

            chan.StopListening(null);

        }

Mutexen

Now we need to handle running only a single Primary instance of our program and quickly detecting that program exists and sending arguments to it without trying to use the same TCP port from 30 different programs at once.  We do this with two Mutexes.   Mutices?  Mutexen?  Ox is to Oxen as Mutex is to Mutexen?    Here is the first chunk of code from my Window class, another cool WPF example in my opinion.  The Window is shaped like the camera we give to most of our clients, with image previews and buttons where the camera LCD screen and buttons where the camera buttons are.  I have some WPF clip geometry to take care of to get circular buttons.  Cool?  Lame?  I’m just the .NET software architect slinging code.

       public partial class CameraWindow

       {

        InterprocessListener _listener;

        Mutex _m;

        private delegate void VoidDelegate();

 

        /// <summary>

        /// Check to see if this instance should run or share its arguments with an already established instance

        /// </summary>

              public CameraWindow()

              {

            Application.Current.DispatcherUnhandledException +=

                new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(Current_DispatcherUnhandledException);

            bool createdNew;

            _m = new Mutex(false, "ExifEditorMutex", out createdNew);

            _m.WaitOne(5, false);

            // All other instances will now fail to create the mutex

            if (createdNew)

            {

                //First instance

                _listener = new InterprocessListener();                   

                ArgServer.ArgAdded += new ArgServer.ArgAddedCallback(ArgServer_ArgAdded);                   

            }

            else

            {

                //Another program is listening already

                Mutex mChild = new Mutex(false, "ExifEditorChild");

                mChild.WaitOne();

 

                SendArguments();

               

                mChild.ReleaseMutex();

                Close();

            }

 

            this.InitializeComponent();

            if (Environment.GetCommandLineArgs().Length > 1)

            {

                _imageList.Items.Add(Environment.GetCommandLineArgs()[1]);

            }

            else if (Environment.GetCommandLineArgs().Length == 1)

            {

                _imageList.Items.Add(Environment.GetCommandLineArgs()[0]);

            }

            //Sorry we couldn't work things out, SendMessage(), it's not you, it's me...

            //System.Windows.Interop.WindowInteropHelper helper = new System.Windows.Interop.WindowInteropHelper(this);

            //System.Windows.Interop.HwndSource hwndSource = System.Windows.Interop.HwndSource.FromHwnd(helper.Handle);

            //hwndSource.AddHook(new System.Windows.Interop.HwndSourceHook(MessageHook));

              }

        /// <summary>

        /// When the in-process arg server gets a message, add arguments to our list of images

        /// </summary>

        /// <param name="newArg"></param>

        void ArgServer_ArgAdded(string newArg)

        {

            Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,

               (VoidDelegate)delegate()

               {

                   _imageList.Items.Add(newArg);

                   _countTxt.Text = _imageList.Items.Count + " selected";

               });

        }

        private void Exif_Editor_Closed(object sender, EventArgs e)

        {

            if (null != _listener)

            {

                _listener.Dispose();

            }

        }

 

        private void Exif_Editor_Closing(object sender, System.ComponentModel.CancelEventArgs e)

        {

            if (null != _m)

            {

                _m.ReleaseMutex();                

            }

        }

So, 30 of these are trying to start at once.  One and only one of them will gain an exclusive lock on a System level Mutex named Underbar M.   Because it has a Name this synchronization primitive is visible outside the current process.  In the Exif_Editor_Closing event we release this mutex, failure to do so would be abandoning the mutex and is a serious error condition in Windows.  The other 29 instances trying to start up wait for 5 milliseconds and fail to acquire the Mutex.  They go into the else block where the second Mutex is encountered.  This is where I have to confess I didn’t look at the Remoting threading model too closely but it seems likely that 29 programs trying to write to port 5785 at the same time could be an issue.  Lucky numbers 2 through 29 WaitOne() indefinately to obtain the mChild Mutex for their turn at sending a message, the mChild mutex is then released and the Window kills itself.  Gracefuly.

I noticed some Google near-hits in the DasBlog stats of people looking for a simple example of the Control.Invoke() equivalent in WPF.  Take a look at my descriptive VoidDelegate and ArgServer_ArgAdded above.

Wrapping it Up

So, we have several useful things here.  You can use a System Mutex to keep more than one instance of your app from running.  Of course there is a Windows Forms property (IsSingleInstance in VB) that does this for you in .NET 2.0 but so far I didn’t see the same property for a Window in WPF.  You could use the same logic and a Semaphor to allow n instances of your program to run.  We also have an extremely simple inter process communication example using .Net Remoting.  Finally, if you wish to have some fancy windows shell actions but want to use APIs and managed code rather than figuring out how to properly hack the registry to get your program to get multiple files passed as arguments, you can put it all together and do that.



Tuesday, June 05, 2007 3:22:54 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Sunday, June 03, 2007

Although I'm nearly as skinny as ever I am only about 2 months on my way back up from the rock bottom of "Worst shape of my adult life".  This climb was inspired by my pending beach vacation to St. Lucia and accomplished mostly by doing a few pushups and yard work.  Last week I got a love note from our neighborhood association stating that a $5/day fine was on its way to me if I didn't stop ruining the neighborhood and plant my two required street trees.  On one hand I suppose I did agree to all 800 pages of restrictions when I bought this land and on the other: busybodies, have you nothing better to do than shake your fingers at delinquent neighbors?  We are getting married and subsequently leaving the country in 7 days, not the best time for items requiring surpise time and expense.

This weekend I bought the two largest autumn blaze maple trees I could find, which apparently only barely meet the necessary restrictions and set about digging holes.  The wonderful Kettle Moraine soil is mostly clay, sand, and rocks.  Lots of rocks.  My back is well-worked, I can barely sit up to write this post.  Despite planting one tree each day and doing a ton of other preparation work I still managed to clean my garage and cook two pretty good meals.  Saturday was steak au poivre with gorganzola sauce, using the Cook's Illustrated skillet to oven method and my own worsteshire and butter skillet technique and addition of chives to the gorgonzola.  Ate this with the pan-roasted asparagus that has become a staple of our diet and roasted red potato.  Today I mequite smoked a ginormous rack of ribs on the grill with a sweet dry rub and took half of them to Jen at work.  That woman will never know how good she has it unless she divorces me and subsequently lives entirely on mac 'n cheese.  I need to take some more pictures of some of this stuff but I'm working on my photographic technique.

I'm going to try to get a very long article out tonight, June will likely end up being a light month for writing due to the goings on.



Sunday, June 03, 2007 7:47:07 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Wednesday, May 30, 2007

Hosting a Designer Surface in Windows Forms Part 1

{if you are just tuning in, you may want to review:

Designer[0]

}

The most important things we’ll be working with is our class that implements System.ComponentModel.Design.IDesignerHost.  This class is the hub of many designer activities such as creating the designed components, Siting Components, and managing designer transactions.  In my case I went a slightly different route for transactions but this class is still very important.  Review the description (http://msdn2.microsoft.com/en-us/library/system.componentmodel.design.idesignerhost(vs.80).aspx) and a trivial sample implementation on MSDN.

Let’s take a look at a few lines of code after where we left off last, after LoadToolBoxItems() from the last article:

            //Setup the control that will hold all the template junk:

            _form = (BlankDesignForm)_designerHost.CreateComponent(typeof(BlankDesignForm));

            _form.Size = new Size(612, 792);

            _form.TopLevel = false;

            _form.Text = "Print Template";

            _form.FormBorderStyle = FormBorderStyle.None;

            _form.Font = new Font("Tahoma", 9);

            _baseFont = _form.Font;

            _form.Location = new Point(5, 5);

 

            _rootDesigner = (IRootDesigner)_designerHost.GetDesigner(_form);

            _designerView = (Control)_rootDesigner.GetView(ViewTechnology.Default);

            _designerView.Dock = DockStyle.Fill;

            _viewHostPnl.Controls.Add(_designerView);

Usually the under the cover plumbing interacts with the designer telling it what was selected in the IToolBoxService implementation and therefore what Type of Component to create.  We manually create a BlankDesignForm because it is the canvas that will contain the visual representation of all other designed Components.  Note that we can guarantee that the type of IDesigner created in this case is an implementation of IRootDesigner as opposed to IDesigner.  The first designed component is the Design Time Root.  An IRootDesigner, as opposed to other classes buried in the framework like System.Windows.Forms.Design.LabelDesigner gives us what we need to display the entire Designer Surface in our program, through its GetView() method.

The BlankDesignForm exists in order to gain some things specific to our problem domain such as drawing the dotted line around the page’s print margin you saw in the last article, but also to lose some functionality inherent to Windows Forms.  I’m talking about scaling.  While not explicitly related to the Designer Surface discussion I did run into this again during these articles and it’s a nice thing to know about anyway.

In order to be more Accessible, Windows Forms will try to scale the overall size of forms and their children in one of two ways in .Net 2.  The first is DPI scaling, meaning if the screen resolution changes from the design time resolution.  The second and more curious is font scaling.  If you have a Form that is 800x600 at design time with 8.25pt Microsoft Sans Serif, and at run-time you set its Font to be 9pt Tahoma, the form and all children will resize by roughly the difference between 8.25 and 9pt.  I say roughly because the behavior does not appear to be perfectly mathematically dependable in a transitive fashion.  If I go from 8.25 à 9 à 63 à 12 à 8.25 I will not end up with a form that’s quite right with respect to its original self.  The child controls may not be positioned in exactly their original places or the size may not be quite right.  I found workarounds for some situations but ultimately the resizing of ScrollableControl and its various viewports and bounds defeated me, it’s a long story for another article.  It’s too bad this doesn’t work, since if it did this would be a swell way to implement Zoom-In and Zoom-Out in pre-WPF applications.  This is all a very long winded way of saying that I needed my program to be somewhat skinable with colors, font family, font size, set at run time by processing a skin file.  Since the WYSIWYG-ness of my final printed document is dependent upon the convention that a 612pixel by 792pixel form represents the same space and proportions as an 8.5” by 11” document printed at 72dpi using my Compact Framework printer driver (http://www.fieldsoftware.com) a little Font scaling error is too much Font scaling error but the GUI skinning could not be given up.  The BlankDesignForm’s main contribution to my mental stability, then, is:

        protected override void ScaleControl(SizeF factor, BoundsSpecified specified)

        {

            //Don't scale!

        }

So the designed area where every pixel counts will not participate in the magical Scaling-based-on-font woo that takes place from within the bowels of Component.OnFontChanged.

In the code figure above everything is obvious except for our IDesignerHost.CreateComponent(Type)  implementation from the DefaultDesignerHost class. 

        /// <summary>

        /// Instructs the DefaultDesignerHost to instantiate a new instance of componentClass, which

        /// is also assumed to be added to the list of components that this DefaultDesignerHost is

        /// designing for through an IContainer implementation.  The component is Sited after listeners are given a chance to cancel this operation via

        /// the ComponentAdding method of the contextual IComponentChangeSerice instance.

        /// </summary>

        /// <param name="componentClass">valid Type</param>

        /// <param name="name">Component Name/Site Name</param>

        /// <returns></returns>

        public IComponent CreateComponent(Type componentClass, string name)

        {

            IComponent newComponent = (IComponent)Activator.CreateInstance(componentClass);

 

            IComponentChangeService changeSvc = (IComponentChangeService)_parent.GetService(typeof(IComponentChangeService));

            changeSvc.ComponentAdding(new ComponentEventArgs(newComponent));

 

            ISite site = new DefaultDesignSite(newComponent, this, name);

            newComponent.Site = site;

Any and all design time classes will attach to the events exposed by an IComponentChangeService implementation if they care about what goes on with Components at design-time. The first issue is the code in red.  It doesn’t work.  Take a look at the IComponentChangeService interface events:

 

Name

Description

ComponentAdded

Occurs when a component has been added.

ComponentAdding

Occurs when a component is in the process of being added.

ComponentChanged

Occurs when a component has been changed.

ComponentChanging

Occurs when a component is in the process of being changed.

ComponentRemoved

Occurs when a component has been removed.

ComponentRemoving

Occurs when a component is in the process of being removed.

ComponentRename

Occurs when a component is renamed.

 

… and the public methods …

 

Name

Description

OnComponentChanged

Announces to the component change service that a particular component has changed.

OnComponentChanging

Announces to the component change service that a particular component is changing.

 

Cruising MSDN shows that there is no public interface that forces any class to implement an OnComponentAdding or OnComponentAdded method.  While I don’t mind being left with a few design problems of my own to solve, this seems a little unfortunate since I am now forced to go outside the Design Time framework that’s been provided and implement something specific to my own Design Time environment.  It seems that it would be ideal to be able to give someone my ISelectionService or IComponentChangeService implementations without depending on behaviors that are outside the published contracts.  Of course I could just be missing something too :D.  Semantics being very important I chose the saucy name ITemplateDesignerComponentChangeService to represent my interface with the necessary methods added.  At least I didn’t just tack a “2” on the end of the original interface, yeah; I’m talking to you Sun.  Talk about lazy; nothing is worse than trying to determine if I should use SomeType or SomeType2.  Apparently this was considered a completely super practice in Java, but thankfully I don’t write Java anymore.

    interface ITemplateDesignerComponentChangeService : IComponentChangeService

    {

        void OnComponentAdding(ComponentEventArgs e);

        void OnComponentAdded(ComponentEventArgs e);

        void OnComponentRemoving(ComponentEventArgs e);

        void OnComponentRemoved(ComponentEventArgs e);

    }

I add an instance of a class implementing this new interface to my SerivceContainer.  Now if there are any classes buried in the framework that are not my own they will have access to an IComponentChangeService implementation for the purpose of event subscription, and my own code can ask for a Service Type implementing ITemplateDesignerComponentChangeService in order to access the extra methods.  The first few lines of our CreateComponent method now look like:

            IComponent newComponent = (IComponent)Activator.CreateInstance(componentClass);

 

            ITemplateDesignerComponentChangeService changeSvc = (ITemplateDesignerComponentChangeService)_parent.GetService(typeof(IComponentChangeService));

            changeSvc.OnComponentAdding(new ComponentEventArgs(newComponent));

 

            ISite site = new DefaultDesignSite(newComponent, this, name);

            newComponent.Site = site;

In the next article, we’ll start looking at more Service class implementations, where we tell the design-time framework about our Service implanting types, and the interactions between all of these pieces of the Designer Surface puzzle.



Wednesday, May 30, 2007 8:00:07 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback

For a geek I sure don't get into many of the tech fads.  Ruby?  You can keep it.  iPod?  Not for me.  Zune, iPhone?  Whatever.

However, this, I must have.



Wednesday, May 30, 2007 9:21:08 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, May 29, 2007

As Larry points out some people just aren't down with using visual editors.  I'll extend this to say that the entire notion of the IDE doesn't resonate with everyone.  Ever since James Gosling proclaimed that "Anything serious is still done in emacs" the luddites have felt more comfortable in proudly claiming that an IDE such as VS2005 offers nothing that's not available from Vi+Shell Scripts.  I'm glad I don't work in that world anymore, but I suppose once you have convinced yourself that nothing new has been brought to the world of code editing in 20 years no Refactoring demo is going to change your mind.

Personally, I'd probably have to have a reference in front of me for creating WSDL but other than that I could hand-code anything I work with.  Editors and IDEs make me more productive.



Tuesday, May 29, 2007 11:42:01 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Sunday, May 27, 2007

In less than two weeks now, Jen and I are getting married.  Five years, a wonderful daughter, building a house, and a whole buch of other stuff have gone by but I'm surprised to be saying that getting married is steal a big deal.  We are "very secular" as anyone who's met me or read this blog for very long can attest but despite the lack of moral pressure to get hitched it seemed to make more and more sense as time went on for reasons that should be obvious.  Also, Jen likes diamonds.  I am currently recovering from my bachelor party about which I will say nothing but that while I consider myself Young still I cannot shrug off an event such as this without at least two days of healthy food and a lot of I am never drinking agains.  I suppose that phrase is the Hail Mary of the repentant imbiber.  Despite his odd notions about "sins" and other strange ethical constructs my brother and best man did a good job of throwing me my last party as an unmarried man.  I am currently developing grass roots support for the notion that the bachelor party should be a yearly occurance similar to celebrating the wedding anniversery.  The debate and voting on this bill seems to predictably fall along party lines but bi-partisan support can surely be gained in the usual political ways: bribes and favor trading or pork legislation burried in a must pass budget bill.  More information on the Payne-Payne Bachelor Reform initiative as it develops.

It looks like all of my long lost friends and respected colleagues that I had room to invite have responded in the affirmative so none of the "You are dead to me!" cards I created will have to go out.  We've got to squeeze in some dancing practice and a lot of final details but at this point my main concern is just making it through the day without some idiotic disastor like dropping the cake or spilling coffee on The Dress or something.  There's also the final Packing to consider.  My folks have some sort of worldwide timeshare thing that led to us getting a week in St. Lucia immediately after the wedding reception.  By immediately I mean we might have time for a 1 hour cat nap before heading down to O'Hare.  This will be the longest vacation I've ever taken and my first time out of the country (Mexicali does not count) so I'm sure there are any number of things that could go wrong but I'm not going to let anything get to me.  As long as we're not demolished by an early hurricane and our daughter can handle a week without Mom and Dad I'll call it good.  The sure-to-be ridiculous spoiling that awaits her with my parents will probably have her forgetting boring old Mom and Dad in no time.

In all seriousness, Jen is fantastic, she's freaking awesome.  What higher praise could a woman want from a nerd such as myself?  I'm lucky to be with someone who is happy to do the laundry (folding clothes is the one domestic skill I never gained competancy in) in exchange for my often experimental cooking.  I brag to my friends that she's almost beaten Zelda on the Wii for the second time.  She does her best to tolerate my Capitalist rantings at 1am after I've just finished a new economics book.  She loves it that I slowly absorb medical terminology such that she can complain about sepsis or a sub-dural hemotoma without also having to serve as a dictionary (it really ruines the flow of a story).  Are these the most important things in a mate? Maybe or maybe not, but its hard to offer examples to outsiders when you just have a rythm that works.  Also, Jen is hot.  We've been through a lot together and the future looks pretty good.



Sunday, May 27, 2007 10:42:23 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback

A respectable fellow recently asked me where I was on the Unit Testing spectrum: Skeptic <----> Zealot, or in between.  Fair question.

I am right-leaning towards zealot though far from what I'd call a unit testing zealot.  For one thing, I'm not into Test-first development.  I've heard the arguments enough times but its not a mental barrier I care to break down.  After years of struggling with laziness and mulling over the value of different approaches, this is a summary of my Unit Testing habits today:

  1. I use NUnit, TestDriven.Net, and NCover.
  2. I don't like unit testing strictly GUI aspects: Web Forms or Windows Forms, UserControl, etc.  I know that there ARE ways to do this but it doesn't resonate with me right now.  I somewhat dogmaticaly use Model-View-Presenter in ASP.Net and the desktop to minimize what is in the code behinds anyway.  I use NUnit.Mocks to work with Mock instances of my View interfaces.
  3. I do a lot of up front design before I write anything non-trivial but I do not create models at the Implementation level.  Writing the code is the first validation of my design, writing the unit tests is the second validation of my design.  Sorry for bludgeoning the deceased equine but if I can't get at method to test it and it also doesn't make sense to test said method through some other calling method, then there's likely a smell in the design.  I will typically revisit my preferred tool (currently StarUML) to see where the smell is, reimpliment, and take another stab at creating the appropriate tests.
  4. Unit tests are the most appropriate artifact you can leave behind for a project.  It seems to me that I run across very few people who do what I would call Real modeling and fewer who make an effort to update models as a system evolves.  I don't update models as a system evolves, but I do update unit tests.  The tests are only valuable as an artifact if they pass and if they can be shown to actually exercise the system.  See #5 regarding this.
  5. Code Coverage is the piece that finally made Unit Testing really click for me.  Forming the habit of using NCover directly from Visual Studio via TestDriven is the single largest improvement to the quality of my code, ever.  I find that I have difficulty inciting the same excitement about Coverage in other people, maybe because it forces one to admit they need to write more unit tests.  So you've tested everything you thought of on the first iteration and NCover shows only 80% coverage of your business logic assembly.  Sometimes you'll see you only tested the "Main success" flow through the code and you need to test the alternates and exceptions.  Sometimes you will see NCover highlighting code that is absolutely never going to be called from your application.  Many times I have caught "premature abstracting" using Ncover, classes or methods I assumed I'd need but nevered ended up needing.  This may not be a defect but I'm of the opinion that if I ever need it I'll recover it from version control so I delete unused methods/properties/classes to make my assembly smaller and compile faster.  Code Coverage is also a good aspect of a Code Review, if you're into those.
  6. I shoot for > 95% code coverage.
  7. While we work on stabalizing a release, testers sometimes find bugs!   As I look at each bug, I think, could this have been caught before acceptance testing if there'd been a specific unit test?  If I can think of a unit test for the bug situation, I add one.
  8. This one should be very obvious: I feel much better making huge changes to important code if there is a unit test suite.

 



Sunday, May 27, 2007 10:04:05 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Friday, May 25, 2007

Priceless:



Friday, May 25, 2007 9:50:22 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, May 23, 2007

I have seen several tutorials online on creating non-rectilinear windows in WPF using transparent images and no Background Brush.  Oddly enough this leaves you with the issue of not being able to grab the title bar (since it does not exist) and drag your curvey new window around.  I initially found no workable solution for this and even asked around to those who are wiser than I; no answer.  By rephrasing my request to google I found the following:

  1. Using Expression Blend, highlight your Window class.  Add an event handler for MouseLeftButtonDown
  2. In Visual Studio, add the following code to said event handler:

private void ExifViewer_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
   DragMove();
}

Fantastic.  The plumbing was already there, easy, and obvious, but because this is a new platform I could not find it.

.NET | WPF


Wednesday, May 23, 2007 3:00:30 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback