Wednesday, February 18, 2009

NCover v3 Magic...

I just upgraded the Gallio NCover integration to support NCover v3.  It all looked okay except that I could not get the integration test to pass!

No matter what I did, NCover would exclude coverage of any Gallio code at all including my test assembly!  However it would include coverage information about Castle assemblies.

On a whim, I ran grep Gallio * over the NCover program files folder, and here's what I found in a file called NCover.Console.exe.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="ncover.systemAssemblies" type="NCover.Framework.SystemAssemblySectionHandler, NCover.Framework"/>
    </configSections>
    <startup>
    </startup>
    <ncover.systemAssemblies>
        <assembly>msvc[mrp].*</assembly>
        <assembly>mscorcfg</assembly>
        <assembly>mscorlib</assembly>
        <assembly>sysglobl</assembly>
        <assembly>CppCodeProvider</assembly>
        <assembly>Microsoft.*</assembly>
        <assembly>PresentationBuildTasks</assembly>
        <assembly>PresentationCore</assembly>
        <assembly>PresentationFramework.*</assembly>
        <assembly>ReachFramework</assembly>
        <assembly>System.*</assembly>
        <assembly>VSLangProj.*</assembly>
        <assembly>VSWebSite\.Interop</assembly>
        <assembly>VSWebSite\.Interop90</assembly>
        <assembly>SMDiagnostics</assembly>
        <assembly>UIAutomationClient</assembly>
        <assembly>UIAutomationClientsideProviders</assembly>
        <assembly>UIAutomationProvider</assembly>
        <assembly>UIAutomationTypes</assembly>
        <assembly>WindowsBase</assembly>
        <assembly>WindowsFormsIntegration</assembly>

        <assembly>nunit\..*</assembly>
        <assembly>nunit-.*</assembly>
        <assembly>xunit.*</assembly>
        <assembly>MbUnit.*</assembly>
        <assembly>MSTest.*</assembly>
        <assembly>log4net</assembly>
        <assembly>QuickGraph.*</assembly>
        <assembly>WiseOwl.Obfuscation</assembly>
        <assembly>Rhino.Mocks</assembly>
       <assembly>Gallio.*</assembly>
        <assembly>mbunit.console</assembly>
        <assembly>Gallio.Echo</assembly>
        <assembly>Gallio.Icarus</assembly>
    </ncover.systemAssemblies>
</configuration>

Aside: This list seems to contain some redundant or incorrect entries.  For example, the old MbUnit v2 console application is called MbUnit.Cons, not MbUnit.Console.

Whoo!

Ok, so out of the box NCover will exclude from coverage analysis anything related to several popular testing packages.  In principle, it's not a bad idea since excluding these assemblies is a common support request from users... but in practice this worries me because it can become overbroad and lead to user confusion (as it did for me).  Gallio in particular is in a good position to take care of specifying its own necessary exclusions automatically (while taking plug-ins into account also).

To work around this issue, it suffices to edit the file.  The list of system assemblies seems to override anything specified in the list of assembly inclusion arguments.

I will send the author a proposal to add a new switch to disable some of this behavior...

Sunday, February 15, 2009

A Duty to Learn

I was called to write this post after reading Jeff Atwood's The Ferengi Programmer and Rob Connery's apt response Patterns, Purists and Sinkholes.  Their central argument is about whether the software development process can be codified.

Could there ever be a sufficiently precise set of rules to successfully build software by the book?  Possibly.

Would it stifle the art?  Certainly.

Are "principles and practices" useful?  Yes!  They provide scaffolding for reasoned analysis and discussion.

Are they universally good and complete?  No.  They are changeable embodiments of ideals.

Is it still worth learning and sharing principles and practices written down by others?  Absolutely!

A Duty to Teach

What is a "best practice"?

First, let's start with the name.  "Best" suggests that in some objective sense, these practices alone were judged to be absolutely superior to all others.  Not merely are they good, they are superlative!

Second, the term is often applied to particular mechanisms used to achieve a particular policy.  For example, "Thou shalt write application log files using protocol XYZ."  There's more to learn about best practice than particular interfaces.

Let's call these things what they are instead: "standard practice".

Standard practice is a compromise by an organization to achieve a mutually agreeable implementation of an ideal principle.  It is a tool to promote uniformity and consensus but it is no substitute for education.  Standard practice should never be used to enforce unquestioned conformity and to stifle further debate.

Merely stating a standard practice does not free the speaker from the duty to teach!

An Unquestioning Mind Remains Unhired

Every professional software practitioner has a duty to learn.  Those who shirk this duty eventually land in the pool of the millions of unemployed programmers who bang at the door of the software industry every day.  They boast about their services yet fail time and again to invest their hearts and minds as barter for the money and recognition they feel is their due.

Let me share a secret...

If you say any of the following statements during an interview, I will probably not hire you.  I don't care what your level of ability or experience is.  These statements tell me you are on the path of eventual stagnation:

  • "I don't know anything about X but it's too complicated and I believe everything should be kept as simple as possible."

    Translation: I am unwilling to learn on my own and I am unwilling to admit it might help my career.
  • "X is obviously better than Y."  (I can't explain it but it is.)

    Translation: I am unwilling to learn on my own and I cannot tell the difference.
  • "In all of the X years of my experience I have never had to do Y."  (So you must be wrong about thinking it might be important.)

    Translation: I am unwilling to learn on my own and I will drag everyone who disagrees with my dogma into the pit of irrelevance.
  • "I did X at all of my other jobs.  X is the solution to all of your problems."  (It slices, it dices.)

    Translation: I am unwilling to learn on my own and I will not let go of my sledgehammer.
  • "All of my work conforms to industry best practices X, Y and Z."  (But I can't explain them.)

    Translation: I am unwilling to learn on my own and I like to impress people with buzzwords.
  • "I really want to work here but in two years do you think I can graduate to department X?"  (X is so much cooler than Y even though I don't know X or Y very well, like development vs. testing.)

    Translation: I am unwilling to learn on my own and I think what you do is beneath my status.
  • "I learned everything on my own.  It's so easy and obvious.  Schools and books are for losers."

    Translation: I am unwilling to accept that others might still have things to teach me and I am stunting my own growth.
  • "I can learn any X.  They're all the same."  (Programming languages)

    Translation: I am unwilling to accept that others might still have things to teach me and that there there are many ways of doing things; some vastly different from what I know.

I would rather endorse and train a candidate fresh out of school full of passion and vitality than a highly experienced person in denial of a closed mind.

A Broken Heart

A friend of mine recently told me this: "I am not sure whether I want to stay in software development much longer.  I always have to learn new things each year and I feel I will never catch up.  I think I should go into management or business intelligence since those fields stay the same all of the time and never change."

It broke my heart.

First, that he was planning to embark on a path of stagnation.   Second, that he unfairly judged those in other disciplines as being somehow less sophisticated.  Third, that he seemed to be making unhealthy decisions by default.

We talked for a long while after that.

Ultimately, I don't mind if he leaves software development (although I will be sad).  I just hope he goes where his passion leads him.  I will support him either way.  Still, for me it was a worthwhile reminder that not everyone values their careers the same way...

Do want you want, but do it with all your heart and mind engaged.  Learn and grow and change...

Friday, February 6, 2009

Edge Cases

It's nice to pretend edge cases don't exist or aren't important, but they do and they are...  Try as you might, someone will stumble upon it and the world will collapse under the weight of invalidated assumptions.

 

Here is one that I've been dealing with lately:

public class Container<T>
{
    public class Outer
    {
        public class Inner : Outer
        {
        }
    }
}

Quiz

1. What does typeof(Inner).GetGenericArguments().Length return?

2a. What does typeof(Inner).GetGenericArguments()[0].ToString() return?

2b. How about typeof(Inner).GetGenericArguments()[0].FullName?

3. What does typeof(Inner).GetGenericArguments()[0].DeclaringType.ToString() return?

3b. How about typeof(Inner).GetGenericArguments()[0].DeclaringType.FullName?

4a. What does typeof(Inner).BaseType.GetGenericArguments()[0].DeclaringType.ToString() return?

4b. How about typeof(Inner).BaseType.GetGenericArguments()[0].DeclaringType.FullName?

5a. What does typeof(Inner).BaseType.ToString() return?

5b. How about typeof(Inner).BaseType.FullName?

Answers

(Select text to reveal.)

1. 1

2a. "T"

2b. null

3a. "Container`1+Outer+Inner[T]"

3b. "Container`1+Outer+Inner"

4a. "Container`1+Outer+Inner[T]"

4b. "Container`1+Outer+Inner"

5a. "Container`1+Outer[T]"

5b. null

Surprise!