
There’s been lots of chatter lately about whether Agile is Dead, or if Scrum is [better|worse] than Lean, and whether Lean can be used for Development teams, or if Scrum should be shot, and so on, and thus forth. Here’s my view, subject to correction:
A lot of this also has to do with things like the Dreyfus Model of Skills Acquisition – beginners need to be told what to do – which is why Scrum works so well. 3 practices, we’ll teach them to you in a weekend, and you can get up and running with it. Scrummerfall is easy to do when you aren’t also combining the practices with continuous improvement models.
So what should you start with if you want to make a software team better? There are two ways I suggest:
So I find the whole arguments silly. If we’re optimizing software teams, then we look to software practices. If we aren’t, we don’t. If I use Value Stream Mapping during my Retrospective with my Onsite Customer right after our Product Demos, it’s all part of becoming agile. I may not be "doing" XP or "doing" Scrum or "doing" Lean – and from the people and leaders I’ve talked to, that’s perfectly fine. But I also have enough respect for their ideas that if I’m mixing and matching, and cutting and tweaking, that I not blame a process I’m not even following. Perhaps if more people would simply acknowledge they aren’t following the process, and instead talk about why they aren’t, we could make more progress as a whole.
Until then, we’ll keep seeing people spinning their wheels and being kicked out of groups and denouncing each other’s practices. When Uncle Bob suggested craftsmanship over crap as the 5th manifesto point, we should have embraced it as a community not only from a software engineering side, but a communication side as well.
Happy Thanksgiving All. Gobble Gobble.
If you are getting any of these types of exceptions compiling code:
Then you are trying to compile code with .NET 3.5 that someone has written using .NET 3.5 SP1. And there ya go.
I’ve been working on some more spikes around my Fluent Fitnesse effort mentioned a couple of days ago. One of the things this is designed to be is a roundtrip tool – so Fitnesse pages get converted to code, and vice versa. This way the business people still use Fitnesse for all of their work, and the coders can build and maintain it in code.
The spike tonight was the basic parsing of a page. I had some ideas of what I wanted to do, but I hadn’t settled on a strategy. So I did what I always do when I’m stuck – I write a test:
[Test]
public void AllLinesStartingWithBangNotInATableShouldBePlacedInTheHeaderBuffer()
{
string expected = @"!contents -R2 -g -p -f -h
!define COMMAND_PATTERN {%m %p}
!define TEST_RUNNER {dotnet2\FitServer.exe}
!path C:\Users\Cory\Documents\Visual Studio 2008\Projects\FluentFitnesse\DivisionFixtures\bin\Debug\DivisionFixtures.dll
";
string actual = HeaderParser.Parse(SAMPLE_PAGE);
Assert.AreEqual(expected, actual);
}
Seemed reasonable enough. I knew in my head this wouldn’t be perfect – definitions can happen throughout the page, and this kind of shoves them all into one. But I knew that would come out later. So I wrote some code to make it pass:
public class HeaderParser
{
public static string Parse(string page)
{
StringBuilder output = new StringBuilder();
foreach (string line in page.Split(new char[] { '\r','\n' }, StringSplitOptions.RemoveEmptyEntries))
{
if (line.StartsWith("!"))
{
if (line.IndexOf("|") > 0)
continue;
output.AppendLine(line);
}
}
return output.ToString();
}
}
Again, not perfect. For example, if you haven’t used Fitnesse, why does it matter if line.IndexOf("|") is greater than 0? (It’s because you can tell the wiki not to process WikiWords inside a table by prefixing the table row with a bang (!)). But I was on a mission – because I knew that this whole thing wouldn’t last. So I wrote my next test:
[Test]
public void CommentTableWithOneLineShouldConvertToFluentFitnesseCommentClass()
{
string commentTable = @"|Comment|
|Module1.DivisionDoFixture|";
string expected = @"using(FluentFitnesse.Comment.BoundTable)" + System.Environment.NewLine
+ "{" + System.Environment.NewLine
+ "FluentFitnesse.Comment.Call.Comment(\"Module1.DivisionDoFixture\");" + System.Environment.NewLine
+ "}" + System.Environment.NewLine;
string actual = CommentParser.Parse(commentTable);
Assert.AreEqual(expected, actual);
}
}
This deals with |Comment| tables in Fitnesse, which won’t be tied to a class. And the code to make this pass? This nasty thing:
public static string Parse(string page)
{
StringBuilder classOutput = new StringBuilder();
bool inCommentTable = false;
foreach (string line in page.Split(new char[] { ‘\r’,'\n’ }, StringSplitOptions.RemoveEmptyEntries))
{
if (line.StartsWith("|Comment|"))
{
inCommentTable = true;
classOutput.AppendLine("using(FluentFitnesse.Comment.BoundTable)");
classOutput.AppendLine("{");
}
else if (inCommentTable)
{
if (line.Trim().Length == 0)
{
classOutput.AppendLine("}");
inCommentTable = false;
}
else
{
string contents = line.Replace(‘|’, ‘ ‘);
classOutput.AppendLine("FluentFitnesse.Comment.Call.Comment(\"" + contents.Trim() + "\");");
}
}
}
if (inCommentTable)
{
classOutput.AppendLine("}");
}
return classOutput.ToString();
}
My spidey-pattern senses were tingling, but I wanted one more test:
[Test]
public void TextNotInATableShouldBeConvertedToFluentFitnesseTextCall()
{
string page = "This is some text";
string expected = "FluentFitnesse.Text.Call.Text(\"This is some text\");";
string actual = PageTextParser.Parse(page);
Assert.AreEqual(expected, actual);
}
And the code?
public static string Parse(string page)
{
return "FluentFitnesse.Text.Call.Text(\"" + page + "\");";
}
Ah! Now that’s more like it. Since text can be anywhere in the page, it has to stay in the same place because otherwise it will be all jumbled. For the header I knew it wasn’t as important, because, after all, it is header information. But page text not in a table means that I have to preserve the line locations. Which means that my initial though of parsing the pages and spitting out whole sections of code is off – I instead need to parse line by line and pass
to a more Chain-based approach to let handlers deal with what to output next.
I’m sure that had I taken time to write and sketch I would have come to the same conclusion, but having the natural feel of the tests and writing code is something that is so, well, satisfying.
One of the biggest challenges for people using FitNesse in any scale is how to manage the pages. Since everything is a wiki, and mapped dynamically to adapter classes, it becomes very easy to break, very easy to make brittle, and pretty difficult to refactor. While there has been work on the interwebs to make things better (for example, Jeremy Miller’s StoryTeller), I kept thinking about ways we could make things better without having to rewrite things.
Last week at KaizenConf I was talking with Scott Bellware about FitNesse and the challenges. The way I see it, right now you’ve got 3 basic options:
We’ve noted FitNesse’s issues already. DSLs are interesting in that they are in the context and domain of your users, but managing editing and creating them can be a pain. I really like RSpec, and have for a long time, but I really only like xSpec in Ruby – I haven’t particularly cared for it in other languages. It runs into a similar challenge of DSLs, and mixes in programming constructs as well.
When I really started thinking about it, most complaints I hear about FitNesse are around refactoring and management. You are writing things in a Wiki syntax that map back to code – but if you need to change that code, it becomes darn near impossible to know what you’ve broken. If we can solve that, then we might be able to make FitNesse a little more usable.
The inspiration point came out of the ALT.NET discussions around Fluent NHibernate – people had challenges writing all the XML configuration (or thinly veiled XML in the form of C# code) to hook up NHibernate, so they made some interfaces and abstracted code to make it much easier to work with. So why not do the same for FitNesse? Let’s look at a typical DoFixture:
!|MathFixtures.DivisionFixture|
|When The Numerator Is|3|And Divisor Is|1|Then Result Is|3|
|When The Numerator Is|7|And Divisor Is|2|Then Result Is|2.5|
|When The Numerator Is|4|And Divisor Is|2|Then Result Is|2|
Pretty straightforward. To run this, you’d have to create a mapping class. Using C#, that would look like:
public class DivisionFixture : fitlibrary.DoFixture
{
public bool WhenTheNumeratorIsAndDivisorIsThenResultIs(double num, double div, double result)
{
return (num / div) == result;
}
}
So we now begin to see the problem. What if we realize our tests should specify the behavior we want, so we want to change it from "Then Result Is" to "Then The Result Should Be"? We have to change both our FitNesse page and our C# class – and we won’t know until runtime that we missed something.
What if, instead, we could do the following?
FluentFitnesse.Fixture
new FluentFitnesse.Fixture
using (f.BoundTable)
{
f.Call.WhenNumeratorIs_AndDivisorIs_ThenResultIs(3.0, 1.0, 3.0);
f.Call.WhenNumeratorIs_AndDivisorIs_ThenResultIs(7.0, 2.0, 3.5);
f.Call.WhenNumeratorIs_AndDivisorIs_ThenResultIs(4.0, 2.0, 2.0);
}
return f.Output;
The output of which is our FitNesse table from above. Now what we have is a specification we can actually refactor. If we change the method name in our underlying classes, it becomes a compile-time issue – not something we discover way down the line. Even better, the call is using our Fixture object – so no concerns about it being out of sync.
The guts behind it is pretty simple, and requires just some minor modifications to your FitNesse fixture class. First, you have to use underscores where the parameter values should be inserted (as you can see from the above example). Second, your methods need to be virtual, as we are creating a DynamicProxy. Third, they need to return bool – something you are probably already doing with a DoFixture anyway.
With that out of the way, simply create a class for each wiki page you want which implements an IFitnessePage instance.
public class DemoDivision : FluentFitnesse.IFitnessePage
{
#region IFitnessePage Members
public string Header()
{
return @"!contents -R2 -g -p -f -h
!define COMMAND_PATTERN {%m %p}
!define TEST_RUNNER {dotnet2\FitServer.exe}
!path C:\Users\Cory\Documents\Visual Studio 2008\Projects\MathFixtures\bin\Debug\MathFixtures.dll";
}
public string Render()
{
FluentFitnesse.Fixture
new FluentFitnesse.Fixture
using (f.BoundTable)
{
f.Call.WhenNumeratorIs_AndDivisorIs_ThenQuotientShouldBe(3.0, 1.0, 3.0);
f.Call.WhenNumeratorIs_AndDivisorIs_ThenQuotientShouldBe(6.0, 2.0, 3.0);
}
f.Call.WhenNumeratorIs_AndDivisorIs_ThenQuotientShouldBe(7.0, 2.0, 3.5);
return f.Output;
}
#endregion
}
Running this will produce the output:
!|MathFixtures.DivisionFixture|
|When Numerator Is|3.0|And Divisor Is|1.0|Then Quotient Should Be|3.0|
|When Numerator Is|6.0|And Divisor Is|2.0|Then Quotient Should Be|3.0|
|When Numerator Is|7.0|And Divisor Is|2.0|Then Quotient Should Be|3.5|
Notice the extra space. That’s because if you are using a Flow-style fixture, you don’t want the rows right underneath the fixture name. What happens is that BoundTable returns an object that inserts an extra line when "disposed".
The entirety of the Fixture class looks like:
namespace FluentFitnesse
{
public class Fixture
{
private StringBuilder output;
private T fixtureObject;
public Fixture()
{
output = new StringBuilder();
fixtureObject = CreateWrapper();
}
; private T CreateWrapper()
{
Castle.DynamicProxy.ProxyGenerator proxyGen = new Castle.DynamicProxy.ProxyGenerator();
T instance = proxyGen.CreateClassProxy
return instance;
}
public IDisposable BoundTable
{
get
{
return new BoundTable(typeof(T), output);
}
}
public T Call
{
get
{
return fixtureObject;
}
}
public string Output
{
get { return output.ToString(); }
}
}
public class MethodInterceptor : Castle.Core.Interceptor.IInterceptor
{
private StringBuilder sb;
private string SplitCamelCase(string s)
{
Regex upperCaseRegex = new Regex(@"[A-Z]{1}[a-z]*");
MatchCollection matches = upperCaseRegex.Matches(s);
List
foreach (Match match in matches)
{
words.Add(match.Value);
}
return String.Join(" ", words.ToArray());
}
public MethodInterceptor(StringBuilder sb)
{
this.sb = sb;
}
#region IInterceptor Members
public void Intercept(Castle.Core.Interceptor.IInvocation invocation)
{
string methodName = invocation.Method.Name;
string[] parts = methodName.Split(‘_’);
if (parts.Length != invocation.Arguments.Length)
{
Console.WriteLine("WARNING! Number of arguments does not match the number of parts in the method name");
Console.ReadLine();
}
int argPos = 0;
sb.Append("|");
foreach (string part in parts)
{
sb.Append(SplitCamelCase(part) + "|" + invocation.Arguments[argPos] + "|");
argPos++;
}
sb.AppendLine();
invocation.ReturnValue = true;
}
#endregion
}
public class BoundTable : IDisposable
{
private StringBuilder output;
public BoundTable(Type t, StringBuilder sb)
{
this.output = sb;
output.AppendLine("!|" + t.FullName + "|");
}
#region IDisposable Members
public void Dispose()
{
output.AppendLine();
}
#endregion
}
}
Which, as you can see, uses the Castle DynamicProxy to wrap the Fixture code and intercept all calls to it. It’s all a bit hacky -I don’t like passing around StringBuilders, etc – but I wanted to get a baseline out there to see if people thought this would be useful.
The basic use case would be that you would gen out all of your FitNesse pages using a utility which took in a list of assemblies that contained your mappers. Ideally we could either reverse-gen C# code from the content pages, or otherwise have a way to tell when the pages are out of date (in case the users are changing them).
I’m really interested in feedback on this. I think this could really help out the "refactoring is hard in FitNesse" stigma. What do you all think?