<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>in Chris Velazquez's words... - .net</title>
    <link>http://www.chrisvelazquez.com/blog/</link>
    <description>a blog fertilized by my mental droppings</description>
    <language>en-us</language>
    <copyright>Christopher S. Velazquez</copyright>
    <lastBuildDate>Wed, 07 Feb 2007 17:27:09 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 1.9.6264.0</generator>
    <managingEditor>chris@chrisvelazquez.com</managingEditor>
    <webMaster>chris@chrisvelazquez.com</webMaster>
    <item>
      <trackback:ping>http://www.chrisvelazquez.com/blog/Trackback.aspx?guid=ed29e8d6-061f-48ed-b15c-58f3e3db33a4</trackback:ping>
      <pingback:server>http://www.chrisvelazquez.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.chrisvelazquez.com/blog/PermaLink,guid,ed29e8d6-061f-48ed-b15c-58f3e3db33a4.aspx</pingback:target>
      <dc:creator>Chris V.</dc:creator>
      <wfw:comment>http://www.chrisvelazquez.com/blog/CommentView,guid,ed29e8d6-061f-48ed-b15c-58f3e3db33a4.aspx</wfw:comment>
      <wfw:commentRss>http://www.chrisvelazquez.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=ed29e8d6-061f-48ed-b15c-58f3e3db33a4</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I can't believe that I've been racking my brains for hours trying to figure out how
to execute my .NET 2.0 code in Microsoft Excel 2003.  Hopefully this tidbit of
information will save somebody else on the web some pain, frustration and time.
</p>
        <p>
Punchline: You need a file called EXCEL.EXE.CONFIG in the same directory as EXCEL.EXE.
</p>
        <p>
I created a class, written in C# and compiled with Visual Studio .NET 2005, with the
.NET 2.0 Framework.  This class has a COM Interop wrapper so that it can consumed
by ActiveX clients, most notably Excel 2003.  This class was compiled with the
"Register for COM interop" setting in the properties turned on.  This arrangement
autogenerates the GUIDs and COM interface for you, though I prefer to define my own
COM interfaces manually in production code.
</p>
        <p>
Here is a sample class in C#:
</p>
        <p>
          <font face="Courier New">// COMClass.cs<br />
using System.Windows.Forms;</font>
        </p>
        <p>
          <font face="Courier New">namespace AnyCOMLib {<br />
    public class COMClass {<br />
        public void DoSomething() {<br />
            MessageBox.Show("I
did something.");<br />
        }<br />
    }<br />
}</font>
        </p>
        <p>
When I compiled this C# class, Visual Studio generated the DLL and TLB files I expected. 
You can invoke it from a COM client, and it seems to work.  Here is the VB code:
</p>
        <p>
          <font face="Courier New">Dim thing As Object<br />
Set thing = CreateObject("AnyCOMLib.COMClass")<br />
thing.DoSomething</font>
        </p>
        <p>
I typed out a simple VBScript file with this code, and it worked.  A message
box popped up saying "I did something.".
</p>
        <p>
          <img src="http://www.chrisvelazquez.com/blog/content/binary/.net-com-interop.gif" border="0" />
        </p>
        <p>
I created a simple VB 6.0 program with this code, and this worked, too.  The
same message box displayed.
</p>
        <p>
I created a VBA macro in Excel 2003.  This did <u>not</u> work.  I had a
message that read:
</p>
        <p>
Run-time error '-2147024894 (80070002)':<br />
File or assembly name AnyCOMLib, or one of its dependencies, was not found.
</p>
        <p>
          <img src="http://www.chrisvelazquez.com/blog/content/binary/2147024894.gif" border="0" />
        </p>
        <p>
So I thought - If I can create a VB6 DLL that can be called from Excel (true) and
VB6 code can call my COM-wrapped C# code (also true) then why not create a VB6 DLL
that calls my C# code and call <em>that</em> from Excel?  Unfortunately, Excel
was not easily fooled by this subversion, and I continued to get the -2147024894 error. 
That was a waste of time.
</p>
        <p>
After spinning my wheels for too long, I finally found something helpful.  It
turns out that I need a file named Excel.exe.config to be placed in the same directory
as Excel.exe (typically at C:\Program Files\Microsoft Office\Office11).  That
file has the following format:
</p>
        <p>
          <font face="Courier New">&lt;configuration&gt;<br />
    &lt;startup&gt;<br />
        &lt;supportedRuntime version="v2.0.50727"/&gt;<br />
        &lt;supportedRuntime version="v1.1.4322"/&gt;<br />
    &lt;/startup&gt;<br />
&lt;/configuration&gt;</font>
        </p>
        <p>
You have to make sure that you have the correct supportedRuntime elements for the
.NET runtime to work.
</p>
        <p>
Here are links to the pages that helped me find out about this:
</p>
        <p>
          <a href="http://groups.google.com/group/microsoft.public.dotnet.framework.sdk/browse_frm/thread/3c4286a1e2887e3b/a05c57869aa3d896?lnk=st&amp;q=supportedRuntime+%22v-phuang%22+winword.exe&amp;rnum=3&amp;hl=en#a05c57869aa3d896">newsgroup
microsoft.public.dotnet.framework.sdk</a>
        </p>
        <p>
          <a href="http://www.msnewsgroups.net/group/microsoft.public.dotnet.languages.csharp/topic15171.aspx">topic
in msnewgroups.net</a>
        </p>
        <p>
These were specifically targetted for MS Word, but the same method applies
to running .NET assemblies in Excel 2003 as well.
</p>
        <p>
I hope this helps somebody!
</p>
        <img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=ed29e8d6-061f-48ed-b15c-58f3e3db33a4" />
      </body>
      <title>Running .NET Code from Microsoft Office 2003</title>
      <guid isPermaLink="false">http://www.chrisvelazquez.com/blog/PermaLink,guid,ed29e8d6-061f-48ed-b15c-58f3e3db33a4.aspx</guid>
      <link>http://www.chrisvelazquez.com/blog/PermaLink,guid,ed29e8d6-061f-48ed-b15c-58f3e3db33a4.aspx</link>
      <pubDate>Wed, 07 Feb 2007 17:27:09 GMT</pubDate>
      <description>&lt;p&gt;
I can't believe that I've been racking my brains for hours trying to figure out how
to execute my .NET 2.0 code in Microsoft Excel 2003.&amp;nbsp; Hopefully this tidbit of
information will save somebody else on the web some pain, frustration and time.
&lt;/p&gt;
&lt;p&gt;
Punchline: You need a file called EXCEL.EXE.CONFIG in the same directory as EXCEL.EXE.
&lt;/p&gt;
&lt;p&gt;
I created a class, written in C# and compiled with Visual Studio .NET 2005, with the
.NET 2.0 Framework.&amp;nbsp; This class has a COM Interop wrapper so that it can consumed
by ActiveX clients, most notably Excel 2003.&amp;nbsp; This class was compiled with the
"Register for COM interop" setting in the properties turned on.&amp;nbsp; This arrangement
autogenerates the GUIDs and COM interface for you, though I prefer to define my own
COM interfaces manually in production code.
&lt;/p&gt;
&lt;p&gt;
Here is a sample class in C#:
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;// COMClass.cs&lt;br&gt;
using System.Windows.Forms;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;namespace AnyCOMLib {&lt;br&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;public class COMClass {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; public void DoSomething() {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MessageBox.Show("I
did something.");&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br&gt;
}&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
When I compiled this C# class, Visual Studio generated the DLL and TLB files I expected.&amp;nbsp;
You can invoke it from a COM client, and it seems to work.&amp;nbsp; Here is the VB code:
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;Dim thing As Object&lt;br&gt;
Set thing = CreateObject("AnyCOMLib.COMClass")&lt;br&gt;
thing.DoSomething&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
I typed out a simple VBScript file with this code, and it worked.&amp;nbsp; A message
box popped up saying "I did something.".
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.chrisvelazquez.com/blog/content/binary/.net-com-interop.gif" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
I created a simple VB 6.0 program with this code, and this worked, too.&amp;nbsp; The
same message box displayed.
&lt;/p&gt;
&lt;p&gt;
I created a VBA macro in Excel 2003.&amp;nbsp; This did &lt;u&gt;not&lt;/u&gt; work.&amp;nbsp; I had a
message that read:
&lt;/p&gt;
&lt;p&gt;
Run-time error '-2147024894 (80070002)':&lt;br&gt;
File or assembly name AnyCOMLib, or one of its dependencies, was not found.
&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.chrisvelazquez.com/blog/content/binary/2147024894.gif" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
So I thought - If I can create a VB6 DLL that can be called from Excel (true) and
VB6 code can call my COM-wrapped C# code (also true) then why not create a VB6 DLL
that calls my C# code and call &lt;em&gt;that&lt;/em&gt; from Excel?&amp;nbsp; Unfortunately, Excel
was not easily fooled by this subversion, and I continued to get the -2147024894 error.&amp;nbsp;
That was a waste of time.
&lt;/p&gt;
&lt;p&gt;
After spinning my wheels for too long, I finally found something helpful.&amp;nbsp; It
turns out that I need a file named Excel.exe.config to be placed in the same directory
as Excel.exe (typically at C:\Program Files\Microsoft Office\Office11).&amp;nbsp; That
file has the following format:
&lt;/p&gt;
&lt;p&gt;
&lt;font face="Courier New"&gt;&amp;lt;configuration&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;startup&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;supportedRuntime version="v2.0.50727"/&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;supportedRuntime version="v1.1.4322"/&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/startup&amp;gt;&lt;br&gt;
&amp;lt;/configuration&amp;gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
You have to make sure that you have the correct supportedRuntime elements for the
.NET runtime to work.
&lt;/p&gt;
&lt;p&gt;
Here are links to the pages that helped me find out about this:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://groups.google.com/group/microsoft.public.dotnet.framework.sdk/browse_frm/thread/3c4286a1e2887e3b/a05c57869aa3d896?lnk=st&amp;amp;q=supportedRuntime+%22v-phuang%22+winword.exe&amp;amp;rnum=3&amp;amp;hl=en#a05c57869aa3d896"&gt;newsgroup
microsoft.public.dotnet.framework.sdk&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.msnewsgroups.net/group/microsoft.public.dotnet.languages.csharp/topic15171.aspx"&gt;topic
in msnewgroups.net&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
These were specifically&amp;nbsp;targetted&amp;nbsp;for MS Word, but the same method applies
to running .NET assemblies in Excel 2003 as well.
&lt;/p&gt;
&lt;p&gt;
I hope this helps somebody!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=ed29e8d6-061f-48ed-b15c-58f3e3db33a4" /&gt;</description>
      <comments>http://www.chrisvelazquez.com/blog/CommentView,guid,ed29e8d6-061f-48ed-b15c-58f3e3db33a4.aspx</comments>
      <category>.net;office</category>
    </item>
    <item>
      <trackback:ping>http://www.chrisvelazquez.com/blog/Trackback.aspx?guid=9908a5a8-b6d5-4a33-941d-75acf748c5b2</trackback:ping>
      <pingback:server>http://www.chrisvelazquez.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.chrisvelazquez.com/blog/PermaLink,guid,9908a5a8-b6d5-4a33-941d-75acf748c5b2.aspx</pingback:target>
      <dc:creator>Chris V.</dc:creator>
      <wfw:comment>http://www.chrisvelazquez.com/blog/CommentView,guid,9908a5a8-b6d5-4a33-941d-75acf748c5b2.aspx</wfw:comment>
      <wfw:commentRss>http://www.chrisvelazquez.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=9908a5a8-b6d5-4a33-941d-75acf748c5b2</wfw:commentRss>
      <slash:comments>6</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This describes yet another way to do things.  Suppose you have input coming from
a common source, but based on the content of that input, you want your program to
do different things.  Naturally, the first thing you think of is the switch statement. 
But I've stumbled across an interesting alternative.
</p>
        <p>
Here is a simplified class in C# that uses a switch statement:
</p>
        <pre>
          <font size="3">public class MyGame: IGame {<br />
    
<br />
    public string ExecuteCommand(string command, string parameter)
{<br />
        string result;<br />
        switch (command) {<br />
            case "ECHO":<br />
               
result = DoEcho(parameters);<br />
               
break;<br />
            case "JOIN":<br />
               
result = DoJoin(parameters);<br />
               
break;<br />
            case "READY":<br />
               
result = DoReady(parameters);<br />
               
break;<br />
            default:<br />
               
result = DoError();<br />
               
break:<br />
        }<br />
        return result;<br />
    }<br />
    
<br />
    public string DoEcho(string parameters) {<br />
        string result;<br />
        // code here<br />
        return result;<br />
    }<br />
    
<br />
    public string DoJoin(string parameters) {<br />
        string result;<br />
        // code here<br />
        return result;<br />
    }<br />
    
<br />
    public string DoReady(string parameters) {<br />
        string result;<br />
        // code here<br />
        return result;<br />
    }<br />
    
<br />
    public string DoError() {<br />
        string result;<br />
        // code here<br />
        return result;<br />
    }<br />
}</font>
        </pre>
        <p>
I decided to play around with generics to see if I could come up with an alternative
to "switch".  By using a Dictionary of delegates, I can look up what the appropriate
action to take would be, and then do it in a generic fashion.
</p>
        <pre>
          <font size="3">public class MyGame: IGame {<br />
    
<br />
    </font>
          <font size="3">
            <font color="#0000ff">private delegate string
CommandHandler(string parameters);<br /></font>    </font>
          <font size="3">
            <font color="#0000ff">protected Dictionary&lt;string,
CommandHandler&gt; commandHandlers = 
<br /></font>
          </font>
          <font size="3">
            <font color="#0000ff">new Dictionary&lt;string, CommandHandler&gt;();<br /></font>    
<br />
    public MyGame() {<br />
        commandHandlers["ECHO"] = new CommandHandler(DoEcho);<br />
        commandHandlers["JOIN"] = new CommandHandler(DoJoin);<br />
        commandHandlers["READY"] = new CommandHandler(DoReady);<br />
    }<br />
    
<br />
    public string ExecuteCommand(string command, string parameter)
{<br />
        CommandHandler handler;<br />
        if (commandHandlers.TryGetValue(command,
out handler)) {<br />
            return handler.Invoke(parameter);<br />
        } else {<br />
            return DoError();<br />
        }<br />
    }<br />
    
<br />
    // handler code is same above.<br />
    
<br />
}</font>
        </pre>
        <p>
I don't know about you, but this is much more satisfying at varying levels. 
I've never liked the switch statement syntax, ever, and this code is easier on the
eyes.  This transforms the dispatch mechanism from a procedural approach to a
table-driven approach.  The one disadvantage is that all the dispatch methods
must have the same figure, but usually uniformity is a welcome attribute to code. 
One cool thing is that by adding a new handler, Resharper will automagically generate
the signature for the new dispatch method.
</p>
        <p>
A place where this approach might be useful is by assigning abstract factory methods
as delegates.  Those have to be uniform, by design contract.
</p>
        <p>
One thing I would like to see is the ability to assign all of the elements in the
dictionary in a single statement.  I understand this will be a new feature in
C# 3.0, but I haven't experimented with that yet.  I just downloaded the SDK
yesterday!
</p>
        <img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=9908a5a8-b6d5-4a33-941d-75acf748c5b2" />
      </body>
      <title>Dictionary of Delegates as an Alternative to the "switch" statement</title>
      <guid isPermaLink="false">http://www.chrisvelazquez.com/blog/PermaLink,guid,9908a5a8-b6d5-4a33-941d-75acf748c5b2.aspx</guid>
      <link>http://www.chrisvelazquez.com/blog/PermaLink,guid,9908a5a8-b6d5-4a33-941d-75acf748c5b2.aspx</link>
      <pubDate>Fri, 02 Feb 2007 17:10:53 GMT</pubDate>
      <description>&lt;p&gt;
This describes yet another way to do things.&amp;nbsp; Suppose you have input coming from
a common source, but based on the content of that input, you want your program to
do different things.&amp;nbsp; Naturally, the first thing you think of is the switch statement.&amp;nbsp;
But I've stumbled across an interesting alternative.
&lt;/p&gt;
&lt;p&gt;
Here is a simplified class in C#&amp;nbsp;that uses a switch statement:
&lt;/p&gt;
&lt;pre&gt;&lt;font size=3&gt;public class MyGame: IGame {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public string ExecuteCommand(string command, string parameter)
{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string result;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; switch (command) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case "ECHO":&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
result = DoEcho(parameters);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
break;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case "JOIN":&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
result = DoJoin(parameters);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
break;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; case "READY":&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
result = DoReady(parameters);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
break;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; default:&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
result = DoError();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
break:&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public string DoEcho(string parameters) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string result;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // code here&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public string DoJoin(string parameters) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string result;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // code here&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public string DoReady(string parameters) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string result;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // code here&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public string DoError() {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; string result;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // code here&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return result;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
}&lt;/font&gt;&lt;/pre&gt;
&lt;p&gt;
I decided to play around with generics to see if&amp;nbsp;I could come up with an alternative
to "switch".&amp;nbsp; By using a Dictionary of delegates, I can look up what the appropriate
action to take would be, and then do it in a generic fashion.
&lt;/p&gt;
&lt;pre&gt;&lt;font size=3&gt;public class MyGame: IGame {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font size=3&gt;&lt;font color=#0000ff&gt;private delegate string
CommandHandler(string parameters);&lt;br&gt;
&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/font&gt;&lt;font size=3&gt;&lt;font color=#0000ff&gt;protected Dictionary&amp;lt;string,
CommandHandler&amp;gt; commandHandlers = 
&lt;br&gt;
&lt;/font&gt;&lt;/font&gt;&lt;font size=3&gt;&lt;font color=#0000ff&gt;new Dictionary&amp;lt;string, CommandHandler&amp;gt;();&lt;br&gt;
&lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public MyGame() {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; commandHandlers["ECHO"] = new CommandHandler(DoEcho);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; commandHandlers["JOIN"] = new CommandHandler(DoJoin);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; commandHandlers["READY"] = new CommandHandler(DoReady);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; public string ExecuteCommand(string command, string parameter)
{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CommandHandler handler;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (commandHandlers.TryGetValue(command,
out handler)) {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return handler.Invoke(parameter);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } else {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return DoError();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; // handler code is same above.&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; 
&lt;br&gt;
}&lt;/font&gt;&lt;/pre&gt;
&lt;p&gt;
I don't know about you, but this is much more satisfying at varying levels.&amp;nbsp;
I've never liked the switch statement syntax, ever, and this code is easier on the
eyes.&amp;nbsp; This transforms the dispatch mechanism from a procedural approach to a
table-driven approach.&amp;nbsp; The one disadvantage is that all the dispatch methods
must have the same figure, but usually uniformity is a welcome attribute to code.&amp;nbsp;
One cool thing is that by adding a new handler, Resharper will automagically generate
the signature for the new dispatch method.
&lt;/p&gt;
&lt;p&gt;
A place where this approach might be useful is by assigning abstract factory methods
as delegates.&amp;nbsp; Those have to be uniform, by design contract.
&lt;/p&gt;
&lt;p&gt;
One thing I would like to see is the ability to assign all of the elements in the
dictionary in a single statement.&amp;nbsp; I understand this will be a new feature in
C# 3.0, but I haven't experimented with that yet.&amp;nbsp; I just downloaded the SDK
yesterday!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=9908a5a8-b6d5-4a33-941d-75acf748c5b2" /&gt;</description>
      <comments>http://www.chrisvelazquez.com/blog/CommentView,guid,9908a5a8-b6d5-4a33-941d-75acf748c5b2.aspx</comments>
      <category>.net</category>
    </item>
    <item>
      <trackback:ping>http://www.chrisvelazquez.com/blog/Trackback.aspx?guid=1ade8044-e7b5-45f3-b1c5-9099b0e29257</trackback:ping>
      <pingback:server>http://www.chrisvelazquez.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.chrisvelazquez.com/blog/PermaLink,guid,1ade8044-e7b5-45f3-b1c5-9099b0e29257.aspx</pingback:target>
      <dc:creator>Chris V.</dc:creator>
      <wfw:comment>http://www.chrisvelazquez.com/blog/CommentView,guid,1ade8044-e7b5-45f3-b1c5-9099b0e29257.aspx</wfw:comment>
      <wfw:commentRss>http://www.chrisvelazquez.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=1ade8044-e7b5-45f3-b1c5-9099b0e29257</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I have this habit of underestimating Microsoft, especially when it comes to the Office
product line. At first blush, I was unimpressed with Office 2007.  To the average
user, on first glance, it looks like Microsoft has traded one set of GUI widgets for
another set of more complicated GUI widgets.  Combining this with the IT pundits
declaring Office 2007 dead on arrival, I ignored it.  It's hard for me to get
very excited about new widgets.
</p>
        <p>
But last night I chanced upon the <a href="http://msdn2.microsoft.com/en-us/office/aa905543.aspx">VSTO
site</a> (Visual Studio Tools for Office), and took a peek at <a href="http://wm.microsoft.com/ms/msdn/office/vsto2005seintro/vsto2005seintro.wmv">this
video</a>.  I was amazed, and had to concede that Microsoft had pulled it
off once again.  They have raised the bar for us programmers and expectations
of users.  Briefly, your WinForms user controls can plug right into the Office
environment, into either the ribbon or in the side docking panel.  Having worked
on a system in C# that emulates a similar behavior, I was very interested,
and a little disappointed that my craftily written code would soon be obsolete.
</p>
        <p>
The thing about Office, and Word and Excel in particular, is that everyone uses it. 
People get a warm fuzzy from software they use frequently and have some understanding
of.  The number one feature request I get is to be able to download data into
an Excel spreadsheet.  And VSTO 2005 SE (Second Edition) makes the job for programmers
integrating into Office a whole lot better.  And it gives a compelling reason
to upgrade to Office 2007.  This is only a minor upgrade for the end-user, but
this is a sea-change upgrade for the Office developer.
</p>
        <p>
VSTO 2005 SE will also allow Office programmers to achieve the type of service-oriented
architecture that was difficult to achieve with our previous tools.  Since your
user controls can do all those wonderful things like consume web services, chat over
networks, query databases, access the file system, etc., the integration possibilities
are nearly endless.  And the ability to dock your components right at the user's
fingertips within the Office application makes the software convenient to summon for
the end-user.
</p>
        <p align="right">
          <img src="http://www.chrisvelazquez.com/blog/content/binary/aa905543_NewVSTOlogo(en-us,MSDN_10).jpg" border="0" />
        </p>
        <p>
Now to work on my "reasons to upgrade" spiel for my clients...
</p>
        <img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=1ade8044-e7b5-45f3-b1c5-9099b0e29257" />
      </body>
      <title>Why Office 2007 Really Does Rock</title>
      <guid isPermaLink="false">http://www.chrisvelazquez.com/blog/PermaLink,guid,1ade8044-e7b5-45f3-b1c5-9099b0e29257.aspx</guid>
      <link>http://www.chrisvelazquez.com/blog/PermaLink,guid,1ade8044-e7b5-45f3-b1c5-9099b0e29257.aspx</link>
      <pubDate>Wed, 31 Jan 2007 17:13:09 GMT</pubDate>
      <description>&lt;p&gt;
I have this habit of underestimating Microsoft, especially when it comes to the Office
product line. At first blush, I was unimpressed with Office 2007.&amp;nbsp; To the average
user, on first glance, it looks like Microsoft has traded one set of GUI widgets for
another set of more complicated GUI widgets.&amp;nbsp; Combining this with the IT pundits
declaring Office 2007 dead on arrival, I ignored it.&amp;nbsp; It's hard for me to get
very excited about new widgets.
&lt;/p&gt;
&lt;p&gt;
But last night I chanced upon the &lt;a href="http://msdn2.microsoft.com/en-us/office/aa905543.aspx"&gt;VSTO
site&lt;/a&gt; (Visual Studio Tools for Office), and took a peek at &lt;a href="http://wm.microsoft.com/ms/msdn/office/vsto2005seintro/vsto2005seintro.wmv"&gt;this
video&lt;/a&gt;.&amp;nbsp; I was amazed, and had to concede that Microsoft had&amp;nbsp;pulled it
off once again.&amp;nbsp; They have raised the bar for us programmers and expectations
of users.&amp;nbsp; Briefly, your WinForms user controls can plug right into the Office
environment, into either the ribbon or in the side docking panel.&amp;nbsp; Having worked
on a system&amp;nbsp;in C#&amp;nbsp;that emulates a similar behavior, I was very interested,
and a little disappointed that my craftily written code would soon be obsolete.
&lt;/p&gt;
&lt;p&gt;
The thing about Office, and Word and Excel in particular, is that everyone uses it.&amp;nbsp;
People get a warm fuzzy from software they use frequently and have some understanding
of.&amp;nbsp; The number one feature request I get is to be able to download data into
an Excel spreadsheet.&amp;nbsp; And VSTO 2005 SE (Second Edition) makes the job for programmers
integrating into Office a whole lot better.&amp;nbsp; And it gives a compelling reason
to upgrade to Office 2007.&amp;nbsp; This is only a minor upgrade for the end-user, but
this is a sea-change upgrade for the Office developer.
&lt;/p&gt;
&lt;p&gt;
VSTO 2005 SE will also allow Office programmers to achieve the type of service-oriented
architecture that was difficult to achieve with our previous tools.&amp;nbsp; Since your
user controls can do all those wonderful things like consume web services, chat over
networks, query databases, access the file system, etc., the integration possibilities
are nearly endless.&amp;nbsp; And the ability to dock your components right at the user's
fingertips within the Office application makes the software convenient to summon for
the end-user.
&lt;/p&gt;
&lt;p align=right&gt;
&lt;img src="http://www.chrisvelazquez.com/blog/content/binary/aa905543_NewVSTOlogo(en-us,MSDN_10).jpg" border=0&gt;
&lt;/p&gt;
&lt;p&gt;
Now to work on my "reasons to upgrade" spiel for my clients...
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=1ade8044-e7b5-45f3-b1c5-9099b0e29257" /&gt;</description>
      <comments>http://www.chrisvelazquez.com/blog/CommentView,guid,1ade8044-e7b5-45f3-b1c5-9099b0e29257.aspx</comments>
      <category>.net;database;office</category>
    </item>
    <item>
      <trackback:ping>http://www.chrisvelazquez.com/blog/Trackback.aspx?guid=4c107a6f-1e48-40ac-9382-276dabef5b05</trackback:ping>
      <pingback:server>http://www.chrisvelazquez.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.chrisvelazquez.com/blog/PermaLink,guid,4c107a6f-1e48-40ac-9382-276dabef5b05.aspx</pingback:target>
      <dc:creator>Chris V.</dc:creator>
      <wfw:comment>http://www.chrisvelazquez.com/blog/CommentView,guid,4c107a6f-1e48-40ac-9382-276dabef5b05.aspx</wfw:comment>
      <wfw:commentRss>http://www.chrisvelazquez.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=4c107a6f-1e48-40ac-9382-276dabef5b05</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I recently tuned into the <a href="http://www.itconversations.com/shows/detail1694.html" target="_blank">podcast
on IT Conversations</a>, hosted by Phil Windley, and featuring David Platt, .NET programmer
and author of the new book "<a href="http://www.amazon.com/exec/obidos/ASIN/0321466756/" target="_blank">Why
Software Sucks</a>".  In the podcast, Platt adds some new light to problems of
user-facing software (as opposed to programmer-facing software).  Much of what
he has to say has already been covered in Alan Cooper's unforgettable book, "<a href="http://www.amazon.com/exec/obidos/ASIN/0764526413/" target="_blank">About
Face</a>".
</p>
        <p>
So what makes some software suck?  Software is supposed to make our lives and
jobs easier to accomplish.  When software makes it difficult for a user to do
things, or forces the user to remember things, or demands that the user do a complex
dance with her keyboard and mouse, then that software sucks unequivocally.
</p>
        <p>
But if you visit the computer lab and ask the programmers what makes software suck,
they will have a totally different perspective.  Code that's hard to read, lack
of unit test coverage, tight coupling of objects, redundancy: these are the problems
that make software suck.
</p>
        <p>
My opinion is that you can have the most highly refactored code, in all of its object-oriented
goodness, and the software can still suck.  My fear is that there are many devotees
of Martin Fowler and Uncle Bob, who in their own minds believe they are writing great
software, but realize only after it has been foisted on the end user that it actually
sucks.
</p>
        <p>
When I tried to de-suckify a feature in the web application we recently released,
I was often met with fierce resistance from programmers, whereas the business analysts
were very open to new ideas on how to make the software more user-friendly. 
One example was when we were required to build an interface whereby a loan representative
could transfer the responsibility for a loan application to another loan rep. 
In our lingo, this is called "pushing a loan".  The original specification required
that the end user would enter the name of the receiving loan rep or their office then
run a search against the database.  I believed that this method would be error-prone
and that there ought to be any easier way.  I sat down with the business analyst
in charge of this new feature and asked her "What do people use this for 90% of the
time?"  She stated that most often, people would push the loan to someone else
within their own loan office.  So I asked how she would like it if, when the
user first selects the feature, he is presented immediately with a list of the loan
reps from his own office, and that this list would precede the search function on
the page.  The business analyst thought this was an excellent alternative, and
she went to draw up the new plans.  Back in the development lab, things ran afoul
because "everyone knows" that the search function "has" to be the first thing on the
page.  This was going to "break the convention" of the look and feel of the rest
of the web application, and this self-imposed directive should take priority over
giving the user what they truly want.  Also, this alternative was going to require
extra programming that we had not originally planned.  I stood my ground on the
customer's behalf, and ultimately we all did agree on this alternative presentation
of the UI.  But this incident illustrates that sometimes even software developers
who are in good communication with the end user will fail to have the end-user's best
interest as their top priority.
</p>
        <p>
In our development shop, we developers would often lapse into the flawed mentality
of "the customer's always right", and I have been just as guilty as others on this. 
The customer would dictate the requirements and the developers' task was to merely
implement whatever they came up with.  Occasionally, the customer would ask for
something so goofy that we developers would have to put our foot down and everyone
would go back to the drawing board.  Such are the risks of assigning the responsibility
of software design to the customer, in this case the business analysts.  The
business indeed knows best what the business needs, but is typically not the best
choice in deciding how to get there.  The developer has the knowledge to create
whatever a specification calls for, but his knowledge of the business need is often
very shallow.  This leaves a disconnect between the customer and the developer. 
This disconnect was partially alleviated by the agile process we used, during the
breakout sessions.  These sessions are great at defining the business need at
a high level that could be understood by both business analysts and developers. 
These session are not so good at defining the user interface.  And user acceptance
is all about the interface.
</p>
        <p>
In Cooper's book, "<a href="http://www.amazon.com/exec/obidos/ASIN/0672326140/" target="_blank">The
Inmates are Running the Asylum</a>", he introduces the concept of the "interaction
designer", a person who's job is to define the user interface and overall orchestration
for a software project.  In software development circles, the "architect" is
more like the lead programmer who has view of the entire system as a whole, including
database structures, development frameworks, and the code base.  Cooper's interaction
designer is more like an architect in the real world, and they are not so concerned
about the mechanics of making it happen as they are with getting it absolutely right
with the customer.  Programmers don't necessarily make good interaction designers,
because of their intense focus on the "how" of creating software, they lose sight
of the "what".  The interaction designer is not so concerned that the chosen
framework doesn't directly support a certain feature, they are focused on the end
product, and have the artistic license to devise the product so that it works intuitively
and flawlessly for the end user.
</p>
        <p>
In Platt's interview, he does not acknowledge many of his observations that have already
been articulated at length by Cooper.  He does offer a few helpful tips for both
end users and developers.  His tips for developers include:
</p>
        <p>
1) Make sure the project includes a "virgin" - that is, someone who is knowledgeable
in software development but comes to the table with a clean slate, unaware of the
software currently under development.  This fresh perspective will cause new
ideas to bloom outside of the box of groupthink that evolves within a development
team.
</p>
        <p>
2) Be willing to break with convention. Doing things the way they've always been done
is no longer good enough.  If you can't find the right GUI widget from your class
library, get a better class library or build it yourself.
</p>
        <p>
3) Don't let edge cases complicate the mainstream.  Programmers tend to write
software that is mathematically correct, when they should be focused on making the
actions and decisions most often taken by the end-user the top priority. Platt says
that it should be easy for the user to do things that are "good, smart and safe" and
difficult for users to do things that are "bad, stupid and dangerous".  Platt
also demonstrates that it's faster and easier to track a UPS delivery by searching
the UPS tracking number in Google than it is in UPS' own web site.  In Cooper's
"About Face", he makes the absurd analogy of putting the eject button right next to
the radio switch in the pilot's cockpit.
</p>
        <p>
4) Instrument the user experience.  Today's software allows you to be able to
report on the user's experience, so you should monitor how the user uses the software
and then use that information to improve the software for the user's actual needs
instead of their stated needs.  If your software is a web application, the simplest
thing you can do is monitor the web server logs, but you can even do more than that.
</p>
        <p>
One of the problems I see with judging software usability is that it relies on subjective
experience.  There is no one good metric to determine how much a piece of software
sucks or doesn't suck.  Aesthetic appeal is the first thing that hits the eye,
but the lasting impression is the ease of interaction.  For instance, my T-Mobile
service lets me pay my bill over the phone, and I don't even have to push a single
button; its voice commands are intuitive, succinct and accurate, and I have even paid
the bill while driving.
</p>
        <p>
I'll have more to say about these issues on future blogs.<br /></p>
        <img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=4c107a6f-1e48-40ac-9382-276dabef5b05" />
      </body>
      <title>Developing Software that Doesn't Suck</title>
      <guid isPermaLink="false">http://www.chrisvelazquez.com/blog/PermaLink,guid,4c107a6f-1e48-40ac-9382-276dabef5b05.aspx</guid>
      <link>http://www.chrisvelazquez.com/blog/PermaLink,guid,4c107a6f-1e48-40ac-9382-276dabef5b05.aspx</link>
      <pubDate>Tue, 16 Jan 2007 22:35:56 GMT</pubDate>
      <description>&lt;p&gt;
I recently tuned into the &lt;a href="http://www.itconversations.com/shows/detail1694.html" target=_blank&gt;podcast
on IT Conversations&lt;/a&gt;, hosted by Phil Windley, and featuring David Platt, .NET programmer
and author of the new book "&lt;a href="http://www.amazon.com/exec/obidos/ASIN/0321466756/" target=_blank&gt;Why
Software Sucks&lt;/a&gt;".&amp;nbsp; In the podcast, Platt adds some new light to problems of
user-facing software (as opposed to programmer-facing software).&amp;nbsp; Much of what
he has to say has already been covered in Alan Cooper's unforgettable book, "&lt;a href="http://www.amazon.com/exec/obidos/ASIN/0764526413/" target=_blank&gt;About
Face&lt;/a&gt;".
&lt;/p&gt;
&lt;p&gt;
So what makes some software suck?&amp;nbsp; Software is supposed to make our lives and
jobs easier to accomplish.&amp;nbsp; When software makes it difficult for a user to do
things, or forces the user to remember things, or demands that the user do a complex
dance with her keyboard and mouse, then that software sucks unequivocally.
&lt;/p&gt;
&lt;p&gt;
But if you visit the computer lab and ask the programmers what makes software suck,
they will have a totally different perspective.&amp;nbsp; Code that's hard to read, lack
of unit test coverage, tight coupling of objects, redundancy: these are the problems
that make software suck.
&lt;/p&gt;
&lt;p&gt;
My opinion is that you can have the most highly refactored code, in all of its object-oriented
goodness, and the software can still suck.&amp;nbsp; My fear is that there are many devotees
of Martin Fowler and Uncle Bob, who in their own minds believe they are writing great
software, but realize only after it has been foisted on the end user that it actually
sucks.
&lt;/p&gt;
&lt;p&gt;
When I tried to de-suckify a feature in the web application we recently released,
I was often met with fierce resistance from programmers, whereas the business analysts
were very open to new ideas on how to make the software more user-friendly.&amp;nbsp;
One example was when we were required to build an interface whereby a loan representative
could transfer the responsibility for a loan application to another loan rep.&amp;nbsp;
In our lingo, this is called "pushing a loan".&amp;nbsp; The original specification required
that the end user would enter the name of the receiving loan rep or their office then
run a search against the database.&amp;nbsp; I believed that this method would be error-prone
and that there ought to be any easier way.&amp;nbsp; I sat down with the business analyst
in charge of this new feature and asked her "What do people use this for 90% of the
time?"&amp;nbsp; She stated that most often, people would push the loan to someone else
within their own loan office.&amp;nbsp; So I asked how she would like it if, when the
user first selects the feature, he is presented immediately with a list of the loan
reps from his own office, and that this list would precede the search function on
the page.&amp;nbsp; The business analyst thought this was an excellent alternative, and
she went to draw up the new plans.&amp;nbsp; Back in the development lab, things ran afoul
because "everyone knows" that the search function "has" to be the first thing on the
page.&amp;nbsp; This was going to "break the convention" of the look and feel of the rest
of the web application, and this self-imposed directive should take priority over
giving the user what they truly want.&amp;nbsp; Also, this alternative was going to require
extra programming that we had not originally planned.&amp;nbsp; I stood my ground on the
customer's behalf, and ultimately we all did agree on this alternative presentation
of the UI.&amp;nbsp; But this incident illustrates that sometimes even software developers
who are in good communication with the end user will fail to have the end-user's best
interest as their top priority.
&lt;/p&gt;
&lt;p&gt;
In our development shop, we developers would often lapse into the flawed mentality
of "the customer's always right", and I have been just as guilty as others on this.&amp;nbsp;
The customer would dictate the requirements and the developers' task was to merely
implement whatever they came up with.&amp;nbsp; Occasionally, the customer would ask for
something so goofy that we developers would have to put our foot down and everyone
would go back to the drawing board.&amp;nbsp; Such are the risks of assigning the responsibility
of software design to the customer, in this case the business analysts.&amp;nbsp; The
business indeed knows best what the business needs, but is typically not the best
choice in deciding how to get there.&amp;nbsp; The developer has the knowledge to create
whatever a specification calls for, but his knowledge of the business need is often
very shallow.&amp;nbsp; This leaves a disconnect between the customer and the developer.&amp;nbsp;
This disconnect was partially alleviated by the agile process we used, during the
breakout sessions.&amp;nbsp; These sessions are great at defining the business need at
a high level that could be understood by both business analysts and developers.&amp;nbsp;
These session are not so good at defining the user interface.&amp;nbsp; And user acceptance
is all about the interface.
&lt;/p&gt;
&lt;p&gt;
In Cooper's book, "&lt;a href="http://www.amazon.com/exec/obidos/ASIN/0672326140/" target=_blank&gt;The
Inmates are Running the Asylum&lt;/a&gt;", he introduces the concept of the "interaction
designer", a person who's job is to define the user interface and overall orchestration
for a software project.&amp;nbsp; In software development circles, the "architect" is
more like the lead programmer who has view of the entire system as a whole, including
database structures, development frameworks, and the code base.&amp;nbsp; Cooper's interaction
designer is more like an architect in the real world, and they are not so concerned
about the mechanics of making it happen as they are with getting it absolutely right
with the customer.&amp;nbsp; Programmers don't necessarily make good interaction designers,
because of their intense focus on the "how" of creating software, they lose sight
of the "what".&amp;nbsp; The interaction designer is not so concerned that the chosen
framework doesn't directly support a certain feature, they are focused on the end
product, and have the artistic license to devise the product so that it works intuitively
and flawlessly for the end user.
&lt;/p&gt;
&lt;p&gt;
In Platt's interview, he does not acknowledge many of his observations that have already
been articulated at length by Cooper.&amp;nbsp; He does offer a few helpful tips for both
end users and developers.&amp;nbsp; His tips for developers include:
&lt;/p&gt;
&lt;p&gt;
1) Make sure the project includes a "virgin" - that is, someone who is knowledgeable
in software development but comes to the table with a clean slate, unaware of the
software currently under development.&amp;nbsp; This fresh perspective will cause new
ideas to bloom outside of the box of groupthink that evolves within a development
team.
&lt;/p&gt;
&lt;p&gt;
2) Be willing to break with convention. Doing things the way they've always been done
is no longer good enough.&amp;nbsp; If you can't find the right GUI widget from your class
library, get a better class library or build it yourself.
&lt;/p&gt;
&lt;p&gt;
3) Don't let edge cases complicate the mainstream.&amp;nbsp; Programmers tend to write
software that is mathematically correct, when they should be focused on making the
actions and decisions most often taken by the end-user the top priority. Platt says
that it should be easy for the user to do things that are "good, smart and safe" and
difficult for users to do things that are "bad, stupid and dangerous".&amp;nbsp; Platt
also demonstrates that it's faster and easier to track a UPS delivery by searching
the UPS tracking number in Google than it is in UPS' own web site.&amp;nbsp; In Cooper's
"About Face", he makes the absurd analogy of putting the eject button right next to
the radio switch in the pilot's cockpit.
&lt;/p&gt;
&lt;p&gt;
4) Instrument the user experience.&amp;nbsp; Today's software allows you to be able to
report on the user's experience, so you should monitor how the user uses the software
and then use that information to improve the software for the user's actual needs
instead of their stated needs.&amp;nbsp; If your software is a web application, the simplest
thing you can do is monitor the web server logs, but you can even do more than that.
&lt;/p&gt;
&lt;p&gt;
One of the problems I see with judging software usability is that it relies on subjective
experience.&amp;nbsp; There is no one good metric to determine how much a piece of software
sucks or doesn't suck.&amp;nbsp; Aesthetic appeal is the first thing that hits the eye,
but the lasting impression is the ease of interaction.&amp;nbsp; For instance, my T-Mobile
service lets me pay my bill over the phone, and I don't even have to push a single
button; its voice commands are intuitive, succinct and accurate, and I have even paid
the bill while driving.
&lt;/p&gt;
&lt;p&gt;
I'll have more to say about these issues on future blogs.&lt;br&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=4c107a6f-1e48-40ac-9382-276dabef5b05" /&gt;</description>
      <comments>http://www.chrisvelazquez.com/blog/CommentView,guid,4c107a6f-1e48-40ac-9382-276dabef5b05.aspx</comments>
      <category>.net;general;web development</category>
    </item>
    <item>
      <trackback:ping>http://www.chrisvelazquez.com/blog/Trackback.aspx?guid=c5ff29ae-1e5b-4293-a3b3-2c92dcec5eee</trackback:ping>
      <pingback:server>http://www.chrisvelazquez.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.chrisvelazquez.com/blog/PermaLink,guid,c5ff29ae-1e5b-4293-a3b3-2c92dcec5eee.aspx</pingback:target>
      <dc:creator>Chris V.</dc:creator>
      <wfw:comment>http://www.chrisvelazquez.com/blog/CommentView,guid,c5ff29ae-1e5b-4293-a3b3-2c92dcec5eee.aspx</wfw:comment>
      <wfw:commentRss>http://www.chrisvelazquez.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c5ff29ae-1e5b-4293-a3b3-2c92dcec5eee</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
The tool that no .NET programmer should suffer without has gotten better!  New
features are enumerated <a href="http://www.jetbrains.com/resharper/features/newfeatures.html">here</a>.
</p>
        <img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=c5ff29ae-1e5b-4293-a3b3-2c92dcec5eee" />
      </body>
      <title>Resharper 2.5 is now available</title>
      <guid isPermaLink="false">http://www.chrisvelazquez.com/blog/PermaLink,guid,c5ff29ae-1e5b-4293-a3b3-2c92dcec5eee.aspx</guid>
      <link>http://www.chrisvelazquez.com/blog/PermaLink,guid,c5ff29ae-1e5b-4293-a3b3-2c92dcec5eee.aspx</link>
      <pubDate>Mon, 08 Jan 2007 15:43:30 GMT</pubDate>
      <description>&lt;p&gt;
The tool that no .NET programmer should suffer without has gotten better!&amp;nbsp; New
features are enumerated &lt;a href="http://www.jetbrains.com/resharper/features/newfeatures.html"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=c5ff29ae-1e5b-4293-a3b3-2c92dcec5eee" /&gt;</description>
      <comments>http://www.chrisvelazquez.com/blog/CommentView,guid,c5ff29ae-1e5b-4293-a3b3-2c92dcec5eee.aspx</comments>
      <category>.net</category>
    </item>
    <item>
      <trackback:ping>http://www.chrisvelazquez.com/blog/Trackback.aspx?guid=96d76482-be1a-4479-be1f-1533cfe71df7</trackback:ping>
      <pingback:server>http://www.chrisvelazquez.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.chrisvelazquez.com/blog/PermaLink,guid,96d76482-be1a-4479-be1f-1533cfe71df7.aspx</pingback:target>
      <dc:creator>Chris V.</dc:creator>
      <wfw:comment>http://www.chrisvelazquez.com/blog/CommentView,guid,96d76482-be1a-4479-be1f-1533cfe71df7.aspx</wfw:comment>
      <wfw:commentRss>http://www.chrisvelazquez.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=96d76482-be1a-4479-be1f-1533cfe71df7</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
NAnt is great.  I have a script that compiles all my source files, builds the
standalone installation packages, fires off Virtual PC for testing, and it can even
FTP the installation package to my client's site.  It seems like there's
nothing NAnt can't do.  But I needed to peel off the version number from the
executable, and I couldn't find any easy way to do this in NAnt.  Fortunately,
I discovered that it's really not that hard to create a custom task in NAnt in C#,
then use it from the target.
</p>
        <p>
Basically, you have to create a &lt;script&gt; block (as shown below) and create a
class that inherits from Task.  The TaskName attribute is what you will use in
the main NAnt script to call it.  Any property with a TaskAttribute attribute
can be used as an XML attribute in the script, and you can set Required=true to require
it.  The Task object has the Project property, which can be used to access anything
at all to do with the build process.  I use it here to set a NAnt property and
log to StdOut.  NAnt will compile the C# code on the fly (if you did everything
correctly) and voila, anything you can think of is now possible.
</p>
        <p>
Here is a sample from the build script I created. 
</p>
        <pre style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New,Courier">&lt;project name="SomeNAntProject" default="DefaultTarget"&gt;

    &lt;property name="version.number" value="0.0.0.0" /&gt;

    &lt;target name="DefaultTarget"&gt;
        &lt;<strong><font color="#ff0000">getversioninfo</font></strong><font color="#0000ff"><strong>filename</strong></font>="C:\Folder\MyExecutable.exe"
/&gt; &lt;echo message="${version.number}" /&gt; &lt;/target&gt; &lt;script language="C#"&gt;
&lt;code&gt; &lt;![CDATA[ [TaskName("getversioninfo")] <font color="#000000">public</font> class
GetVersionInfoTask: Task { private string _fileName; [TaskAttribute("filename", Required=true)]
public string FileName { get {return _fileName; } set {_fileName = value; } } protected
override void ExecuteTask() { System.Diagnostics.FileVersionInfo fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(_fileName);
Project.Properties["version.number"] = fvi.ProductVersion; Project.Log(Level.Info,
" [script] Got version info for " + _fileName); } } ]]&gt; &lt;/code&gt; &lt;/script&gt;
&lt;/project&gt; </pre>
        <img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=96d76482-be1a-4479-be1f-1533cfe71df7" />
      </body>
      <title>Customizing a NAnt Build Script with C#</title>
      <guid isPermaLink="false">http://www.chrisvelazquez.com/blog/PermaLink,guid,96d76482-be1a-4479-be1f-1533cfe71df7.aspx</guid>
      <link>http://www.chrisvelazquez.com/blog/PermaLink,guid,96d76482-be1a-4479-be1f-1533cfe71df7.aspx</link>
      <pubDate>Fri, 05 Jan 2007 01:58:31 GMT</pubDate>
      <description>&lt;p&gt;
NAnt is great.&amp;nbsp; I have a script that compiles all my source files, builds the
standalone installation packages, fires off Virtual PC for testing, and it can even
FTP the installation package&amp;nbsp;to my client's site.&amp;nbsp; It seems like there's
nothing NAnt can't do.&amp;nbsp; But I needed to peel off the version number from the
executable, and I couldn't find any easy way to do this in NAnt.&amp;nbsp; Fortunately,
I discovered that it's really not that hard to create a custom task in NAnt in C#,
then use it from the target.
&lt;/p&gt;
&lt;p&gt;
Basically, you have to create a &amp;lt;script&amp;gt; block (as shown below) and create a
class that inherits from Task.&amp;nbsp; The TaskName attribute is what you will use in
the main NAnt script to call it.&amp;nbsp; Any property with a TaskAttribute attribute
can be used as an XML attribute in the script, and you can set Required=true to require
it.&amp;nbsp; The Task object has the Project property, which can be used to access anything
at all to do with the build process.&amp;nbsp; I use it here to set a NAnt property and
log to StdOut.&amp;nbsp; NAnt will compile the C# code on the fly (if you did everything
correctly) and voila, anything you can think of is now possible.
&lt;/p&gt;
&lt;p&gt;
Here is&amp;nbsp;a sample from the build script I created.&amp;nbsp;
&lt;/p&gt;
&lt;pre style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New,Courier"&gt;&amp;lt;project name="SomeNAntProject" default="DefaultTarget"&amp;gt;

    &amp;lt;property name="version.number" value="0.0.0.0" /&amp;gt;

    &amp;lt;target name="DefaultTarget"&amp;gt;
        &amp;lt;&lt;strong&gt;&lt;font color=#ff0000&gt;getversioninfo&lt;/font&gt;&lt;/strong&gt; &lt;font color=#0000ff&gt;&lt;strong&gt;filename&lt;/strong&gt;&lt;/font&gt;="C:\Folder\MyExecutable.exe"
/&amp;gt; &amp;lt;echo message="${version.number}" /&amp;gt; &amp;lt;/target&amp;gt; &amp;lt;script language="C#"&amp;gt;
&amp;lt;code&amp;gt; &amp;lt;![CDATA[ [TaskName("getversioninfo")] &lt;font color=#000000&gt;public&lt;/font&gt; class
GetVersionInfoTask: Task { private string _fileName; [TaskAttribute("filename", Required=true)]
public string FileName { get {return _fileName; } set {_fileName = value; } } protected
override void ExecuteTask() { System.Diagnostics.FileVersionInfo fvi = System.Diagnostics.FileVersionInfo.GetVersionInfo(_fileName);
Project.Properties["version.number"] = fvi.ProductVersion; Project.Log(Level.Info,
" [script] Got version info for " + _fileName); } } ]]&amp;gt; &amp;lt;/code&amp;gt; &amp;lt;/script&amp;gt;
&amp;lt;/project&amp;gt; &lt;/pre&gt;
&lt;img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=96d76482-be1a-4479-be1f-1533cfe71df7" /&gt;</description>
      <comments>http://www.chrisvelazquez.com/blog/CommentView,guid,96d76482-be1a-4479-be1f-1533cfe71df7.aspx</comments>
      <category>.net</category>
    </item>
    <item>
      <trackback:ping>http://www.chrisvelazquez.com/blog/Trackback.aspx?guid=c98968e6-c0eb-4e5b-b99f-9241f4c9fc7c</trackback:ping>
      <pingback:server>http://www.chrisvelazquez.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.chrisvelazquez.com/blog/PermaLink,guid,c98968e6-c0eb-4e5b-b99f-9241f4c9fc7c.aspx</pingback:target>
      <dc:creator>Chris V.</dc:creator>
      <wfw:comment>http://www.chrisvelazquez.com/blog/CommentView,guid,c98968e6-c0eb-4e5b-b99f-9241f4c9fc7c.aspx</wfw:comment>
      <wfw:commentRss>http://www.chrisvelazquez.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c98968e6-c0eb-4e5b-b99f-9241f4c9fc7c</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I found an interesting alternative data access layer (DAL) to NHibernate called <a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=actionpack" target="_blank">SubSonic</a>. 
It was formerly called "ActionPack", but I guess there must be enough confusion with
Microsoft's "<a href="http://oem.microsoft.com/script/sites/public/action_pack.htm" target="_blank">Action
Pack</a>" that they changed the name.  SubSonic is open-source (MPL) 
</p>
        <p>
SubSonic has been hailed as "Ruby on Rails" for .NET developers.  There is a
screencast of it <a href="http://www.wekeroad.com/actionpackintro.html" target="_blank">here</a>,
prepare to be amazed.  It works kind of like this:
</p>
        <p>
1) Add a reference to the SubSonic DLL<br />
2) Modify your web.config with connection string info and SubSonic build provider
info<br />
3) Build the project<br />
4) ...<br /><img src="http://www.chrisvelazquez.com/blog/content/binary/miracle3.gif" border="0" />Copyright
(C) Sidney Harris.
</p>
        <p>
5) Amazing!  Domain objects and data access layer have been automagically created!
</p>
        <p>
I foresee this as a great way to quickly get a data-driven site up with a minimum
of development effort.  Realizing this is not the end-all and be-all of data
access, you are still free to use "traditional" ADO.NET techniques.  A recent
benefit is that CodePlex has come out with an XmlProvider, so that if you would rather
persist to XML instead of a database, it can handle that data access layer, too. 
This thing keeps getting better and better.
</p>
        <img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=c98968e6-c0eb-4e5b-b99f-9241f4c9fc7c" />
      </body>
      <title>SubSonic - The Zero Code DAL</title>
      <guid isPermaLink="false">http://www.chrisvelazquez.com/blog/PermaLink,guid,c98968e6-c0eb-4e5b-b99f-9241f4c9fc7c.aspx</guid>
      <link>http://www.chrisvelazquez.com/blog/PermaLink,guid,c98968e6-c0eb-4e5b-b99f-9241f4c9fc7c.aspx</link>
      <pubDate>Wed, 03 Jan 2007 16:27:55 GMT</pubDate>
      <description>&lt;p&gt;
I found an interesting alternative data access layer (DAL)&amp;nbsp;to NHibernate called &lt;a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=actionpack" target=_blank&gt;SubSonic&lt;/a&gt;.&amp;nbsp;
It was formerly called "ActionPack", but I guess there must be enough confusion with
Microsoft's "&lt;a href="http://oem.microsoft.com/script/sites/public/action_pack.htm" target=_blank&gt;Action
Pack&lt;/a&gt;" that they changed the name.&amp;nbsp; SubSonic is open-source (MPL) 
&lt;/p&gt;
&lt;p&gt;
SubSonic has been hailed as "Ruby on Rails" for .NET developers.&amp;nbsp; There is a
screencast of it &lt;a href="http://www.wekeroad.com/actionpackintro.html" target=_blank&gt;here&lt;/a&gt;,
prepare to be amazed.&amp;nbsp; It works kind of like this:
&lt;/p&gt;
&lt;p&gt;
1) Add a reference to the SubSonic DLL&lt;br&gt;
2) Modify your web.config with connection string info and SubSonic build provider
info&lt;br&gt;
3) Build the project&lt;br&gt;
4) ...&lt;br&gt;
&lt;img src="http://www.chrisvelazquez.com/blog/content/binary/miracle3.gif" border=0&gt;Copyright
(C) Sidney&amp;nbsp;Harris.
&lt;/p&gt;
&lt;p&gt;
5) Amazing!&amp;nbsp; Domain objects and data access layer have been automagically created!
&lt;/p&gt;
&lt;p&gt;
I foresee this as a great way to quickly get a data-driven site up with a minimum
of development effort.&amp;nbsp; Realizing this is not the end-all and be-all of data
access, you are still free to use "traditional" ADO.NET techniques.&amp;nbsp; A recent
benefit is that CodePlex has come out with an XmlProvider, so that if you would rather
persist to XML instead of a database, it can handle that data access layer, too.&amp;nbsp;
This thing keeps getting better and better.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.chrisvelazquez.com/blog/aggbug.ashx?id=c98968e6-c0eb-4e5b-b99f-9241f4c9fc7c" /&gt;</description>
      <comments>http://www.chrisvelazquez.com/blog/CommentView,guid,c98968e6-c0eb-4e5b-b99f-9241f4c9fc7c.aspx</comments>
      <category>database;web development;.net</category>
    </item>
  </channel>
</rss>