SEVDNUG: Continuous Integration Presentation

Along with the Agile presentation, I also had the pleasure of discussing Continuous Integration.  The talk centered on Cruise Control .Net and Nant.  I enjoyed giving the talk and sharing but unfortunately I didn't do a great job with the demos and they didn't across the way I wanted them to.  I will post some additional information over the next couple of weeks on Nant and CI.  For now, the link below will get you the presentation, the sample application with all of the build scripts, 3 Nant custom task and CCNET Config file that I used for the demo.

CI.zip (390.59 KB)

Included in the ZIP File:

Demo Code

  • default.build - Master build file for the solution
  • common.build - All of the global properties (variables) for the scripts
  • common.build - Project.build - Nant task that can be reused
  • NantSchema.build - nant script to generate nant.xsd that is needed for VS intellisense
  • HelloWorld.DataObject - C# Class Library
  • HelloWorld.SQL - VS 2007 Team System Database Project
  • HelloWorld.SSIS - Has SSIS sample build script
  • HelloWorld.Tests - NUnit Test Project
  • HelloWorld.Web - Web Application Project
  • HelloWorld.WinForm - WinForm Project

Nant Custom Tasks

  • AppSettingsWriter
    • Add/Update AppSettings Nodes in App.config and Web.Config files
    • Very Simple Task. 
    • XMLPoke should take care of what this task does
  • CleanupOldBuildFiles
    • Removes Files/Directories based on either a number of revisions or on a given number of days since creation.
  • TaskSchedulerTasks
    • Add/Updates/Removes Windows Scheduled Task

SEVDNUG: Agile Presentation

Tonight I have the pleasure of presenting on Agile development at the SEVDNUG meeting.  I focused the talk on things that I have learned over the last 4 years of using Agile.  I figured that folks can read the Agile/XP books and get the Agile concept but the books don't discuss things to look out for that can trip you up or how to really convert your project to Agile from a different process.  The presentation started off with a quick overview of Agile and the benefit and then jump into the learnings.  I did include in the backup slides the Agile overview/concept slides since I already had them done from other presentations that I have given.

Agile.zip (464.45 KB)

The presentation is in Powerpoint 2007 format.  If you don't have Office 2007, you can download the Compatibility Pack which will allow you to view/edit/save Office 2007 formatted files


How to run a CMD command as a CCNet Prebuild Task without additional bat files

I have had a problem for ages with when a build fails in CCNET is runs the file merge tasks that are part of my publishers to include the nunit test results. I finally got around to implementing something to delete those results xml files before the build runs. Originally I was just going to add it to nant but I found in the CCNET docs that there is now a prebuild section. One of the tasks included with the CCNET is an exec but it is not very clear on how to use CMD instead of creating a separate batch file. Luckily someone else figured this out at posted it to the mailing list @ http://groups.google.com.ag/group/ccnet-user/browse_thread/thread/d3f19074845bacf7/f58fa4bf7e221b3d?lnk=gst&q=prebuild+&rnum=9#f58fa4bf7e221b3d

Just in case the link goes away, below is how to do it.

<prebuild>
    <exec>
        <baseDirectory>C:\Temp</baseDirectory>
        <executable>CMD</executable>
        <buildArgs>/C RD "%ccnetworkingdirectory%" /S /Q</buildArgs>
    </exec>
</prebuild>


nAnt Versioning the Microsoft Way

Good post on how to use nant to update the version information in the assemblyinfo.cs the way that Microsoft does it.

Versioning the Microsoft way... with NAnt

I was inspired by a recent blog entry by Jeff Atwood here about how Microsoft versions their products and how the build number is significant. I thought it would be good to post a walkthrough of how to build your own versioning system ala Microsoft but using NAnt. I'm sure some budding geek out there could convert this to MSBuild, but you know my love of that tool so NAnt it is.

First off, NAnt has a great facility for generating that AssemblyInfo.cs file that every project has. It's the asminfo task and basically looks like this:

<?xml version="1.0"?>
<project name="Test" default="UpdateAssemblyInfo">
    <target name="UpdateAssemblyInfo">
        <asminfo output="AssemblyInfo.cs" language="CSharp">
            <imports>
                <import namespace="System.Reflection" />
                <import namespace="System.Runtime.InteropServices" />
            </imports>
            <attributes>
                <attribute type="AssemblyTitleAttribute" value="ClassLibrary1" />
                <attribute type="AssemblyDescriptionAttribute" value="" />
                <attribute type="AssemblyConfigurationAttribute" value="" />
                <attribute type="AssemblyCompanyAttribute" value="" />
                <attribute type="AssemblyProductAttribute" value="ClassLibrary1" />
                <attribute type="AssemblyCopyrightAttribute" value="Copyright (c) 2007" />
                <attribute type="AssemblyTrademarkAttribute" value="" />
                <attribute type="AssemblyCultureAttribute" value="" />
 
                <attribute type="ComVisibleAttribute" value="false" />
 
                <attribute type="GuidAttribute" value="f98c8021-fbf1-44ff-a484-946152cefdb8" />
 
                <attribute type="AssemblyVersionAttribute" value="1.0.0.0" />
                <attribute type="AssemblyFileVersionAttribute" value="1.0.0.0" />
            </attributes>
        </asminfo>
    </target>
</project>

This will product a default AssemblyInfo.cs file that looks like this:

using System.Reflection;
using System.Runtime.InteropServices;
 
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:2.0.50727.42
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
 
[assembly: AssemblyTitleAttribute("ClassLibrary1")]
[assembly: AssemblyDescriptionAttribute("")]
[assembly: AssemblyConfigurationAttribute("")]
[assembly: AssemblyCompanyAttribute("")]
[assembly: AssemblyProductAttribute("ClassLibrary1")]
[assembly: AssemblyCopyrightAttribute("Copyright (c) 2007")]
[assembly: AssemblyTrademarkAttribute("")]
[assembly: AssemblyCultureAttribute("")]
[assembly: ComVisibleAttribute(false)]
[assembly: GuidAttribute("f98c8021-fbf1-44ff-a484-946152cefdb8")]
[assembly: AssemblyVersionAttribute("1.0.0.0")]
[assembly: AssemblyFileVersionAttribute("1.0.0.0")]

Notice however a few things. First is the Guid. We had to hard code that which might be okay, but lets dig into NAnt scripting by replacing it with a real Guid. NAnt also has the ability to let you write embedded code (C#, VB.NET, etc.) via the <script> task, so let's write a small task to do that. We'll just have it generate a new Guid and set a new custom property in the NAnt script that we'll use in our asminfo task. Create a property in the NAnt script to hold our Guid:

<property name="project.guid" value="f98c8021-fbf1-44ff-a484-946152cefdb8" />

Then use that property in our GuidAttribute:

<attribute type="GuidAttribute" value="${project.guid}" />

Finally here's the task to generate a Guid via NAnt (make the default UpdateAssemblyInfo task dependent on this one):

<target name="CreateUniqueGuid">
    <script language="C#">
        <code>
            <![CDATA[
                public static void ScriptMain(Project project) {
                    project.Properties["project.guid"] = Guid.NewGuid().ToString();
                }
            ]]>
        </code>
    </script>
</target>

Great. We now have a NAnt script that will generate a new version file with a unique Guid everytime. Next we want to tackle the versioning issue.

As described by Jensen Harris here, the Microsoft Office scheme is pretty simple:

  • Take the year in which a project started. For Office "12", that was 2003.
  • Call January of that year "Month 1."
  • The first two digits of the build number are the number of months since "Month 1."
  • The last two digits are the day of that month.

Using this we'll need to setup a couple of properties. One is to hold the year the project starts, the other is the build version we want to set:

<property name="project.year" value="2003" />
<property name="build.version" value="1.0.0.0" />

Now we could write a lot of NAnt code as there are functions to manipulate dates, but it's much easier using the <script> task and some C#. Here's the NAnt task to generate the build number using the Microsoft Office approach:

<target name="GenerateBuildNumber">
    <script language="C#">
        <imports>
            <import name="System.Globalization" />
            <import name="System.Threading" />
        </imports>
        <code>
            <![CDATA[
                public static void ScriptMain(Project project) {
                    Version version = new Version(project.Properties["build.version"]);
                    int major = version.Major;
                    int minor = version.Minor;
                    int build = version.Build;
                    int revision = version.Revision;
 
                    int startYear = Convert.ToInt32(project.Properties["project.year"]);
                    DateTime start = new DateTime(startYear, 1, 1);
                    Calendar calendar = Thread.CurrentThread.CurrentCulture.Calendar;
                    int months = ((calendar.GetYear(DateTime.Today)
                        - calendar.GetYear(start)) * 12)
                        + calendar.GetMonth(DateTime.Today)
                        - calendar.GetMonth(start);
                    int day = DateTime.Now.Day;
                    build = (months * 100) + day;
 
                    version = new Version(major, minor, build, revision);
                    project.Properties["build.version"] = version.ToString();
                }
            ]]>
        </code>
    </script>

We get the version in the NAnt script as a starter (since we're only replacing the build number) and then assign values to it (they're read-only in .NET). Then this is written back out to the property as a string.

If this is run today (February 17, 2007) it's been 49 months since the start of 2003 and today is the 17th day. So the build number is 4917. 

Here's the finaly output from this NAnt script:

using System.Reflection;
using System.Runtime.InteropServices;
 
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:2.0.50727.42
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
 
[assembly: AssemblyTitleAttribute("ClassLibrary1")]
[assembly: AssemblyDescriptionAttribute("")]
[assembly: AssemblyConfigurationAttribute("")]
[assembly: AssemblyCompanyAttribute("")]
[assembly: AssemblyProductAttribute("ClassLibrary1")]
[assembly: AssemblyCopyrightAttribute("Copyright (c) 2007")]
[assembly: AssemblyTrademarkAttribute("")]
[assembly: AssemblyCultureAttribute("")]
[assembly: ComVisibleAttribute(false)]
[assembly: GuidAttribute("a6e7ff79-63ba-443f-8bc3-0c4b43f43ffe")]
[assembly: AssemblyVersionAttribute("1.0.4917.0")]
[assembly: AssemblyFileVersionAttribute("1.0.4917.0")]
 

And here's the full NAnt script:

    1 <?xml version="1.0"?>
    2 <project name="Test" default="UpdateAssemblyInfo">
    3 
    4     <property name="project.guid" value="f98c8021-fbf1-44ff-a484-946152cefdb8" />
    5     <property name="project.year" value="2003" />
    6     <property name="build.version" value="1.0.0.0" />
    7 
    8     <target name="UpdateAssemblyInfo" depends="CreateUniqueGuid, GenerateBuildNumber">
    9         <asminfo output="AssemblyInfo.cs" language="CSharp">
   10             <imports>
   11                 <import namespace="System.Reflection" />
   12                 <import namespace="System.Runtime.InteropServices" />
   13             </imports>
   14             <attributes>
   15                 <attribute type="AssemblyTitleAttribute" value="ClassLibrary1" />
   16                 <attribute type="AssemblyDescriptionAttribute" value="" />
   17                 <attribute type="AssemblyConfigurationAttribute" value="" />
   18                 <attribute type="AssemblyCompanyAttribute" value="" />
   19                 <attribute type="AssemblyProductAttribute" value="ClassLibrary1" />
   20                 <attribute type="AssemblyCopyrightAttribute" value="Copyright (c) 2007" />
   21                 <attribute type="AssemblyTrademarkAttribute" value="" />
   22                 <attribute type="AssemblyCultureAttribute" value="" />
   23 
   24                 <attribute type="ComVisibleAttribute" value="false" />
   25 
   26                 <attribute type="GuidAttribute" value="${project.guid}" />
   27 
   28                 <attribute type="AssemblyVersionAttribute" value="${build.version}" />
   29                 <attribute type="AssemblyFileVersionAttribute" value="${build.version}" />
   30             </attributes>
   31         </asminfo>
   32     </target>
   33 
   34     <target name="CreateUniqueGuid">
   35         <script language="C#">
   36             <code>
   37                 <![CDATA[
   38                     public static void ScriptMain(Project project) {
   39                         project.Properties["project.guid"] = Guid.NewGuid().ToString();
   40                     }
   41                 ]]>
   42             </code>
   43         </script>
   44     </target>
   45 
   46     <target name="GenerateBuildNumber">
   47         <script language="C#">
   48             <imports>
   49                 <import name="System.Globalization" />
   50                 <import name="System.Threading" />
   51             </imports>
   52             <code>
   53                 <![CDATA[
   54                     public static void ScriptMain(Project project) {
   55                         Version version = new Version(project.Properties["build.version"]);
   56                         int major = version.Major;
   57                         int minor = version.Minor;
   58                         int build = version.Build;
   59                         int revision = version.Revision;
   60 
   61                         int startYear = Convert.ToInt32(project.Properties["project.year"]);
   62                         DateTime start = new DateTime(startYear, 1, 1);
   63                         Calendar calendar = Thread.CurrentThread.CurrentCulture.Calendar;
   64                         int months = ((calendar.GetYear(DateTime.Today)
   65                             - calendar.GetYear(start)) * 12)
   66                             + calendar.GetMonth(DateTime.Today)
   67                             - calendar.GetMonth(start);
   68                         int day = DateTime.Now.Day;
   69                         build = (months * 100) + day;
   70 
   71                         version = new Version(major, minor, build, revision);
   72                         project.Properties["build.version"] = version.ToString();
   73                     }
   74                 ]]>
   75             </code>
   76         </script>
   77     </target>
   78 
   79 </project>

Enjoy!


ReSharper Blog Post Series

For all of the .NET Developers, if you are using ReSharper, there is a good blog post series going on at http://excastle.com/blog/ .

If you are not using ReSharper and are wondering what it is, you can view details about it at http://www.jetbrains.com/resharper/


Microsoft Patterns and Practice Lab Video

Channel 9 has a pretty cool video on the patterns and practice lab and how they set it up to enable the agile development that they do. I would love to have a setup like this. The workspace looked fairly fun to work in.

http://channel9.msdn.com/Showpost.aspx?postid=238321

 


The Programming Divide

I have to say that I completely agree with the blog post below.  I have experienced many developers that could code but were not good developers.

Original Blog Post From: http://codebetter.com/blogs/jeremy.miller/archive/2007/01/31/Being-a-Better-Programmer.aspx

There's a flurry of great posts and comment discussions going on right now about the divide between good developers and bad developers

 

The Great Divide

Like Jeff Atwood, I do believe there is an almost binary switch between effective and ineffective developers.  I'm not exactly sure why this is, but if you'll indulge me, I've got a couple pet theories:

  • People that are good coders are able to do make code work faster, which leads to getting more experience than their slower , and spare more thought cycles for how to do things better next time.  The innately talented developer is able to get better and faster each time, which gives him or her more time to invest in getting better.  From there I think it's simply a snowball effect.
  • To Phil Haack's point that it's not entirely innate ability, any degree of contemplative thoughtfulness on the part of a developer will make that developer much better over time.  The smartest guy in the world can still be intellectually lazy (but I don't see how you *could* be smart without intellectual inquisitively).  Thoughtful people gain more valuable experience.  People who aren't thoughtful may only be practicing their typing skills.
  • Joannes added this as a prerequisite for being a great developer:  "… a passionate curiosity for software related matter …."  Every very good or great developer I've ever worked with enjoyed software development.  I've been interviewing developer candidates lately, and a passion and intellectual curiosity about software development counts far more with me than Trivial Pursuit Q&A exchanges.
  • Software development takes a very strong ability for abstract thought.  I don't think that concrete thinkers have an easy time with software that's by definition a mental model of something else.  I'd say visualization is important, but I've worked with good developers who had zero visualization ability.  All the great developers I've worked with did though.  People do think differently and have different modes of learning.  

 

You can get Better

Like everyone else I believe that your best bet is to hire the best and brightest, but in reality you have who you have.  Maybe the hiring process gets you the wide swings in productivity, but wringing out a 10-30% productivity gain out of journeyman developers is still a substantial gain.  Training, coaching, discipline, better practices, communication techniques -- they can all contribute to productivity.  "It's not the methodology, it's the man" is a hackneyed and cheap way to get some sort of imaginary high ground in any discussion, but it's partially BS.  Anybody can get better, even if it's only in the way they interract with other people in the team.  Besides, it's extremely unlikely that you can instantly go and replace poorly performing team members with better developers at will.  You're largely stuck with the folks that you have.  Making them better is probably your only option.

Following a tangent, when any debate about software practices or processes is going on some clown always pulls out this phrase:  "you should just pick the best practices from waterfall, XP, Agile, RUP, whatever..."  Hah!  I've now seized the high ground you might think.  No you haven't, you've simply indulged in the intellectual equivalent of empty calories.  It's a worthless statement.  The question "what *is* the best way to work" is still on the table.  If we knew what the best of everything was, without a shred of doubt, we wouldn't be having the debate, now would we?  Plus it's even harder than that because mix and match practices might not work well because many practices reinforce each other.  I think you could happily add TDD and CI to any methodology and get some benefits, but they shine a bit more in an adaptive process.  On the other hand, doing continuous design or adaptive project management on a codebase without automated tests and CI sounds dangerous to me.


How to get users to RTFM

Good post on how to get users to read the manual.  The post is a little but it has some good points.

How to get users to RTFM


Test Types

Great Post on Test Types

from: http://blogs.msdn.com/ploeh/archive/2006/08/27/727211.aspx

 There's not a single clear definition of what a unit test is and the fact that you can use unit testing frameworks (such as Visual Studio 2005 Team System or NUnit) to drive not only unit tests, but also other types of tests, confounds the issue.

Although some people find such categorization semantic (or even pedantic), I distinguish between the following test types:

  • Unit tests subject a single unit to various stimuli in isolation from its volatile dependencies. In my terminology, when talking about .NET, a unit corresponds to an assembly, although other people view a unit as corresponding to a specific type. Viewing a unit as a single type is, in my opinion, too specific, as it effectively prohibits scenario-driven (or agile) development methods, since you will not be able to test the interaction between several types in the same assembly.
    Isolation from volatile dependencies is essential, because it enables you to develop your unit without having to rely on its dependencies.
  • Integration tests cover a wide variety of scenarios where you connect two or more units into an integrated subsystem. This covers the simple case where two units are used together in the same process; e.g. if you want to test the interaction between a UI controller unit and a domain logic unit.
    Integration tests can also span process or even machine boundaries, which is the case if you test a data access component against a relational database system, or if you test a web service by making requests against it using a proxy class.
    Sometimes I wish the terminology would allow us to distinguish between the in-proc and out-of-process scenarios, but they are all integration tests.
    Since integration tests involve the interaction of several moving parts, they are typically more difficult to set up to run as fully automated tests, although unit testing frameworks such as Visual Studio 2005 Team System are well suited also for this task.
  • System tests are by some also called acceptance tests. These test a system in its entirety, by using its intended interfaces - typically its user interface.
    Since the entire application, including user interfaces, is being tested, it is typically very difficult to run system tests in a fully automated fashion, because there is often much deployment and configuration to be done.

As you can see from the comments to my earlier post, people sometimes feel they have problems with unit tests, when in fact they have problems with integration tests. Integration tests are more difficult to configure for full automation, which is why I recommend that you try to test as much of your code as possible with unit tests.

For example, instead of testing a web service with an integration test where you make requests against the service using a proxy class, you should impement the service logic in a testable unit (i.e. a library), and then unit test that logic. Exposing the service as a web service will then be a simple case of implementing the Remote Façade design pattern, and you probably will not need to test the web service at all, because its implementation will be very simple.

That is not to say that I don't recommend integration or system tests - these can provide valuable insights into the interaction of multiple components that would be difficult to reproduce otherwise. Because integration and system tests are more difficult to automate than unit tests, you can get more value for your effort early in the development process with unit tests, but as you approach project completion, you need to begin testing the complex interactions.


Free eBook Essential Skills for Agile Development

I stumbled upon this freely downloadable EBook (though you can also buy it at Amazon in Print) called Essential Skills for Agile Development (external). You can download it as PDF from www.AgileSkills.Org (external)I haven't read it yet, but it seems like a nice recap of some of the most essential skills a developer would want to learn first. they specifically state they are going for the 80-20 rule: teaching the 20% of skills that gets you 80% there in terms of agility.