Driving a “no bugs” team culture – level 200

I've been reviewing Jim Shore and chromatic's upcoming Agile book, and I especially like the "No Bugs" section here: http://jimshore.textdriven.com/Agile-Book/no_bugs.html

Large, dusty bug databases abound.  Some teams have a process where this is unavoidable.  Some teams use a bug database as a roadmap *shudder*. 

Personally, I believer that a "low priority bug" doesn't exist.  If it's a bug, why would you ever think of not fixing it?  If a product manager decides that the current behavior of the system is acceptable for the time being, then why would you call it a bug?  You may find the behavior of the system undesirable, but ultimately, it's the product owner's call what is desirable or not.  Maybe he agrees it's undesirable, but there are other things more undesirable (like the complete absence of several large stories). 

In my experience, poor management leads to a code-and-fix culture – working off a bug list.  It's "easy" if there is just a running list of bugs.  The team stays busy, and you can track work (kind of).  What is hard is to lay out a prioritized road map and manage the growth of the product.  Managing the product is actual work. 

Many things can contribute to a low bug count:  proper roadmap planning, good developers, automated tests, good software design, etc.  I think the average life of a bug is also very important for the team culture.

To drive a culture of "no bugs", bugs cannot be allowed to live long.  If a bug is announced, and nothing happens, the team accepts that the bug is there, and they will fix it "when they get to it".  If someone stops and immediately addresses the bug, then the team knows that bugs are not acceptable.  From a management perspective, I give bugs top priority.  If there is a bug on our wall (red index card), it has top priority – no questions.  The bug is not allowed to live.  This is key for driving a "no bugs" team culture.
 

Product Review: VisualSVN, Subversion plugin for Visual Studio – level 200

As stated on its website, VisualSVN is a plugin for Microsoft Visual Studio for seamless integration with Subversion.

This is an early review since I’ve been using it for less than a week.  Many think to Scott Bellware for making me aware of this product because it has made my day just a bit easier.  Up until now I’ve been using TortoiseSVN, a windows shell extension, for my integration with our Subversion source control repositories. 

VisualSVN wraps TortoiseSVN and makes all the commands available from within Visual Studio 2003 or 2005.  I’m using VS 2005, so I have not tried it with 2003.  I am very pleased with my experience so far.  VisualSVN puts a colored diamond next to each file (green/yellow/red for unchanged/changed/conflicted).  I can show a diff, revert, etc from the solution explorer.  I can also update commit either from the menu or the Solution root.  The user experience is the same as Tortoise since VisualSVN doesn’t introduce a new way to update/commit.  VisualSVN actually pulls up the TortoiseSVN window for update/commit.  TortoiseSVN is actually doing the work, but VisualSVN pulls in access to it into the IDE.  This takes away the need to switch back to Windows Explorer for source code interactions.

In short, I’m very impressed with my trial so far, and I plan and laying down the $19 for the great tool.  After Christmas, they plan on setting the price back at $49. 

Searching in .Net (don’t search manually, let .Net do it for you) – level 100

With .Net 2.0, we have some basic search
functionality baked in to the .Net Framework.  With Linq coming out in .Net 3.5,
we will have full querying support on IEnumerable types, but we have quite a bit
of power with .Net 2.0.  In this short article, I'll outline how to search
objects in memory with .Net 2.0 or higher.

Consider the following class, Person:

public class Person : IComparable

{

    private string _firstName;

    private string
_lastName;

 

    public Person(string firstName,
string
lastName)

   
{

        _firstName
= firstName;

       
_lastName = lastName;

    }

 

    public string FirstName

    {

        get { return _firstName;
}

    }

 

    public string
LastName

    {

        get { return _lastName;
}

    }

 

    public string
FullName

    {

        get { return string.Format("{0} {1}",
FirstName, LastName); }

    }

 

    public int CompareTo(object obj)

    {

        Person person = (Person)obj;

        int compareResult =
LastName.CompareTo(person.LastName);

        if(compareResult == 0)

        {

               
compareResult = FirstName.CompareTo(person.FirstName);

        }

 

        return compareResult;

    }

 

    public override string
ToString()

   
{

        return
FullName;

   
}

}

Consider
this a basic domain object within the application.  We have the need to work
with many instances of this class in memory.  Assume that there is no need for a
relational database for this application.  We pull Person instances in memory
and work with them.  Often, we'll need to pare down the set to only include
instances that match some criteria.  We could loop through each one and create a
new list with matches, but with .Net 2.0 and "Comparison"(s), we have a more
elegant way.  Here is an example.

        public void ShouldQueryArray()

   
    {

            Person[] people = new Person[]{new Person("Homer", "Simpson"), new
Person("Jeffrey", "Palermo")};

           
Person[] matches = Array.FindAll<Person>(people, delegate(Person
obj)

                                               
                {

                                   
                                return
(obj.FirstName.Contains("ome"));

                                                           
    });

 

            foreach(Person
person in matches)

            {

               
Console.WriteLine(person);

            }

        }


In this example, we can just specify the
condition that causes an instance to match, and we'll get back a new array with
only the matches.  In this case, we get the following output:

Homer Simpson

I work with
arrays a lot.  In fact, it is my favorite IEnumerable data structure because of
it's power, but it isn't the only structure that supports comparisons (and there
are other methods similar to FindAll, but FindAll is the most common).  

public void ShouldQueryIList()

{

    List<Person>
list = new List<Person>();

   
list.Add(new Person("Homer",
"Simpson"));

   
list.Add(new Person("Jeffrey",
"Palermo"));

 

    List<Person>
matches = list.FindAll(delegate(Person obj)

               
                            {

                       
                        return
(obj.FirstName.Contains("ome"));

                                            });

 

    foreach (Person
person in matches)

    {

        Console.WriteLine(person);

    }

}


Here, we are using the
List<T> class for our search.  The following example is more complex. 
This illustrates that the matching criteria can be as complicated as you need it
to be.

public void ShouldQueryArrayWithComplexComparison()

{

    Person[] people = new Person[] { new Person("Homer", "Simpson"), new
Person("Jeffrey", "Palermo") };

    Person[] matches = Array.FindAll<Person>(people, delegate(Person
obj)

                                               
        {

                                           
                return
(obj.FirstName.StartsWith("j", StringComparison.InvariantCultureIgnoreCase)

                                                           
       && obj.LastName.EndsWith("mo"));

               
                                        });

 

    foreach (Person person in
matches)

    {

        Console.WriteLine(person);

    }

}


By the way, if you aren't
familiar with the "delegate" keyword, this is an anonymous method.  I could
refactor it into a private method, but I'm using it inline instead.  In short,
FindAll just requires a delegate.  However you wish to provide it is fine.