What FizzBuzz can
teach us about design
"You take the red pill, you stay in
Wonderland and I show you
how deep the rabbit-hole goes"
TDD Training
and Design
and Refactoring
FizzBuzz + TDD
Nothing new
Nothing new
existing knowledge
Nothing new
existing knowledge
re-packaged in a way
that make sense to me
1. Context
2. Code Katas
1. Context
1. Context
make observation on software
design at a micro level
1. Context
make observation on software
design at a micro level
which is needed to be able to
evolve a codebase over time
2. Code Katas
2. Code Katas
Why? Am I wasting time?
2. Code Katas
Why? Am I wasting time?
Perfect to practice a
technique in isolation
2. Code Katas
Why? Am I wasting time?
Perfect to practice a
technique in isolation
Isolation allows to
improve more effectively
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "FizzBuzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "FizzBuzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
Change request
Change request
7 -> Bang
3 -> Fizz
Change request
3 -> Fizz
5 -> Buzz
Change request
3 -> Fizz
5 -> Buzz
3&5 -> FizzBuzz
Change request
3 -> Fizz 7 -> Bang
5 -> Buzz
3&5 -> FizzBuzz
Change request
3 -> Fizz 7 -> Bang
5 -> Buzz
3&5 -> FizzBuzz 3&7 -> FizzBang
5&7 -> BuzzBang
3&5&7 -> ...
Change request
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "FizzBuzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
Assess impact of change
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "FizzBuzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
Assess impact of change
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "FizzBuzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
Assess impact of change
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "FizzBuzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
Assess impact of change
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
Change request
3,5 3 branches
Change request
3, 5, 7 7 branches
3,5 3 branches
Change request
3, 5, 7
3,5,7,11
7 branches
???
3,5 3 branches
Change request
3, 5, 7
3,5,7,11
7 branches
???
3,5 3 branches
19 branches
Surprised image?
Data change
Behaviour change
vs
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "FizzBuzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "FizzBuzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
} Not exactly the ideal design
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "FizzBuzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
} where do we start?
what do we do?
What do we do?
What do we do?
1. We implement the feature
and then refactor
What do we do?
1. We implement the feature
and then refactor
2. We refactor first and the
implement the feature
What do we do?
1. We implement the feature
and then refactor
2. We refactor first and the
implement the feature
Refactoring
Refactoring
1. Big Bang, tests broken till
the end (if you ever reach it)
Refactoring
1. Big Bang, tests broken till
the end (if you ever reach it)
2. Small safe steps, tests stay
green
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "FizzBuzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
Assess impact of change
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
Challenge
Challenge
one line code change?
Challenge
one line code change?
no more if branches
Challenge
no more tests
one line code change?
no more if branches
Where do we start?
Where do we start?
Simplest code?
Where do we start?
Simplest code? More complex code?
Where do we start?
Simplest code? More complex code?
Top?
Where do we start?
Simplest code? More complex code?
Top? Bottom?
Where do we start?
Simplest code? More complex code?
Top? Bottom? Middle?
Where do we start?
Not a unique answer
Simplest code? More complex code?
Top? Bottom? Middle?
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "FizzBuzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "FizzBuzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "Fizz"+"Buzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
Evident Data
Reveal the intent of data making
their relationship evident
Too small to be
worth doing
Too small to be
worth doing
Refactoring session
Your plan
Refactoring session
Your plan
Refactoring session
Reality
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "Fizz"+"Buzz";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "Fizz"+"Buzz";
var result = "";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "Fizz"+"Buzz";
var result = "";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "Fizz"+"Buzz";
var result = "";
if (num % 3 == 0)
return "Fizz";
if (num % 5 == 0)
return "Buzz";
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "Fizz"+"Buzz";
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
return "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
return "Buzz";
}
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "Fizz"+"Buzz";
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
return "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
return "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "Fizz"+"Buzz";
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
return "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
return "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "Fizz"+"Buzz";
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
return "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "Fizz"+"Buzz";
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
return "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
if (num % 3 == 0 && num % 5 == 0)
return "Fizz"+"Buzz";
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
Is it better?
Assess impact of change
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
Assess impact of change
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
Assess impact of change
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
data duplication between test and prod
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
data duplication between test and prod
code duplication - if branches
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5 * 2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine();
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
data duplication between test and prod
code duplication - if branches
primitive types
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
same code,
different data
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
same code,
different data
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (num % 3 == 0)
{
result += "Fizz";
}
if (num % 5 == 0)
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
}
Can we name the
intent of this code?
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (IsDivisible(num, 3))
{
result += "Fizz";
}
if (IsDivisible(num, 5))
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor)
{
return num % divisor == 0;
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (IsDivisible(num, 3))
{
result += "Fizz";
}
if (IsDivisible(num, 5))
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor)
{
return num % divisor == 0;
}
}
same code,
different data
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (IsDivisible(num, 3))
{
result += "Fizz";
}
if (IsDivisible(num, 5))
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor)
{
return num % divisor == 0;
}
}
same code,
different data
Reconcile
differences
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
if (IsDivisible(num, 3))
{
result += "Fizz";
}
if (IsDivisible(num, 5))
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor)
{
return num % divisor == 0;
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var fizzDivisor = 3;
if (IsDivisible(num, fizzDivisor))
{
result += "Fizz";
}
if (IsDivisible(num, 5))
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor)
{
return num % divisor == 0;
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var fizzDivisor = 3;
var fizzWord = "Fizz";
if (IsDivisible(num, fizzDivisor))
{
result += fizzWord;
}
if (IsDivisible(num, 5))
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var fizzDivisor = 3;
var fizzWord = "Fizz";
if (IsDivisible(num, fizzDivisor))
{
result += fizzWord;
}
if (IsDivisible(num, 5))
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
Data clump
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var fizzDivisor = 3;
var fizzWord = "Fizz";
var divAndWord = (Divisor: fizzDivisor, Word: fizzWord);
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
if (IsDivisible(num, 5))
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var fizzDivisor = 3;
var fizzWord = "Fizz";
var divAndWord = (Divisor: fizzDivisor, Word: fizzWord);
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
if (IsDivisible(num, 5))
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
Ugly name
arlobelshee.com/tag/naming-is-a-process/
Design is
Design is
Structure and naming
Design is
Structure and naming
Goals
Design is
Structure and naming
Enable change
Goals
Design is
Structure and naming
Enable changeEnable unexpected change
Goals
Design is
Structure and naming
Enable change
Handle complexity
Enable unexpected change
Goals
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var fizzDivisor = 3;
var fizzWord = "Fizz";
var divAndWord = (Divisor: fizzDivisor, Word: fizzWord);
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
if (IsDivisible(num, 5))
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var divAndWord = (Divisor: 3, Word: "Fizz");
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
if (IsDivisible(num, 5))
{
result += "Buzz";
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var divAndWord = (Divisor: 3, Word: "Fizz");
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
var divAndWord2 = (Divisor: 5, Word: "Buzz");
if (IsDivisible(num, divAndWord2.Divisor))
{
result += divAndWord2.Word;
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var divAndWord = (Divisor: 3, Word: "Fizz");
var divAndWord2 = (Divisor: 5, Word: "Buzz");
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
if (IsDivisible(num, divAndWord2.Divisor))
{
result += divAndWord2.Word;
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var divAndWord = (Divisor: 3, Word: "Fizz");
var divAndWord2 = (Divisor: 5, Word: "Buzz");
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
if (IsDivisible(num, divAndWord2.Divisor))
{
result += divAndWord2.Word;
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
Same code, multiple data suggests...
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var divAndWord = (Divisor: 3, Word: "Fizz");
var divAndWord2 = (Divisor: 5, Word: "Buzz");
var divAndWords = new [] {divAndWord};
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
if (IsDivisible(num, divAndWord2.Divisor))
{
result += divAndWord2.Word;
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var divAndWord = (Divisor: 3, Word: "Fizz");
var divAndWord2 = (Divisor: 5, Word: "Buzz");
var divAndWords = new [] {divAndWord};
foreach (var divAndWordItem in divAndWords)
{
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
}
if (IsDivisible(num, divAndWord2.Divisor))
{
result += divAndWord2.Word;
}
if (result != "")
return result;
return num.ToString();
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var divAndWord = (Divisor: 3, Word: "Fizz");
var divAndWord2 = (Divisor: 5, Word: "Buzz");
var divAndWords = new [] {divAndWord};
foreach (var divAndWordItem in divAndWords)
{
if (IsDivisible(num, divAndWordItem.Divisor))
{
result += divAndWordItem.Word;
}
}
if (IsDivisible(num, divAndWord2.Divisor))
{
result += divAndWord2.Word;
}
if (result != "")
return result;
return num.ToString();
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var divAndWord = (Divisor: 3, Word: "Fizz");
var divAndWord2 = (Divisor: 5, Word: "Buzz");
var divAndWords = new [] {divAndWord, divAndWord2};
foreach (var divAndWordItem in divAndWords)
{
if (IsDivisible(num, divAndWordItem.Divisor))
{
result += divAndWordItem.Word;
}
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var result = "";
var divAndWords = new[]
{
(Divisor: 3, Word: "Fizz"),
(Divisor: 5, Word: "Buzz")
};
foreach (var divAndWordItem in divAndWords)
{
if (IsDivisible(num, divAndWordItem.Divisor))
{
result += divAndWordItem.Word;
}
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
(Divisor: 3, Word: "Fizz"),
(Divisor: 5, Word: "Buzz")
};
var result = "";
foreach (var divAndWordItem in divAndWords)
{
if (IsDivisible(num, divAndWordItem.Divisor))
{
result += divAndWordItem.Word;
}
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
(Divisor: 3, Word: "Fizz"),
(Divisor: 5, Word: "Buzz")
};
var result = "";
foreach (var divAndWordItem in divAndWords)
{
if (IsDivisible(num, divAndWordItem.Divisor))
{
result += divAndWordItem.Word;
}
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
(Divisor: 3, Word: "Fizz"),
(Divisor: 5, Word: "Buzz")
};
var result = "";
foreach (var divAndWordItem in divAndWords)
{
if (IsDivisible(num, divAndWordItem.Divisor))
{
result += divAndWordItem.Word;
}
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
Abstraction in code
Details in metadata
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
(Divisor: 3, Word: "Fizz"),
(Divisor: 5, Word: "Buzz")
};
var result = "";
foreach (var divAndWordItem in divAndWords)
{
if (IsDivisible(num, divAndWordItem.Divisor))
{
result += divAndWordItem.Word;
}
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
Feature Envy
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
(Divisor: 3, Word: "Fizz"),
(Divisor: 5, Word: "Buzz")
};
var result = "";
foreach (var divAndWordItem in divAndWords)
{
if (IsDivisible(num, divAndWordItem.Divisor))
{
result += divAndWordItem.Word;
}
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
Primitive type
Feature Envy
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
(Divisor: 3, Word: "Fizz"),
(Divisor: 5, Word: "Buzz")
};
var divAndWords2 = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWordItem in divAndWords)
{
if (IsDivisible(num, divAndWordItem.Divisor))
{
result += divAndWordItem.Word;
}
}
if (result != "")
return result;
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
(Divisor: 3, Word: "Fizz"),
(Divisor: 5, Word: "Buzz")
};
var divAndWords2 = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWordItem in divAndWords)
{
if (IsDivisible(num, divAndWordItem.Divisor))
{
result += divAndWordItem.Word;
}
}
if (result != "")
return result;
Parallel
implementation
public class DivisorAndWord
{
public int Divisor { get; }
public string Word { get; }
public DivisorAndWord(int divisor, string word)
{
Divisor = divisor;
Word = word;
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
(Divisor: 3, Word: "Fizz"),
(Divisor: 5, Word: "Buzz")
};
var divAndWords2 = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWordItem in divAndWords)
{
if (IsDivisible(num, divAndWordItem.Divisor))
{
result += divAndWordItem.Word;
}
}
if (result != "")
return result;
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
(Divisor: 3, Word: "Fizz"),
(Divisor: 5, Word: "Buzz")
};
var divAndWords2 = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWordItem in divAndWords2)
{
if (IsDivisible(num, divAndWordItem.Divisor))
{
result += divAndWordItem.Word;
}
}
if (result != "")
return result;
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords2 = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWordItem in divAndWords2)
{
if (IsDivisible(num, divAndWordItem.Divisor))
{
result += divAndWordItem.Word;
}
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWord in divAndWords)
{
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWord in divAndWords)
{
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWord in divAndWords)
{
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWord in divAndWords)
{
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
}
if (result != "")
return result;
return num.ToString();
}
static bool IsDivisible(int num, int divisor) {...}
}
Implicit else branch
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWord in divAndWords)
{
if (IsDivisible(num, divAndWord.Divisor))
{
result += divAndWord.Word;
}
else
{
result += "";
}
}
if (result != "")
return result;
return num.ToString();
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWord in divAndWords)
{
var word = "";
if (IsDivisible(num, divAndWord.Divisor))
{
word = divAndWord.Word;
result += divAndWord.Word;
}
else
{
word = "";
result += "";
}
}
if (result != "")
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWord in divAndWords)
{
var word = "";
if (IsDivisible(num, divAndWord.Divisor))
{
word = divAndWord.Word;
result += word;
}
else
{
word = "";
result += word;
}
}
if (result != "")
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWord in divAndWords)
{
var word = "";
if (IsDivisible(num, divAndWord.Divisor))
{
word = divAndWord.Word;
}
else
{
word = "";
}
result += word;
}
if (result != "")
return result;
public class FizzBuzzMachine
{
...
static string EvaluateAndGetWordOrEmpty(
int num, DivisorAndWord divAndWord)
{
string word;
if (IsDivisible(num, divAndWord.Divisor))
{
word = divAndWord.Word;
}
else
{
word = "";
}
return word;
}
...
}
public class DivisorAndWord
{
public int Divisor { get; }
public string Word { get; }
public DivisorAndWord(int divisor, string word)
{
Divisor = divisor;
Word = word;
}
public string EvaluateAndGetWordOrEmpty(int num)
{
if (IsDivisible(num, Divisor))
return Word;
else
return "";
}
public static bool IsDivisible(int num, int divisor)
{
return num % divisor == 0;
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWord in divAndWords)
{
result += divAndWord.EvaluateAndGetWordOrEmpty(num);
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzMachine
{
public string Say(int num)
{
var divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
var result = "";
foreach (var divAndWord in divAndWords)
{
result += divAndWord.EvaluateAndGetWordOrEmpty(num);
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzMachine
{
DivisorAndWord[] divAndWords;
public FizzBuzzMachine()
{
this.divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
}
public string Say(int num)
{
var result = "";
foreach (var divAndWord in divAndWords)
{
result += divAndWord.EvaluateAndGetWordOrEmpty(num);
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzMachine
{
DivisorAndWord[] divAndWords;
public FizzBuzzMachine()
{
this.divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
}
public string Say(int num)
{
var result = "";
foreach (var divAndWord in divAndWords)
{
result += divAndWord.EvaluateAndGetWordOrEmpty(num);
}
if (result != "")
return result;
return num.ToString();
}
}
Push data up and
behaviour down
public class FizzBuzzMachine
{
DivisorAndWord[] divAndWords;
public FizzBuzzMachine(DivisorAndWord[] divAndWords)
{
this.divAndWords = divAndWords;
}
public string Say(int num)
{
var result = "";
foreach (var divAndWord in divAndWords)
{
result += divAndWord.EvaluateAndGetWordOrEmpty(num);
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3*2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5*2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
Let's review the
tests...
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3*2));
}
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5*2));
}
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
Let's review the
tests...
public class FizzBuzzTest
{
...
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
...
}
public class FizzBuzzTest
{
...
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
...
}
public class FizzBuzzTest
{
...
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
...
}
public class FizzBuzzTest
{
...
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
...
}
Input-output correlation
public class FizzBuzzTest
{
...
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
...
}
Input-output correlation
public class FizzBuzzTest
{
...
[Fact]
public void Fizz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
...
}
Input-output correlation
No hard-coded data in prod
public class FizzBuzzTest
{
...
[Fact]
public void SingleMatch()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
...
}
public class FizzBuzzTest
{
...
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5*2));
}
...
}
public class FizzBuzzTest
{
...
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5*2));
}
...
}
public class FizzBuzzTest
{
...
[Fact]
public void Buzz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5*2));
}
...
}
public class FizzBuzzTest
{
...
[Fact]
public void SingleMatch()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5*2));
}
...
}
public class FizzBuzzTest
{
...
[Fact]
public void SingleMatch()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5*2));
}
...
}
Equivalent to SingleMatch
but with different data
public class FizzBuzzTest
{
...
[Fact]
public void SingleMatch()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Buzz", fizzBuzz.Say(5));
Assert.Equal("Buzz", fizzBuzz.Say(5*2));
}
...
}
Equivalent to SingleMatch
but with different data
public class FizzBuzzTest
{
...
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
public class FizzBuzzTest
{
...
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
public class FizzBuzzTest
{
...
[Fact]
public void FizzBuzz()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
public class FizzBuzzTest
{
...
[Fact]
public void MultipleMatch()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
public class FizzBuzzTest
{
[Fact]
public void SimpleNumber()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
...
public class FizzBuzzTest
{
[Fact]
public void NoMatch()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
...
public class FizzBuzzTest
{
[Fact]
public void NoMatch()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void SingleMatch()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void MultipleMatches()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
public class FizzBuzzTest
{
[Fact]
public void NoMatch()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void SingleMatch()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void MultipleMatches()
{
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
});
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
public class FizzBuzzTest
{
readonly DivisorAndWord[] divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
[Fact]
public void NoMatch()
{
var fizzBuzz = new FizzBuzzMachine(divAndWords);
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void SingleMatch()
{
var fizzBuzz = new FizzBuzzMachine(divAndWords);
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void MultipleMatches()
{
var fizzBuzz = new FizzBuzzMachine(divAndWords);
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
Assess impact of change
public class FizzBuzzMachine
{
DivisorAndWord[] divAndWords;
public FizzBuzzMachine(Div...[] divAndWords)
{
this.divAndWords = divAndWords;
}
public string Say(int num)
{
var result = "";
foreach (var divAndWord in divAndWords)
{
result += divAndWord
.EvaluateAndGetWordOrEmpty(num);
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzTest
{
readonly DivisorAndWord[] divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
[Fact]
public void NoMatch()
{
var fizzBuzz = new FizzBuzzMachine(divAndWords);
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void SingleMatch()
{
var fizzBuzz = new FizzBuzzMachine(divAndWords);
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void MultipleMatches()
{
var fizzBuzz = new FizzBuzzMachine(divAndWords);
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
Assess impact of change
public class FizzBuzzMachine
{
DivisorAndWord[] divAndWords;
public FizzBuzzMachine(Div...[] divAndWords)
{
this.divAndWords = divAndWords;
}
public string Say(int num)
{
var result = "";
foreach (var divAndWord in divAndWords)
{
result += divAndWord
.EvaluateAndGetWordOrEmpty(num);
}
if (result != "")
return result;
return num.ToString();
}
}
public class FizzBuzzTest
{
readonly DivisorAndWord[] divAndWords = new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz")
};
[Fact]
public void NoMatch()
{
var fizzBuzz = new FizzBuzzMachine(divAndWords);
Assert.Equal("1", fizzBuzz.Say(1));
Assert.Equal("2", fizzBuzz.Say(2));
}
[Fact]
public void SingleMatch()
{
var fizzBuzz = new FizzBuzzMachine(divAndWords);
Assert.Equal("Fizz", fizzBuzz.Say(3));
Assert.Equal("Fizz", fizzBuzz.Say(3 * 2));
}
[Fact]
public void MultipleMatches()
{
var fizzBuzz = new FizzBuzzMachine(divAndWords);
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5));
Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2));
}
}
No changes here
Assess impact of change
public class FizzBuzzMachine
{
DivisorAndWord[] divAndWords;
public FizzBuzzMachine(Div...[] divAndWords)
{
this.divAndWords = divAndWords;
}
public string Say(int num)
{
var result = "";
foreach (var divAndWord in divAndWords)
{
result += divAndWord
.EvaluateAndGetWordOrEmpty(num);
}
if (result != "")
return result;
return num.ToString();
}
}
static void Main(string[] args)
{
Console.WriteLine("Welcome to FizzBuzz");
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz"),
});
for (int i = 1; i < 1000; i++)
{
var result = fizzBuzz.Say(i);
Console.Write($"{result} ");
}
}
Assess impact of change
public class FizzBuzzMachine
{
DivisorAndWord[] divAndWords;
public FizzBuzzMachine(Div...[] divAndWords)
{
this.divAndWords = divAndWords;
}
public string Say(int num)
{
var result = "";
foreach (var divAndWord in divAndWords)
{
result += divAndWord
.EvaluateAndGetWordOrEmpty(num);
}
if (result != "")
return result;
return num.ToString();
}
}
static void Main(string[] args)
{
Console.WriteLine("Welcome to FizzBuzz");
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz"),
});
for (int i = 1; i < 1000; i++)
{
var result = fizzBuzz.Say(i);
Console.Write($"{result} ");
}
}
Assess impact of change
public class FizzBuzzMachine
{
DivisorAndWord[] divAndWords;
public FizzBuzzMachine(Div...[] divAndWords)
{
this.divAndWords = divAndWords;
}
public string Say(int num)
{
var result = "";
foreach (var divAndWord in divAndWords)
{
result += divAndWord
.EvaluateAndGetWordOrEmpty(num);
}
if (result != "")
return result;
return num.ToString();
}
}
static void Main(string[] args)
{
Console.WriteLine("Welcome to FizzBuzz");
var fizzBuzz = new FizzBuzzMachine(new[]
{
new DivisorAndWord(3, "Fizz"),
new DivisorAndWord(5, "Buzz"),
new DivisorAndWord(7, "Bang")
});
for (int i = 1; i < 1000; i++)
{
var result = fizzBuzz.Say(i);
Console.Write($"{result} ");
}
}
What's next?
What's next?
Refactor foreach -> reduce
Better name for DivisorAndWord
Better name for EvaluateAndGetWordOrEmpty()
Maybe<Word> instead of empty string?
Wrap up
Wrap up
Push data up and
behaviour down
Parallel implementation Making the implicit, explicit
Abstraction in code
Details in metadata
Naming
Data clump
Reconcile differences
Evident data Refactoring in small safe steps
Design Data change vs
behaviour change
Massimo Iacolare
@iacoware
Massimo Iacolare
@iacoware
Thanks!

What FizzBuzz can teach us about design

  • 1.
    What FizzBuzz can teachus about design "You take the red pill, you stay in Wonderland and I show you how deep the rabbit-hole goes"
  • 2.
  • 3.
  • 7.
  • 8.
  • 9.
    Nothing new existing knowledge re-packagedin a way that make sense to me
  • 10.
  • 11.
  • 12.
    1. Context make observationon software design at a micro level
  • 13.
    1. Context make observationon software design at a micro level which is needed to be able to evolve a codebase over time
  • 14.
  • 15.
    2. Code Katas Why?Am I wasting time?
  • 16.
    2. Code Katas Why?Am I wasting time? Perfect to practice a technique in isolation
  • 17.
    2. Code Katas Why?Am I wasting time? Perfect to practice a technique in isolation Isolation allows to improve more effectively
  • 22.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "FizzBuzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } }
  • 23.
    public class FizzBuzzTest { [Fact] publicvoid SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 24.
    public class FizzBuzzTest { [Fact] publicvoid SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } } public class FizzBuzzMachine { public string Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "FizzBuzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } }
  • 27.
  • 28.
  • 29.
  • 30.
    3 -> Fizz 5-> Buzz Change request
  • 31.
    3 -> Fizz 5-> Buzz 3&5 -> FizzBuzz Change request
  • 32.
    3 -> Fizz7 -> Bang 5 -> Buzz 3&5 -> FizzBuzz Change request
  • 33.
    3 -> Fizz7 -> Bang 5 -> Buzz 3&5 -> FizzBuzz 3&7 -> FizzBang 5&7 -> BuzzBang 3&5&7 -> ... Change request
  • 34.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "FizzBuzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } } Assess impact of change public class FizzBuzzTest { [Fact] public void SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 35.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "FizzBuzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } } Assess impact of change public class FizzBuzzTest { [Fact] public void SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 36.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "FizzBuzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } } Assess impact of change public class FizzBuzzTest { [Fact] public void SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 37.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "FizzBuzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } } Assess impact of change public class FizzBuzzTest { [Fact] public void SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 38.
  • 39.
    Change request 3, 5,7 7 branches 3,5 3 branches
  • 40.
    Change request 3, 5,7 3,5,7,11 7 branches ??? 3,5 3 branches
  • 41.
    Change request 3, 5,7 3,5,7,11 7 branches ??? 3,5 3 branches 19 branches
  • 42.
  • 43.
  • 44.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "FizzBuzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } }
  • 45.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "FizzBuzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } } Not exactly the ideal design
  • 46.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "FizzBuzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } } where do we start? what do we do?
  • 47.
  • 48.
    What do wedo? 1. We implement the feature and then refactor
  • 49.
    What do wedo? 1. We implement the feature and then refactor 2. We refactor first and the implement the feature
  • 50.
    What do wedo? 1. We implement the feature and then refactor 2. We refactor first and the implement the feature
  • 51.
  • 52.
    Refactoring 1. Big Bang,tests broken till the end (if you ever reach it)
  • 53.
    Refactoring 1. Big Bang,tests broken till the end (if you ever reach it) 2. Small safe steps, tests stay green
  • 55.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "FizzBuzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } } Assess impact of change public class FizzBuzzTest { [Fact] public void SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 56.
  • 57.
  • 58.
    Challenge one line codechange? no more if branches
  • 59.
    Challenge no more tests oneline code change? no more if branches
  • 60.
  • 61.
    Where do westart? Simplest code?
  • 62.
    Where do westart? Simplest code? More complex code?
  • 63.
    Where do westart? Simplest code? More complex code? Top?
  • 64.
    Where do westart? Simplest code? More complex code? Top? Bottom?
  • 65.
    Where do westart? Simplest code? More complex code? Top? Bottom? Middle?
  • 66.
    Where do westart? Not a unique answer Simplest code? More complex code? Top? Bottom? Middle?
  • 67.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "FizzBuzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } }
  • 68.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "FizzBuzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } }
  • 69.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "Fizz"+"Buzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } }
  • 70.
    Evident Data Reveal theintent of data making their relationship evident
  • 71.
    Too small tobe worth doing
  • 72.
    Too small tobe worth doing
  • 73.
  • 74.
  • 75.
  • 76.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "Fizz"+"Buzz"; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } }
  • 77.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "Fizz"+"Buzz"; var result = ""; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } }
  • 78.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "Fizz"+"Buzz"; var result = ""; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } }
  • 79.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "Fizz"+"Buzz"; var result = ""; if (num % 3 == 0) return "Fizz"; if (num % 5 == 0) return "Buzz"; return num.ToString(); } }
  • 80.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "Fizz"+"Buzz"; var result = ""; if (num % 3 == 0) { result += "Fizz"; return "Fizz"; } if (num % 5 == 0) { result += "Buzz"; return "Buzz"; } return num.ToString(); } }
  • 81.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "Fizz"+"Buzz"; var result = ""; if (num % 3 == 0) { result += "Fizz"; return "Fizz"; } if (num % 5 == 0) { result += "Buzz"; return "Buzz"; } if (result != "") return result; return num.ToString(); }
  • 82.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "Fizz"+"Buzz"; var result = ""; if (num % 3 == 0) { result += "Fizz"; return "Fizz"; } if (num % 5 == 0) { result += "Buzz"; return "Buzz"; } if (result != "") return result; return num.ToString(); }
  • 83.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "Fizz"+"Buzz"; var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; return "Buzz"; } if (result != "") return result; return num.ToString(); } }
  • 84.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "Fizz"+"Buzz"; var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; return "Buzz"; } if (result != "") return result; return num.ToString(); } }
  • 85.
    public class FizzBuzzMachine { publicstring Say(int num) { if (num % 3 == 0 && num % 5 == 0) return "Fizz"+"Buzz"; var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } }
  • 86.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } }
  • 87.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } }
  • 88.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } } Is it better?
  • 89.
    Assess impact ofchange public class FizzBuzzMachine { public string Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } } public class FizzBuzzTest { [Fact] public void SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 90.
    Assess impact ofchange public class FizzBuzzMachine { public string Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } } public class FizzBuzzTest { [Fact] public void SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 91.
    Assess impact ofchange public class FizzBuzzMachine { public string Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } } public class FizzBuzzTest { [Fact] public void SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 93.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } } public class FizzBuzzTest { [Fact] public void SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 94.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } } public class FizzBuzzTest { [Fact] public void SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } } data duplication between test and prod
  • 95.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } } public class FizzBuzzTest { [Fact] public void SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } } data duplication between test and prod code duplication - if branches
  • 96.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } } public class FizzBuzzTest { [Fact] public void SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5 * 2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } } data duplication between test and prod code duplication - if branches primitive types
  • 97.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } }
  • 98.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } }
  • 99.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } } same code, different data
  • 100.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } } same code, different data
  • 101.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (num % 3 == 0) { result += "Fizz"; } if (num % 5 == 0) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } } Can we name the intent of this code?
  • 102.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (IsDivisible(num, 3)) { result += "Fizz"; } if (IsDivisible(num, 5)) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) { return num % divisor == 0; } }
  • 103.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (IsDivisible(num, 3)) { result += "Fizz"; } if (IsDivisible(num, 5)) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) { return num % divisor == 0; } } same code, different data
  • 104.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (IsDivisible(num, 3)) { result += "Fizz"; } if (IsDivisible(num, 5)) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) { return num % divisor == 0; } } same code, different data Reconcile differences
  • 105.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; if (IsDivisible(num, 3)) { result += "Fizz"; } if (IsDivisible(num, 5)) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) { return num % divisor == 0; } }
  • 106.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var fizzDivisor = 3; if (IsDivisible(num, fizzDivisor)) { result += "Fizz"; } if (IsDivisible(num, 5)) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) { return num % divisor == 0; } }
  • 107.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var fizzDivisor = 3; var fizzWord = "Fizz"; if (IsDivisible(num, fizzDivisor)) { result += fizzWord; } if (IsDivisible(num, 5)) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 108.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var fizzDivisor = 3; var fizzWord = "Fizz"; if (IsDivisible(num, fizzDivisor)) { result += fizzWord; } if (IsDivisible(num, 5)) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} } Data clump
  • 109.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var fizzDivisor = 3; var fizzWord = "Fizz"; var divAndWord = (Divisor: fizzDivisor, Word: fizzWord); if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } if (IsDivisible(num, 5)) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 110.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var fizzDivisor = 3; var fizzWord = "Fizz"; var divAndWord = (Divisor: fizzDivisor, Word: fizzWord); if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } if (IsDivisible(num, 5)) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} } Ugly name
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
    Design is Structure andnaming Enable change Goals
  • 116.
    Design is Structure andnaming Enable changeEnable unexpected change Goals
  • 117.
    Design is Structure andnaming Enable change Handle complexity Enable unexpected change Goals
  • 118.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var fizzDivisor = 3; var fizzWord = "Fizz"; var divAndWord = (Divisor: fizzDivisor, Word: fizzWord); if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } if (IsDivisible(num, 5)) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 119.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var divAndWord = (Divisor: 3, Word: "Fizz"); if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } if (IsDivisible(num, 5)) { result += "Buzz"; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 120.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var divAndWord = (Divisor: 3, Word: "Fizz"); if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } var divAndWord2 = (Divisor: 5, Word: "Buzz"); if (IsDivisible(num, divAndWord2.Divisor)) { result += divAndWord2.Word; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 121.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var divAndWord = (Divisor: 3, Word: "Fizz"); var divAndWord2 = (Divisor: 5, Word: "Buzz"); if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } if (IsDivisible(num, divAndWord2.Divisor)) { result += divAndWord2.Word; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 122.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var divAndWord = (Divisor: 3, Word: "Fizz"); var divAndWord2 = (Divisor: 5, Word: "Buzz"); if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } if (IsDivisible(num, divAndWord2.Divisor)) { result += divAndWord2.Word; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} } Same code, multiple data suggests...
  • 123.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var divAndWord = (Divisor: 3, Word: "Fizz"); var divAndWord2 = (Divisor: 5, Word: "Buzz"); var divAndWords = new [] {divAndWord}; if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } if (IsDivisible(num, divAndWord2.Divisor)) { result += divAndWord2.Word; } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 124.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var divAndWord = (Divisor: 3, Word: "Fizz"); var divAndWord2 = (Divisor: 5, Word: "Buzz"); var divAndWords = new [] {divAndWord}; foreach (var divAndWordItem in divAndWords) { if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } } if (IsDivisible(num, divAndWord2.Divisor)) { result += divAndWord2.Word; } if (result != "") return result; return num.ToString(); }
  • 125.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var divAndWord = (Divisor: 3, Word: "Fizz"); var divAndWord2 = (Divisor: 5, Word: "Buzz"); var divAndWords = new [] {divAndWord}; foreach (var divAndWordItem in divAndWords) { if (IsDivisible(num, divAndWordItem.Divisor)) { result += divAndWordItem.Word; } } if (IsDivisible(num, divAndWord2.Divisor)) { result += divAndWord2.Word; } if (result != "") return result; return num.ToString(); }
  • 126.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var divAndWord = (Divisor: 3, Word: "Fizz"); var divAndWord2 = (Divisor: 5, Word: "Buzz"); var divAndWords = new [] {divAndWord, divAndWord2}; foreach (var divAndWordItem in divAndWords) { if (IsDivisible(num, divAndWordItem.Divisor)) { result += divAndWordItem.Word; } } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 127.
    public class FizzBuzzMachine { publicstring Say(int num) { var result = ""; var divAndWords = new[] { (Divisor: 3, Word: "Fizz"), (Divisor: 5, Word: "Buzz") }; foreach (var divAndWordItem in divAndWords) { if (IsDivisible(num, divAndWordItem.Divisor)) { result += divAndWordItem.Word; } } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 128.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { (Divisor: 3, Word: "Fizz"), (Divisor: 5, Word: "Buzz") }; var result = ""; foreach (var divAndWordItem in divAndWords) { if (IsDivisible(num, divAndWordItem.Divisor)) { result += divAndWordItem.Word; } } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 129.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { (Divisor: 3, Word: "Fizz"), (Divisor: 5, Word: "Buzz") }; var result = ""; foreach (var divAndWordItem in divAndWords) { if (IsDivisible(num, divAndWordItem.Divisor)) { result += divAndWordItem.Word; } } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 130.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { (Divisor: 3, Word: "Fizz"), (Divisor: 5, Word: "Buzz") }; var result = ""; foreach (var divAndWordItem in divAndWords) { if (IsDivisible(num, divAndWordItem.Divisor)) { result += divAndWordItem.Word; } } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} } Abstraction in code Details in metadata
  • 131.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { (Divisor: 3, Word: "Fizz"), (Divisor: 5, Word: "Buzz") }; var result = ""; foreach (var divAndWordItem in divAndWords) { if (IsDivisible(num, divAndWordItem.Divisor)) { result += divAndWordItem.Word; } } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} } Feature Envy
  • 132.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { (Divisor: 3, Word: "Fizz"), (Divisor: 5, Word: "Buzz") }; var result = ""; foreach (var divAndWordItem in divAndWords) { if (IsDivisible(num, divAndWordItem.Divisor)) { result += divAndWordItem.Word; } } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} } Primitive type Feature Envy
  • 133.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { (Divisor: 3, Word: "Fizz"), (Divisor: 5, Word: "Buzz") }; var divAndWords2 = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWordItem in divAndWords) { if (IsDivisible(num, divAndWordItem.Divisor)) { result += divAndWordItem.Word; } } if (result != "") return result;
  • 134.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { (Divisor: 3, Word: "Fizz"), (Divisor: 5, Word: "Buzz") }; var divAndWords2 = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWordItem in divAndWords) { if (IsDivisible(num, divAndWordItem.Divisor)) { result += divAndWordItem.Word; } } if (result != "") return result; Parallel implementation
  • 135.
    public class DivisorAndWord { publicint Divisor { get; } public string Word { get; } public DivisorAndWord(int divisor, string word) { Divisor = divisor; Word = word; } }
  • 136.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { (Divisor: 3, Word: "Fizz"), (Divisor: 5, Word: "Buzz") }; var divAndWords2 = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWordItem in divAndWords) { if (IsDivisible(num, divAndWordItem.Divisor)) { result += divAndWordItem.Word; } } if (result != "") return result;
  • 137.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { (Divisor: 3, Word: "Fizz"), (Divisor: 5, Word: "Buzz") }; var divAndWords2 = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWordItem in divAndWords2) { if (IsDivisible(num, divAndWordItem.Divisor)) { result += divAndWordItem.Word; } } if (result != "") return result;
  • 138.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords2 = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWordItem in divAndWords2) { if (IsDivisible(num, divAndWordItem.Divisor)) { result += divAndWordItem.Word; } } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 139.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWord in divAndWords) { if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 140.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWord in divAndWords) { if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 141.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWord in divAndWords) { if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} }
  • 142.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWord in divAndWords) { if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } } if (result != "") return result; return num.ToString(); } static bool IsDivisible(int num, int divisor) {...} } Implicit else branch
  • 143.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWord in divAndWords) { if (IsDivisible(num, divAndWord.Divisor)) { result += divAndWord.Word; } else { result += ""; } } if (result != "") return result; return num.ToString();
  • 144.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWord in divAndWords) { var word = ""; if (IsDivisible(num, divAndWord.Divisor)) { word = divAndWord.Word; result += divAndWord.Word; } else { word = ""; result += ""; } } if (result != "")
  • 145.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWord in divAndWords) { var word = ""; if (IsDivisible(num, divAndWord.Divisor)) { word = divAndWord.Word; result += word; } else { word = ""; result += word; } } if (result != "")
  • 146.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWord in divAndWords) { var word = ""; if (IsDivisible(num, divAndWord.Divisor)) { word = divAndWord.Word; } else { word = ""; } result += word; } if (result != "") return result;
  • 147.
    public class FizzBuzzMachine { ... staticstring EvaluateAndGetWordOrEmpty( int num, DivisorAndWord divAndWord) { string word; if (IsDivisible(num, divAndWord.Divisor)) { word = divAndWord.Word; } else { word = ""; } return word; } ... }
  • 148.
    public class DivisorAndWord { publicint Divisor { get; } public string Word { get; } public DivisorAndWord(int divisor, string word) { Divisor = divisor; Word = word; } public string EvaluateAndGetWordOrEmpty(int num) { if (IsDivisible(num, Divisor)) return Word; else return ""; } public static bool IsDivisible(int num, int divisor) { return num % divisor == 0; } }
  • 149.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWord in divAndWords) { result += divAndWord.EvaluateAndGetWordOrEmpty(num); } if (result != "") return result; return num.ToString(); } }
  • 150.
    public class FizzBuzzMachine { publicstring Say(int num) { var divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; var result = ""; foreach (var divAndWord in divAndWords) { result += divAndWord.EvaluateAndGetWordOrEmpty(num); } if (result != "") return result; return num.ToString(); } }
  • 151.
    public class FizzBuzzMachine { DivisorAndWord[]divAndWords; public FizzBuzzMachine() { this.divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; } public string Say(int num) { var result = ""; foreach (var divAndWord in divAndWords) { result += divAndWord.EvaluateAndGetWordOrEmpty(num); } if (result != "") return result; return num.ToString(); } }
  • 152.
    public class FizzBuzzMachine { DivisorAndWord[]divAndWords; public FizzBuzzMachine() { this.divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; } public string Say(int num) { var result = ""; foreach (var divAndWord in divAndWords) { result += divAndWord.EvaluateAndGetWordOrEmpty(num); } if (result != "") return result; return num.ToString(); } } Push data up and behaviour down
  • 153.
    public class FizzBuzzMachine { DivisorAndWord[]divAndWords; public FizzBuzzMachine(DivisorAndWord[] divAndWords) { this.divAndWords = divAndWords; } public string Say(int num) { var result = ""; foreach (var divAndWord in divAndWords) { result += divAndWord.EvaluateAndGetWordOrEmpty(num); } if (result != "") return result; return num.ToString(); } }
  • 154.
    public class FizzBuzzTest { [Fact] publicvoid SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3*2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5*2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } } Let's review the tests...
  • 155.
    public class FizzBuzzTest { [Fact] publicvoid SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void Fizz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3*2)); } [Fact] public void Buzz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5*2)); } [Fact] public void FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } } Let's review the tests...
  • 156.
    public class FizzBuzzTest { ... [Fact] publicvoid Fizz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } ... }
  • 157.
    public class FizzBuzzTest { ... [Fact] publicvoid Fizz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } ... }
  • 158.
    public class FizzBuzzTest { ... [Fact] publicvoid Fizz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } ... }
  • 159.
    public class FizzBuzzTest { ... [Fact] publicvoid Fizz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } ... } Input-output correlation
  • 160.
    public class FizzBuzzTest { ... [Fact] publicvoid Fizz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } ... } Input-output correlation
  • 161.
    public class FizzBuzzTest { ... [Fact] publicvoid Fizz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } ... } Input-output correlation No hard-coded data in prod
  • 162.
    public class FizzBuzzTest { ... [Fact] publicvoid SingleMatch() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } ... }
  • 163.
    public class FizzBuzzTest { ... [Fact] publicvoid Buzz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5*2)); } ... }
  • 164.
    public class FizzBuzzTest { ... [Fact] publicvoid Buzz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5*2)); } ... }
  • 165.
    public class FizzBuzzTest { ... [Fact] publicvoid Buzz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5*2)); } ... }
  • 166.
    public class FizzBuzzTest { ... [Fact] publicvoid SingleMatch() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5*2)); } ... }
  • 167.
    public class FizzBuzzTest { ... [Fact] publicvoid SingleMatch() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5*2)); } ... } Equivalent to SingleMatch but with different data
  • 168.
    public class FizzBuzzTest { ... [Fact] publicvoid SingleMatch() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Buzz", fizzBuzz.Say(5)); Assert.Equal("Buzz", fizzBuzz.Say(5*2)); } ... } Equivalent to SingleMatch but with different data
  • 169.
    public class FizzBuzzTest { ... [Fact] publicvoid FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 170.
    public class FizzBuzzTest { ... [Fact] publicvoid FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 171.
    public class FizzBuzzTest { ... [Fact] publicvoid FizzBuzz() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 172.
    public class FizzBuzzTest { ... [Fact] publicvoid MultipleMatch() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 173.
    public class FizzBuzzTest { [Fact] publicvoid SimpleNumber() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } ...
  • 174.
    public class FizzBuzzTest { [Fact] publicvoid NoMatch() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } ...
  • 175.
    public class FizzBuzzTest { [Fact] publicvoid NoMatch() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void SingleMatch() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void MultipleMatches() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 176.
    public class FizzBuzzTest { [Fact] publicvoid NoMatch() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void SingleMatch() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void MultipleMatches() { var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 177.
    public class FizzBuzzTest { readonlyDivisorAndWord[] divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; [Fact] public void NoMatch() { var fizzBuzz = new FizzBuzzMachine(divAndWords); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void SingleMatch() { var fizzBuzz = new FizzBuzzMachine(divAndWords); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void MultipleMatches() { var fizzBuzz = new FizzBuzzMachine(divAndWords); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 178.
    Assess impact ofchange public class FizzBuzzMachine { DivisorAndWord[] divAndWords; public FizzBuzzMachine(Div...[] divAndWords) { this.divAndWords = divAndWords; } public string Say(int num) { var result = ""; foreach (var divAndWord in divAndWords) { result += divAndWord .EvaluateAndGetWordOrEmpty(num); } if (result != "") return result; return num.ToString(); } } public class FizzBuzzTest { readonly DivisorAndWord[] divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; [Fact] public void NoMatch() { var fizzBuzz = new FizzBuzzMachine(divAndWords); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void SingleMatch() { var fizzBuzz = new FizzBuzzMachine(divAndWords); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void MultipleMatches() { var fizzBuzz = new FizzBuzzMachine(divAndWords); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } }
  • 179.
    Assess impact ofchange public class FizzBuzzMachine { DivisorAndWord[] divAndWords; public FizzBuzzMachine(Div...[] divAndWords) { this.divAndWords = divAndWords; } public string Say(int num) { var result = ""; foreach (var divAndWord in divAndWords) { result += divAndWord .EvaluateAndGetWordOrEmpty(num); } if (result != "") return result; return num.ToString(); } } public class FizzBuzzTest { readonly DivisorAndWord[] divAndWords = new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz") }; [Fact] public void NoMatch() { var fizzBuzz = new FizzBuzzMachine(divAndWords); Assert.Equal("1", fizzBuzz.Say(1)); Assert.Equal("2", fizzBuzz.Say(2)); } [Fact] public void SingleMatch() { var fizzBuzz = new FizzBuzzMachine(divAndWords); Assert.Equal("Fizz", fizzBuzz.Say(3)); Assert.Equal("Fizz", fizzBuzz.Say(3 * 2)); } [Fact] public void MultipleMatches() { var fizzBuzz = new FizzBuzzMachine(divAndWords); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5)); Assert.Equal("FizzBuzz", fizzBuzz.Say(3 * 5 * 2)); } } No changes here
  • 180.
    Assess impact ofchange public class FizzBuzzMachine { DivisorAndWord[] divAndWords; public FizzBuzzMachine(Div...[] divAndWords) { this.divAndWords = divAndWords; } public string Say(int num) { var result = ""; foreach (var divAndWord in divAndWords) { result += divAndWord .EvaluateAndGetWordOrEmpty(num); } if (result != "") return result; return num.ToString(); } } static void Main(string[] args) { Console.WriteLine("Welcome to FizzBuzz"); var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz"), }); for (int i = 1; i < 1000; i++) { var result = fizzBuzz.Say(i); Console.Write($"{result} "); } }
  • 181.
    Assess impact ofchange public class FizzBuzzMachine { DivisorAndWord[] divAndWords; public FizzBuzzMachine(Div...[] divAndWords) { this.divAndWords = divAndWords; } public string Say(int num) { var result = ""; foreach (var divAndWord in divAndWords) { result += divAndWord .EvaluateAndGetWordOrEmpty(num); } if (result != "") return result; return num.ToString(); } } static void Main(string[] args) { Console.WriteLine("Welcome to FizzBuzz"); var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz"), }); for (int i = 1; i < 1000; i++) { var result = fizzBuzz.Say(i); Console.Write($"{result} "); } }
  • 182.
    Assess impact ofchange public class FizzBuzzMachine { DivisorAndWord[] divAndWords; public FizzBuzzMachine(Div...[] divAndWords) { this.divAndWords = divAndWords; } public string Say(int num) { var result = ""; foreach (var divAndWord in divAndWords) { result += divAndWord .EvaluateAndGetWordOrEmpty(num); } if (result != "") return result; return num.ToString(); } } static void Main(string[] args) { Console.WriteLine("Welcome to FizzBuzz"); var fizzBuzz = new FizzBuzzMachine(new[] { new DivisorAndWord(3, "Fizz"), new DivisorAndWord(5, "Buzz"), new DivisorAndWord(7, "Bang") }); for (int i = 1; i < 1000; i++) { var result = fizzBuzz.Say(i); Console.Write($"{result} "); } }
  • 185.
  • 186.
    What's next? Refactor foreach-> reduce Better name for DivisorAndWord Better name for EvaluateAndGetWordOrEmpty() Maybe<Word> instead of empty string?
  • 187.
  • 188.
    Wrap up Push dataup and behaviour down Parallel implementation Making the implicit, explicit Abstraction in code Details in metadata Naming Data clump Reconcile differences Evident data Refactoring in small safe steps Design Data change vs behaviour change
  • 190.
  • 191.