Contents tagged with Agile

  • Code to Interfaces. Right. What’s an Interface?

    The premise of coding to interfaces has been around for awhile now. The concept is simple. Given a definition of something you create things based on that definition. That might be a horrible description of an interface but I didn’t want to go all Computer Science on you.

    Interface? What’s an Interface?

    Here’s a simple interface:

       1: interface ICustomerService

    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2">   2:</span> {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3">   3:</span>     IEnumerable&lt;Customer&gt; GetAllCustomers();</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4">   4:</span> }</pre>
    

    Pretty basic. We have a Customer class somewhere and this interface describes a method called GetAllCustomers that will return you a list of Customer objects.

    With an interface you don’t have an implementation. There’s no code here to say where we get the customers from, just that we expect this to return us a list of them.

    Now in our code we can write something like this:

       1: public void DisplayAllCustomers(ICustomerService service)
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2">   2:</span> {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3">   3:</span>     <span style="color: #0000ff">foreach</span> (var customer <span style="color: #0000ff">in</span> service.GetAllCustomers())</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4">   4:</span>     {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5">   5:</span>         <span style="color: #008000">// Output whatever customer info here</span></pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6">   6:</span>     }</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7">   7:</span> }</pre>
    

    The method here expects an object that implements the ICustomerService interface. That’s how we can build and compile this but we have yet to build an implementation of this method. Of course the code won’t run because your application doesn’t know how to create an object that implements ICustomerService.

    Like I said, the implementation is up to you but you’ll probably be driving it from requirements or what the user needs to see or whatever. Here’s a sample implementation:

       1: internal class CustomerRepository : ICustomerService
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2">   2:</span> {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3">   3:</span>     <span style="color: #0000ff">public</span> IEnumerable&lt;Customer&gt; GetAllCustomers()</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4">   4:</span>     {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5">   5:</span>         <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> List&lt;Customer&gt;</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6">   6:</span>                     {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7">   7:</span>                         <span style="color: #0000ff">new</span> Customer {Name = <span style="color: #006080">&quot;Harold&quot;</span>}, </pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8">   8:</span>                         <span style="color: #0000ff">new</span> Customer {Name = <span style="color: #006080">&quot;Kumar&quot;</span>}</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9">   9:</span>                     };</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10">  10:</span>     }</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11">  11:</span> }</pre>
    

    So if we created an object of this CustomerRepository class and passed it to the DisplayAllCustomers method above, we would output Harold and Kumar’s names (or whatever your display code was).

    The $10,000 Question

    People will stare at the code and say, why? Why create that ICustomerService and then have to go to the trouble of creating it and passing it along to the DisplayAllCustomers. More code to maintain they say. More work.

    Let’s try to dispel some myths here.

    Coding to Interfaces is Hard

    Really? Do you understand the code above? That’s coding to an interface. Could you do that yourself? Sure you can. Let’s move on.

    Coding to Interfaces Constrains Me

    It’s true. If you added the method “void AddCustomer(Customer customer)” to your inteface, you wouldn’t be able to compile your code. The CustomerRepostory class (and any other class that implemented the ICustomerService interface) would require it. Stop thinking about this as a constraint, it’s a design choice. It’s like the Architect giving you a window or door on the side of your house. You don’t go cutting open another hole because you want another window. You have to take into account load bearing walls, structural integrity, etc. which is what the Architect does (I know, I used to be one). Just because it looks good or you need it, doesn’t mean it should be done (at least in the way you might want it).

    Coding to Interfaces makes you do extra work

    Yes, you have to create those interfaces so yeah, that’s extra work. Some might argue that if your implementation is simple then you’re writing double the code. Again, all true. There are benefits that will outweigh this which we’ll look at in a moment.

    Where are the Benefits?

    Let’s talk some benefits here. First coding to an interface is giving you a layer of abstraction. Remember that ICustomerService above? The implementation is sort of silly but shows that we can write code that does what the system intends. We could also build an implementation that reads from a database. Or Active Directory. Or SAP. Or a Web Service. Each time we write a new implementation, we don’t have to change our DIsplayAllCustomers method.

    That’s abstraction. You don’t have to worry in your DisplayAllCustomers method where the data came from or what infrastructure may or may not exist. All you care about is that you expect a list of customers to come back.

    Now multiply that by 10 or 100 and you get the benefits of abstraction against a real codebase.

    Some people will talk about future proofing and interfaces and while that may be a benefit down the road, and it can happen, consider it icing on the cake. Imagine if you had coded to an IEnumerable interface instead of ArrayList? Now you *might* not have to rewrite a lot of code (or any if you’re really lucky).

    I do believe, and have rarely seen, entire implementations changed. For example one classic is the “build a database interface so we can swap between SQL and Oracle”. You build an abstraction over a database to make it simpler to code to but not necessarily swap out technologies.

    Just don’t use the future proofing claim as a crutch to not code to interfaces claiming YAGNI or something. There are different reasons for this.

    The other big thing is testing. Going back to our CustomerRepository. It’s an in-memory representation to a list of customers. Imagine you had additional methods on your interface like this:

       1: internal interface ICustomerService
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2">   2:</span> {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3">   3:</span>     IEnumerable&lt;Customer&gt; GetAllCustomers();</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4">   4:</span>     <span style="color: #0000ff">void</span> AddCustomer(Customer newCustomer);</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5">   5:</span>     <span style="color: #0000ff">void</span> DeleteCustomer(Customer customerToDelete);</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6">   6:</span> }</pre>
    

    And now with your in-memory representation you can write tests that ensure items are added and deleted in your repository and the counts all match and the list comes back with the right names. Now you’re starting to test against your interface, which is a good thing.

    Testing

    Testing frameworks will let  you do things like create stubs or fake implementations of the interface, without actually writing code to return actual values. Without interfaces if you tried to test the AddCustomer method in say a SQL based implementation, you would need a database, login information, test data, etc. That’s great for infrastructure tests but for unit tests it’s a lot of overhead you shouldn’t be getting into.

    Another benefit is getting ahead of infrastructure. Imagine if your ICustomerService is going to talk to a web service, as web service that won’t be written for another month. You could go ahead and wait for the infrastructure to show up, code concrete classes against it, and then start your testing but now you’re in the crunch to get the system done and you’re just starting your unit testing.

    Instead, based on requirements and perhaps UI discussions with users using paper, whiteboard, or digital wireframes, you come up with the interface. “We’re going to need to display the customer fields and oh yeah, we want to search by first and last name”. Great. From that description you can come up with an interface something like this:

       1: interface ICustomerService
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2">   2:</span> {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3">   3:</span>     IEnumerable&lt;Customer&gt; FindBy(<span style="color: #0000ff">string</span> firstName);</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4">   4:</span>     IEnumerable&lt;Customer&gt; FindBy(<span style="color: #0000ff">string</span> firstName, <span style="color: #0000ff">string</span> lastName);</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5">   5:</span> }</pre>
    

    Again we can write up some implementation (maybe going against a preset list of names you import from a spreadsheet) and actually build out a working UI. The user can put their hands on it, search by names, and see the results returned. All without that pesky infrastructure. Then come the say the database gets built, you create your implementation to read it and do searches and BAM, your system is online and working end-to-end.

    On the testing front again, how would you test something that’s dependent on DateTime? For example you have a piece of code that ages some items in a system based on some business rules (or expires them).

    It’s all well and fine to start tossing around DateTime objects like this:

       1: public void ExpireTest(ICustomerService service, DateTime date)
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2">   2:</span> {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3">   3:</span>     <span style="color: #0000ff">foreach</span> (var customer <span style="color: #0000ff">in</span> service.GetAllCustomers())</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4">   4:</span>     {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5">   5:</span>         <span style="color: #0000ff">if</span>(customer.ContractDate &gt; date)</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6">   6:</span>         {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7">   7:</span>             ExpireContractFor(customer);</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8">   8:</span>         }</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9">   9:</span>     }</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10">  10:</span> }</pre>
    

    However things get real ugly real fast. First I have to write this test and I’m sort of breaking both encapsulation and responsibility of the customer class. Maybe I should have a method on customer that takes in a DateTime object. Yuck. Now I’m passing that value into my business object which might be okay (it depends) but now consider the idea of something like this business rule:

       1: foreach (var customer in service.GetAllCustomers())
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2">   2:</span> {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3">   3:</span>     <span style="color: #0000ff">if</span>(customer.ContractDate.Day == date.Day &amp;&amp; date.Hour &gt; 12)</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4">   4:</span>     {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5">   5:</span>         ExpireContractFor(customer);</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6">   6:</span>     }</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7">   7:</span> }</pre>
    

    Now I’ll only expire the contract if the date passed in is the same day as my contract and it’s after noon. Silly logic yes, but would require another test method, another date object to be passed in, etc. A lot of setup to test something and then along comes this somewhere in my Customer class:

       1: class Customer
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2">   2:</span> {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3">   3:</span>     <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Name { get; set; }</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4">   4:</span>&#160; </pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5">   5:</span>     <span style="color: #0000ff">public</span> DateTime ContractDate { get; set; }</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6">   6:</span>&#160; </pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7">   7:</span>     <span style="color: #0000ff">public</span> <span style="color: #0000ff">int</span> AgeOfContract()</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8">   8:</span>     {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9">   9:</span>         <span style="color: #0000ff">return</span> (<span style="color: #0000ff">int</span>) (DateTime.Now - ContractDate).TotalDays;</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10">  10:</span>     }</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11">  11:</span> }</pre>
    

    Now I’m screwed, both in testing in code and testing on the site. I’m going to have to create test data with very specific dates, maybe mess around with the values (because I certainly can’t change the clock on the server) and frankly I’m going to cry.

    Interfaces can save you here. What if we had an interface called:

       1: interface IDateTime
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2">   2:</span> {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3">   3:</span>     DateTime Now { get; set; }</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4">   4:</span> }</pre>
    

    And instead of the concrete implementation in our customer class we use the IDateTime interface. Here’s the Customer class refactored to use an interface:

       1: class Customer
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2">   2:</span> {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3">   3:</span>     <span style="color: #0000ff">readonly</span> IDateTime _dateTime;</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4">   4:</span>&#160; </pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5">   5:</span>     Customer(IDateTime dateTime)</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6">   6:</span>     {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7">   7:</span>         _dateTime = dateTime;</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8">   8:</span>     }</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9">   9:</span>&#160; </pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10">  10:</span>     <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Name { get; set; }</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11">  11:</span>&#160; </pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12">  12:</span>     <span style="color: #0000ff">public</span> IDateTime ContractDate { get; set; }</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13">  13:</span>&#160; </pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14">  14:</span>     <span style="color: #0000ff">public</span> <span style="color: #0000ff">int</span> AgeOfContract()</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15">  15:</span>     {</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16">  16:</span>         <span style="color: #0000ff">return</span> (<span style="color: #0000ff">int</span>) (_dateTime.Now - ContractDate).TotalDays;</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17">  17:</span>     }</pre>
    
    <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &#39;Courier New&#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18">  18:</span> }</pre>
    

    Yes, there’s more that needs to be here like how an IDateTime can subtract values from each other, return a TImeSpan object, etc. but this is just for concepts.

    With the interface added, I’m now abstracted away from the concrete implementation of DateTime hard coded into my Customer class. I’ll pass in something that might implement DateTime to return some real time but for testing I can set it to anything I want.

    Testing is easier now and I don’t have to change my domain logic to deal with responsibilities outside of my concerns.

    Interfaces vs. Classes is the kind of thing to start holy flame wars. Some argue it adds extra code/work to the developer, others claim it unnecessarily future-proofs your app (aka YAGNI) and others think it makes for easier testing and abstraction away from things that have yet to come.

    I like to live in the latter world where I build my systems loosely coupled but tightly integrated. Interfaces provide me that ability. I hope this article sheds some light on the subject for you, whatever you choose.

    Enjoy.

  • How do you know she’s a witch?

    She looks like one! So begins one of my favourite skits in movie history, the witch scene from Monty Python and Holy Grail. The gist of it is: If she weighs the same as a duck then she’s made of wood and therefore… A witch! And what do we do with witches?  We teach them Agile!

    ShesAWitch

    What do witch hunts have to do with software development? Plenty.

    How do you know you’re really “doing Agile” or following Scrum practices in your project? How do you know if you’re doing the right thing or not? How do you know when it’s done? How do you measure success? Why is the sky blue?

    All of these questions come up when things start going sideways in the Agile sense, and you fall into the Scrummerfall way of doing things. Practicing traditional Waterfall management techniques but calling it Scrum. Tasks are assigned to people rather than claimed by owners. Customers are non-existent and uncommitted. And the team really doesn’t know what they’re delivering or why, they just keep doing stuff to stay busy because the PM tells them to.

    Brad Wilson describes Scrummerfall as the way to ensure failure at a much faster rate than you had with Waterfall alone. There are some clear signs you’re on a slippery slope and if you see them, you should grab hold of something (preferably a pair of coconuts) and find yourself a swallow (African or European – your choice).

    Three key things that you can bank on in Scrum:

    • The practice regularly delivers business value
    • The team is frequently aligned with the business requirements
    • The business drives the project based on their needs and values

    There are other elements of Scrum here but I like to highlight these ones as they’re not bogged down in techno-babble terms that nobody understands.

    Delivering Business Value in a Predictable Way

    A sure sign of Scrummerfall is having a schedule that follows some mythical Gantt chart or Waterfall-ish schedule that’s about delivering “phases” or “stages” of the product. Waterfall PMs will plaster these on the wall, attach them in monthly reports, and bring them to sprint reviews to show the customer “how well we’re doing”. How well you’re doing in an Agile project is measured by the business value you deliver and that can only be determined by your customer, not IT. Regular sprints of fixed lengths creates that predictability that is often missing in Waterfall projects where milestones keep slipping because of uncertainty with features that were estimated and planned months previously. If your team demonstrates value-added features at the end of your sprint and the business is on board to move to the next one, then you’re doing something right. And you’ll be hopefully able to more accurately predict the level of effort next time around.

    The Business Requirement Alignment Shuffle

    Shrubbery Requirements and business users change their minds. Especially after seeing results. It’s human nature. How many times have you brought that “perfect” tapestry home only to have your wife say “No, now that I see it on our castle wall it’s just not right. I want a shrubbery”. System solutions are the same thing and that’s fine. After a sprint ends, the business has every right; nay the privilege; to say what’s in or out next sprint. And heck they may even introduce brand new features as they see the system take hold and start dreaming up new stuff. This is not scope creep. It’s manageable expectations that are agreed upon by everyone once they understand the depth of the requirement.

    The Scrummerfall bing-bong alarm will go off if you’re in your 3rd day of the sprint and the PM starts picking and choosing from “other items” in the product backlog, substituting them in because of impediments. Avoid this at all costs. Features are not interchangeable like Lego. Even stories with the same number of points doesn’t mean it’s the same size. In situations where you’re not using story points or any kind of measurement system of feature/story size you’re in Scrummerfall land and cannot, under any circumstances, play the shell game with yet-to-be-determined-features.

    Business Driven

    In Scrum, the business drives the project by prioritization and commitment in order to help the entire team achieve some business value (which down the road should equate to some ROI). In Scrummerfall, the business just says “you pick what you need to do, propeller-heads, we really don’t care and will do our thing, you do yours”. A customer who’s not committed to the process but demands the project succeeds is an impediment. I think the biggest success factors in any Agile project is a fluid customer involvement. If you’re not engaging your customer, for whatever reason, then correcting that is Step #1 to success. IT cannot make business decisions. I’ve been on projects where we did, against my advice but forced by the PM, and when the client finally crawled out of whatever rock they were under, they took one look at the assumptions we made and blew 2 weeks worth of a teams work out of the water. Again, the powers that be, who only read Scrummerfall monthly reports, will chalk this up to Agile failure and blame Scrum.

    Engage the customer. They may not always be right, but, like any engagement, it’s a courtship and a democracy, not a dictatorship. There may need to be some hand holding at first and you might have to wade into the pool with them step by step, but it’s for the greater of the entire team and success of the project to do so. Or you could take the Scrummerfall approach and just push them off the cliff hoping they know how to swim (and maybe tossing them a life preserver if you’re really feeling generous).

    Peter Schuh has a great article here on 7 simple steps to go Agile without going extreme. It’s more geared for the nerds and developers, but there’s a great tip in a section called “Identify and collaborate with your customer”. That’s what this is all about.

    Know the Signs

    Knowing is half the battle and if you sense you’re on the slippage towards Scrummerfall (or are already knee deep in it) it’s time to sink or swim. Step back and get everyone involved to help identify what’s not working. If need be, stop the project and regroup. It might be to get some level of understanding in the requirements (or even the problem that you’re trying to solve) or get resources on track or whatever. PMs and other manager-types around the world are saying “Warning, warning, danger Will Robinson. We can’t afford to stop this project”. Frankly, you can’t afford not to stop it for a few days or a week at most. The entire team won’t be running flat out during this time but when things get back on track, the team should be better off. Don’t let this technological terror manage you and keep driving down the road with nobody at the wheel just to satisfy some planned delivery date. While you can screw around for the next few months/years on the project (and hey, some firms have all the fun because of unlimited funds) there’s little value in just doing stuff to keep busy.

    Killer_rabbit

    Adoption is a two way street and sometimes you’re going to face killer bunnies and sorcerers named Tim. It’s not pretty sometimes but Agile is about adaptability. Humans adapt well to their environment so should projects adapt well to theirs. If you’re setting out to change the world in one fell swoop, stop kidding yourself and be a little more pragmatic. If however you’re looking for a few small wins to move inches closer to an Agile approach to project delivery, it’s an attainable result given some realistic goals. Know your audience and your environment and play nice with the other kids.

    Waterfall is still valid today. Document, design, test, are all still there in every project. Practicing Scrummers (is that a word?) just do it in a different sequence.

    A bit of a side tangent. When I’m mentoring people on development, specifically refactoring, we do the refactoring manually and by the book. It’s painful in this day and age but it’s done for a reason, to help understand the meaning behind the refactoring and what each step of say an extract method is doing (and more importantly, why). After that, we can pull out the copy of ReSharper and accomplish the same refactorings with 1 or 2 keystrokes. I see Scrum the same way. Implement it by the book at least the first few times. Get into it, understand it and prove that it works. Then tweak it and massage it to better fit into your organization and how things may have been done in the past, perhaps grafting PMO processes, reports, and budget tracking into it.

    I don’t believe for a second that any organization out there can say “We’re doing Scrum everyone, pack up your PMI certifications and get rid of those silly monthly reports, we’re Agile now!” and drop everything. Even after learning and practicing it, they come to an understanding of what works and what doesn’t. If the team is geographically divided (with some members in different time zones for example) it’s impractical to have 8:30 AM stand-ups every day with everyone. Adjust to what makes sense to everyone.

    Agile is about adaptation and it can adjust itself quite well because it doesn’t follow strict rigorous policies that need to be approved by a committee and signed off by 15 heads of state before it can be followed. The Scrum approach is much like a morning brunch in a Dim Sum restaurant. You pick and choose what you like and ignore the chicken feet, no matter how appealing they may look like.

    It’s about what works for the team and the team has to discover that with practice and experience. If you only implement one or two practices (say daily stand-ups and a product/sprint backlog) and they work for you not against you, then good for you! You’ve taken your first step. However it needs a fighting chance to start. Wedging Scrum (or any Agile practice) in where it doesn’t belong is a bad practice in anyone’s books and not the fault of the process but the person trying to force it in. Don’t blame Scrum for bad choices you make.

    At the end of the day, whatever methodology, practice, or process you follow it needs to be backed by the new-but-old methodology, Common Sense. Agile is a powerful tool but not a religion. Scrum can be tailored for your needs, but you need to be able to identify those needs first before trying to apply any practice against them. Again, Common Sense reigns supreme here. There is no end-all methodology that will save any project from the depths of Hell. It’s the ability to identify, use, and adapt pieces of Agile that will help you to the end goal.

  • Transforming Tree Surgeon using the Adaptive Console Framework

    I'm a command line app junkie as I love working with it. I guess it's my DOS/Linux roots but I find things go faster when you're not dealing with a GUI and a mouse. Command line tools like NAnt and MSBuild have all sorts of options and syntax. Some of it discoverable, some of it not so much. NAnt for example will try to find a buildfile to run and execute it. It also will display the name and version of the app (which is useful in build logs so you know what's going on). There are other things like trying to find out how to run a command line tool. For example if you type "nant /?" you'll get this:

    NAnt 0.86 (Build 0.86.3075.0; nightly; 02/06/2008)
    Copyright (C) 2001-2008 Gerry Shaw
    http://nant.sourceforge.net

    Unknown argument '/?'

    Try 'nant -help' for more information

    Entering the proper syntax of "nant -help" displays this:

    NAnt 0.86 (Build 0.86.3075.0; nightly; 02/06/2008)
    Copyright (C) 2001-2008 Gerry Shaw
    http://nant.sourceforge.net

    NAnt comes with ABSOLUTELY NO WARRANTY.
    This is free software, and you are welcome to redistribute it under certain
    conditions set out by the GNU General Public License.  A copy of the license
    is available in the distribution package and from the NAnt web site.

    Usage : NAnt [options] <target> <target> ...
    Options :

      -t[argetframework]:<text>      Specifies the framework to target
      -defaultframework:<text>       Specifies the framework to target (Short format: /k)
      -buildfile:<text>              Use given buildfile (Short format: /f)
      -v[erbose][+|-]                Displays more information during build process
      -debug[+|-]                    Displays debug information during build process

      -q[uiet][+|-]                  Displays only error or warning messages during
    build process
      -e[macs][+|-]                  Produce logging information without adornments
      -find[+|-]                     Search parent directories for build file
      -indent:<number>               Indentation level of build output
      -D:<name>=<value>              Use value for given property
      -logger:<text>                 Use given type as logger
      -l[ogfile]:<filename>          Use value as name of log output file
      -listener:<text>               Add an instance of class as a project listener
      -ext[ension]:<text>            Load NAnt extensions from the specified assembly
      -projecthelp[+|-]              Prints project help information
      -nologo[+|-]                   Suppresses display of the logo banner
      -h[elp][+|-]                   Prints this message
      @<file>                        Insert command-line settings from a text file.

    A file ending in .build will be used if no buildfile is specified.

    A lot of options there but pretty standard fare for a console application. And a lot of work to parse the options, validate them, display help messages, etc. I had a link to this thing called the Adaptive Console Framework sitting in my Action folder in Outlook and finally got around to looking at it. It's a library by Sunny Chen that takes the pain of command line junk by doing most of the heavy lifiting for you.

    This is what the console framework provides for you. A nice, simple way of not having to write a lot of code to deal with complex command line options and something that gives you a few other benefits along the way like automatic help text generation and easy access to command line options. Notice that the syntax for displaying NAnt help was "nant -help" but it wouldn't allow variations like "nant /?" or "nant -?". The framework as we'll see let's us make it easy to just add variations to command line syntax without doing a lot of work.

    The framework is a little gem of a library that I didn't think much about before but now after spending an entire hour of my hard earned time I think it's pretty slick. Here's a transformation of the console version of Tree Surgeon.

    The old version of the Tree Surgeon console (betcha didn't even think there was one!) was a little boring and actually broken. If you ran it without any arguments you got this:

    TreeSurgeon version 1.1
    Copyright (C) 2007 - 2008 Bil Simser
    Copyright (C) 2005 - 2006 Mike Roberts, ThoughtWorks, Inc

    Creates a .NET Development tree

    TreeSurgeon projectName

    Please note - project name must not contain spaces. We recommend you use CamelCase for project names.

    You could probably surmise you need to provide a project name at least. But what about those other options like version and what unit test framework to use? And frankly this is wrong since it's not version 1.1, this output was from the 2.0 version. Lots of little problems here.

    Here's the source for the command line runner:

    [STAThread]

    private static int Main(string[] args)

    {

        try

        {

            return RunApp(args);

        }

        catch (Exception e)

        {

            Console.WriteLine("Unhandled Exception thrown. Details follow: ");

            Console.WriteLine(e.Message);

            Console.WriteLine(e.StackTrace);

            return -1;

        }

    }

    And here's the RunApp method:

    private static int RunApp(string[] args)

    {

        Console.WriteLine("TreeSurgeon version 1.1");

        Console.WriteLine("Copyright (C) 2007 - 2008 Bil Simser");

        Console.WriteLine("Copyright (C) 2005 - 2006 Mike Roberts, ThoughtWorks, Inc");

        Console.WriteLine();

        if (args.Length != 2)

        {

            Usage();

            return -1;

        }

        Console.WriteLine("Starting Tree Generation for " + args[0]);

        Console.WriteLine();

        string outputDirectory = new TreeSurgeonFrontEnd(

            Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), args[1]).

            GenerateDevelopmentTree(args[0], "NUnit");

        Console.WriteLine("Tree Generation complete. Files can be found at " + outputDirectory);

        return 0;

    }

    RunApp would output the logo and copyright info and give you the ugly Usage() message (which wasn't too useful) if you didn't pass in at least a project name. You could pass in a version to build (2003, 2005, or 2008) but the unit test framework was hard coded to NUnit. Like I said, not too useful.

    After taking a quick glance at what the Adaptive Console Framework (ACF) could do I decided to transform the Tree Surgeon console runner using it and see what we could get.

    The ACF basically has two steps to it (this is overly simplifying it but you'll see it's pretty easy). First you make a slight adjustment to your main console application method, then you get down and dirty by creating option contracts (via attributes, classes, and properties). This has a big bonus that I immediately saw which was to move the command line options into a separate assembly and class which meant I could test it without actualy having to run the application and secondly it would take care of most of the heavy lifting of dealing with command line syntax.

    So the first thing I did was to ditch that RunApp method and replace the call to have the ConsoleApplicationManager class from the ACF do my work. Here's the updated Main method from the Tree Surgeon console app:

    [STAThread]

    private static void Main(string[] args)

    {

        try

        {

            ConsoleApplicationManager.RunApplication(args);

        }

        catch (Exception e)

        {

            Console.WriteLine("Unhandled Exception thrown. Details follow:");

            Console.WriteLine(e.Message);

            Console.WriteLine(e.StackTrace);

        }

    }

    Next I created a new assembly (called TreeSurgeonConsoleApplication.dll) and added an app.config file to the console app so the ACF could find my option contracts and added a reference to the ACF assembly. Here's the newly added app.config file:

    <?xml version="1.0" encoding="utf-8" ?>

    <configuration>

      <configSections>

        <section name="AdaptiveConsole"

                 type="AdaptiveConsole.Config.AdaptiveConsoleConfigHandler, AdaptiveConsole"/>

      </configSections>

      <AdaptiveConsole provider="TreeSurgeonConsoleApplication.TreeSurgeon, TreeSurgeonConsoleApplication"

                       contractRepository="TreeSurgeonConsoleApplication"/>

    </configuration>

    The app.config file just tells the ACF two things. The name and location of my console provider and the assembly where to find the option contracts. That was all I had to do in my TreeSurgeonConsole project so after removing the reference to the Core project (where the actual Tree Generation would happen) I closed down the console app project. Thinking about it, with the app.config file you could really use a generic console application project for any console app since there's nothing specific in here anymore. Nice.

    The console provider is a class derived from ConsoleApplicationBase in the ACF and has two string overrides you provide, a logo and a description. Here's the TreeSurgeon class that we just specified in our app.config file:

    public class TreeSurgeon : ConsoleApplicationBase

    {

        public TreeSurgeon(string[] args) : base(args)

        {

        }

     

        protected override string Logo

        {

            get

            {

                var sb = new StringBuilder();

                sb.AppendFormat("TreeSurgeon version 2.0{0}", Environment.NewLine);

                sb.AppendFormat("Copyright (C) 2007 - 2008 Bil Simser{0}", Environment.NewLine);

                sb.Append("Copyright (C) 2005 - 2006 Mike Roberts, ThoughtWorks, Inc.");

                return sb.ToString();

            }

        }

     

        protected override string Description

        {

            get { return "Creates a .NET development tree"; }

        }

    }

    We're emulating part of the old RunApp method here. When I run the console app now I get this:

    TreeSurgeon version 2.0
    Copyright (C) 2007 - 2008 Bil Simser
    Copyright (C) 2005 - 2006 Mike Roberts, ThoughtWorks, Inc.

    Creates a .NET development tree

    Looks pretty much the same however like I said, I can now test the TreeSurgeon class (for example make sure the logo is set correctly because I might decide down the road to make the property a little more dynamic like fetching values using Reflection). I'm also not actually running anything yet so if I was building my app using TDD this fits nicely with that approach.

    That's it for this part of the conversion but like I said, I don't have it running my TreeSurgeonFrontEnd class yet or generating the development tree or verifying the command line or displaying help. That now comes with our options.

    With the ACF you define your command line options through something called "Option Contracts". There are four types in the ACF: None, Exact, Patternized, and Free. For Tree Surgeon I want the user to be able to run the application using these options:

    • Display help if the user enters nothing
    • Provide the name of the project to generate (required)
    • Provide an optional version of the system to generate (with a default)
    • Provide an optional unit test framework to use (with a default)

    We'll only look at the None Contract and the Patternized contract types.

    The None Contract is a class that you inherit from OptionContractBase. It will be executed if the user provides no command line arguments to the application. Create a class that derives from OptionContractBase in your contract assembly. Here's the None contract for Tree Surgeon:

    [OptionContract(

        Type = ContractType.None,

        Description = "Prints the help information on the screen.")]

    public class TreeSurgeonEmptyContract : OptionContractBase

    {

        public override void Execute(

            ConsoleApplicationBase consoleApplication,

            IList<ArgumentInfo> args)

        {

            consoleApplication.PrintHelpMessage();

        }

    }

    The class is decorated with an OptionContractAttribute that let's you specify the type of contract (None, Exact, Free, Patternized) and a description. Note we haven't done anything anywhere else in the system (the app.config file is done, the console Main method is done, and the ConsoleApplicationBase class is baked). All we're doing is adding a new class to the assembly we specified as our contractRepository in our app.config file.

    Here's the output of the app now when no arguments are passed to it:

    TreeSurgeon version 2.0
    Copyright (C) 2007 - 2008 Bil Simser
    Copyright (C) 2005 - 2006 Mike Roberts, ThoughtWorks, Inc.

    Creates a .NET development tree


    > Calling the application without arguments
      Prints the help information on the screen.

    Sweet. Now let's start adding our options for actually running the app.

    We'll add a new class called TreeSurgeonCommandsContract (again derived from OptionContractBase). This time rather than specifying the type as "None" we'll use "Patternized". The Patternized type is a contract type where your console application requires a complex command line argument. You can define the options that are mandatory or not within the contract, you can define the options that carry a list of values and you can even define the switches in the patternized contracts. here's our TreeSurgeonCommandsContract class:

    [OptionContract(

        Type = ContractType.Patternized,

        Description = "Generates a new .NET development tree for a given project name.")]

    public class TreeSurgeonCommandsContract : OptionContractBase

    The main thing we need to capture is the project name that we want to generate the tree for. We'll do this by creating a property (called ProjectName) and decorating it with the OptionAttribute:

    [Option(

        Type = OptionType.SingleValue,

        Name = "/p;/project",

        Required = true,

        Description = "Specifies the project name.\r\n\t" +

                      "Please note - project name must not contain spaces.\r\n\t" +

                      "We recommend you use CamelCase for project names.")]

    public string ProjectName { get; set; }

    This tells the ACF that a) this option has a single value b) it's specified by either "/p:" or "/project:" and c) it's required. There's also a description we provide which will be displayed in our output that looks like this now:

    TreeSurgeon version 2.0
    Copyright (C) 2007 - 2008 Bil Simser
    Copyright (C) 2005 - 2006 Mike Roberts, ThoughtWorks, Inc.

    Creates a .NET development tree

    TreeSurgeonConsole.exe </p|/project:>

    > Calling the application without arguments
      Prints the help information on the screen.

    > Generates a new .NET development tree for a given project name.
      /p|/project:value (required):
            Specifies the project name.
            Please note - project name must not contain spaces.
            We recommend you use CamelCase for project names.

    Notice that we now have the application name (TreeSurgeonConsole.exe) along with a required property. And the help is displayed for that property. Again, pretty damn simple so far. At this point we could actually implement the required Execute method on the TreeSurgeonCommandsContract class and call out to our TreeSurgeonFrontEnd, passing it the ProjectName property. We would generate a developement tree just like the original system and we're done. However we're only about 20 minutes into our conversion so we can do a lot more.

    First we'll add a property to specify the version of the development tree we want to generate. This is again just a string property in our TreeSurgeonCommandsContract class decorated with the OptionAttribute. We'll make this optional and provide a default value for it along with instructions:

    [Option(

        Type = OptionType.SingleValue,

        Name = "/v;/version",

        Required = false,

        Default = "2008",

        Description = "Specifies the Visual Studio version to generate.\r\n\t" +

                      "Valid options are: \"2003\", \"2005\", or \"2008\"\r\n\t" +

                      "Default is \"2008\"")]

    public string Version { get; set; }

    Then we'll do the same for our UnitTestFramework we want to specify (NUnit or MbUnit):

    [Option(

        Type = OptionType.SingleValue,

        Name = "/t;/test",

        Required = false,

        Default = "NUnit",

        CaseSensitive = true,

        Description = "Specifies the Unit Test framework to use when generating the tree.\r\n\t" +

              "Valid options are: \"NUnit\", or \"MbUnit\"\r\n\t" +

              "Default is \"NUnit\"")]

    public string UnitTestFramework { get; set; }

    Now we can run our app and see the help the ACF is providing:

    TreeSurgeon version 2.0
    Copyright (C) 2007 - 2008 Bil Simser
    Copyright (C) 2005 - 2006 Mike Roberts, ThoughtWorks, Inc.

    Creates a .NET development tree

    TreeSurgeonConsole.exe </p|/project:> [/v|/version:] [/t|/test:]

    > Calling the application without arguments
      Prints the help information on the screen.

    > Generates a new .NET development tree for a given project name.
      /p|/project:value (required):
            Specifies the project name.
            Please note - project name must not contain spaces.
            We recommend you use CamelCase for project names.

      /v|/version:value :
            Specifies the Visual Studio version to generate.
            Valid options are: "2003", "2005", or "2008"
            Default is "2008"

      /t|/test:value :
            Specifies the Unit Test framework to use when generating the tree.
            Valid options are: "NUnit", or "MbUnit"
            Default is "NUnit"

    Lots of great stuff here and all we've done was specify some attributes around a few properties. What I really like are a few things we got for free:

    • Our required parameters are specified here and included in the help message
    • Optional parameters are surrounded by "[xxx]" in our command line syntax display
    • We're able to add varations to our command line options ("/t" or "/test") just by specifying the values in the OptionAttribute

    Now we'll actually implement the code to run our generator and use whatever values you pass along in the command line.

    To get the framework to do our bidding, we implement the Execute method in our TreeSurgeonCommandsContract class. This method passes in a copy of the ConsoleApplicationBase class (we specified above as TreeSurgeon) and an IList of ArgumentInfo values which were passed into the application. This is more than just a string so we can get information from our arguments like what type of argument they are.

    For Tree Surgeon, we need at least one option (the project name). We'll use a little LINQ to get the list of options from our passed in parameter and check to make sure that a) we have at least 1 option and b) we have a project name:

    var options = from arg in args

                where arg.Type == ArgumentType.Option

                select arg;

     

    if(options.Count() < 1 || string.IsNullOrEmpty(ProjectName))

    {

        consoleApplication.PrintHelpMessage();

        return;

    }

    Now that we've got a valid command line we'll reproduce what our old RunApp method did, namely invoke the TreeSurgeonFrontEnd class which will generate our development tree for us. We'll make it a little more interesting than version 1.1 and print out a little more information on what options we're using to generate the tree. Here's our Execute method so far:

    public override void Execute(ConsoleApplicationBase consoleApplication, IList<ArgumentInfo> args)

    {

        var options = from arg in args

                    where arg.Type == ArgumentType.Option

                    select arg;

     

        if(options.Count() < 1 || string.IsNullOrEmpty(ProjectName))

        {

            consoleApplication.PrintHelpMessage();

            return;

        }

     

        consoleApplication.PrintLogo();

     

        Console.WriteLine("Starting Tree Generation{0}", Environment.NewLine);

     

        Console.WriteLine("       Project Name: \"{0}\"", ProjectName);

        Console.WriteLine("            Version: \"{0}\"", Version);

        Console.WriteLine("Unit Test Framework: \"{0}\"", UnitTestFramework);

     

        Console.WriteLine();

     

        var frontEnd = new TreeSurgeonFrontEnd(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), Version);

        var outputDirectory = frontEnd.GenerateDevelopmentTree(ProjectName, UnitTestFramework);

        Console.WriteLine("Tree Generation complete.{0}{0}Files can be found at:{0}\"{1}\"", Environment.NewLine, outputDirectory);

    }

    And here's the output using the command line "treesurgeonconsole.exe /p:test":

    TreeSurgeon version 2.0
    Copyright (C) 2007 - 2008 Bil Simser
    Copyright (C) 2005 - 2006 Mike Roberts, ThoughtWorks, Inc.

    Creates a .NET development tree

    Starting Tree Generation

           Project Name: "test"
                Version: "2008"
    Unit Test Framework: "NUnit"

    Tree Generation complete.

    Files can be found at:
    "C:\Documents and Settings\simserb\My Documents\TreeSurgeon\test"

    Wait! We're only 45 minutes into our conversion and there's more features we can take on. Most apps let you turn off the silly logo/copyright info (usually with a "/nologo" switch). The ACF has a nice feature to specify switches on properties. You just add a boolean property to your class and decorate accordingly. Here's our "/nologo" switch:

    [Option(

        Type = OptionType.Switch,

        Name = "/nologo",

        Description = "When turned on, the logo and description\r\n\t" +

                      "information will not be displayed.")]

    public bool NoLogo { get; set; }

    Now that we have a bool property if the user adds "/nologo" to the command line we should not print out the header info:

    if(!NoLogo)

    {

        consoleApplication.PrintLogo();

    }

    Finally one last thing before we're done. A bug in the old system was that if you tried to generate a new tree over top of an existing directory, it would bomb out with something like this:

    TreeSurgeon version 1.1
    Copyright (C) 2007 - 2008 Bil Simser
    Copyright (C) 2005 - 2006 Mike Roberts, ThoughtWorks, Inc

    Starting Tree Generation for test

    Unhandled Exception thrown. Details follow:
    Can't generate directory [C:\Documents and Settings\simserb\My Documents\TreeSurgeon\test] since it already exists on disk. Wait until a later version, or delete the existing directory!
       at ThoughtWorks.TreeSurgeon.Core.SimpleDirectoryBuilder.CreateDirectory(String directoryName) in C:\Development\TreeSurgeon-2000.source\src\Core\SimpleDirectoryBuilder.cs:line 12
       at ThoughtWorks.TreeSurgeon.Core.TreeSurgeonFrontEnd.GenerateDevelopmentTree(String projectName, String unitTestName) in C:\Development\TreeSurgeon-2
    000.source\src\Core\TreeSurgeonFrontEnd.cs:line 42
       at ThoughtWorks.TreeSurgeon.TreeSurgeonConsole.TreeSurgeonConsoleMain.RunApp(String[] args) in C:\Development\TreeSurgeon-2000.source\src\TreeSurgeonConsole\TreeSurgeonConsoleMain.cs:line 44
       at ThoughtWorks.TreeSurgeon.TreeSurgeonConsole.TreeSurgeonConsoleMain.Main(String[] args) in C:\Development\TreeSurgeon-2
    000.source\src\TreeSurgeonConsole\TreeSurgeonConsoleMain.cs:line 15

    Highly useful. Let's add a new feature to our command line, an "/overwrite" swtich. It'll be just like the "/nologo" switch except that if it's specified, we'll delete the directory before we generate the tree:

    [Option(

        Type = OptionType.Switch,

        Name = "/overwrite",

        Description = "When turned on, any project with the same name\r\n\t" +

              "will be deleted.")]

    public bool Overwrite { get; set; }

    And here's the updated tree generation code with the check to see if we should delete the output directory first: 

    var frontEnd = new TreeSurgeonFrontEnd(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), Version);

     

    if (Overwrite)

    {

        Directory.Delete(frontEnd.GetOutputPath(ProjectName), true);

    }

     

    var outputDirectory = frontEnd.GenerateDevelopmentTree(ProjectName, UnitTestFramework);

    Console.WriteLine("Tree Generation complete.{0}{0}Files can be found at:{0}\"{1}\"", Environment.NewLine, outputDirectory);

    That's it! In under 60 minutes we were able to totally transform the command line tool into something a little more robust and testable (and even add a new feature to fix an old bug). Now when we run the Tree Surgeon console app we get a rich descriptive help screen:

    TreeSurgeon version 2.0
    Copyright (C) 2007 - 2008 Bil Simser
    Copyright (C) 2005 - 2006 Mike Roberts, ThoughtWorks, Inc.

    Creates a .NET development tree

    TreeSurgeonConsole.exe </p|/project:> [/v|/version:] [/nologo] [/overwrite] [/t|/test:]

    > Calling the application without arguments
      Prints the help information on the screen.

    > Generates a new .NET development tree for a given project name.
      /p|/project:value (required):
            Specifies the project name.
            Please note - project name must not contain spaces.
            We recommend you use CamelCase for project names.

      /v|/version:value :
            Specifies the Visual Studio version to generate.
            Valid options are: "2003", "2005", or "2008"
            Default is "2008"

      [/nologo]:
            When turned on, the logo and description
            information will not be displayed.

      [/overwrite]:
            When turned on, any project with the same name
            will be deleted.

      /t|/test:value :
            Specifies the Unit Test framework to use when generating the tree.
            Valid options are: "NUnit", or "MbUnit"
            Default is "NUnit"

    A few benefits I got from this conversion:

    • Options can be specified in any order. In the original code args[0] was the project name and args[1] was the version number. Now the user can specify the project name anywhere
    • The old system would bomb out if we tried to overwrite an existing directory. It will still do that, but we now have an "/overwrite" option that was added using one property and 3 lines of code
    • A highly descriptive help message is displayed to the user so discoverabilyt of what options are available is now there and didn't cost me anything in formatting
    • Users can specify options using long names "/version" or short "/v". Also I could add a new variation just by updating the attribute
    • My options are now fully testable and I don't have to run the app or even mock or fake it out 
    • I have a highly flexible command line runner that I can extend with ease

    So, if you've got a console application sitting around you might want to give the ACF a spin and try it out. Or if you're building a new app take a look at it. It was low impact and high value for my investment and gave me a better end result that's now testable and easy to extend. You might find it useful like I did. Many thanks to Sunny Chen for putting this library together, it's a great tool.

    Enjoy!

  • ALT.NET Canada - Day 3 - The Sharing Circle

    ALT.NET Canada wrapped up in the grand ballroom at the University Sunday afternoon. It was a great end to an awesome weekend. As with Open Spaces Technology there's a closing, and Doc introduced the Sharing Circle to everyone (some of Open Spaces Technology is rooted in Native American traditions). Everyone had something to say about the experience (you're not obligated to say anything) so it's a great way to see how our little gathering affected everyone. Enjoy!

  • ALT.NET Canada - Day 3 - Frameworks Fishbowl

    We had a lively discussion with everyone on day 3 around what frameworks you would use (Microsoft or otherwise) and how to decide. Some of the converstations get a little heated thanks to various individuals and the original fishbowl morphs as more chairs are added in the middle (as opposed to being taken away). Should be an enjoyable watch.

    BTW, I screwed up editing this thing (thanks Windows Movie Maker, you know how I feel about you) so the beginning starts about halfway through (around the 25 minute mark) then it jumps back to the beginning. Sorry about that.

  • ALT.NET Canada - Day 3 - Coupling and Decoupling your Applications

    Here we are at day 3 at ALT.NET Canada. This session was hosted by Donald Belcham and focused around discussing techniques and designs to decouple your solutions. As with most of the sessions this weekend, the conversation went to other places like deployment tools and techniques, coding to interfaces, and talks around how to introduce these techniques to your teams. Enjoy the vid:

  • ALT.NET Canada - Day 2 - Noah, build me an Ark!

    Saturday at ALT.NET Canada kicked off with a talk on the build process. The discussion was centered around build files and asks the question if NAnt has outlived it's usefulness, or are we putting too much into our build files? Lots of discussions of alternatives (Boo, Ruby, etc.) and products. The second half of the conversation shifted more to the deploy side, but as you'll see it's all related. Great stuff to start off the day. Here's the vid:

  • ALT.NET Canada - Day 2 - DDD and more D

    Today was DDD day at ALT.NET Canada as we had several sessions on Domain Driven Design. There was a chalk talk hosted by Greg Young, a talk on Distributed Domain Driven Design (DDDD) that I initiated, and a Birds of a Feather style chat towards the end of the day (including the topic of "where the f**k do you put business logic"). It was a healthy discussion that went to a lot of great places. Here's the video for the chalk talk:

  • ALT.NET Canada Open Spaces is LIVE!

    It’s Canada Day, and what better way to celebrate geekdom with a 100% All-Beef Canadian announcement.

    We’re very proud to present the first major Canadian Open Spaces ALT.NET event, hosted right here in my hometown of Calgary August 15-17, 2008. The event follows the same principals and format as the previous ALT.NET Open Spaces hosted in Seattle and Austin.

    image

    We’ll be hosting it at the local University and they’ll be tons’o’fun as with any of the ALT.NET events. Lots of cool local Canadian guys will be there. Vancouver or Bust Greg Young, the Bahama Connection with Kyle Baley, the regular NHibernate Mafia gang headed up by James Kovacs, the Edmonton Contingent with Donald Belcham, Justice Gray will be doing hair product demos, and a host of others will be there.

    Don’t miss out on this once in a lifetime event!

    Registration is open now and space is limited to the first 100 participants. You can visit the site here and get in on the coolest event in Western Canada (besides that Stampede thing).

  • Tree Surgeon 2.0 Released

    We’ve released version 2.0 of Tree Surgeon. This is the first major release since I took the project over from Mike Roberts.

    image

    This release adds the following features:

    • 2005 and 2008 support in addition to the original 2003 support
    • Ability to choose the unit test framework generated (NUnit or MbUnit)
    • Updated tool resources to latest versions
    • NAnt build scripts will use the appropriate .NET versions (1.1, 2.0 and 3.5)
    • Minor bug fixes
    • Improved User Interface

    Please download the latest project files here. Source code, zip file, and installer are all available.