Devlico.Us
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @devlicious

Christopher Bennage

Our WPF book is now available!

August 2007 - Posts

  • Tallahassee Code Camp

    Registration is now open for the 3rd annual Tallahassee Code Camp.

    It will be held on September 22nd, at Florida State University kicking off at 8AM. I'm very excited as this will be my first time presenting at a Code Camp.  I'm going to do an introductory session on TDD.  (It's really going to be a summary of what I've learned over the last 3 years with test driven.)

    Rob Eisenberg will presenting as well. We'll be handing out a couple of free ReSharper licenses that JetBrains was kind enough to donate.  Red Gate and others are donating some goodies as well, there's even some rumor of an Xbox 360 giveaway!

    Click here to register.  It's free!

  • TDD Example: Querying a Repository

    I'm always a little intimidated when I post code examples.  There are a lot of smart (and opinionated) people out there reading blogs.  Fear won't get us anywhere though.  That said, I'm posting this example and asking for criticism.

    Here's the story.  A school of music needs to schedule auditions for incoming students. The faculty need to be able to view the schedule for the next two upcoming terms, and some of staff needs to be able to edit the audition schedule.

    The "schedule" is really a set of rooms set aside on certain dates for certain types of students.  For example, room 1874 will be used for violins on September 21. Thus, a ScheduledRoom is a certain on a certain date, with rules about who can audition there.  Right now, we're just concerned with retrieving the list of rooms for a given Term, which is a unique combination of year and semester.

    We have a repository for handling audition schedules, and a service that talks to the repository.  The service is in turn accessed by a desktop client, and a web client.  I'm going to focus on just the repository here.

    namespace Specifications.Integrated.The_repository_for
    {
        [TestFixture]
        public class the_audition_schedule
        {
            private AuditionScheduleRepository _repository;
    
            [SetUp]
            public void SetUp
            {
                _repository = new AuditionScheduleRepository();
            }
    
            [Test, RollBack]
            public void can_retrieve_the_list_of_scheduled_rooms_for_a_given_term()
            {
                //setup data for test
                Term fall2000 = a_term_for_Fall_2000();
                Term spring2001 = a_term_for_Spring_2001();
    
                schedule_a_room_for_(fall2000);
                schedule_a_room_for_(fall2000);
                schedule_a_room_for_(fall2000);
                schedule_a_room_for_(spring2001);
    
                //here's the actual code under test
                IList<ScheduledRoom> rooms = _repository.GetRooms(fall2000);
    
                //verify the results
                Assert.AreEqual(3, rooms.Count);
            }
        }
    }
    

    The methods a_term_for_Fall_2000(), a_term_for_Spring_2001(), and schedule_a_room_for_() are helper methods that do nothing more than persist some test data.  In my [Setup], I create a new instance of _repository, so that it's fresh for every test.

    What am I really testing here?  An important question, Joey Beninghove has a good post on the topic here.

    I want to ensure that GetRooms() behaves the way I expect.  I expect it to return 3 out of the 4 terms I have persisted. The actual implementation for GetRooms() builds an NHibernate.ICriteria and call its List<>() method.

    Thoughts? Comments?  More examples to come...

    kick it on DotNetKicks.com
  • Confidence in your code

    First, I highly recommend Kent Beck's Test Driven Development: By Example.  It's an excellent book.

    I mentioned Beck's book, because it is there that I gained an insight affecting the way I'm writing unit tests.  (So Christopher, you're saying that one of the seminal works on unit testing has affected the way you are writing tests?  Um, yes, I am saying that.)

    Kent asks a question about when you should remove duplicate or overlapping tests.  His answer was that if it doesn't decrease your confidence in the code, then it's okay to delete it.  (I hope I'm getting that right, my copy is loaned out at the moment.)

    My current project uses WCF to handle communication from the desktop client to the server.  We have a set of interfaces for our services shared in a common assembly.  When I create a new interface, I always forget to decorate it with the ServiceContract attribute, or I'll create a DTO and forget the DataContract/DataMember attributes, or (and here's the worst) I'll forget to add the PrincipalPermission attribute to the actual implementation of our services!

    This has been bothering me for a month or two, and finally it dawned on me: why don't I write tests for all of this?  I'm not confident in the code, I'm fearful that I'm forgetting things; let's write tests and remove the doubt!

    Here's what one of the tests looks like:

    [TestFixture]
    public class Service_interfaces
    {
    	private const string ASSEMBLY = "SomeAssembly";
    	private const string SERVICE_NAMESPACE = "ServiceInterfaces";
    
    	[Test]
    	public void must_have_a_ServiceContract_attribute()
    	{
    		bool atLeastOne = false;
    
    		foreach (Type type in Assembly.Load(ASSEMBLY).GetTypes())
    		{
    			if (type.Namespace.Contains(SERVICE_NAMESPACE))
    			{
    				atLeastOne = true;
    
    				object[] attributes = type.GetCustomAttributes(typeof (ServiceContractAttribute), false);
    				Assert.IsTrue(attributes.Length > 0,
    							  string.Format("The {0} does is not decorated with the ServiceContractAttribute", type));
    			}
    		}
    
    		Assert.IsTrue(atLeastOne,
    					  string.Format("No service interfaces were found in {0} in the namepace {1}.",
    									ASSEMBLY,
    									SERVICE_NAMESPACE));
    	}
    }

    So I am just the last on the bus?  What do you think?  Is there a better way to handle this? 

  • Continuous Integration with Draco.NET

    At our most recent .NET users group meeting, Joe Healy asked for a show of hands for those doing Continuous Integration.  There were about 40 of us and (I'm pretty sure) no one raised their hand.

    A few years back, I had a NAnt script that was scheduled to execute nightly (you could also call it manually via a classic ASP page).  The script would grab the source from Subversion, build it, execute some SQL scripts to construct a fresh database, bcp in some data, and finally publish the Web application to the staging server. (Notice that I didn't mention anything about unit testing). This was the closest I ever got to Continuous Integration, and I was tempted to raise my hand.

    Why I didn't do it...

    I've thought about CI many times over the years, but I kept putting it off.  The configuration challenge was always a bit daunting. A couple of months ago, I started to get excited again after watching the dnrTV episode on CI Factory. However, even with the simplification brought about by CI Factory, it didn't quite seem worth the effort.  (I should punctuate that we are still a small shop operating in teams of 2 or 3). 

    I had mostly experimented with CruiseControl.NET in the past, and the configuration was more than I wanted to deal with.

    I Value Simplicity.

    Or as Ayende might say Zero Friction.  I imagine that CC.NET might have been zero friction to use, if I had ever gotten past the setup.  (I will readily admit a good deal of laziness here).

    After Joe's admonition about not doing CI, I asked Google about my choices for CI in the .NET world and it reminded me of Draco.NET.

    I installed Dract.NET, and I was happily doing CI within an hour.

    How to configure Draco.NET

    Specifically, I will step through how I set it up to work with Subversion 1.4.4 and NAnt 0.85.

    • Download Draco Server 1.6.4 from here.
    • The installer will create a service named "Draco.NET".
      In order to have this service work properly with NAnt I had to run it under domain account.  (At first I used Local System Account with Allow service to interact with desktop, but it reported a File Not Found when it attempted to call nant.exe.)
    • Add the bin directory for NAnt to your path.  Additionally, I copied the some assemblies from NAntContrib and MbUnit in the NAnt bin directory in order to access tasks for msbuild and MbUnit within my NAnt script.
    • The install will create a directory at "C:\Program Files\Draco.NET Service" and place two config files in a subdirectory bin.
    • The default Draco.exe.config is fine, but I recommend taking a look at it.
    • The other file, Draco.builds.config, tells Draco what projects to monitor.  It can point to many projects under diverse source control. 
    • I deleted all of the <build/> nodes expect for the one referencing Subversion. You will have one <build/> node for every project the server monitors.
    • Inside the <build /> node:
      <name /> is merely a unique name to identify the project.
      <nant /> tells Draco to use NAnt to execute the build process, and points to your build file within the source that it checked out.
      <svn /> tells Draco the repository that it will monitor for this build.  You'll probably want to create a readonly account for Draco to use.

    What Draco does

    Aside from hating Harry Potter...

    Draco will poll the repository in the build every 60 by default.  If it finds any modifications since the last build, it will wait for the repository to be quiet for a designated amount of time (again 60 seconds by default).  Quiet means no further commits during the period.  After the repository been quiet, it will check out the source to a temp directory and then execute NAnt script.

    At this point, it is really up to your NAnt script.  Currently, mine is very simple.  It calls msbuild to compile the solutions, and then calls MbUnit to execute the tests.

    Monitoring the Build

    Draco.NET has a client for monitoring the status of builds available here.  I installed 1.6.4, and it did not add anything to my start menu.

    It installed a help file to this location:
    C:\Program Files\Draco.NET Client Tools\Draco.chm

    And a monitoring app that runs in the systray here:
    C:\Program Files\Draco.NET Client Tools\bin\DracoGui.exe

    In addition to monitoring, you can:

    • Start Build - which tells Draco to check the repository for modifications, but only starts the build if there has been a change.
    • Force Start Build - which kicks off a build even if there no modifications.

    Finally, there is an install for monitoring builds over the Web, but I haven't played with that yet.

    kick it on DotNetKicks.com
  • Scrumming for the first time

    We finished our second sprint today.  In fact, I just left the Sprint Retrospective Meeting (which was actually quite brief).

    We've been very lucky to have a client that insisted on using Scrum to manage the project.  Before this I only had a cursory knowledge of Scrum. We are a small shop, and while we've been influenced significantly by Extreme Programming (XP), we haven't had the mass to implement all the practices we'd like.

    What is Scrum?

    I discovered quickly that I had a misconception about Scrum.  I had assumed that it was just a different flavor of the same thing as XP. But there's a difference of scale, Scrum is about managing a project, or multiple projects.  Within Scrum you might have multiple teams, and each of those teams is responsible for Self Organizing.  XP is one way for a team to self-organize.  In this way, XP fits nicely inside of Scrum. 

    I began reading Ken Schwaber's book just before this project started.  I highly recommend it.  It is a set of case studies discussing how Scrum works, and it comes across as honest and realistic.

    The significant parts of Scrum, as adapted from Ken's book, are:

    • Scrum Master - The individual responsible for managing the Scrum process.  The Scrum Master's job is to facilitate the project. On our current project, this role is filled by our client's IT Director.
    • Product Owner - The representative of the stakeholders.  An individual responsible for making the final decisions about what needs to get done.  On our current project, this role is filled by an employee who was a Power User of the legacy system we are replacing.
    • The Team - The people responsible for doing the work.  In this case, it's my company.
    • Sprint - Typically, a sprint is a 30 day span of time, during which the team is working toward a specific goal.  On our current project, sprints are just two weeks (some XP influence here).  I think 30 days is preferable though.
    • Product Backlog - this is the list of requirements.  It can always be added to.  In our case, it is a list of User Stories.  Each sprint begins with a meeting to decide which stories from the Product Backlog will be worked on in the upcoming sprint.  The stories that the team commits to are then moved the Sprint Backlog.
    • Daily Scrum - A daily, but brief meeting, where the Scrum Master has the the team answer three questions: What did you do yesterday? What are you doing today? And what is getting in your way?

    First Impressions

    I will first acknowledge my basis: I believe in Agile methodology and the concepts underlying Scrum resonate with me. 

    But how does it shake out in practice?

    I think that Scrum is a great way to manage software projects.  Possibly, the best that I have attempted. However, based on my limited experience here are few things to consider.

    It is hard to write good user stories.  I've struggled with this for several years now, and I hate to admit it. The problem mostly lies with my tendency toward optimism. We'll write some initial stories, they'll sound great to the stakeholders.  We commit to delivering them by such and such a date, then we begin to realize that we left out a number of prerequisites.  I always pad my numbers, so it has always worked out, but it feels too much like guess work to me.  (I have Mike Cohn's User Stories Applied on my desk, but I have to finish finding out what happens to Harry first.)

    The mechanics of tracking are awkward. We've been using TargetProcess to keep track of the Product Backlog, monitor burn down, etc.  I had used version 1.x and I liked it, however 2.x is a little overkill I think.  I believe that it's likely a great tool, but I lack the patience to overcome the learning curve, at least at the moment. 4 x6 note cards are becoming  more and more attractive to me.  (I also like white boards!)

    Ok, so neither of these caveats is the fault of Scrum.  However, they both fall in a region that Scrum leaves undefined.

    Finally

    I think it is hard to sell Scrum to a client.  We are a consulting company.  Our clients come to us and they want to know exactly how much they will spend to get custom software. We all know that it is inherently impossible to predict the cost of developing custom software.  Scrum (and agile practices in general) acknowledge this and provide a solution.  However, clients still want a commitment to deliver X for Y amount of money in Z amount of time.  It is hard to convince a client to work with something "open-ended" like Scrum.  (I think that this is not a problem for in house projects). Again, we've been very been very blessed to have a client who understands custom software development and asked for this.

    kick it on DotNetKicks.com
More Posts

Our Sponsors

Red-Gate!