Wednesday, November 5, 2008

How to verify an user story

I write my user stories like this:

As a [role]
I want to [do something]
So that I [get some business value]

Let's look at an example (read it column by column).

As a/an I want to... so that...
web designer create a default layout for my site I can decide the look and feel I want

Now, how can I verify that my application has implemented this story? To do that you can use Stormwind Accuracy. It's an excellent tool to implement acceptance tests by BDD. And if you have any feedback about it then Bernardo Heynemann is glad to hear from you.

Ok. Let's write a test to verify that in our story we can save a template for our site.

First we setup the story

   1: story = Story    
   2:   .AsA("web designer")    
   3:   .IWantTo("create a default layout for my site")    
   4:   .SoThat("I can decide the look and feel I want");
then we setup the scenario for this story

   1: story.WithScenario("User can save valid template")    
   2:   .Given(I.GoTo("Create Template Page"))    
   3:   .When(I.Fill("Template name").TextBox.With("MyTemplate"))    
   4:   .And(I.Fill("template content").TextBox.With("MyTemplateContent"))    
   5:   .And(I.Click("template save").Button)    
   6:   .Then(I.WaitFor("Template saved successfully").Message);

When we then run our story (test) we will get this output


When_creating_templates.Should_save_valid_template : Passed

Story:

As a web designer
I want to create a default layout for my site
so that I can decide the look and feel I want

Scenario 1: User can save valid template
Narrative:
Given That
I navigate to Create Template Page at http://localhost/admin/template/new
When
I fill the Template name with "MyTemplate"
And I fill the template content with "MyTemplateContent"
And I click the "template save" button
Then
Wait for the message Template saved successfully to appear.

Compare the output with the story definition in the beginning. Sweet!

Now I can have "automagic" acceptance tests to verify that my application works for future changes. Today and tomorrow!

Tuesday, October 7, 2008

Register services in Windsor - take 2

I had to write my Find service method in almost every solution I made so it was time to add it to Castle. Now you can write this to auto register all your services, repositories, views, etc:

[TestFixture]
public class AllTypesTestCase
{
[Test]
public void Should_register_by_service_interface()
{
var kernel = new DefaultKernel();
kernel.Register(AllTypes
.Of<IService>()
.FromAssembly(typeof(ProductService).Assembly)
.WithService.FromInterface());

Assert.AreEqual(typeof(ProductService), kernel.Resolve<IProductService>().GetType());
Assert.AreEqual(typeof(OrderService), kernel.Resolve<IOrderService>().GetType());
}
}

public interface IService
{
}

public interface IProductService : IService
{
}

public class ProductService : IProductService
{
}

public interface IOrderService : IService
{
}

public class OrderService : IOrderService
{
}

Thanks Craig Neuwirt for applying my patch (with some modifications) to Castle.

Friday, October 3, 2008

Keeping Quality

I got a comment some days ago that the design and quality decreases over the lifetime of the product and that it's not possible to keep the initial quality. I strongly disagree*. This is where TDD and NDepend comes to a rescue. TDD is not (only) about test but also design. What is the first thing you write in your test method? Is it an Assert statement or is it how you interact with your service under test? If you skip TDD when the product becomes bigger then your quality will decrease.

But how do you set design rules for your system e.g. that you should follow DIP? That's where NDepend comes to rescue. Set up a rule that says "do not depend on a specific external system". If you have your infrastructure, external dependencies, etc in their own assemblies (App.Repository for example) then you can write the rule something like this:

  WARN IF Count > 0 IN
SELECT NAMESPACES FROM ASSEMBLIES "App.Model"
WHERE IsDirectlyUsing "App.Repository.*"
If someone adds a reference to this assembly from your model, tomorrow, next summer or whenever, then the alarm will start to sound!

If you do some clever rules and use TDD then I think you can have design and code quality in the future as well. But, and it's a big but, you can't and you shouldn't put all the trust to the tools. You need co-workers that understand why you should follow the dependency inversion principle, how to write good test, and so on. That's the greatest chance to keeping good quality in your system!

* I disagree that it's not possible, not that it's a fact for most systems.

Thursday, October 2, 2008

Register services in Windsor

This code handles almost all your future Windsor components. Very nice in my opinion!

protected virtual void InitializeWindsor()
{
if (container == null)
{
container = new WindsorContainer();

ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container));

//register all services
container.Register(
AllTypes.FromAssembly(typeof (ProductService).Assembly)
.BasedOn<IService>()
.WithService.Select(type => FindService(type, typeof (IService))));

//register all repositories
container.Register(
AllTypes.FromAssembly(typeof (ProductRepository).Assembly)
.BasedOn<IRepository>()
.WithService.Select(type => FindService(type, typeof (IRepository))));

//and so on...
}
}

private static Type FindService(Type type, Type implements)
{
return FindService(type, implements, new Type[0]);
}

private static Type FindService(Type type, Type implements, ICollection<Type> typesToIgnore)
{
Type first = null;
Type[] interfaces = type.GetInterfaces();
foreach (Type theInterface in interfaces)
{
if (theInterface.GetInterface(implements.FullName) != null && !typesToIgnore.Contains(theInterface))
{
first = theInterface;
break;
}
}
return first;
}

The alternative is this. But this one doesn't handle future components and you have to register them one by one.

protected virtual void InitializeWindsor()
{
if (container == null)
{
container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container));

// Register all services
container.Register(
Component
.For<IProductService>()
.ImplementedBy<ProductService>());

container.Register(
Component
.For<IOrderService>()
.ImplementedBy<OrderService>());

// continue with all other services, repositories, etc..
}
}

What is the cost of a story

When estimating the cost of finishing a story most people only thinks about implementation. What's really important is the cost to get it to production and maintenance. Managers stress a low cost on implementation but that can lead to a high maintenance cost. If you think about how much it cost to finish a project compared to maintaining the product, then hopefully you realize that having a product and a team that can handle changes is very important. Some people think that after they get the system into production then the workload will go down quite a lot. But the opposite can happen because then you have both production issues and new change request/defects to handle. That's why it's so important to have a good way to handle changes because they will come. I don't think that your product will be version 1.0 that long.

There are many ways to handle changes from software development to organization. I will talk about some of them in future posts. Stay tuned.

Wednesday, August 27, 2008

Add more people is not always the best solution

A quite common "solution" when there is a risk to not reach a deadline is to add more people to the group. What I usually say is that you should do the opposite and "remove" those persons that takes time from other developers and let the group work with no disturbances. If you add more people then the velocity usually* goes down. Now I have some figures to point to when I red Mike Cohn's post regarding if it's possible to predict the team size in a sprint.

What I wanted to know was “What is the average impact of adding a person to a seven-person team?” I would have loved the answer to be something like “Velocity goes up 15%.” Unfortunately, it wasn’t that straightforward because velocity often dipped for a couple of iterations before going up.
Note that in the long term it can be better to add more people thou.

* If you add developers that know the details and can start to produce directly then the velocity can go up but that case is quite rare