Showing posts with label Lean. Show all posts
Showing posts with label Lean. Show all posts

Sunday, 22 November 2015

Revisiting the Cone

In a twitter discussion with folk on the #NoEstimates thread again (I don't know why I go back there) Henrik Ebbeskog (@henebb) stated there is no reason to fix time. Absolutely, and as mentioned to others though, fixing time means the other dimensions of software delivery [are allowed to, or must] vary. This isn't a surprise to most of us in the agile space, nor is it a surprise to management scientists either.

As part of the discussion, Henrik mentioned that you could fix time to 1 second and it reminded me of a discussion I once had with an old Senior PM (at the time), Duncan McCreadie. It centred around agile development some 5 years ago and in the discussion, he stated that if he wanted to monitor an realign the delivery, he'd look to bring delivery rates down to every day or every 4 hours. He was spot on with this and I agree.

The reason is in part due to the Cone of Uncertainty I keep banging on about mathematically, and even get heckled at, but that doesn't change the math, nor does it change the empirical numbers, which also back it up.

Why Delivery Rate Matters

If you deliver software continuously, each delivery gives you knowledge about your process that you didn't have before. What has happened, has happened, you can't change that, but you can both learn from it and consider it's variance zero (it's happened - there is no variance, it's a certainty) and if you are, then make things happen faster.

This is like I illustrate in:

http://goadingtheitgeek.blogspot.co.uk/2014/10/cone-head.html

In essence:
You've delivered a coin flip. It's now become known and in a fixed number of delivery cycles, this changes the expected outcome for all coin flips and it's potential overall variance.
Each flip of a coin is a delivery. Now, substitute the words 'coin flip' with 'story' and 'all coin flips' to 'major release' and reread the above.

As you can see from the graphs of actual project data shown at:

http://goadingtheitgeek.blogspot.co.uk/2015/04/monitoring-value.html

This applies across the board. There isn't a real delivery process in the entire world which doesn't follow this rule. The only possible case, is if the process extends to infinity, since this just pushes out the variance to perpetuity, which follows the last [sketched] graph at:

http://goadingtheitgeek.blogspot.co.uk/2015/04/lean-agile-metrics-like-it-or-not-stats.html

However, you'll note that nothing exists to infinite time. Even the Universe isn't considered to be able to exist at infinite time and I'd argue that your project budget would run out before then. Using faster monitoring approaches, as well as employing lean architectures, you will make the most of that budget as well as making it easier to either align or find a new direction.



E

Thursday, 11 December 2014

What's wrong with a Little predictability?

I was asked recently about Little's law. For the uninitiated, it is a fundamental, but elegant result in queuing theory. It's akin to the simplicity of Einstein's 'E' equals mc squared as it reduces a whole heap of complexity into a few simple variables. It is now finally being applied to software Kanban having existed way before the field of software engineering ever existed.

In software, it's pretty simple and relates the average number of cards in play (between the backlog and done) to the average cycle time and arrival rate. If your arrival rate is the same as your service rate, which in Scrum you would expect it to be if you're delivering all your cards in that Sprint's time period, you end up with a pretty good link.

So what's the problem?


The issue is (again) that people miss a crucial detail. It's how KISS differs from Occam's razor and how folk abuse the agile manifesto. Remember the items on the right? Now do you remember the last statement that references them? ("Whilst there is value in the items on the right, we value the items on the left more").

With Little's law, it is that the team has to attain predictability. That predictability is the team consistently delivering the same number of points every sprint and/or having a consistent cycle time. Little's law doesn't technically have a stochastic component, so obviously needs stability to attain a zero variance. The problem you have, especially at the beginning of each 'project' [*grumble* *humbug* need #NoProjects] is that you do not have that stability. Teams can under or over-perform, so there isn't stability. That said, a team that is also improving and delivering 'more', which is always desirable, then has the disadvantage that they're not naturally stable! They are delivering more, so naturally the average changes.

But isn't improving a good thing?

Totally! It's the best thing you can do! However, if you are hoping to use Little's law to project/forecast in an environment which is improving, you can't do it because of this. At least, you can't do it without the introduction of a stochastic component, or comparing against the desired burn-up. Believe it or not, improving is instability which naturally increases the variance of the delivery as a whole. That's your trade off! Continual improvement means you cannot gain the stability needed to use Little's law!

*shock horror*

Are you sure?

Yep, very!

Consider the following graph. it shows a team's data where they do not improve their delivery and are running late to start. If projecting forwards, their variance is very narrow. You're going to be very late, but you're pretty sure they are going to be late. If you plot the projection of the end of the 'project' through the average burn-up as you accumulate ACTUAL data, you'll see where it's likely to be:


Team who do not improve


Little's Law could be used here to project where they're going to be and if you look at the range of possible outcomes in the time allotted or the time variance needed to complete the scope (remembering the golden triangle) you'll see this is much narrower than the team who improve below!

Team practising continuous improvement
Here Little's Law is pretty much no use! Indeed, in most teams, you can't get enough of a data set for each improvement to measure the average and deviation reliably.

Conclusion: What to do?

At the end of the day, you're just trying to give yourself the best chance. It’s not intuitive to applaud greater variance, since that’s normally greater risk, but because the variance needs to ‘cross’ a value (the average, which in this case is the original burn-up. i.e. 'fixed' at the outset if scope is fixed), it’s the more points you deliver ‘above the thick red line’ that count. If it swings wildly with the majority of the mass below the red line, you’re scr3wed. If it’s above, you're rocking! This is why I prefer to get the average of teams to be on or above the red line and then reduce the variance, since this gives you greater certainty about the burn-up rate.

So, in short, there are a million and one tools out there to help folk with software development and predictability. Teams have to be careful they don't pick a tool and misapply it and it's these limits that often tell us whether it is appropriate or not to use it. The situation where it doesn't work may outnumber the ones that do. We're not all hammering nails, after all.

Friday, 21 November 2014

#LeanConf 2014: 4 Fave Presenters

Short one this one, as it has been an exhausting week!

I was at #LeanConf in Manchester this week and of the amazing and inspiring speakers, there were a few that stood out. My top 4 were:

Ton Wesseling 

twitter handle: @tonw

Hands down my personal favourite presenter there! Being a bit of a data geek myself, I loved the data and educational elements of his presentation. Whilst not new to me, he's the sort of guy in the industry who can help organisations close the leaning loop by allowing you to truly understand your data, improvements, A/B-test results, what to focus on and what to ignore. When you are the only guy in pretty much every single company you go into who walks and talk agile metrics, performance, statistics, learning, data, data and more data, it can get to be a very lonely place until you find another person in the world who shares the same passion, knows what's just enough, and both its importance and pitfalls.

I took the time to speak to Ton after his presentation, specifically about how to get the statistical thinking into some teams as this often requires bridging a huge skills gap ad his answer was pretty simple. Employ psychologists! I have long thought that psychologists have a place in organisations, but I as yet to be convinced that I could justify suggesting a formal psychologist role at team level so steered clear of suggesting them. Psychologists bring both human psychodynamics AND statistics to the table, since they have to study it. So having this suggestion come from someone who's done it does add some validity to the idea, so I look forward to trying it out.

Janice Fraser 

twitter handle: @clevergirl

My favourite presentation from an entertainment point of view. It was awesome to see her present and she had me and the rest of the audience in fits of laughter! My stomach was aching the whole day after as if I'd had a session at the gym... and I do go to the gym! Her presentation about Gab Zichermann's new educational system and use of games and puzzles to educate helped promote curiosity and traditional skills in education. I have to vouch for this, as whilst I was classically educated, it was the stuff I did outside school that put it into practise and hence, allowed me to score highly in school/college/uni yet not have to do a single day's worth of revision, because these were skills I used all the time. Definitely think there is something in this.

Tristan Kromer 

twitter handle: @TriKro

My best memory award goes to Tristan. His slides didn't work unfortunately, but he blasted through the whole presentation, by heart, without missing a step. Awesome professionalism!

This isn't to say that other presenters weren't good, as it was a tough choice. Everyone will have a different favourite 3. For example, Barry O'Reilly from ThoughtWorks provided an informative talk on a classical Enterprise Agile problem, optical illusions and plenty of Watermelons :)

Ash Maurya

twitter handle: @ashmaurya

The author of Running Lean spoke about how companies are basically customer factories. Thy produce happy customers. He also talked about testing the market and the crucial feedback loop that allows the factory to respond to market opinion and change. He's certainly well aware of the need to consider the data when deciding how much to invest and work with.

Enjoyed #LeanConf! Especially since I won a copy of Ash Maurya's book, Running Lean for asking a question at the right time. Looking forward to next year! :)

Tuesday, 1 July 2014

The Drawback of Shared Services

In many organisations, the concept of shared services is a pretty standard one. A shared service doesn't sit on a line of business, but is a cross cutting concern for across all lines of business. Examples of shared services are Human Resources, Marketing, IT, Finance and Regulatory Compliance.

Shared services came about because it's easy to segment such business functions into individual cost centres, potentially even into single accounts within a company's CoA (aka charts of accounts) which do make things much easier to report on. They also seem to have evolved functions at board level, such as CFO, CIO and CTO.

In recent years, it has become clear that this is a somewhat wasteful idea for a number of reasons and in the reporting sphere, not least because the end of month, quarter and annual reports and management accounts occur so infrequently relative to the lines of business operating all the time. However, there is an even bigger problem with this and it is the level of complexity this introduces into the organisation's operating model which happens to also mean that any operational task spanning multiple shared services contends for its time, is more complex to manage, passes through several chains of responsibility and due to the contention, generally takes longer to pass through the operating chain. For this intro, I will skip a significant portion of the maths, but the whole process of illustrative relevance is based around queuing theory.

Modern methods which aim to make organisations more responsive, such as Lean Start-up or agile software development, have inadvertently stumbled onto the answer. The reason they address this pain point so well is they amalgamate functions of all the various shared service centres into one, self-sufficient team. This type of organisational unit makes it really easy to manoeuvre in the space, shortens the time through the queue (aka the cycle-time) and inherently reduces complexity. Today I'll work through an example of the problem and compare this model to the newer, more agile cross-functional teams.

Traditional Hierarchy

In a traditional shared services hierarchy, you may have a chief operating officer who is responsible for the operations of the enterprise, which will include operational services, call centre management and such like. A CTO or CIO who has responsibility to deliver IT shared services. Some companies have CMOs, of course, CFOs exist etc. What is often correlated with that board structure is a hierarchy of specialisms. So an accounts division or department, a marketing division or department, an information systems division or department.

The interesting thing is that managers who have been through typical managerial courses, especially at MBA level, will have drawn up 'value chains'. These chains start with a raw material, and refine it into an end product. Alternatively, they begin with a customer entry into the system and travel through a series of steps, services or stages through the organisation before coming out at the other end, healthier, wealthier and wiser.

Consider the following organisation:

Typical organogram

Let's suppose this represents ACME plc. That wonderful road-runner extermination device provider. Coyote is getting old and needs ACME, who he has bought products from for decades, to come in and do the extermination for him. For this, there are a number of processes at work.


  1. Coyote, an existing customer, contacts the Customer Services department 
  2. They are put through to sales and purchases a consultation with an engineer. 
  3. The Sales adviser finds Coyote's details in the system and created a sales entry for an engineer visit.
  4. Through communications: 
    1. Engineering gets a request which waits in a queue until an engineer is assigned. 
    2. Legal prepare a new agreement for the extra work and send it out
  5. Engineering schedule their work and assign an engineer to come out, but not before conducting a quick risk assessment.
  6. A notification message is returned to a CSA to notify Mr/Ms Coyote (could you tell?) that they should expect a visit in some 8 hour window on a day some time from today.
  7. An engineer arrives at Coyote and does whatever business they do.
  8. The engineer finishes the consultation and registers the completion of the job.
  9. ...Which triggers a journal entry in Accounts, incrementing the bill which in turn formalises the contract. This waits in respective queues until officers from each department get to them.
  10. At the end of the month:
    1. Accounts run a report for the board on the sales which include Coyote's new order and...
    2. Marketing Analysts determine the performance of the previous month's sales v costs and effort and adjust for the next month. This is reported to the board and...
    3. Marketing prepare a press release to tell the world they helped Coyote finally catch roadrunner.
    4. Credit control raise invoices for all purchases, including Coyote's.
If we map this to the departments and division which the order touches (which remember, is a proxy for the view of the customer ACME have):

ACME activities in Coyote's Value Chain

What's wrong with that?


...I hear you ask. Well, if every department reacts as soon as they get the notification, absolutely nothing. However, in reality, this never happens! Different types of tasks contend for personnel's time. Crucially, because it's a shared service, Coyote is not the only customer that each shared service in ACME has, nor is Coyote's request the only type of request that a department processes (it's the nature of shared services after all).

ACME, having branched out, now have clients including Family Guy Peter Griffin, Chief Wiggum from The Simpsons and Roger Rabbit all wanting different things from the sales people or customer services, maybe calling up customer services to get in contact with tech support etc.

So let's add some numbers to that workload. The arrows represent how long it takes one [red] item to flow in and then out of each subsystem. Effectively, for tech guys, this is your departmental 'cycle-time' and is the difference between the arrival time and the service time. The red dots, where highest priority is reserved for the item on the top right, denote all the work there is and X is Coyote's task which passes into each department at that position in the work queue.

Aggregate workload


In each subsystem, counting each dot from highest priority to Coyote's cross (inclusive) and multiplying it by the time in each corresponding arrow, we get the time that Coyote has to wait. Doing this for all subsystems to the point at which Coyote gets a bill, marketing get an idea of whether their latest marketing campaign has worked, the board get a view of how sales of the consultancy service are doing etc. is:

Total flow of Coyote's new sale

Note that due to the request being able to come in at any time in the month and us using the very best case of the final day before the reporting run, that is an absolute minimum of 201.75 hours! 201.75 hours! At best over 25 days! That is a minimum of 25 days (and maximum of 55) before marketing can get an understanding of whether or not their campaign worked; the data showing up on the financial reports; the PR exercise coming through (potentially allowing your competition to get in before you with something more interesting for your customers); and before an understanding of your company position can be made! Not to mention crucially, that's 25 working days for your customer to get through this business process! If your cool off period is 14 days, what do you think this leaves them with? The road-runner is certainly long gone!

Working More Effectively

The key to being agile is responding to change and hence knowing faster, working faster and hence reacting to your market when you know you need to change. To 'know it' you need to be able to sample the effect on your market of a campaign and your customer's journey is crucial in this respect.

In this scenario, think about switching capabilities from horizontal structures built around the technical services your company provide to each other department, to a fully aligned business process with one member of each of the departments concerned in one, single, cohesive team. The work is also aligned so that it doesn't go out of order. This time the team consists of all members of operational staff and they focus on each case as it comes in, aside from the engineers, who have to take 2 days to schedule and work on their tasks in bulk, as they are out on the road. Let's assume that we remove 50% of the types of task that each department member deals with, so they focus only on this service. The reduction naturally means that they address needs that come in more frequently, using only one type of process, which  naturally reduces context switching. To keep things simple, we'll assume a zero-cost  context switch for this demo and we can imagine the saving not context switching gives. It will just add to the benefit.

There is always a way to improve. However, a first transition may yield:


New flow arrangement

Conducting the same analysis on the above yields.

Newer, aligned processes

WOW! What happened?

That's a bit of a difference eh? Now ACME can see the effects of a marketing change on Coyote (or anyone else) in less than a week! The removal of invoicing from the month-end shared service process also both shortens the cycle-time AND reduces variance! Imagine that? The ability as a CEO or COO to know how your organisation is doing and you will not be more than 1 week out of date and be pretty certain of the result! This compares to more than 5 weeks to up to 9 weeks in the previous example. That means you can assess your market standing in less time and know when to change with a high level of certainty. It also means you don't spend so much of your revenue if a process doesn't work. Given the fixed costs of ACME's wage bill and overheads, it would be paying 5 weeks worth to find out what you could have done in less than a week! That means at worst, you are 5 times more efficient and being aligned to the appropriate value chain, shifting 5 times as much traffic through ACME's system translates to being around 5 times more effective! Thinking about this as a factor in the Rate-of-Return of an investment and suddenly this looks very good indeed!

Summary

The process above shows the difference that the use of multidisciplinary teams and systems can have on your business process. I've left out some of the complex details, such as task variance and hence system variability.

Make no mistake, moving to a more agile business architecture is a culture shift, requiring a significant change in mind-set. Most organisations and indeed managers have spent a lot of time being told that shared services are the way to go and most staff assume hierarchies are the norm. After all, we get 'promoted' and gain higher salaries for higher positions. Hence, changing that will require small, careful, iterative change management, aligning services that already have some overlap with (and hence sympathy for) other services is the path of least resistance and the best road to travel. Take care to run those for a little while and see how it copes. Address issues as they arise and see where the system constraint moves to next (a la Theory of Constraints).

Whilst I am certainly can't advocate the removal of shared services where they are already aligned with the value chain, customer experience or workflow, I do caution that you look out for 'shared services' that appear to be essential to the operational flow, as these are the ones that need to be carefully reshaped. Happy reorganising!

Thursday, 16 January 2014

Why do we test?

In my last contract at a digital agency, I was having a discussion with a chap I worked with. He's good at TDD and we were discussing why we write tests.

The benefits of testing at developer level are well known. Writing them first and cleanly, amongst other things, provides:

  • An acceptance framework containing specifications to develop software against, using success criteria.
  • An ability to continually, reliably and consistently test against the same test case 
  • Provides developer 'documentation', in turn providing an understanding of how the system is supposed to work. 
  • Confidence that what you changed hasn't borked anything
  • When combined with automated test and reporting frameworks, they give fast feedback and a degree of progress reporting. 
One thing that came up was that we shouldn't refactor tests. I am personally dead against this idea, since this introduces extra work to change the spec if the functionality need changing. The give-away is over 100% test path coverage. That means you WILL be editing more tests than you should do, which is just wasted time and effort. Note though, if it's a choice of 150% tests or 90% tests, I would choose 150% every time.

However, one thing that wasn't brought up, which I personally think is equally important, especially if the project is high value, high risk or highly sensitivity, is governance.

Ewww... Management speak.

Yes, basically it is.

We have to remember that being agile involves being multi-skilled. Part of that is managing risk and whilst tests give you some degree of that, the test coverage gives you the governance of the code and development that you need. If you have 10% coverage in your project, people have not been doing TDD now have they?

Self-sufficient agile development teams are able to govern the development of the system. Some might think governance is used because you don't trust the developers, but really, it's just as much about managing the risks with the code and gaining the biggest bang for the developer buck (effort). As a team of developers, in order to become self-sufficient, we have to be able to govern the development of the software and by proxy, the team. 

QAs and BAs have a pivotal role in this process. They know the real business value in the system and as such, they can guide where to put the testing effort. Developers can also get a sense of the importance of the code because they'll have touched specific code more than once. 

Cyclomatic complexity can also be key to all this, since the greater the cyclomatic complexity, the greater the number of tests required. If the cyclomatic complexity is high, the number of tests is high simply because of the combinatorial nature of the tests required to cover this cyclomatic complexity metric.

For example, we are human beings and we are not faultless. Anyone who claims otherwise is deluded. So if you have a piece of code which is touched by several developers, or even the same developers multiple times, it is more likely to contain bugs over time than a piece of code written the same way once and not touched since. The purpose of the tests, amongst other things, is to make sure you don't break anything when the next person touches it or you next touch it. It gives you the confidence to refactor it too. Without automated tests, and the quick feedback it brings, refactoring becomes a nightmare. After all, logical bugs don't go through the automated test sections of the covered code, they fall through the holes where the code isn't (whether due to the lack of acceptance criteria or missed path coverage).

Q: Isn't cyclomatic complexity useless?

Nope. I do often wonder why people say that. The explanations I keep seeing or hearing show they actually understand none of it. You also get criticism from developers that QAs insist on a metric such as cyclmatic complexity less than 10 and we end up coding too much 'crap'. However, let's look at why we have it.

Let's use a variation of the one shown on the MSDN website. This code is deliberately rubbish, without full statement coverage but could still be created using TDD (characterisation tests first) and before refactoring anything.

Using FxCop, dotCover and the Code Analysis Powertools in VS2010, you can analyse the solution and get the following:

dotCover statement coverage and the FxCop equivalent code metrics.

The key metric we're focussing on is the cyclomatic complexity (CC) of the method named 'Method'. This is high for the method, but what does this actually mean?

Well, the path test coverage on this would require the developer to write a test for each of those cyclomatic paths through the system. In this case, 15 of them. Filling in the rest as proof:


dotCover and FxCop analysis of code

Now, the interesting thing is we have 16 tests for a cyclomatic complexity of 16. Let's understand what this means:

  • There are only 10 lines of code in one method, and we have had to write 16 test for it - In itself, not a problem
  • We can see some clear areas for refactoring. Again, a good thing (see below as I go through it)
However, let's compare this with a wrapper  if statement (which tests for whether you care or not), then we can see we have to change more code than we otherwise would have to and this costs the business more.

I've refactored it to use a surrounding 'if' wrapper. The tests still pass, but the cyclomatic complexity has reduced to 9.

dotCOver and FxCop analysis after refactor
However, we still have 15 tests. So our coverage now sits at about 167%. That is 67 percentage points more code that another developer (or even ourselves) would have to change if we needed to change the class to do something. This is also only one level of nesting. Adding this method to another method as full, which is covered 166%  means the total combinatorial effect means we have 276% coverage. If the combined TDD development time of a module is 5 days at say, 3:2 dev to test during the TDD iterations, then the tests should only account for about 0.72 of a day and development taking the same amount of time (3 days), the other 1.28 days is just sheer waste. That's 26% of the development time.

Scale this (best case) to each time a block of code changes and suddenly, if the code is changed 10 times across stories in an iteration, you suddenly have 12.8 days that just disappeared out of a 50 day project! That's a lot of effort, time and money wasted. Development teams should respect the people that trust them to deliver, who also pay their wages.

The following is the NUnit TestFixture:

using NUnit.Framework;
 
namespace WhatCanIDo.Test
{
    [TestFixture]
    public class DayOfTheWeekTest
    {
        [Test]
        public void WhenItsMondayAndYouCareThenSayItsMonday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Monday, true), Is.EqualTo("Today is Monday!"));
        }
 
        [Test]
        public void WhenItsMondayAndIDontCareThenSayYouDontCare()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Monday, false), Is.EqualTo("You don't care!"));
        }
 
        [Test]
        public void WhenItsTuesdayAndYouCareThenSayItsTuesday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Tuesday, true), Is.EqualTo("Today is Tuesday!"));
        }
 
        [Test]
        public void WhenItsTuesdayAndIDontCareThenSayYouDontCare()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Tuesday, false), Is.EqualTo("You don't care!"));
        }
 
        [Test]
        public void WhenItsWednesdayAndYouCareThenSayItsWednesday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Wednesday, true), Is.EqualTo("Today is Wednesday!"));
        }
 
        [Test]
        public void WhenItsWednesdayAndIDontCareThenSayYouDontCare()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Wednesday, false), Is.EqualTo("You don't care!"));
        }
 
        [Test]
        public void WhenItsThursdayAndYouCareThenSayItsThursday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Thursday, true), Is.EqualTo("Today is Thursday!"));
        }
 
        [Test]
        public void WhenItsThursdayAndIDontCareThenSayYouDontCare()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Thursday, false), Is.EqualTo("You don't care!"));
        }
 
        [Test]
        public void WhenItsFridayAndYouCareThenSayItsFriday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Friday, true), Is.EqualTo("Today is Friday!"));
        }
 
        [Test]
        public void WhenItsFridayAndIDontCareThenSayYouDontCare()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Friday, false), Is.EqualTo("You don't care!"));
        }
 
        [Test]
        public void WhenItsSaturdayAndYouCareThenSayItsSaturday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Saturday, true), Is.EqualTo("Today is Saturday!"));
        }
 
        [Test]
        public void WhenItsSaturdayAndIDontCareThenSayYouDontCare()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Saturday, false), Is.EqualTo("You don't care!"));
        }
 
        [Test]
        public void WhenItsSundayAndYouCareThenSayItsSunday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Sunday, true), Is.EqualTo("Today is Sunday!"));
        }
 
        [Test]
        public void WhenItsSundayAndIDontCareThenSayYouDontCare()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Sunday, false), Is.EqualTo("You don't care!"));
        }
 
        [Test]
        public void WhenItsDunnoDayAndIDontCareThenSayYouDontCare()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.DunnoDay, false), Is.EqualTo("You don't care!"));
        }
    }
}

You can see that as we went along, we 'coded' the tests for each of the "don't care what day it is" scenarios right into the code. The excess ones now are not needed at all, since whatever we do, the don't care is actually decided separately from each check on the day. So these can be removed, which will remove 7 test cases.


Important Notes
If you do refactor tests, and I personally think you should, then:

  1. NEVER refactor tests if the code is red! 
  2. Use the tests to green the code and the code to green the tests but never change both at once!
Removing the 7 extraneous tests then makes the test class look like:


    [TestFixture]
    public class DayOfTheWeekTest
    {
        [Test]
        public void WhenItsMondayAndYouCareThenSayItsMonday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Monday, true), Is.EqualTo("Today is Monday!"));
        }
 
        [Test]
        public void WhenItsTuesdayAndYouCareThenSayItsTuesday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Tuesday, true), Is.EqualTo("Today is Tuesday!"));
        }
 
        [Test]
        public void WhenItsWednesdayAndYouCareThenSayItsWednesday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Wednesday, true), Is.EqualTo("Today is Wednesday!"));
        }
 
 
        [Test]
        public void WhenItsThursdayAndYouCareThenSayItsThursday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Thursday, true), Is.EqualTo("Today is Thursday!"));
        }
 
 
        [Test]
        public void WhenItsFridayAndYouCareThenSayItsFriday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Friday, true), Is.EqualTo("Today is Friday!"));
        }
 
        [Test]
        public void WhenItsSaturdayAndYouCareThenSayItsSaturday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Saturday, true), Is.EqualTo("Today is Saturday!"));
        }
 
        [Test]
        public void WhenItsSundayAndYouCareThenSayItsSunday()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.Sunday, true), Is.EqualTo("Today is Sunday!"));
        }
 
        [Test]
        public void WhenItsDunnoDayAndIDontCareThenSayYouDontCare()
        {
            Assert.That(DayOfWeekConverter.Method(DayOfWeek.DunnoDay, false), Is.EqualTo("You don't care!"));
        } 

    } 

gives us 8 remaining tests and sure enough:

dotCover results after removal of 7 extraneous tests

Summary

In short, cyclomatic complexity is a brilliant metric for governing how many tests are needed in your solution. There are two main useful comparisons in isolation and teams should take heed:
  • If cyclomatic complexity is greater than the number of tests, then you're missing test scenarios and risk introducing bugs into the system. If there is a hole in a bucket, Henry can't carry as much water. Most Agilists should aim to get here as a bare minimum in today's industry.
  • If the cyclomatic complexity of a method is less than the number of unit tests around it, then you have over 100% coverage and you introduce waste into your process. This comes when you step agile up to the lean plate!
So to be lean, 100% should be the norm. Anything else is suboptimal or worse.