ale2014 let tests drive or let dijkstra derive

40
Let tests drive or let Dijkstra derive? Sander Kooijmans ALE 2014

Upload: sanderslideshare

Post on 22-Apr-2015

66 views

Category:

Software


0 download

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.

TRANSCRIPT

Page 1: ALE2014 let tests drive or let dijkstra derive

Let tests drive orlet Dijkstra derive?

Sander Kooijmans

ALE 2014

Page 2: ALE2014 let tests drive or let dijkstra derive

Who is Sander Kooijmans?

www.hightechict.nl

[email protected]

www.gogognome.nl

Page 3: ALE2014 let tests drive or let dijkstra derive

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)

Page 4: ALE2014 let tests drive or let dijkstra derive

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

Page 5: ALE2014 let tests drive or let dijkstra derive

My experience with TDD

Page 6: ALE2014 let tests drive or let dijkstra derive

My experience with tests

Tests require clean code

Page 7: ALE2014 let tests drive or let dijkstra derive

My experience with tests

• Tests protect against accidental modification of existing behavior• When adding new functionality

• When refactoring existing functionality

Page 8: ALE2014 let tests drive or let dijkstra derive

My experience with tests

Tests are examples of how production code must be used

Page 9: ALE2014 let tests drive or let dijkstra derive

My experience with tests

Tests as specification

Page 10: ALE2014 let tests drive or let dijkstra derive

My experience with tests

Writing tests first helps to clarify specifications

Page 11: ALE2014 let tests drive or let dijkstra derive

My experience with tests

I don’t dare to deliver production code without tests!

Page 12: ALE2014 let tests drive or let dijkstra derive

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

Page 13: ALE2014 let tests drive or let dijkstra derive

Edsger Wybe Dijkstra (1930-2002)

“Program testing can be used to show the presence of bugs,

but never to show their absence!”

Page 14: ALE2014 let tests drive or let dijkstra derive

Edsger Wybe Dijkstra

Page 15: ALE2014 let tests drive or let dijkstra derive

Edsger Wybe Dijkstra

program derivation: to “develop proof and program hand in hand”

Page 16: ALE2014 let tests drive or let dijkstra derive

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

Page 17: ALE2014 let tests drive or let dijkstra derive

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:

Page 18: ALE2014 let tests drive or let dijkstra derive

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

Page 19: ALE2014 let tests drive or let dijkstra derive

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

Page 20: ALE2014 let tests drive or let dijkstra derive

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)}

Page 21: ALE2014 let tests drive or let dijkstra derive

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

Page 22: ALE2014 let tests drive or let dijkstra derive

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)

Page 23: ALE2014 let tests drive or let dijkstra derive

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

Page 24: ALE2014 let tests drive or let dijkstra derive

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

Page 25: ALE2014 let tests drive or let dijkstra derive

While-loop

Let us prove

Page 26: ALE2014 let tests drive or let dijkstra derive

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

Page 27: ALE2014 let tests drive or let dijkstra derive

While-loop

Let us prove

Page 28: ALE2014 let tests drive or let dijkstra derive

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

Page 29: ALE2014 let tests drive or let dijkstra derive

Deriving a solution to the Prime Factors Kata

Page 30: ALE2014 let tests drive or let dijkstra derive

Deriving a solution to the Prime Factors Kata

originalN == 140

Page 31: ALE2014 let tests drive or let dijkstra derive

Deriving a solution to the Prime Factors Kata

Page 32: ALE2014 let tests drive or let dijkstra derive

Deriving a solution to the Prime Factors Kata

originalN == 180

Page 33: ALE2014 let tests drive or let dijkstra derive

Deriving a solution to the Prime Factors Kata

Page 34: ALE2014 let tests drive or let dijkstra derive

Deriving a solution to the Prime Factors Kata

Page 35: ALE2014 let tests drive or let dijkstra derive

Deriving a solution to the Prime Factors Kata

Page 36: ALE2014 let tests drive or let dijkstra derive

Deriving an alternate solution

Page 37: ALE2014 let tests drive or let dijkstra derive

Deriving an alternate solution

Page 38: ALE2014 let tests drive or let dijkstra derive

The Prime Factors Kata by Uncle Bob

The algorithm is three lines of code!

Page 39: ALE2014 let tests drive or let dijkstra derive

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

Page 40: ALE2014 let tests drive or let dijkstra derive

Questions?

www.hightechict.nl

[email protected]

www.gogognome.nl