SlideShare una empresa de Scribd logo
1 de 191
Descargar para leer sin conexión
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!

Más contenido relacionado

La actualidad más candente

Лекция 1: Введение в алгоритмы
Лекция 1: Введение в алгоритмыЛекция 1: Введение в алгоритмы
Лекция 1: Введение в алгоритмы
Mikhail Kurnosov
 

La actualidad más candente (20)

Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
7 rules of simple and maintainable code
7 rules of simple and maintainable code7 rules of simple and maintainable code
7 rules of simple and maintainable code
 
Hexagonal architecture with Spring Boot
Hexagonal architecture with Spring BootHexagonal architecture with Spring Boot
Hexagonal architecture with Spring Boot
 
Лекция 1: Введение в алгоритмы
Лекция 1: Введение в алгоритмыЛекция 1: Введение в алгоритмы
Лекция 1: Введение в алгоритмы
 
Clean Architecture Essentials - Stockholm Software Craftsmanship
Clean Architecture Essentials - Stockholm Software CraftsmanshipClean Architecture Essentials - Stockholm Software Craftsmanship
Clean Architecture Essentials - Stockholm Software Craftsmanship
 
Real Life Clean Architecture
Real Life Clean ArchitectureReal Life Clean Architecture
Real Life Clean Architecture
 
The Art of Unit Testing - Towards a Testable Design
The Art of Unit Testing - Towards a Testable DesignThe Art of Unit Testing - Towards a Testable Design
The Art of Unit Testing - Towards a Testable Design
 
Functional Patterns with Java8 @Bucharest Java User Group
Functional Patterns with Java8 @Bucharest Java User GroupFunctional Patterns with Java8 @Bucharest Java User Group
Functional Patterns with Java8 @Bucharest Java User Group
 
Apresentação Clean Code
Apresentação Clean CodeApresentação Clean Code
Apresentação Clean Code
 
Clean architecture
Clean architectureClean architecture
Clean architecture
 
Hexagonal architecture: how, why and when
Hexagonal architecture: how, why and whenHexagonal architecture: how, why and when
Hexagonal architecture: how, why and when
 
Padrão Command
Padrão CommandPadrão Command
Padrão Command
 
Mockist vs. Classicists TDD
Mockist vs. Classicists TDDMockist vs. Classicists TDD
Mockist vs. Classicists TDD
 
Introduction to Design Patterns and Singleton
Introduction to Design Patterns and SingletonIntroduction to Design Patterns and Singleton
Introduction to Design Patterns and Singleton
 
Method parameters in c#
Method parameters in c#Method parameters in c#
Method parameters in c#
 
Builder design pattern
Builder design patternBuilder design pattern
Builder design pattern
 
Desafio Rest API
Desafio Rest APIDesafio Rest API
Desafio Rest API
 
Clean code slide
Clean code slideClean code slide
Clean code slide
 
.NET Fest 2019. Alexandre Malavasi. The future of Web: what Microsoft Blazor ...
.NET Fest 2019. Alexandre Malavasi. The future of Web: what Microsoft Blazor ....NET Fest 2019. Alexandre Malavasi. The future of Web: what Microsoft Blazor ...
.NET Fest 2019. Alexandre Malavasi. The future of Web: what Microsoft Blazor ...
 
The Art of Clean code
The Art of Clean codeThe Art of Clean code
The Art of Clean code
 

Similar a What FizzBuzz can teach us about design

Bdd: Tdd and beyond the infinite
Bdd: Tdd and beyond the infiniteBdd: Tdd and beyond the infinite
Bdd: Tdd and beyond the infinite
Giordano Scalzo
 
FizzBuzz Guided Kata
FizzBuzz Guided KataFizzBuzz Guided Kata
FizzBuzz Guided Kata
Mike Clement
 
F*cking with fizz buzz
F*cking with fizz buzzF*cking with fizz buzz
F*cking with fizz buzz
Scott Windsor
 

Similar a What FizzBuzz can teach us about design (14)

KISS - im Prinzip ganz einfach
KISS - im Prinzip ganz einfachKISS - im Prinzip ganz einfach
KISS - im Prinzip ganz einfach
 
FUNctional programming in Python
FUNctional programming in PythonFUNctional programming in Python
FUNctional programming in Python
 
Bdd: Tdd and beyond the infinite
Bdd: Tdd and beyond the infiniteBdd: Tdd and beyond the infinite
Bdd: Tdd and beyond the infinite
 
Get Kata
Get KataGet Kata
Get Kata
 
FizzBuzz Guided Kata
FizzBuzz Guided KataFizzBuzz Guided Kata
FizzBuzz Guided Kata
 
ATS language overview
ATS language overviewATS language overview
ATS language overview
 
Test Driven Development Workshop
Test Driven Development WorkshopTest Driven Development Workshop
Test Driven Development Workshop
 
XpUg Coding Dojo: KataYahtzee in Ocp way
XpUg Coding Dojo: KataYahtzee in Ocp wayXpUg Coding Dojo: KataYahtzee in Ocp way
XpUg Coding Dojo: KataYahtzee in Ocp way
 
Basic TDD moves
Basic TDD movesBasic TDD moves
Basic TDD moves
 
Introducing Swift - and the Sunset of Our Culture?
Introducing Swift - and the Sunset of Our Culture?Introducing Swift - and the Sunset of Our Culture?
Introducing Swift - and the Sunset of Our Culture?
 
F*cking with fizz buzz
F*cking with fizz buzzF*cking with fizz buzz
F*cking with fizz buzz
 
Fizz and buzz of computer programs in python.
Fizz and buzz of computer programs in python.Fizz and buzz of computer programs in python.
Fizz and buzz of computer programs in python.
 
Testing the Next Generation
Testing the Next GenerationTesting the Next Generation
Testing the Next Generation
 
Exploring type-directed, test-driven development: a case study using FizzBuzz
Exploring type-directed, test-driven development: a case study using FizzBuzzExploring type-directed, test-driven development: a case study using FizzBuzz
Exploring type-directed, test-driven development: a case study using FizzBuzz
 

Más de Massimo Iacolare (7)

Coding Dojo Firenze - vol1
Coding Dojo Firenze - vol1 Coding Dojo Firenze - vol1
Coding Dojo Firenze - vol1
 
Discover React
Discover ReactDiscover React
Discover React
 
#NoEstimates Thinking
#NoEstimates Thinking#NoEstimates Thinking
#NoEstimates Thinking
 
NoEstimates @ miniIAD
NoEstimates @ miniIADNoEstimates @ miniIAD
NoEstimates @ miniIAD
 
Web Performance Optimization @Develer
Web Performance Optimization @DevelerWeb Performance Optimization @Develer
Web Performance Optimization @Develer
 
Web performance optimization
Web performance optimizationWeb performance optimization
Web performance optimization
 
Single Page Applications
Single Page ApplicationsSingle Page Applications
Single Page Applications
 

Último

%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
masabamasaba
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
masabamasaba
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
masabamasaba
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
masabamasaba
 

Último (20)

%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
%+27788225528 love spells in new york Psychic Readings, Attraction spells,Bri...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 

What FizzBuzz can teach us about design

  • 1. 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"
  • 4.
  • 5.
  • 6.
  • 9. Nothing new existing knowledge re-packaged in a way that make sense to me
  • 12. 1. Context make observation on software design at a micro level
  • 13. 1. Context make observation on software design at a micro level which is needed to be able to evolve a codebase over time
  • 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
  • 18.
  • 19.
  • 20.
  • 21.
  • 22. 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(); } }
  • 23. 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)); } }
  • 24. 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(); } }
  • 25.
  • 26.
  • 29. 3 -> Fizz Change request
  • 30. 3 -> Fizz 5 -> Buzz Change request
  • 31. 3 -> Fizz 5 -> Buzz 3&5 -> FizzBuzz Change request
  • 32. 3 -> Fizz 7 -> Bang 5 -> Buzz 3&5 -> FizzBuzz Change request
  • 33. 3 -> Fizz 7 -> Bang 5 -> Buzz 3&5 -> FizzBuzz 3&7 -> FizzBang 5&7 -> BuzzBang 3&5&7 -> ... Change request
  • 34. 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)); } }
  • 35. 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)); } }
  • 36. 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)); } }
  • 37. 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)); } }
  • 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
  • 44. 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(); } }
  • 45. 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
  • 46. 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?
  • 47. What do we do?
  • 48. What do we do? 1. We implement the feature and then refactor
  • 49. What do we do? 1. We implement the feature and then refactor 2. We refactor first and the implement the feature
  • 50. What do we do? 1. We implement the feature and then refactor 2. We refactor first and the implement the feature
  • 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
  • 54.
  • 55. 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)); } }
  • 58. Challenge one line code change? no more if branches
  • 59. Challenge no more tests one line code change? no more if branches
  • 60. Where do we start?
  • 61. Where do we start? Simplest code?
  • 62. Where do we start? Simplest code? More complex code?
  • 63. Where do we start? Simplest code? More complex code? Top?
  • 64. Where do we start? Simplest code? More complex code? Top? Bottom?
  • 65. Where do we start? Simplest code? More complex code? Top? Bottom? Middle?
  • 66. Where do we start? Not a unique answer Simplest code? More complex code? Top? Bottom? Middle?
  • 67. 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(); } }
  • 68. 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(); } }
  • 69. 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(); } }
  • 70. Evident Data Reveal the intent of data making their relationship evident
  • 71. Too small to be worth doing
  • 72. Too small to be worth doing
  • 76. 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(); } }
  • 77. 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(); } }
  • 78. 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(); } }
  • 79. 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(); } }
  • 80. 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(); } }
  • 81. 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(); }
  • 82. 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(); }
  • 83. 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(); } }
  • 84. 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(); } }
  • 85. 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(); } }
  • 86. 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(); } }
  • 87. 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(); } }
  • 88. 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?
  • 89. 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)); } }
  • 90. 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)); } }
  • 91. 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)); } }
  • 92.
  • 93. 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)); } }
  • 94. 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
  • 95. 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
  • 96. 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
  • 97. 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(); } }
  • 98. 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(); } }
  • 99. 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
  • 100. 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
  • 101. 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?
  • 102. 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; } }
  • 103. 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
  • 104. 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
  • 105. 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; } }
  • 106. 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; } }
  • 107. 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) {...} }
  • 108. 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
  • 109. 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) {...} }
  • 110. 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
  • 114. Design is Structure and naming Goals
  • 115. Design is Structure and naming Enable change Goals
  • 116. Design is Structure and naming Enable changeEnable unexpected change Goals
  • 117. Design is Structure and naming Enable change Handle complexity Enable unexpected change Goals
  • 118. 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) {...} }
  • 119. 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) {...} }
  • 120. 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) {...} }
  • 121. 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) {...} }
  • 122. 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...
  • 123. 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) {...} }
  • 124. 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(); }
  • 125. 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(); }
  • 126. 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) {...} }
  • 127. 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) {...} }
  • 128. 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) {...} }
  • 129. 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) {...} }
  • 130. 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
  • 131. 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
  • 132. 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
  • 133. 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;
  • 134. 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
  • 135. public class DivisorAndWord { public int Divisor { get; } public string Word { get; } public DivisorAndWord(int divisor, string word) { Divisor = divisor; Word = word; } }
  • 136. 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;
  • 137. 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;
  • 138. 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) {...} }
  • 139. 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) {...} }
  • 140. 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) {...} }
  • 141. 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) {...} }
  • 142. 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
  • 143. 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();
  • 144. 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 != "")
  • 145. 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 != "")
  • 146. 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;
  • 147. public class FizzBuzzMachine { ... static string EvaluateAndGetWordOrEmpty( int num, DivisorAndWord divAndWord) { string word; if (IsDivisible(num, divAndWord.Divisor)) { word = divAndWord.Word; } else { word = ""; } return word; } ... }
  • 148. 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; } }
  • 149. 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(); } }
  • 150. 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(); } }
  • 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] 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...
  • 155. 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...
  • 156. 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)); } ... }
  • 157. 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)); } ... }
  • 158. 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)); } ... }
  • 159. 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
  • 160. 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
  • 161. 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
  • 162. 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)); } ... }
  • 163. 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)); } ... }
  • 164. 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)); } ... }
  • 165. 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)); } ... }
  • 166. 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)); } ... }
  • 167. 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
  • 168. 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
  • 169. 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)); } }
  • 170. 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)); } }
  • 171. 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)); } }
  • 172. 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)); } }
  • 173. 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)); } ...
  • 174. 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)); } ...
  • 175. 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)); } }
  • 176. 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)); } }
  • 177. 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)); } }
  • 178. 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)); } }
  • 179. 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
  • 180. 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} "); } }
  • 181. 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} "); } }
  • 182. 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} "); } }
  • 183.
  • 184.
  • 186. What's next? Refactor foreach -> reduce Better name for DivisorAndWord Better name for EvaluateAndGetWordOrEmpty() Maybe<Word> instead of empty string?
  • 188. 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
  • 189.