I have found it valuable to distinguish between the refactoring done in Red-Green-Refactor and the Refactoring done when I have a new story to implement and the design needs to change to accommodate the new feature.
This second form I call Prefactoring.
Prefactoring is performed on otherwise clean well factored code in preparation of a new feature. Prefactoring is perfectly normal on any XP project and in-fact indicates a healthy ongoing design process.
The distinction grew in my mind when we were facing a lot of exiting code debt. I needed a way to distinguish between the 'repair work' I was doing and the 'perfectly acceptable design work'. This was in response to questions like "How much more refactoring is left?" which really meant "How much repair work is left?".
A quick word on Prefactoring and Iterative Design.
Ideally your design applies the OpenClosedPrinciple, which would imply that adding new features would simply require you to add new code. That is great as long as the feature fits one of the axis you have opened your design to change.
However YAGNI indicates you should keep your code as simple as possible. Attempting to open your design to changes in more ways than you currently need can be over-design.
The solution is that you keep your code simple but Prefactor when you need your design to be open in a new dimension. You can then simply add the new feature by adding code. Utopia!
Splitting the work into these two steps makes implementing new features a much simpler process. The new tests are always easy to write. The design always nicely accommodates the the new feature.
As ever, I appreciate Rob for shaming me into finally blogging about this and helping me separate the dumb ideas from the gems.
Nigel Thorne's software development blog, focusing on finding simple solutions to real work problems.
Tuesday, February 26, 2008
Thursday, January 24, 2008
Dynamic .Net
Thanks to LinFu C# has DuckTyping, MixIns, MultiDispatch and much more...
I'm already used this library for a new open source project, I'll blog on that next.
I'm already used this library for a new open source project, I'll blog on that next.
Monday, November 19, 2007
NCoverCop trunk... for coverage
If you grab NCoverCop from svn you can check out a couple of improvements.
E.g. "trunk.*" (as above) will truncate "C:/something/trunk/somedir/file.cs" to "trunk/somedir/file.cs" when comparing with another results file.
Let me know if you find NCoverCop useful.
Note: Big big thanks to VarianInc for allowing me to do some work on NCoverCop on their dime. They have introduced a policy of using opensource code wherever they can, and contributing back to the community.
Varian (Melbourne) are by far the most agile company I have worked for to date. I highly recommend anyone that is keen to be part of a well functioning agile .Net team to get in contact with them. Email me and I'll forward your details if you like.
- Refactoring Allowed.. If you delete tested code that is no longer needed, then this will unfortunately have the side effect of dropping your coverage percentage. NCoverCop allows for this by checking the number of untested lines. If it has not increased then the build is passes as you didn't make things worse.
- Coverage Differences are displayed when a build fails to give you an idea of the lines in the file that have become uncovered, or been added without test.
- sectionOfFilePathToCompareRegex allows you to specify a section of the document paths in the NCoverResults.xml files to ignore when comparing the files. This allows you to compare the build's file with your local one even if your trunk paths differ.
coverageFile="${ncover.output.filename}"
minCoveragePercentage="59"
previousCoverageFile="${ncover.backup.filename}"
autoUpdate="${environment::get-machine-name() == debug.buildbox.name}"
sectionOfFilePathToCompareRegex="trunk.*"
/>E.g. "trunk.*" (as above) will truncate "C:/something/trunk/somedir/file.cs" to "trunk/somedir/file.cs" when comparing with another results file.
Let me know if you find NCoverCop useful.
Note: Big big thanks to VarianInc for allowing me to do some work on NCoverCop on their dime. They have introduced a policy of using opensource code wherever they can, and contributing back to the community.
Varian (Melbourne) are by far the most agile company I have worked for to date. I highly recommend anyone that is keen to be part of a well functioning agile .Net team to get in contact with them. Email me and I'll forward your details if you like.
Labels:
.Net,
C#,
cc.net,
code coverage,
Cruise Control,
NAnt,
nant custom task,
ncovercop,
testing
Unveiling NCoverCop
Duncan Bayne (who I have the pleasure of working with at the moment) had the idea of writing a small exe to parse an NCoverResults file and fail a build if the coverage drops below a set threshold. I loved it... and decided to up the ante.
From that seed I have built NCoverCop.
NCoverCop is a custom NAnt task that not only fails your build if your coverage drops, but lifts the threshold each time a new build passes with a higher threshold.
It works by keeping a copy of the best coverage file.
Here's how I use it..
Here are a few tips...
We have the previousCoverageFile in a location that is visible on the network and referenced in the build file through it's network address. Coupled with being able to turn autoUpdate off for everyone except the build machine means that you can run ncoverCop locally and see if you are going to break the build before you check in.
From that seed I have built NCoverCop.
NCoverCop is a custom NAnt task that not only fails your build if your coverage drops, but lifts the threshold each time a new build passes with a higher threshold.
It works by keeping a copy of the best coverage file.
Here's how I use it..
coverageFile="${ncover.output.filename}"
previousCoverageFile="${ncover.backup.filename}"
minCoveragePercentage="65"
autoUpdate="${environment::get-machine-name() == debug.buildbox.name}"
/>
- coverageFile is the location of the NCoverResults.xml file you want to compare.
- previousCoverageFile is the file that will be overwitten if a successful build beats the current threshold.
- minCoveragePercentage is used when you don't have a previousCoverageFile yet or the specified percentage is higher than that of the previousCoverageFile.
- autoUpdate can be turned off so the previousCoverageFile doesn't get updated in a passing build.[defaults to on]
Here are a few tips...
We have the previousCoverageFile in a location that is visible on the network and referenced in the build file through it's network address. Coupled with being able to turn autoUpdate off for everyone except the build machine means that you can run ncoverCop locally and see if you are going to break the build before you check in.
Labels:
C#,
cc.net,
Cruise Control,
NAnt,
nant custom task,
ncovercop
Friday, November 16, 2007
Get your build fixed faster... broadcast your failures!
We've been talking about setting up a build box light for ages.
The other day my project manager bought a USB Visual Signal Indicator. An hour of hacking .. and we now have a light that's green on a passing build and flashes red on a breaking build.
We are using CruiseControl.Net as our build machine, so I controled the light using a custom build publisher.
The result we are experiencing is the build is gets fixed faster. I have a few theories as to why.
Here is the code...
Our ccnet.config file contains the following snippet...
Note: We have few sequencial builds set up so we don't class the build as green until all the builds have passed. I therefore have all the builds able to make the light go red, but only the last build make it go green.
The other day my project manager bought a USB Visual Signal Indicator. An hour of hacking .. and we now have a light that's green on a passing build and flashes red on a breaking build.
We are using CruiseControl.Net as our build machine, so I controled the light using a custom build publisher.
The result we are experiencing is the build is gets fixed faster. I have a few theories as to why.
Here is the code...
using System;
using System.Text;
using Exortech.NetReflector;
using ThoughtWorks.CruiseControl.Core;
using ThoughtWorks.CruiseControl.Remote;
namespace FlashLightPublisher
{
[ReflectorType("flashlight")]
public class FlashLightPublisher : ITask
{
[ReflectorProperty("goGreenOnPass", Required = false)] public bool GoGreenOnPass = true;
public void Run(IIntegrationResult result)
{
StringBuilder DeviceName = new StringBuilder(Delcom.MAXDEVICENAMELEN);
int Result = Delcom.DelcomGetNthDevice(Delcom.USBDELVI, 0, DeviceName);
if (Result == 0)
{
throw new Exception("no usb device");
}
uint hUSB = Delcom.DelcomOpenDevice(DeviceName, 0);
switch (result.Status)
{
case IntegrationStatus.Success:
if (GoGreenOnPass)
{
Delcom.DelcomLEDControl(hUSB, Delcom.REDLED, Delcom.LEDOFF);
Delcom.DelcomLEDControl(hUSB, Delcom.GREENLED, Delcom.LEDON);
Delcom.DelcomLEDControl(hUSB, Delcom.BLUELED, Delcom.LEDOFF);
}
break;
case IntegrationStatus.Exception:
case IntegrationStatus.Failure:
Delcom.DelcomLEDControl(hUSB, Delcom.GREENLED, Delcom.LEDOFF);
Delcom.DelcomLEDControl(hUSB, Delcom.REDLED, Delcom.LEDFLASH);
Delcom.DelcomLEDControl(hUSB, Delcom.BLUELED, Delcom.LEDOFF);
break;
case IntegrationStatus.Unknown:
Delcom.DelcomLEDControl(hUSB, Delcom.BLUELED, Delcom.LEDON);
break;
}
Delcom.DelcomCloseDevice(hUSB);
}
}
}Our ccnet.config file contains the following snippet...
...
<publishers>
<flashlight/>
...
</publishers>
Note: We have few sequencial builds set up so we don't class the build as green until all the builds have passed. I therefore have all the builds able to make the light go red, but only the last build make it go green.
Subscribe to:
Posts (Atom)