Wednesday 12 December 2012

Sprint Burn-up

I recently switched to using burn-up charts for the release plan on a project, it has the advantage of showing changes in scope as well as progress. It takes a short while to get used to seeing the graph 'up-side-down' and adds a little complexity but soon becomes as natural as the burn-down chart and everyone on the team + customer 'got it'.

Having seen the advantages I wondered if it was possible to use a burn-up for the individual sprints rather than burn-down. I found some blogs on the idea but they seemed to want to track 'work done' in the same way as the release burn-up and they concluded it didn't work.
As an aside, I mistakenly tracked 'work done' during sprints when first starting out with Scrum but quickly realised it wasn't very useful and often misleading as it doesn't show how much work is actually remaining at any day during the sprint. Estimates change constantly throughout the sprint (they are only estimates after all) and so it is far more valuable to know the current best-estimate for the remaining work at the start of each day (something that was estimated as 4 hours yesterday and was worked on all-day may still be 4 hours today if the estimate was bad or there were unforeseen problems!). This requires the team to keep the estimates and sprint backlog updated during the sprint (we update the estimates after the daily stand-up before drawing the burn chart).
I wanted to track the remaining work each day but also get the advantages of a burn-up chart's ability to show scope changes. The solution was to track the 'scope' and the 'scope - remaining work', which I call the "Progress", each day of the sprint. The initial 'scope' is the total hours estimated by the team during the sprint planning meeting (the point where a normal burn-down would start). A real example from the first sprint on one of our projects can be seen below (showing the normal over-commitment associated with the first sprint):


In this burn-up we can see that the team committed to just over 160 hours at the start of the sprint and by the end had dropped the scope to just under 120 hours, so over 40 hours of scope had been dropped from the sprint. Note also the convergence of the Scope and Progress lines by the last day of the sprint, this is the same as hitting 0 hours on the last day of a burn-down chart, if the lines don't converge then the team failed to adapt correctly during the sprint. Compare this to the equivalent burn-down chart (this is using the same data as the burn-up chart above):

.
Here it isn't obvious what happened, did the team make really good progress on day 7 and 8 or remove scope? I normally add annotations to the graphs to explain the events during the sprint but this doesn't offer the same at-a-glance obvious information that the burn-up shows.

One issue with the burn-up above is that the guideline (dotted grey line) gets less useful as the scope changes, to combat this I draw a new guideline (blue) whenever the scope changes, an example of this can be seen below on day 7 of a sprint and on day 10, where scope has been added as the team was ahead of the estimates:




Note that the Guide has change between day 7 and 10 to account for the new scope that was added, it is re-drawn whenever the scope changes.

We had a discussion within the team about what actually constitutes scope change during a sprint, and agreed these main points:

  • If a task in the sprint backlog takes longer than expected (or less time) this is not scope change, the original estimate was wrong and the "Progress" will reflect this by not tracking the Guide just like in a burn-down. 
  • If work is removed from the sprint backlog then this is a reduction in scope by the original estimate on the task. 
  • If new work is added to the sprint backlog then it is estimated by the team and constitutes an increase in scope. 
Some corner cases arose when adding and removing tasks from the sprint backlog and we agreed:
  • If a task is missed during sprint planning session but later found to be required to complete the story, it is estimated and added to the sprint backlog, we agreed this wasn't a scope change but was down to poor estimating (inability to identify all work required for the story during estimating).
  • If a task is removed from the sprint backlog because it turns out not to be needed (perhaps it was completed during other tasks without realising), we agreed this wasn't a scope change and was probably caused by poor estimating/work breakdown.

When written down in a post like this it probably sounds complicated and a lot of effort compared to a burndown but actually in practice it works well and doesn't take much effort, the team got used to it quickly and we have a good understanding of what constitutes scope changes and what doesn't without actually referring to any rules or formal process, it just becomes habit.

We reviewed the use of the burn-up chart for sprints during a number of sprint retrospective meetings and the team concluded that they found it more informative and gives clearer visibility both inside and outside the team (we draw it on a whiteboard in the team area) of what actually happens during the sprint, we agreed to continue to use the burn-up chart for sprints.

I have shared an Excel spreadsheet with an example of how to draw the burn-up charts for a sprint here: https://docs.google.com/open?id=0B4GRkkm75Sq6WHIyZ1NMV3VaYlE

P.S I had been meaning to write this post and Steven's post (http://itsadeliverything.com/correcting-overcommitment-during-a-sprint) gave me the final push to get it done, be sure to check out his blog.

Update 1 (15/12/2012):

Steven's comment to this post...
Nice idea. Like make changes to scope explicit. Given the Scope line is essentially a forecast you could project it out to the end of the sprint assuming the future scope is the same as the last known value. Your guideline would then always track to the end of this line making the diagram clearer - at least for me.
...suggests the great idea of extending the scope out as a prediction, I've created a modified version of the example spreadsheet with this change and an example graph can be seen below:


I swapped the "Baseline" and "Guide" line styles so that the Scope Prediction and Guide are both dashed lines as I think this is easier to understand.

You can download the updated spreadsheet here: https://docs.google.com/open?id=0B4GRkkm75Sq6X1NwNHJYRGM5TlE

Update 2 (17/12/2012):

I experimented a bit after Steven's comment and decided to add an Initial Scope line as well so that the final and original scope/guide could be seen together, like a shadow on the graph (note Baseline is now Initial Guide):


This graph is pretty busy, it make sense to me and I find it very informative but stakeholders may be overwhelmed by all the data, when reporting outside the team it may be better to delete some of the lines depending on the audience and the length of explanation you're prepared to do!

This version of the spreadsheet can be found here: https://docs.google.com/open?id=0B4GRkkm75Sq6SjhyVHl1bFpNdWc

Sunday 14 November 2010

VW Golf Plus Brake Change

Adam and I set about changing the rear discs and pads on my '55 reg (2005) 1.6 FSI VW Golf Plus.


The replacement discs were 255mm and I think a pair of discs and four (premium) pads cost around £40 from the local motor factors, bargain! Beware that there appear to be two different sets of discs and pads for this car, the 255mm and a 260mm set. There didn't appear to be anyway to know which were correct and the Haynes manual gave no hint, we choose 255mm (a guess) and it turned out to be the correct fit.

It took us around 5 hours, we took it very slow and documented the process (what you're reading now), I think we could probably do it in 2 hours next time. We had a Haynes manual for this car which we followed.

In this post I'll describe the process of changing the discs (rotors if you're American) and pads.

Before you read anything it is worth noting that you will need two things that you might not own:
  • An M14 Spline (Triple Square) bit which most socket sets probably don't include to remove the discs on this car. The one I bought cost £10, so they aren't cheap! Also I recommend you don't get a "Long" bit, this will be clear later but it makes the job harder.
  • A caliper rewind tool (required for rear brakes only), see later on in this post for details.

Update: I've received some information from a VW technician indicating that it is not necessary to disconnect or adjust the handbrake (it is self adjusting on this car) or to bleed the caliper when rewinding (VW don't do it). See volkswagenownersclub.com for details. Feel free to skip these steps below, this should save some time.


First put the car in gear and chock the front wheels, I bought these for a few quid but blocks of wood or bricks will do just as well:


Before jacking up the car loosen the wheel bolts a little as this is much easier to do with the tyres on the ground.


Next jack up the car. I recently bought a Silverline trolley jack but foolishly didn't do any research before hand. It really isn't good enough for this car, the maximum height is too low to get a decent clearance and fit some axle stands under. Adam already owned a Halfords jack which has a higher maximum lift which we used instead. The difference in size between the two can be seen below (Halfords is yellow, Silverline blue):

Never work on a car being supported only by a trolley jack, be sure to place axle stands under and lower the car onto them. More Silverline grief followed, I had also bought a pair of 3-tonne Sileverline axle stands, but the "V" shape of the support is too steep and can dig into the underbody of the car when placed under the sil:
I have to say I'm pretty disappointed with the Silverline equipment and will be avoiding it in future! Fortunatly Adam also owned some Halfords Axle stands which didn't suffer this problem. Additionally the Silverline stands had a higher minimum height, which meant that when using the Silverline trolley jack we couldn't even get the car high enough off the ground to fit the Silverline axle stands under! Whoever designed this jack/stand combo for Silverline did a terrible job.
You'll see from the photo above the the 'correct' jacking point for this car is slightly further forward than where this axle stand is located. This is indicated by an indented arrow shape on the body work and the thicker area of the sil. Adam and I still haven't figured out how you can jack the car up on the correct jacking point AND fit an axle stand at the same point, there simply isn't enough space to fit both the trolley jack and axle stand this close together. As a result you can see the sil is bending slightly under the weight, not great! We put the Silverline stands under the jacking point as well 'just-in-case'.

Next we had to disconnect the handbrake cable from inside the car. To do this, there is a screw underneath the rear cup holder, the cover over the handbrake lever can then be slid out revealing the cables. This step can be skipped according to a VW technician.

Unscrew the nut holding the two cables in place, it has a very fine thread so takes quite some time! The handbrake cables should be completely free once the nut is loosened:


Back outside, remove the wheel, giving access to the wheel hub.

First we want to remove the brake caliper that houses the pads. There are two bolts holding the assembly together, one top and one bottom. This can be seen below, and requires two spanners (a 13mm and 15mm) to undo.

Below is the back side of the caliper, revealing the 13 and 15mm nuts.

Fix the spanners to the nuts


You can pull the two spanners together in your hand to make the work easier.


Once both bolts are removed the caliper is free. However, if it does not come away easily a few taps with a rubber mallet should get things moving.

It's important not to let the caliper hang on the brake hose, so use some cable ties or similar to attach it to a part of the car. We wrapped the ties around the suspension arm as there wasn't anything easy to loop them through.
With the caliper removed both of the old brake pads can be taken out.

You can see the difference between the old and new pads below. The old pads are approaching their useful limit, these aren't something you want to wait to fail!


If you were only changing the pads you could now jump the rewinding the caliper below and skip the disc removal.

To remove the discs you have to first remove the caliper housing. This requires an M14 spline bit I mentioned at the start. I bought this "Long" one by mistake and it made things harder because of the tight spaces involved, so try to get a regular size or "Short" if such a bit exists.


The hole where this bit goes is not easy to access, the red arrow in the photo below shows where the first one is on the back of the caliper housing. The other bolt is on the bottom of the backside of the caliper.

This bolt was very tight and quite awkward to access. There are all sorts obstructions on the underbody of the car that make this job harder. The "Long" M14 bit left only just enough room for a wrench to fit in, we had to use the smaller of the two breaker bars we had because the knuckle on the longer bar wouldn't fit (yes it was that tight!). We could have really done with the longer breaker bar as well because the bolt needed some serious force to break loose.

Adding to the problems, the handle end of the breaker bar we used hit the wheel arch, or the ground or the body of the car so there wasn't much room to play with.



The bottom of the two bolts had more room to work with, but again the handle of the breaker bar kept hitting various things. We managed to avoid some obstructions by using an extension bar and a longer breaker bar, it wasn't ideal but eventually we got them out.


The photo below shows the caliper housing, give it a clean to remove dirt and rust.


Once the caliper housing is removed (may need bashing with a mallet), the disc can be taken off. There is a single screw holding the disc in place.


Once the disc is removed, get rid of any rust and dirt, we used wire wool.


We're now ready to start fitting the new components. First the calipers will need rewinding, this is because the new pads and discs are of course thicker than the older ones and the caliper piston will be too far out to fit over the new thicker components.

According to the Haynes manual, in order to avoid damage to paintwork caused by pushing brake fluid back up the brake hose and overflowing the master cylinder reservoir or getting dirt into the ABS solenoid valves, a tube must be fitted to the bleed valve on the caliper. Once the tube is in place the nut on the bleed needs to be loosened to allow the fluid out. However, a VW technician indicates that VW do not perform this step, so can be skipped.


I bought this 'bleed kit' which has a one-way valve to prevent air getting into the system and drains the fluid into a container.


The rear calipers on this car need to be wound back, that is, rotated clockwise whilst being compressed in. To do this you must have a rewind tool, I bought this set for around £40, I don't recommend trying this job without it as you will probably damage the caliper.

You can see below how the tool fits into the caliper and onto the piston. It takes a fair amount of force to turn the piston back in, you should see brake fluid moving down the tube attached to the bleed value as you turn. With new pads and discs the piston had to be pushed all the way in.

Don't forget to close the bleed value when you're finished!


After the piston is done, apply some copper grease to the wheel hub to prevent seizure. Don't get any grease on the friction surfaces of the new discs or pads!


Slide the new disc on and refit the single retaining screw, again avoiding getting grease on the disc surface (either side).


Refit the caliper housing using the M14 spline bit.

Add some copper grease to the back and sides of the brake pads (not the front!). This will stop the brakes seizing (not good) and prevent squealing.


Fit into position either side of the caliper housing and refit the brake caliper. The brake pads should have come with new bolts to use for this instead of refitting the old ones.


Bolt the wheels back on then reconnect the handbrake cable (if you removed it), ensure both cables are connected. This will need adjusting it a bit so don't refit the handbrake cover just yet.



Lower the car and tighten the wheel bolts. Now start the engine and pump the brake pedal 3-4 times then release it. Now apply and release the handbrake a few times.

If you removed the handbrake cable you will need to re-adjust it, if you didn't remove it, lower the car and tighten the wheel nuts then skip to 'Finally' paragraph below.

To adjust the handbrake, you need to jack the car up again and support it on axle stands.

You'll need someone under the car at this point who can get a clear view of the back of the brake calipers. They should be able to see the handbrake cable and the arm that it attaches to on the caliper, if you apply and release the handbrake they should see the arm and cable move on the caliper. There is a metal stop on the caliper that the 'arm' the handbrake cable pulls can rest upon when the handbrake is released.

Fully release the handbrake and then slaken the handbrake adjustment nut (in the cabin of the car) until the 'arm' on the caliper touches the end stop on the caliper. Now tighten the adjuster nut (in the cabin of the car) until the 'arm' on the caliper just moves off the stop, about 1.0-1.5mm off the stop. Check both sides of the car are the same, although we're not sure what you can do if they aren't!

If the adjustment is correct, when the handbrake is released the wheels should rotate freely and be impossible to turn by hand when the handbrake is engaged. The Haynes manual indicates that the handbrake should be fully engaged within 3-7 clicks of the lever being pulled, but don't get too hung up on that, if the handbrake works it works.

Refit the handbrake cover and lower the car and tighten the wheel nuts and go for a test drive.

Check the handbrake works on a steep hill and do at least 10 mins driving. When we did this the first time we hadn't found the adjustment advice above and the handbrake adjustment nut was too tight (handbrake always applied as a result) and the brakes smelt like burning clutches as soon as we got out the car and the wheels were too hot to touch! After following the adjustment advice the handbrake was perfect.

Finally
Be gentle for at least the first 100 miles after fitting (avoid heaving braking when possible). The discs/pads should indicate how far you should drive before they are bedded in.

Thursday 19 February 2009

Integers As Hex In The PropertyGrid (C# .NET)





I've been working on a utility at work that makes heavy use of the PropertyGrid in C#. One of my collegues asked that the program be able to display the numbers in hexadecimal.



I noticed a couple of articles online that showed how to do this using TypeConverter classes attached directly the property you want converted e.g.


using System;
using System.ComponentModel;

namespace PropertyGridHexNumeric
{
class TestClass
{
[TypeConverter(typeof(IntToHexTypeConverter))]
public int IntValue { get; set; }


public TestClass() { }
}
}
This works well, except you have to apply the TypeConverter (in this case IntToHexTypeConverter -- defined furthur down) to every property that you want the PropertyGrid to display in hex. This works because when the PropertyGrid gets a value for a property from a class it checks if there are any TypeConverters attached to the property and tries to use them to do the conversion, which is almost always a conversion to a string.

To get around this problem I experimented with the TypeDescriptor static members and noticed that there is a "GetProvider" and "AddProvider" pair. These appear to set global providers. By creating a custom TypeDescriptionProvider and using TypeDescriptor.AddProvier(...) you are able to override the TypeConverter used for all values of the specified type.

For this example I'll use an int. Given a class like so:

using System;
using System.ComponentModel;

namespace PropertyGridHexNumeric
{
class TestClass
{
public int IntValue { get; set; }

public TestClass() { }
}
}

We want to display "IntValue" in hex in the PropertyGrid but without using a TypeConverter attached directly to the IntValue property. I'll spare you the pain of trying to figure this out, create a new Form with one Checkbox and one PropertyGrid, add a handler for the Checkbox.CheckedChanged event and use the following code:
using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace PropertyGridHexNumeric
{
public partial class Form1 : Form
{
private TypeDescriptionProvider m_OriginalProvider = null;

public Form1()
{
InitializeComponent();

propertyGrid1.SelectedObject = new TestClass();
}

private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (checkBox1.Checked)
{
m_OriginalProvider = TypeDescriptor.GetProvider(typeof(int));
IntToHexTypeDescriptionProvider hexProvider = new IntToHexTypeDescriptionProvider(m_OriginalProvider);
TypeDescriptor.AddProvider(hexProvider, typeof(int));
}
else
{
TypeDescriptor.AddProvider(m_OriginalProvider, typeof(int));
}

propertyGrid1.Refresh();
}
}
   public class IntToHexTypeDescriptionProvider : TypeDescriptionProvider
   {
private IntToHexCustomTypeDescriptor m_Descriptor = new IntToHexCustomTypeDescriptor();

public IntToHexTypeDescriptionProvider(TypeDescriptionProvider parent) :
base(parent) { }

public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
if (objectType == typeof(int))
{
return m_Descriptor;
}
else
{
return base.GetTypeDescriptor(objectType, instance);
}
}
}

public class IntToHexCustomTypeDescriptor : CustomTypeDescriptor
{
private IntToHexTypeConverter m_Converter = new IntToHexTypeConverter();
public override TypeConverter GetConverter()
{
return m_Converter;
}
}

public class IntToHexTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
else
{
return base.CanConvertFrom(context, sourceType);
}
}

public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return true;
}
else
{
return base.CanConvertTo(context, destinationType);
}
}

public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string) && value.GetType() == typeof(int))
{
return string.Format("0x{0:X8}", value);
}
else
{
return base.ConvertTo(context, culture, value, destinationType);
}
}

public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value.GetType() == typeof(string))
{
string input = (string)value;

if (input.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
{
input = input.Substring(2);
}

return int.Parse(input, NumberStyles.HexNumber, culture);
}
else
{
return base.ConvertFrom(context, culture, value);
}
}
}
}


This should do the trick, now you can use the checkbox to toggle the hex display of ints in the PropertyGrid, this will work for ANY object you set the PropertyGrid to display! Of course you can apply this method to any Type and I'm sure you will want to add uint, short, ushort etc to the TypeDescriptor so you can see all numeric values in hex.

If you only want to make the hex values readonly you can choose not to override the CanConvertFrom method and the PropertyGrid will prevent you from entering anything.