Browsing Posts in Agile

Coming to a .NET User Group near you*… This Tuesday only…

Topic: Light Up Your Application with Convention-Over-Configuration
Date: Tuesday, February 24, 2009 Postponed
Time: 5:00 pm – 5:15 pm (registration)
  5:30 pm – ??? (presentation)
Location: Nexen Conference Center
801-7th Ave. S.W., Calgary, AB. (Plus 15 level)
Map

Inversion of Control (IoC) containers, such as Castle Windsor, increase the flexibility and testability of your architecture by decoupling dependencies, but as an application grows, container configuration can become onerous. We will examine how convention-over-configuration can allow us to achieve simplicity in IoC configuration while still maintaining flexibility and testability. You can have your cake and eat it too!

* Assuming that you live in Calgary. smile_regular

A friend, having recently upgraded to Rhino Mocks 3.5, expressed his confusion regarding when to use mocks vs. stubs. He had read Martin Fowler’s Mocks Aren’t Stubs (recommended), but was still confused with how to actually decide whether to use a mock or a stub in practice. (For a pictorial overview, check out Jeff Atwood slightly NSFW photo montage of dummies, fakes, stubs, and mocks.) I thought I’d share my response which cleared up the confusion for my friend…

It’s easy to get confused. Basically, mocks specify expectation. Stubs are just stand-in objects that return whatever you give them. For example, if you were testing that invoices over $10,000 required a digital signature…

// Arrange
var signature = DigitalSignature.Null;
var invoice = MockRepository.GenerateStub<IInvoice>();
invoice.Amount = new Money(10001M);
invoice.Signature = signature;
var signatureVerifier = MockRepository.GenerateMock<ISignatureVerifier>();
signatureVerifier.Expect(v => v.Verify(signature)).Return(false);
var invoiceRepository = MockRepository.GenerateMock<IInvoiceRepository>();
var accountsPayable = new AccountsPayable(signatureVerifier, invoiceRepository);
 
// Act 
accountsPayable.Receive(invoice);
 
// Assert 
invoiceRepository.AssertWasNotCalled(r => r.Insert(invoice));
signatureVerifier.VerifyAllExpectations(); 

I don’t have a real invoice. It’s a proxy generated by Rhino Mocks using Castle DynamicProxy. You just set/get values on the properties. Generally I use the real object, but stubs can be handy if the real objects are complex to set up. (Then again, I would consider using an ObjectMother first.)

Mocks on the other hand act as probes to detect behaviour. We are detecting whether the invoice was inserted into the database without requiring an actual database. We are also expecting the SignatureVerifier to be called and specifying its return value.

Now the confusing part… You can stub out methods on mocks too. If you don’t care whether a method/property on a mock is called (by you do care about other aspects of the mock), you can stub out just that part. You cannot however call Expect or Stub on stubs.

UPDATE: I’m including my comments inline as they respond to important points raised by Aaron and John in the comments here and many readers don’t bother looking through comments. :)

@Aaron Jensen – As Aaron points out in the comments, you are really mocking or stubbing a method or property, rather than an object. The object is just a dynamically generated proxy to intercept these calls and relay them back to Rhino Mocks. Whether it’s a mock/stub/dummy/fake doesn’t matter.

Like Aaron, I prefer AssertWasCalled/AssertWasNotCalled. I only use Expect/Verify if the API requires me to supply return values from a method/property as shown above.

I also have to agree that Rhino Mocks, while a great mocking framework that I use everyday, is showing its age. It has at least 3 different mocking syntaxes (one of which I contributed), which increases the confusion. It’s powerful and flexible, but maybe a bit too much. Rhino Mocks vNext would likely benefit from deprecating all but the AAA syntax (the one borrowed from Moq) and doing some house-cleaning on the API. I haven’t given Moq an honest try since its initial release so I can’t comment on it.

@John Chapman – Thanks for the correction. I’ve had Rhino Mocks throw an exception when calling Expect/Stub on a stub. I assumed it was expected behaviour that these methods failed for stubs, but it looks like a bug. (The failure in question was part of an overly complex test and I can’t repro the issue in a simple test right now. Switching from stub to mock did fix the issue though.) stub.Stub() is useful for read-only properties, but generally I prefer getting/setting stub.Property directly. Still stub.Expect() and stub.AssertWasCalled() seems deeply wrong to me. :)

My first dnrTV episode went live today. I am talking with Carl Franklin about dependency inversion, dependency injection, and inversion of control. I demonstrate how to build a very simple IoC container. My intent is to show developers that it isn’t any thing crazy scary. I talk about how IoC facilitates decoupling dependencies and creating more easily testable software. Check it out!

dnrTV #126: James Kovacs’ roll-your-own IoC container

Feedback is always welcome.

Carl and I plan to do another show focused on IoC containers in the next few weeks. Specifically we’ll be talking about what a full-fledged container offers over and above the roll-your-own. If you have other IoC questions you would like answered on the next show, drop me an email.

I’m writing some integration tests around the .NET PetShop, which has no tests whatsoever. Since the architecture is tightly coupled, you can’t really start writing unit tests effectively. You have to start applying Michael Feather’s techniques for breaking dependencies. Before doing that, I want some smoke tests around the application. That’s where WatiN comes in. I am writing integration tests at the browser level. These tests are slow because you’re exercising the full stack – browser to web server to database. You need at least some of these full stack tests in every application. A good heuristic (for a large application) is a few dozen full stack integration tests, a few hundred presenter/controller integration tests, and a few thousand unit tests. (Smaller applications would probably be a dozen full stack integration, 50 presenter/controller integration, and a few hundred unit tests.) Enough testing theory… I wrote the following unit test:

[Test]

public void CanLoadHomePage() {

    using(var ie = new IE(“http://localhost:9999″)) {

        Assert.AreEqual(“Welcome to .NET Pet Shop Evolved”, ie.Title);

    }

}

 

When I ran the test (using Gallio‘s awesome ReSharper 4 Unit Test Runner support for MbUnit), Internet Explorer appeared, but I got a failed unit test:

image

and this stack trace (reproduced in text form from the image for Google’s indexing benefit):

WatiN.Core.Exceptions.TimeoutException: Timeout while waiting for main document becoming available
   at WatiN.Core.WaitForComplete.ThrowExceptionWhenTimeout(String timeoutMessage)
   at WatiN.Core.WaitForComplete.WaitWhileMainDocumentNotAvailable(DomContainer domContainer)
   at WatiN.Core.WaitForComplete.WaitForCompleteOrTimeout()
   at WatiN.Core.IEWaitForComplete.DoWait()
   at WatiN.Core.DomContainer.WaitForComplete(IWait waitForComplete)
   at WatiN.Core.IE.WaitForComplete()
   at WatiN.Core.IE.CreateNewIEAndGoToUri(Uri uri, LogonDialogHandler logonDialogHandler, Boolean createInNewProcess)
   at WatiN.Core.IE..ctor(String url)
   at WatiNTests.HomePageTests.CanLoadHomePage

 

Alrighty then. A TimeoutException and the Internet Explorer* instance was left stranded on my desktop. Taking a look at WatiN’s FAQ, I find this:

Which windows versions are supported?

Windows 2000, Windows XP and Windows 2003. Using WatiN on Vista gives some problems when User Account Control (UAC) is enabled. If you disable UAC almost all WatiN unit tests pass.

Disable UAC to run a testing framework??? Note that I’ve used WatiN on Vista before without disabling UAC. So it had to be some other setting. I noticed that Internet Explorer was running in Protected Mode, which dramatically limits the damage that a hijacked browser can do. Protected Mode runs IE in low integrity mode. (Low integrity processes are dramatically limited in which window messages they can send to higher integrity processes – such as Visual Studio and where they can read/write files.)

image

Solution

The obvious solution is to turn off IE Protected Mode for the site. Easiest way to do this? Add the site to your trusted sites list.

image

Survey says!

image

image

So rather than turning off UAC or Protected Mode in IE completely, you can just add the site under test to your trusted sites list and WatiN works.

For the Paranoid

The astute among you may be wondering if I haven’t opened up a security vulnerability by adding http://localhost to my trusted sites list. Let’s put it this way… If some l33t haxor can drop files on your box and start a webserver, they have already pwned your box. They don’t need you to navigate to a local site with unprotected IE to infect you more. smile_tongue

* For the curious, I rarely use IE, mostly just for certain Microsoft sites that are still IE only. Heck, I’ve been running RCs of FireFox 3 for awhile and upgraded to the RTM version yesterday when it was released. If you haven’t tried FireFox 3, you really need to. Gmail is oodles faster in FF3 than IE or FF2. You might wonder why I’m using IE with WatiN… WatiN only started supporting FireFox as of WatiN v2, which is currently in CTP. Historically WatiN (and WatiR) have relied on IE’s COM automation API to interact with the browser, which is also why WatiN/R doesn’t provide a way of getting HTTP status codes – because the COM API doesn’t expose them!

Another DevTeach has come and gone. I had an awesome time. I enjoyed hanging out with old friends and meeting some new ones. I saw a lot of great sessions, but the best part, as always, is the hallway and bar conversations. (No, I still haven’t quite figured out Metastones, even after playing for hours.) I wanted to especially thank everyone involved in the agile track – both presenters and attendees. I have received a lot of positive feedback on the track. Given that I organized the track, I am immensely pleased with its success.

You can download my slides and demos from here or the DevTeach site.

Achieving Persistence Ignorance with NHibernate (2.6 MB)

Taming Software Dependencies with DI and IoC (20.9 MB)

I have started keeping my latest presentations online in Google Code’s Subversion repository.

svn checkout http://jameskovacs.googlecode.com/svn/Presentations/

Take a look in the tags to get the slide deck and demos for a particular event. For example, you’ll find tags/DevTeachToronto2008 contains the version from – surprise, surprise – DevTeach Toronto 2008. If you have any questions or comments on slides, demos, or techniques, please don’t hesitate to email me.

DevTeach is returning to Montreal on December 1 to 5, 2008. I’ll be the Agile Track Tech Chair again. Jean-Rene will be putting out a call for sessions in the near future and you should find the announcement here. If you are interested in speaking in the Agile Track, feel free to email me. If you attended any sessions in the Agile Track and have suggestions for things that you’d like to see again or suggestions for improvement, email me!

During my geekSpeak screencast last week, one of the attendees asked:

Any recommendations for refactoring existing code to insert interfaces? (e.g., what’s the best dependency to break first, the database?)

Excellent question! Most of us do not have the luxury of working on greenfield projects, but instead work on brownfield projects – existing applications that could use some tender loving care. Brownfield projects are often inflicted with legacy code. What do I mean by legacy code? I agree with Michael Feathers’ definition:

Legacy code is simple code without tests.

Michael elaborates further saying:

Code without tests is bad code. It doesn’t matter how well written it is; it doesn’t matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don’t know if our code is getting better or worse.

If you haven’t read Michael’s book, Working Effectively with Legacy Code, you really must. It is on my short list of must-read development books. Michael provides excellent strategies and patterns for safely implementing tests around untested code, which is crucial in order to make non-breaking changes to an existing application AKA refactoring. If you can refactor your code, you can improve your code.

Now back to the question at hand… Which dependency to break first? Let me turn the question around. Which dependency is causing you the most pain?

In my experience, it is typically the database as round-tripping to a database on each test to fetch or save data dramatically slows the tests down. If you have slow tests, you’ll be unlikely to run them as often and then the tests start to lose their value as a safety net. (N.B. You still want integration tests that access the database. You just don’t want each and every unit test to do so.) As well it requires a lot of effort to keep consistent data for tests, often using test data setup scripts or rolling back transactions at the end of tests.

Other areas that often cause pain are integration points – web services, DCOM/Enterprise Services, external text files, … Anywhere your application is relying on an external application. Integration points are problems for tests because if you’re relying on them, your tests will fail when the external applications are unavailable due to crashes, service outages, integration point upgrades, external network failures, behaviour changes, … Imagine that your e-commerce website integrates with 6 external systems (credit card processor, credit check, inventory, sales, address verification, and shipping). Your development environment integrates with DEV/QA versions of each of these services. Each service has 95% uptime, which translates into 1.5 days of downtime a month for maintenance, upgrades, and unexpected outages. The chance of all systems being available is the product of their availabilities or 95%*95%*95%*95%*95%*95%=73.5% uptime for all 6 integration points. If your tests directly use these test systems, your test suite will fail over 25% of the time for reasons beyond your control. Now is that because you introduced a breaking change or because one of your integration points is temporarily unavailable or misbehaving? Life gets worse when you integrate with more systems or when the availability of those systems is lower. Imagine you have to integrate with 12 integration points with 95% availability – your test suite will only pass 54% of the time. Or if your 6 test systems only have 90% availability, your test suite only passes 53% of the time. In each case, it’s a coin toss whether you know for certain whether the change you just made broke the application. When you start getting a lot of false negatives (failing tests when the problem is in an integration point), you stop trusting your tests and you’re essentially flying without a parachute.
By decoupling yourself from your integration points by using interfaces for the majority of your tests, you know that the code base is healthy and you can separately test the interactions with your integration points.

To figure out which dependency to break first, take a critical look at your codebase. What is causing you the most pain? Pain can manifest itself as long debug sessions, waiting for external services to be available, high bug counts, … Solve the pain by decoupling yourself from that dependency. Then look at what is now causing you the most pain and solve that. Lather, rinse, repeat. It might take a few weeks or months, but eventually you’ll have a codebase that is a pleasure to work with. If you don’t believe me, read this email that I received from Karl (originally posted here):

Hi James,

I’m writing you because I just wanted to thank you!

It was about two months ago and I attended TechEd/Orlando. I have to say that it was the first time for me and it really was an honor to be the one and only chosen from approximately 300 software developers working in my company to go to Orlando. I was very impressed about the good quality of the sessions, especially on the architecture track, but your tiny little discussion on Tuesday evening really opened my mind. At that time I had been working as a software developer for 7 years with about 5 years experience in software design and project management and 5 years of .NET experience. I was fighting with a 400,000 LOC .NET legacy monster that’s used by public safety agencies around the world in security related areas. I have a team of 12 developers and we were trying really hard to keep this beast up and running and extend it with new features. I think you can imagine that most of the time we were using the trial and error approach to get new features in (just hack it in and prepare for long debugging sessions hunting weird bugs in parts of the application you never expected to be affected by the new feature…). The main problem was – guess what – the dependencies. There were about 50 classes (all singleton “Managers”), and every single manager was tied to at least 10 other managers – no interfaces at all – and that’s just one of several layers of the app… We knew that dependencies were our problem, but we had no clue how to solve it – there was this chicken/egg problem – I want to decouple my system, which needs a lot of refactoring. To ensure that I don’t break anything I’d need unit tests but I can’t use them because my system is so highly coupled ;-) We have tried TypeMock, but my feeling was that this went in the wrong direction. Needless to say that this attempt failed.

During the discussion after your session you gave me some quite useful hints:

1. Read Applying Domain Driven Design and Patterns by Jimmy Nilsson
2. Read Working Effectively with Legacy Code by Michael Feathers
3. Use ReSharper (especially for Refactoring)
4. Use a Mock-Framework (preferably RhinoMocks)
5. Use a Dependency Injection Framework like Spring.NET

I bought Jimmy Nilsson’s book in the conference store and read it cover to cover on my flight back to Vienna. Then I bought the second book and read it within one week. I started to use ReSharper more extensively to apply some of the patterns from Michael Feathers’ book to get some unit tests in place. I extracted a lot of interfaces, brought Spring.NET into action and used RhinoMocks and the VS2005 built in UnitTest-Framework to write some useful unit tests. I also used the built in code coverage functionality in combination with the unit tests. In addition we already started Design for a messaging based service application that we want to develop in a very TDDish style.

As you can see there’s a lot going on since I attended your session. It was really this discussion about agile principles that gave me sort of a boost.

So again – thanks for opening my mind and keep on doing this great work!

Regards,
Karl

In my opinion, Karl and his team are the real heroes here. You can be a hero too by taming your software dependencies!

Today at lunch* I’ll be joining Glen Gordon and Lynn Langit on geekSpeak to talk about Taming Your Software Dependencies. Specifically I’ll be talking about moving from tightly-coupled to loosely-coupled architectures using dependency inversion, dependency injection, and inversion of control containers. geekSpeak is an interactive LiveMeeting driven by audience questions with no PowerPoint and lots of code. Come and geek out with me on geekSpeak! Register here.

* Today at lunch == Wednesday, March 26, 2008 from 12-1pm PST or 1-2pm MST or 2-3pm CST or 3-4pm EST or …

My latest article just hit the web in the March 2008 issue of MSDN Magazine. Loosen Up: Tame Your Software Dependencies for More Flexible Apps takes you on a journey from a highly-coupled architecture, which we’re all familiar with, to gradually more loosely-coupled ones. First stop is the problems inherent in highly-coupled applications. To start solving those problems, I look to dependency inversion and service location. Next stop is poor man’s dependency injection and then a simple, hand-rolled inversion of control (IoC) container. From there, I look at the features provided by full-fledged IoC containers and use Castle Windsor as an example, along with some Binsor thrown in for configuration goodness. My goal was to help developers understand the benefits of dependency injection and IoC containers by showing them the problems solved at each stage of the journey.

A big thanks to Howard Dierking, MSDN Magazine editor extraordinaire, for his encouragement and not having an issue with using Windsor for the advanced examples. Thanks to Oren Eini for help debugging a Binsor configuration problem in one of the examples. And an especially big thanks to my spouse and two young sons for their patience while I was writing.

Thanks in advance for reading the article. I welcome your feedback and questions.

DISCLAIMER: For the agilists reading this post, there is nothing new here. I just hear a lot of misconceptions around terms like YAGNI and wanted to provide my own take on things.

YAGNI is an acronym for “you ain’t gonna need it”. You often hear it bandied about agile shops. One developer suggests an over-architected solution and the other cries out YAGNI. For example:

Dev#1: We can transfer that file using BizTalk!

Dev#2: YAGNI. We can download it using HttpWebRequest.

I’m not knocking BizTalk here. My point is that if all you need to do is transfer a file from point A to point B, BizTalk is an awfully complicated and expensive way to do it.

Many agile critics see YAGNI as an excuse for developers to do stupid things. Critics claim that YAGNI encourages developers to hard-code connection strings and other silliness. “In development, you’re not going to need to change the connection string. So by the YAGNI principle, you should hard-code your connection strings. Isn’t agile stupid?” YAGNI is a principle like any other and should be applied intelligently. It’s about keeping simple problems simple. It’s about the right tools for the right job – don’t try to drive a finishing nail with a sledgehammer. Too often we as an industry implement “enterprise solutions” to solve otherwise trivial problems.

YAGNI isn’t an excuse to be sloppy with your architecture. If you’re building the next hot social bookmarking application, it better scale. You better design with caching, distribution, load-balancing, etc. in mind. I would want some architectural spikes demonstrating acceptable performance at high user loads. Similarly if you’re developing an internal application to be used by 10 users, I would bet that you don’t need the complexity of a load-balanced web farm, distributed middle-tier cache infrastructure, and a clustered database. YAGNI is about choosing the appropriate amount of complexity for the problem at hand.

YAGNI is about building software at the last responsible moment. The “responsible” part is key. You can’t slap an asynchronous architecture in after the fact. You need to design that in up front. At the same time you should avoid speculative generalization. Solve the problems at hand with a responsible eye toward future requirements. Keep yourself lean and nimble enough to respond to those future requirements, but don’t build them “just in case we need them”. What you will need in the future seldom has any resemblance to what you might build now. Even worse, unused features add complexity and rigidity to a codebase. You’re actually worse off than if you didn’t have those features at all! Keeping your architecture simple, lean, and nimble requires a lot of discipline.

So next time someone suggests using a SOA-based ESB to integrate the disparate workflows in the document lifecycle, ask yourself whether a wiki couldn’t work just as well. :^)

I spent last week hanging out at DevTeach in Vancouver. Awesome conference. Although heavily Canadian, people from around the world showed up. (I finally got a chance to meet Oren Eini (aka Ayende Rahien) in person after emailing/IMing/etc. for a long time.) The Agile track was particularly well-attended, often with standing room only available. Of all the presentations, the ones that stand out in my mind are:

Jeremy Miller’s Creating a Maintainable Software Ecosystem – Jeremy echoes so many of my thoughts on good software design, but does it much more eloquently. If you haven’t subscribed to Jeremy’s blog, go do so right now. I’ll wait… Oh good, you’re back. One of the most amusing moments in Jeremy’s talk when he demonstrated environmental testing in StructureMap. (StructureMap is the first .NET inversion of control container built by Jeremy himself before Castle Windsor or Sprint.NET.) Jeremy turns to Oren and says, “Here’s something that Windsor doesn’t have. Environmental testing.” The basic idea is you can mark certain methods with an attribute to indicate that they validate your IoC configuration. Oren agrees that Windsor does not have such functionality. At the end of Jeremy’s presentation, Oren calls me over and shows me some code on his laptop. Not to be one to turn down a challenge, Oren implemented the feature in Windsor while Jeremy finished his talk! You can check out the code on Oren’s blog and I can attest that he did code this start-to-finish during Jeremy’s talk.

David Laribee‘s Domain Driven Design – David has style like no other developer I know and he has the technical chops to match. He did an admirable job explaining the fundamental concepts of DDD and re-affirming my own understanding. I particularly liked his very visual slide design focused around a picture and short statement to convey the overall meaning. I’ve tried this in a few talks and been pleased with how it works. I was taking mental notes during David’s talk and figuring out how to better incorporate visual imagery into my own presentations. Great stuff.

But neither of those matched…

Justice Gray‘s Microsoft MVC Architecture…what side are YOU on? – Oh my gosh! This was the presentation to end all other presentations. Just read his abstract:

Everybody who is anybody is talking about the new MVC. And when you’ve heard it mentioned, you’ve *also* heard the standard “We can all play nice together”, “there’s still room for choice”, “this is just an alternative” and all those other phrases that likely also involve group hugs and the Care Bear Stare. FORGET THAT. The world is waiting for a man to take a stand – a name that people trust to start the next great religious war in software! So at DevTeach, North America’s Metrosexual Development Hero is going to break his silence and show you why the Microsoft MVC is the *only* Microsoft web architecture you should be developing with. Sure, Justice *doesn’t* have the advance betas, lines of cocaine at every table, and free entry to shady massage parlors that Microsoft gives their MVPs, but he *does* have the ability to incite a full-scale *RIOT*!! Why is this the most important piece of MS web architecture in ten thousand years? What’s the problem with traditional WebForms development? How do the mysterious Page Controller and Front Controller patterns figure into this? Why do Datasets suck? Will Justice even get a beta in time? Will you get laid tonight? Who hit you over the head with that beer bottle? The answers to these and *many* other questions can only be found in THIS PRESENTATION, so make sure you’re there for the session that neither you or the local authorities will *ever* forget!!

The abstract pales in comparison to actual presentation though. I don’t think anyone else could have carried this off. He mixed humour with excellent technical content and insight. Explaining the model-view-controller (MVC) concept using Steven Rockarts’ drug habits* was brilliant. (I know Steven Rockarts personally and I can attest that he is very anti-drug. It made Justice’s presentation all the more funny to see Steve in the back of the room muttering to everyone who would listen, “I don’t do drugs. I don’t have a meth addiction. I don’t do coke. Ah, come-on, Justice!!!”) After demonstrating a MVC app to cure Steve of his various addictions, Justice went on to demonstrate another MVC app in an effort to assist Donald Belcham, The Igloo Coder. Enter The Igloo of Love – A Dating Website for Donald Belcham. On Donald’s list of potential paramours was The Mad Mexican, Martin Fowler, and Scott Bellware. (Showing off the MVC routing engine using the search-engine optimized (SEO) URL http://igloooflove.com/paramours/thatare/slutty/ and having Scott Bellware’s name appear was a riot.) I’ve never seen Donald turn such a brilliant shade of red. Justice had a rollicking good time roasting his fellow EDMUG directors. He was over-the-top and showed that you could have fun while being highly technical. Justice’s presentation style isn’t for everyone, but I for one found it incredibly refreshing and entertaining. Well done, Justice!

Most of the fun at the conference was just hanging out with the other presenters and attendees. There is no line drawn between the two at this conference and everything is set up to encourage interactions between presenters and attendees. (For instance, there is no presenter room. If you really need to prepare, go to your hotel room. Otherwise hang out and talk to everyone.) One dinner was at a Thai place. When we got there, we had to split over two tables. I was at the smaller table with six people. Half the people at the table were presenters. Where else does this happen?

Other fun happenings… I talked to some attendees at the JetBrains booth. While talking, I said to Jeff (JetBrains), it’ll be easier if I just show them. I took over the booth for about 10 minutes demonstrating everything I love about ReSharper. How many of your customers will do that for your product? :)

Thanks to everyone I talked to at the conference for making it such a fun time. If you’re thinking of going to a conference in 2008, I would encourage you to make DevTeach one of your choices. I know I’ll be at the next one… How can I be so certain? Because the organizing committee asked me to be the Agile Tech Chair. I’ll be organizing the agile track for DevTeach Toronto coming up May 12 to 16, 2008. If you’re interested in speaking, submissions are due by January 15, 2008. I would also welcome any feedback from attendees regarding topics that they’d like to hear about.

For those looking for slides and demos from my presentations, I’ll be posting those later today. So stay tuned.