var blog = new ThoughtStream(me); RSS 2.0
 Monday, March 10, 2008

Have you ever:

  • had a problem that you were having a hard time solving?
  • been in need of a design idea for a particular situation, and you don't know where to start?
  • solved a problem that was nagging you for a while?
  • come up with a good design for a common situation?
  • written some code that you wanted to keep around, to remind yourself how you did something?
  • wanted to find some code examples on how to do something with a specific technology?
  • wanted to know how to do something for a specific project?
  • wanted to share your knowledge on how to use a specific technology a specific way?
  • wanted to learn how to use a specific feature of a project?
  • wanted the world to know your opinion of a piece of software or technology, be it good or bad?

If you can answer "yes" to any one of these questions - you should be blogging.

If you can answer "yes" to more than one of these questions and you are not blogging, then shame on you! Start blogging today!

Don't think your opinion matters, or that you have anything worth saying? Stop fooling yourself. If you write code, you have opinions and preferences. If you have opinions and preferences, they are worth sharing. It's not possible to write code without opinions. Software development is not a mechanical process like building a house or a car - you can't sick a robot on a keyboard and write a functional piece of software.

The worst case scenario: If you post code examples on issues that you have solved, you will have a history of code you have written and issues you have solved. You'll be able to go back to this history and re-use existing knowledge, rather than having to think through the problem again.

The best case scenario: If you post your code examples, your thoughts on software development, your opinions and preferences; chances are that someone else in this wide world of ours has the same opinion or has had the same issues and will find the information you provide useful.

Why should you blog? Because you're a person with ideas worth listening to.

...

Get started now. Register a domain name and buy some web hosting so you can have a blog that is accessible to the world. I use dasBlog and WebHost4Life. There are thousands of options out there - find the one that works for you.

Monday, March 10, 2008 10:37:30 AM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: General

 Saturday, March 08, 2008

After many years of being a loyal RSSBandit user, I've jumped ships and started using Outlook 2007 to manage all of my RSS feeds. My only reason is that I'm already using Outlook for so many other functions, and now that we are implementing SharePoint, that list of reasons is growing.

One of the things I did not like about Outlooks' default RSS capabilities, was not being able to see a quick, concise list of the feeds / posts that I have not yet read. Fortunately, there is an easy solution to this: Search Folders.

To create a quick, easy way to view all of the unread posts in your feed list, follow these simple steps:

  1. Right click on "Search Folders" in the Outlook tree and select "New Search Folder..."
    image
  2. On the screen that pops up, choose "Create a custom Search Folder" at the bottom of the list:
    image
  3. Click the "Choose" button for specifying criteria and name your folder
    image
  4. Click "Browse" to select the folders that you want to search. Unsleect the root "Mailbox" folder, and select the "RSS Feeds" sub-folder. Ensure that "Search subfolders" is selected.
      image
  5. Click OK to close the "Select Folder(s)" screen. Now click the "Criteria" button, and under the "More Choises" tab, select "Only items that are: ", "unread".
    image
  6. Click OK to close the criteria screen, click OK to close the Custom Search Folder screen, and Click OK to close the New Search Folder screen. You now have an "Unread RSS" folder in your Search Folders. Drag this item into your "Favorite Folder" list and you are done! 
    image

Now your unread RSS feeds are only a button click away! And the great part about this simple solution is that you can create some very specific RSS searches, in additional custom Search Folders. Just follow this process again, only selecting the specific folders that you want.

Saturday, March 08, 2008 9:15:29 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags:

I just can't help myself... I had to flesh out the Account Transfer behavior from my previous post. I was interested in two things:

  1. Adding a second set of Acceptance Criteria for a valid transfer
  2. Implementing the crazy looking "account.Transfer(ammount).To(account)" syntax

Expanded Acceptance Criteria

Existing User Story:

As an account holder,
I want to transfer money between accounts
So that I can avoid overdraft fees

Acceptance Criteria:

  1. Given a transfer between accounts,
    When the requested transfer amount is greater than the originating account's balance
    Then the transfer should fail and the balance of the originating and receiving accounts should not change
  2.  

  3. Given a transfer between accounts,
    When the requested transfer amount is less than the originating account's balance
    Then the transfer is successful, the originating account is debited the transfer amount and the receiving amount is credited the transfer amount

Implementing The Transfer.To Syntax

This was the fun part, really - seeing if I could implement the API that I wanted to see. It turned out to be significantly easier than I had thought it would be.

I started with the Account object, and added the "Transfer" method. I knew that this method needed to return an object so that I could have the "To" method accept an Account object. A few moments of thinking this through and I decided to go with an object called TransferCriteria. This would let me collect all of the information that I need, about the transfer.

public TransferCriteria Transfer(double ammount)
{
    TransferCriteria criteria = new TransferCriteria(this, ammount);
    return criteria;
}

The end-goal of this syntax model is to return an AccountTransfer object, directly. So, the TransferCriteria.To method then creates an AccountTransfer object, using the TransferCriteria.

public AccountTransfer To(Account receivingAccount)
{
    ReceivingAccount = receivingAccount;
    return new AccountTransfer(this);
}


In the end, I have an AccountTransfer object that contains all of the information I need - the originating account, the receiving account, and the transfer amount. With that in place, the rest of the code is simple.

Behavior Specification

AccountTransferSpecifications.cs

using AccountSample.Domain;
using NUnit.Framework;
using SpecUnit;
 
namespace AccountSample.Specifications
{
 
    [TestFixture]
    [Concern("Account Transfers")]
    public class When_The_Requested_Transfer_Amount_Is_Greater_Than_The_Originating_Account_Balance : ContextSpecification
    {
 
        #region Context
 
        private const double originatingAccountBalance = 100;
        private const double receivingAccountBalance = 0;
        private const double requestedTransferAmmount = 125.95;
        private Account originatingAccount;
        private Account receivingAccount;
        private AccountTransfer accountTransfer;
 
        protected override void Context()
        {
            originatingAccount = new Account(originatingAccountBalance);
            receivingAccount = new Account(receivingAccountBalance);
 
            accountTransfer = originatingAccount.Transfer(requestedTransferAmmount).To(receivingAccount);
        }
 
        #endregion
 
        #region Observations
 
        [Test]
        [Observation]
        public void The_Transfer_Should_Fail()
        {
            accountTransfer.Status.ShouldEqual(TransferStatus.Failed);
        }
 
        [Test]
        [Observation]
        public void The_Originating_Account_Balance_Should_Not_Be_Changed()
        {
            originatingAccount.Balance.ShouldEqual(originatingAccountBalance);
        }
 
        [Test]
        [Observation]
        public void The_Receiving_Account_Balance_Should_Not_Be_Changed()
        {
            receivingAccount.Balance.ShouldEqual(receivingAccountBalance);
        }
 
        #endregion
 
    }
 
    [TestFixture]
    [Concern("Account Transfers")]
    public class When_The_Requested_Transfer_Amount_is_Less_Than_The_Originating_Account_Balance: ContextSpecification
    {
 
        #region Context
 
        private const double originatingAccountBalance = 100;
        private const double receivingAccountBalance = 0;
        private const double requestedTransferAmmount = 25;
        private Account originatingAccount;
        private Account receivingAccount;
        private AccountTransfer accountTransfer;
 
        protected override void Context()
        {
            originatingAccount = new Account(originatingAccountBalance);
            receivingAccount = new Account(receivingAccountBalance);
 
            accountTransfer = originatingAccount.Transfer(requestedTransferAmmount).To(receivingAccount);
        }
    
        #endregion
 
        #region Observations
 
        [Test]
        [Observation]
        public void The_Transfer_Is_Successful()
        {
            accountTransfer.Status.ShouldEqual(TransferStatus.Success);
        }
 
        [Test]
        [Observation]
        public void The_Originating_Account_Is_Debited_The_Transfer_Amount()
        {
            const double newBalance = originatingAccountBalance - requestedTransferAmmount;
            originatingAccount.Balance.ShouldEqual(newBalance);
        }
 
        [Test]
        [Observation]
        public void The_Receiving_Account_Is_Credited_The_Transfer_Amount()
        {
            const double newBalance = receivingAccountBalance + requestedTransferAmmount;
            receivingAccount.Balance.ShouldEqual(newBalance);
        }
 
        #endregion
 
    }
 
}

Behavior Implementation

Account.cs

namespace AccountSample.Domain
{
 
    public class Account
    {
 
        #region Properties
 
        public double Balance { get; private set; }
 
        #endregion
 
        #region Constructor
 
        public Account(double currentAccountBalance)
        {
            Balance = currentAccountBalance;
        }
 
        #endregion
 
        #region Methods
 
        public TransferCriteria Transfer(double ammount)
        {
            TransferCriteria criteria = new TransferCriteria(this, ammount);
            return criteria;
        }
 
        public void Debit(double ammount)
        {
            Balance -= ammount;
        }
 
        public void Credit(double ammount)
        {
            Balance += ammount;
        }
 
        #endregion
 
    }
 
}

 

AccountTransfer.cs

namespace AccountSample.Domain
{
 
    public class AccountTransfer
    {
 
        #region Vars
 
        private TransferStatus _status = TransferStatus.None;
 
        #endregion
 
        #region Properties
 
        public TransferStatus Status
        {
            get { return _status; }
            private set { _status = value; }
        }
 
        public double TransferAmmount { get; private set; }
 
        public Account OriginatingAccount { get; private set; }
 
        public Account ReceivingAccount { get; private set; }
 
        #endregion
 
        #region Constructor
 
        public AccountTransfer(TransferCriteria criteria)
        {
            OriginatingAccount = criteria.OriginatingAccount;
            ReceivingAccount = criteria.ReceivingAccount;
            TransferAmmount = criteria.TransferAmount; 
            Execute();
        }
 
        #endregion
 
        #region Methods
 
        private void Execute()
        {
            if (TransferAmmount > OriginatingAccount.Balance)
            {
                Status = TransferStatus.Failed;
            }
            else
            {
                OriginatingAccount.Debit(TransferAmmount);
                ReceivingAccount.Credit(TransferAmmount);
                Status = TransferStatus.Success;
            }
        }
 
        #endregion
 
    }
}

 

TransferCriteria.cs

namespace AccountSample.Domain
{
 
    public class TransferCriteria
    {
 
        #region Properties
 
        public double TransferAmount { get; private set; }
 
        public Account OriginatingAccount { get; private set; }
 
        public Account ReceivingAccount { get; private set; }
 
        #endregion
 
        #region Constructor
 
        public TransferCriteria(Account originatingAccount, double transferAmount)
        {
            OriginatingAccount = originatingAccount;
            TransferAmount = transferAmount;
        }
 
        #endregion
 
        #region Methods
 
        public AccountTransfer To(Account receivingAccount)
        {
            ReceivingAccount = receivingAccount;
            return new AccountTransfer(this);
        }
 
        #endregion
 
    }
}

 

And finally, TransferStatus.cs

namespace AccountSample.Domain
{
 
    public enum TransferStatus
    {
        None = 0,
        Failed = -1,
        Success = 1
    }
 
}

Conclusion

I am madly in love with Behavior Driven Development.

Saturday, March 08, 2008 9:11:27 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Agile | Behavior Driven Development | Unit Testing

In A Previous Post, I talked about how I'm jumping on board the BDD wagon, and I gave an example of a TDD style Unit Test that was close to BDD style, based on how I worded the test. I've decided to test that theory and follow the progression from a standard Unit Test as I was writing them, into a BDD test system such as SpecUnit.NET.

Typical Requirement, Typical Test

Let's look at a very basic requirement, derived and stolen from the presentation done by Scott Bellware at the Agile Austin User Group meeting that I attended last week.

If an account holder has multiple accounts and one is low on funds, allow the account holder to transfer funds between accounts. If the amount to transfer is greater than the amount in the originating account, then the transfer should not be allowed and the balance of both accounts should remain the same. This will let the account holder avoid overdraft fees on the account with insufficient funds.

A basic TDD implementation may look like this:

[TestFixture]
public class AccountTransferTestFixture
{
 
    [Test]
    public void TransferFailsIfRequestedAmmountIsGreaterThanOriginatingAccountsBalance()
    {
        double fromAccountStartingBalance = 100;
        double toAccountStartingBalance = 0;
        double requestedTransferAmmount = 125.95;
 
        Account originatingAccount = new Account(fromAccountStartingBalance);
        Account receivingAccount = new Account(toAccountStartingBalance);
 
        TransferStatus transferStatus = AccountTransfer.Transfer(originatingAccount, receivingAccount, requestedTransferAmmount);
 
        Assert.AreEqual(transferStatus.Failed, transferStatus);
        Assert.AreEqual(fromAccountStartingBalance, originatingAccount.Balance);
        Assert.AreEqual(toAccountStartingBalance, receivingAccount.Balance);
    }
 
}

There is nothing particularly wrong with this unit test. It looks like decent code - appears to be well organized, makes good use of separated objects, and checks to see that everything is as it should be.

Change the Test

Now let's change up the test a bit and move it towards BDD style, the way I have been writing my unit tests recently. The first thing we'll need to do is change the name of the test. Secondly, let's rewrite the object model to be a bit more clear on what's really going on with the transfer.

[TestFixture]
public class AccountTransferTestFixture
{
 
    [Test]
    public void WhenARequestedTransferAmmountIsGreaterThanTheOriginatingAccountBalance_ThenTheTransferShouldFailAndTheAccountBalancesShouldNotBeChanged()
    {
        double originatingAccountBalance = 100;
        double receivingAccountBalance = 0;
        double requestedTransferAmmount = 125.95;
 
        Account originatingAccount = new Account(originatingAccountBalance);
        Account receivingAccount = new Account(receivingAccountBalance);
 
        AccountTransfer accountTransfer = originatingAccount.Transfer(requestedTransferAmmount).To(receivingAccount);
 
        Assert.AreEqual(TransferStatus.Failed, accountTransfer.Status);
        Assert.AreEqual(originatingAccountBalance, originatingAcount.Balance);
        Assert.AreEqual(receivingAccountBalance, receivingAccount.Balance);
    }
 
}

The first thing you'll notice is that the Unit Test's name is significantly closer to the business requirement. This is desired, because it allows a develop and a non-developer to both see what this unit test is really supposed to be doing - how the system should behave when something happens. Secondly, notice the differences in the AccountTransfer object. In the first UnitTest, AccountTransfer was used to attempt the actual transfer and return the status of that transfer. In this test, though, AccountTransfer is an object that is produced by the Account.Transfer method. And lastly, notice the change in APIs to do the actual transfer. Remember that in Test Driven Development, you should be designing the API that you want to call - and then you implement it. I want my API to be very expressive - almost english. This particular change is really a matter of preference, though.

The one thing that has not changed is the list of Asserts. We are still checkign to make sure that the transfer status is "Failed" and that the balance of the originating and receiving accounts is unchanged.

Change the Requirement's Format

Now let's take this example into BDD land.

The first thing we need to do is make sure we have enough information to actually test the behavior of the system. This involves creating a User Story from the requirement that we were given. I won't go into depth on User Stories, here. Just keep the basic format of a User Story in mind, borrowed from Dan North:

As a [role], I want [Feature], so that [benefit]

Let's apply this to the requirement, above:

As an account holder,
I want to transfer money between accounts
So that I can avoid overdraft fees

We can't work on user stores alone, though. The only way a User Story can have any value to a software developer, is when we add Acceptance Criteria to the story. Again, I won't go into detail. Here is the basic format that Acceptance Criteria should follow, borrowed from Dan North, again:

Given [context] [and [some more context], …], When [event], Then [outcome] [and [another outcome], …]

Now let's apply the acceptance criteria to our story

Given a transfer between accounts,
When the requested transfer amount is greater than the originating account's balance
Then the transfer should fail and the balance of the originating and receiving accounts should not change

Notice what we have done with the original requirements, compared to the User Story and Acceptance Criteria. Essentially, we have broken the requirement out into two separate parts that provide more value to the business and to the developer. The User Story is the real business value - what do you want to do, and why. The Acceptance Criteria is where the Developer receives the knowledge of how the system should actually work. Both of these are english statements, though. Nowhere in the Story or Criteria, have we specified any language that deals with a computer, software, or any other technical or implementation detail.

Unit Test the Behavior

With the User Story and Acceptance Criteria separated now, we can write the software and test it. Rather than doing standard Test Driven Development and writing a Unit Test, though; let's focus on Behavior Driven Development and test the behavior of this software using the specified behavior.

This example code is still using NUnit as the test framework, to illustrate that point that you don't need a specific BDD test framework. You can fit BDD style tests into a standard xUnit framework. However, you might feel that it is a little mashed-in and not quite the fit that you want.

namespace Given.A.Transfer.Between.Accounts
{
 
    [TestFixture]
    public class When_The_Requested_Transfer_Amount_is_Greater_Than_The_Originating_Accounts_Balance
    {
 
        double originatingAccountBalance = 100;
        double receivingAccountBalance = 0;
        double requestedTransferAmmount = 125.95;
        private Account originatingAccount;
        private Account receivingAccount;
        private AccountTransfer accountTransfer;
 
        [SetUp]
        public void ContextSpecification()
        {
            originatingAccount = new Account(originatingAccountBalance);
            receivingAccount = new Account(receivingAccountBalance);
 
            accountTransfer = originatingAccount.Transfer(requestedTransferAmmount).To(receivingAccount);
        }
 
        [Test]
        public void The_Transfer_Should_Fail()
        {
            Assert.AreEqual(TransferStatus.Failed, accountTransfer.Status);
        }
 
        [Test]
        public void The_Originating_Account_Balance_Should_Not_Be_Changed()
        {
            Assert.AreEqual(originatingAccountBalance, originatingAccount.Balance);
        }
 
        [Test]
        public void The_Receiving_Account_Balance_Should_Not_Be_Changed()
        {
            Assert.AreEqual(receivingAccountBalance, receivingAccount.Balance);
        }
 
    }
 
}

Notice what we have done with the Acceptance Critiera - we've directly turned it into the tests. We have specified how the system will behave with the various part of the criteria being mapped directly to the various parts of the tests. The [context] has been turned into a namespace; the [event] has been turned into the text fixture's class name; and each of the [outcome] has become a test.

But, why bother splitting all of the parts of the behavior specification out like this? Why not leave it as the unit test was in the previous example? The answer is really the business value of the test and the readability / grok-ability of the tests for developers. I can show anyone on the team - a business analyst, the customer, or a developer - the overview of this specification, and it should be easily understood. A business analyst or customer may not understand the technical details of the Assert statement, or the reason that we have variables declared. However, if they see the collapsed code, it becomes very obvious that the developer has implemented the requested Acceptance Criteria for the user story.

image 

Specify the Behavior

Now that we've seen how to stuff a behavior's specification into an xUnit testing framework, let's look at how to implement it in a testing framework that is designed for BDD: SpecUnit.NET.

namespace AccountTransferSpecifications
{
    
    [Concern("Account Transfers")]
    public class When_The_Requested_Transfer_Amount_is_Greater_Than_The_Originating_Accounts_Balance: ContextSpecification
    {
 
        double originatingAccountBalance = 100;
        double receivingAccountBalance = 0;
        double requestedTransferAmmount = 125.95;
        private Account originatingAccount;
        private Account receivingAccount;
        private AccountTransfer accountTransfer;
 
        protected override void Context()
        {
            originatingAccount = new Account(originatingAccountBalance);
            receivingAccount = new Account(receivingAccountBalance);
 
            accountTransfer = originatingAccount.Transfer(requestedTransferAmmount).To(receivingAccount);
        }
 
        [Observation]
        public void The_Transfer_Should_Fail()
        {
            accountTransfer.Status.ShouldEqual(TransferStatus.Failed);
        }
 
        [Observation]
        public void The_Originating_Account_Balance_Should_Not_Be_Changed()
        {
            originatingAccount.Balance.ShouldEqual(originatingAccountBalance);
        }
 
        [Observation]
        public void The_Receiving_Account_Balance_Should_Not_Be_Changed()
        {
            receivingAccount.Balance.ShouldEqual(receivingAccountBalance);
        }
 
    }
 
}

The major differences between an xUnit framework as a SpecUnit framework, is that the idea of Context is a first class citizen. Aside from that and a few changes to the attribute names used, a SpecUnit test class looks surprisingly similar to the behavior test in NUnit. You'll also notice that we're not using Assert.Equals() anymore. Rather, we're taking advantage of .NET 3.5's Extension Methods and providing a expressive statement. This is somewhat of a syntax preference, though.

We can still compress this code and show it to a business analyst or customer. Even better - SpecUnit.NET comes with a simple report generator that produces an HTML report document based on the specification tests, themselves. The output is essentially a cleaned up version of the collapsed code in an HTML format that anyone can read.

Conclusions: xUnit vs. SpecUnit

The real difference between an xUnit Unit Test and a SpecUnit Specification Test is semantics and a few mechanics. Whether you are using an xUnit framework or a SpecUnit framework, Specification Testing and Behavior Driven Development have a significant benefit to the business when compared to Unit Testing and Test Driven Development alone. As I've said before, this does not mean that TDD is dead or irrelevant. This is only to say that TDD has evolved - it has grown an attachment to Domain Driven Design and Scrum project management, giving it a new home and a new life on it's own. Consider the following:

A Unit Test has the connotation of testing an individual unit of code - a System Under Test as some have called it.

When you pass the value "123" into object XYZ's, ABC method, the result is a change to Foo's Bar property and Widget's Digitize method was called.

Specification Testing, and Behavior Driven Development, on the other hand are all about behavior.

In the context of XYZ, when ABC is done, then the Foo's Bar has been Digitized.

Which would you rather show a business analyst, or the customer? Chances are you could explain the details of the first so that they would understand it... and chances are, that they would understand the second without any need for explanation.

Saturday, March 08, 2008 7:04:02 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Agile | Behavior Driven Development | Unit Testing

(reposting a few items from my old blog to my new one)

...

I hereby declare my love affair with Test Driven Development over, and my new infatuation with Behavior Driven Development beginning. Call me a cool-aid drinker, a bandwagon jumper, or whatever you want... I finally get it...

When I write TDD / Unit Test code like this:

[Test]
public void WhenMagic8BallIsShaken_ThenAnAnswerIsGiven()
{
  //insert code and asserts, here.
}

(and yes, this is an actual example of a unit test I wrote last week, during a TDD training session I was doing for some coworkers), what am I really doing? I'm not just doing TDD, I'm not just Unit Testing... I'm specifying the behavior of the system; I'm specifying the experience of using the magic 8 ball; and really, I'm only about one step away from the mechanics of Behavior Driven Development.

It's an eye-opening realization for me, and gets me all kinds of excited and re-invigorated to learn more.

Now, I'm not going to say that TDD is dead or invalid - it's more like saying I finally see how Domain Driven Design and Test Driven Development are truly married together... and then you change the semantics of the name to fit that marriage.

It's also worth noting that this jump, for me, is purely from the engineering perspective so far. I still have no real experience with a true agile development project / process. Although I'm slowly stepping closer to that - the more I see in the engineering practices, the more I see the need for the project management practices.

... more to come, as I travel down this path.

Saturday, March 08, 2008 3:29:00 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Agile | Behavior Driven Development | Unit Testing

(reposting a few items from my old blog to my new one)

...

Another interesting side effect of my conversations with Scott Bellware, today... I'm not sure if he agrees with these conclusions, but I certainly didn't come to them by my own thoughts alone.

My understanding of the Test Lab or QA department in a software development shop has been based on the idea that the QA team members are not developers - and that they shouldn't be, because a developer will write tests that they know will pass. Well, as it turns out - the reason was correct, but the conclusion was wrong.

In reality, a software development project needs to automate every level of testing - all the way out to the point where the actual customer is sitting down and using the software. This includes: Unit Testing, Integration Testing, and UI Testing. Whether or not you distinguish between these three levels is irrelevant; the testing of the system must be automated as much as possible. This leads us to the next question: What is an automated test? Typically speaking, it's code. Who writes code? Software developers. Do you see where this is heading? maybe?

If software is developed by software developers (duh), why is the software that tests the software not written by software developers?

Lets take this to the agile world of 2 week iterations (or sprints or whatever you want to call them). If the software requirements are being defined every two weeks, then the tests are being defined every two weeks as well. If we are automating the tests during these two week cycles, and the tests are written as code, then why are the software developers not writing the tests? The obvious answer is my reason above - the developer will write the test that they know will pass, because they wrote the code that is being tested. So don't let that happen - don't let the developer who is writing the code, write the integration / UI test code. Then, how do we let a developer write the integration / UI test code? Triples Programming.

The standard XP / Agile practice currently has developers working in pairs - one driving the keyboard / mouse, and one thinking two steps ahead. I say we add a third role and a third person to the mix - one developer to write the integration / UI tests at the same time that the unit tests / production code are being written. What you CANNOT do, though, is include that third role in only two people. The moment you break down to two people, you need to remove the integration / UI test writing or you end up with the original dilemma. You also need to ensure that the developers in the triple, are swapping positions on a regular basis - make sure everyone gets a change to drive the keyboard, think ahead, and code the integration tests.

By programming in triples, you get the advantage of specifying the integration tests as soon as the code is functional. You don't lose motivation to write those test, you don't lose clarity of what the functionality is supposed to be, and you don't have to re-discover the same functionality and clarity at a later time with a new set of minds (the QA team).

So, what happens to the QA team? They are still needed, certainly. But now they can focus on their subject matter expertise - the human interaction of manual and random of software testing by using the actual application. i.e. the parts of testing that can't (or shouldn't) be automated.

...

Ok, ok, ok... if you really want to stick with pair programming you can take this concept and assign 2 teams per story; 1 team to unit test / write production code; and 1 team to integration / UI test.

Saturday, March 08, 2008 3:27:51 PM (Central Standard Time, UTC-06:00)  #    Comments [2]. Trackback 
Tags: Agile | Unit Testing

(reposting a few items from my previous blog to my new one)

...

I follow a lot of Agile Engineering Practices, at this point in my career: Test Driven Development, Domain Driven Design, Single Responsibility Principal, Separation of Concerns, Inversion of Control, Dependency Injection, etc. To get to this point, I've basically taught myself - I read blogs, books, example code, and work my butt off to make sure I know what I'm talking about so that I can stay a few steps ahead of my team(s). In all this effort, learning, failure, success and otherwise, I've learned a few key things about software development as it relates to the Agile world.

  1. Unit Testing is an absolute must, even if you don't do Agile
  2. Unit Testing is not Test Driven Development
  3. Test Driven Development is Agile Engineering, not Agile Process
  4. Agile Engineering alone, does not make Agile software development

1. Unit Testing is an Absolute Must

Whether or not you are trying to do any sort of agile software development, or even test driven development; if you do not unit test your code, you are opening your code up for breaking unexpectedly. In the worst case scenario, you are preventing your code base from being able to change with the needs of the business and causing crippling problems by not keeping your code separated appropriately.

Think about the goals of object oriented development: well encapsulated, highly cohesive and low coupled objects that can easily be re-used. These goals are very high, very lofty and they may be pie-in-the-sky dreams for some developers. So how do you achieve such goals? Single Responsibility Principle, Separation of Concerns, and Inversion of Control. All of these practices are much closer to the implementation level of code - they tell us to keep our code as small as possible; only write the code that needs to be written, in this class. When you see code that does not quite fit into the class you are currently writing, you look for a better place to put that code. This means that you need to split data access out of your business processing, user interface out of your business processing, and often times you will need to split your business process out into multiple classes.

The hard part is, single responsibility, separation of concerns, etc. are not one-time coding practices per class. They are processes that require a continuous series of design, redesign, and refactoring of your code. Don't assume that an object you write, now, will be the same 10 minutes or 10 days from now. If you find yourself in a situation where two objects are very similar, you may have an opportunity to create a better abstraction that can fit both scenarios - whether it becomes a single object, a template pattern, strategy pattern, or other solution.

If you are continuously redesigning your code to fit the business needs, and you are continuously separating your code into more and more classes, creating the high cohesion and loose coupling of true OOD; how do you manage the process and ensure that you are not breaking your application as you go? The answer is simple: Unit Testing. If you are not unit testing your application, then you do not know if the application works until you actually run it and try to use it. If your application is small - one or two classes, one or two screens - this may be reasonable and you may just run the application in it's entirety to see if it works. If your application is medium to large, though - one or two hundred or thousand classes and screens - you will quickly find yourself in a situation where you cannot expect to run the entire application in a reasonable amount of time and you are likely to miss some of the features and functionality if you do try to run it all. The only reasonable way to ensure that your code still works, is to have an automated test suite that can be executed on a regular basis. The easiest way to achieve this, at a very low level, is to do Unit Testing and ensure that your code is 100% covered with the unit tests. By unit testing every line of code in your system, you will have a rapid feedback tool that tells you when you break something. This rapid feedback will allow you to quickly fix anything that is broken, compared to the "run it and see" process.

With all that being said, it's very important to understand ...

2. Unit Testing is not Test Driven Development

Test Driven Development involves Unit Testing. In fact, Test Driven Development doesn't exist without Unit Tests. However, just because you are Unit Testing, that does not mean that you are doing Test Driven Development. When it comes down to it, Unit Testing is all about insurance - make sure your code is covered because change will happen, and change breaks things. Test Driven Development, on the other hand, is all about software design; writing your unit tests first, to drive the design of the software that you are really writing. TDD is not just Unit Testing; TDD is not just Test-First-Development, either. True TDD is the practice of designing the APIs in your code, by writing out the API that you want to see before you try and implement it.

To do any sort of software development, you need to have some basic functional requirements - what is this software going to do, and why? When you start breaking these requirements down into pieces that are small enough to implement, you can begin to see how the software will look - what classes will be there, what processes will run, and how it all fits together.

When you have good requirements it's easy for a developer to see some of the low level code implementation - using whatever design pattern to create these classes, with this code underneath so that this feature can call into them and do something... TDD, though, wants you to step back a few paces. Don't worry about the low level implementation details, yet. Let's focus on how you want to call into the implementation - what is the API that you want to call, in order to do these processes. Rather than looking at a requirement and saying that you don't know what the API will look like because they have not implemented any of the details, TDD forces you to think backwards - you don't know what the implementation is, but here is the API that you want to call.

3. TDD is Agile Engineering Only

There is a huge disconnect from Test Driven Development, to a true Agile software process. Agile Engineering is a great set of practices that every developer should adopt. This includes Test Driven Development, Domain Driven Design, even Pair Programming. However, these engineering practices can and do fit into any software development lifecycle: RUP, Waterfall, iterative waterfall, and everything else you can image, can all have Agile Engineering practices put in place. I would go so far as to say that we shouldn't even call it Agile Engineering - rather, we should just call these good software engineering practices.

To illustrate this - look at the projects that I work on. They are all standard waterfall type projects. We've implemented these engineering practices in every project that I have lead, for the last 2 years, though.

4. Agile Engineering is not Agile Software Development

Real Agile software development is more than just good engineering practices. It encompasses the entire software development lifecycle - from requirements gathering to requirements definition, continuous discussions with the customer to elaborate on those requirements, discussions with the customer to determine what requirements go into what release and iteration, and more discussions with the client to ensure that the software is heading down the path that they actually want. Have you noticed a trend, here? There's a lot of constant, continuous discussion with the customer in real Agile development. This is an absolute must, in Agile work. If you don't stay in regular communications - as in daily, if not more often - then you don't know if the customer is getting what they want.

I've worked on various projects that do some of these - short iterations, continuous integration for unit testing, regular releases to the customer, even pair programming; but I have never worked on a true agile project. It's just not possible to do true agile software development if you don't have complete buy-in and ownership from the entire team - from the customer down to the individual developer. I dream of the day that I'll have a chance to work in an environment like this.

The Future of Agile

Agile engineering, Agile process... how does this all tie together? Where is the knowledge moving and how do we get there? Personally, I'm on board with Behavior Driven Development group. Imagine taking every aspect of Agile, and wrapping it up into one very cohesive set of processes and practices. I get all kinds of excited just thinking about it.

Saturday, March 08, 2008 3:26:08 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags: .NET | Agile | Model-View-Presenter | Unit Testing

I decided to go ahead and jump over to a new domain, and a new blog engine... if you are already a subscriber to my FeedBurner feed, then this switch will be automatic for you - you won't have to change anything.

I really like the simplicity of dasBlog, so far. It was really easy to set up and pretty much has everything i want in a blog system, without all the fluff of other systems.

... here's to a new blog and a new domain name.

Saturday, March 08, 2008 12:46:14 PM (Central Standard Time, UTC-06:00)  #    Comments [0]. Trackback 
Tags:

Navigation
About Me
View Derick Bailey's profile on LinkedIn

Send mail to the author(s) Contact Me
Archive
<March 2008>
SunMonTueWedThuFriSat
2425262728291
2345678
9101112131415
16171819202122
23242526272829
303112345
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
Derick Bailey
Sign In
Statistics
Total Posts: 115
This Year: 0
This Month: 0
This Week: 0
Comments: 44
Themes
Pick a theme:
All Content © 2010, Derick Bailey
DasBlog theme 'Business' created by Christoph De Baene (delarou)