Upload
sanderslideshare
View
63
Download
0
Embed Size (px)
DESCRIPTION
Test-Driven Development is presented as the one and only way to write code. Some people consider you not a professional software developer if you do not use it. Uncle Bob uses TDD to solve the Primes Kata with just three lines of code. These three lines were justified by only seven tests. However, tests have one big problem: tests can only prove the presence of bugs, not their absence. So how does TDD help you writing correct programs? Prof. E.W. Dijkstra, winner of the Turing Award, developed a formal way of deriving and proving algorithms. Formal proofs are constructed with pre- or postconditions. Rules to prove the postcondition of a single assignment and a single if-statement are shown. Using an invariant and a bound function the postcondition of a while-loop can be proved. Using these simple rules a solution of the Primes Kata is derived. The formal proof of the correctness for these three lines make one thing clear: seven tests are not sufficient to prove this algorithm! Do not fear very detailed and formal mathematical proofs. The derivations are presented in a practical and informal way.
Citation preview
Let tests drive orlet Dijkstra derive?
Sander Kooijmans
ALE 2014
Why this presentation?
• TDD is currently hyped
• Many TDD trainers say• You are not a serious programmer if you do not use TDD
• The only way to write correct programs is using TDD
• Uncle Bob (Robert Martin) says• Applying TDD and transformations may be a formal proof of
correctness (still to be proven)
Why this presentation?
• TDD is currently hyped
• Many TDD trainers say• You are not a serious programmer if you do not use TDD
• The only way to write correct programs is using TDD
• Uncle Bob (Robert Martin) says• Applying TDD and transformations may be a formal proof of
correctness (still to be proven)
http://blog.8thlight.com/uncle-bob/2013/05/27/TheTransformationPriorityPremise.htmlhttp://blog.8thlight.com/uncle-bob/2014/05/02/ProfessionalismAndTDD.html http://cleancoders.com/episode/clean-code-episode-6-p2/show
My experience with TDD
My experience with tests
Tests require clean code
My experience with tests
• Tests protect against accidental modification of existing behavior• When adding new functionality
• When refactoring existing functionality
My experience with tests
Tests are examples of how production code must be used
My experience with tests
Tests as specification
My experience with tests
Writing tests first helps to clarify specifications
My experience with tests
I don’t dare to deliver production code without tests!
The Prime Factors Kata by Uncle Bobpackage primeFactors;
import static primeFactors.PrimeFactors.generate;
import junit.framework.TestCase;
import java.util.*;
public class PrimeFactorsTest extends TestCase {
private List<Integer> list(int... ints) {
List<Integer> list = new ArrayList<Integer>();
for (int i : ints)
list.add(i);
return list;
}
public void testOne() throws Exception {
assertEquals(list(),generate(1));
}
public void testTwo() throws Exception {
assertEquals(list(2),generate(2));
}
public void testThree() throws Exception {
assertEquals(list(3),generate(3));
}
public void testFour() throws Exception {
assertEquals(list(2,2),generate(4));
}
public void testSix() throws Exception {
assertEquals(list(2,3),generate(6));
}
public void testEight() throws Exception {
assertEquals(list(2,2,2),generate(8));
}
public void testNine() throws Exception {
assertEquals(list(3,3),generate(9));
}
}
package primeFactors;
import java.util.*;
public class PrimeFactors {
public static List<Integer> generate(int n) {
List<Integer> primes = new ArrayList<Integer>();
for (int candidate = 2; n > 1; candidate++)
for (; n%candidate == 0; n/=candidate)
primes.add(candidate);
return primes;
}
}
The algorithm is three lines of code!
http://butunclebob.com/files/downloads/Prime%20Factors%20Kata.ppt
Edsger Wybe Dijkstra (1930-2002)
“Program testing can be used to show the presence of bugs,
but never to show their absence!”
Edsger Wybe Dijkstra
Edsger Wybe Dijkstra
program derivation: to “develop proof and program hand in hand”
PredicatesAll variables of your program int i=0; int j=100;
After execution these predicates hold:P(i,j) Î i==0Q(i,j) Î i<jR(i,j) Î i==0 && j==100
For brevity we write
R Î i==0 && j==100
true or false
Hoare triple
The Hoare triple {Pre} S {Post} means:When Pre holds and S is executed
then if S terminates Post holds
In the Java code samples I use this notation:
Assignment
{Pre} x = E {Post} is equivalent to Pre Á Post(x:=E)
Let us prove
{x == 5} x = x+3 {x > 7}
(x > 7)(x:=x+3)Î { substitution }
x+3 > 7Î { calculus }
x > 4Ë { precondition }
x == 5
Assignment
{Pre} x = E {Post} is equivalent to Pre Á Post(x:=E)
And another proof. In this case Pre is equivalent to Post(x:=E).
{x == 40} x = x+2 {x == 42}
(x == 42)(x:=x+2)Î { substitution }
x+2 == 42Î { arithmetic }
x == 40
If-statement
{Pre} if (B) S else T {Post} is equivalent to:
{Pre && B} S {Post} and {Pre && !B} T {Post}
Let us prove
{true} if (y>=x) u=y else u=x {u == max(x,y)}
If-statement {Pre && B} S {Post}
We use the following definition of max in our proofu=max(x,y) Î (u==x || u==y) && u>=x && u>=y
{true} if (y>=x) u=y else u=x {u == max(x,y)}
(u == max(x,y))(u:=y)Î { substitution }
y == max(x,y)Î { definition of max }
(y==x || y==y) && y>=x && y>=yÎ { calculus }
y >= x
If-statement {Pre && !B} T {Post}
{true} if (y>=x) u=y else u=x {u == max(x,y)}
(u == max(x,y))(u:=x)Î { substitution }
x == max(x,y)Î { definition of max }(x==x || x==y) && x>=x && x>=y
Î { calculus }x >= y
Ë { calculus }y < x
Î { calculus }!(y>=x)
While-loop
{Inv} while (B) S {Post} follows from• {Inv && B} S {Inv}• Inv && !B Á Post• Provided that the loop terminates
Inv is called an invariant
Termination of a while-loop
Termination is proved using a bound function• A bound function decreases with at least one each iteration
• The bound function is bounded from below
While-loop
Let us prove
While-loop
Let us prove
Proof for {Inv && B} S {Inv}
(p * 2n == 2originalN)(p:=2*p)(n:=n-1)Î { substitutions }(2*p * 2n-1 == 2originalN)
Î { calculus }p * 2n == 2originalN
Î { definitionof invariant }true
While-loop
Let us prove
While-loop
Let us prove
Proof for {Inv && B} S {Inv}
(sum == 1 + 2 + … + p)(p:=p+1)(sum := sum+p+1)Î { substitution p := p+1 }(sum == 1 + 2 + … + p + (p+1))(sum := sum+p+1)
Î { substitution sum := sum + p+1}sum + (p+1) == 1 + 2 + … + p + (p+1)
Î { use invariant sum = 1 + 2 + … + p }sum + (p+1) == sum + (p+1)
Î { calculus }true
Deriving a solution to the Prime Factors Kata
Deriving a solution to the Prime Factors Kata
originalN == 140
Deriving a solution to the Prime Factors Kata
Deriving a solution to the Prime Factors Kata
originalN == 180
Deriving a solution to the Prime Factors Kata
Deriving a solution to the Prime Factors Kata
Deriving a solution to the Prime Factors Kata
Deriving an alternate solution
Deriving an alternate solution
The Prime Factors Kata by Uncle Bob
The algorithm is three lines of code!
Conclusions
• There is no guarantee that TDD results in correct code
• Deriving and proving an algorithm can go hand in hand
• TDD and formal proofs are tools, not goals
• The goal is correct code
• Tests help to keep the code correct