ALE2014 let tests drive or let dijkstra derive

Post on 22-Apr-2015

63 views 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 of ALE2014 let tests drive or let dijkstra derive

Let tests drive orlet Dijkstra derive?

Sander Kooijmans

ALE 2014

Who is Sander Kooijmans?

www.hightechict.nl

sander.kooijmans@hightechict.nl

www.gogognome.nl

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

Questions?

www.hightechict.nl

sander.kooijmans@hightechict.nl

www.gogognome.nl