Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C)...

28
Εισαγωγή στο TDD Test Driven Development Δομημένος Προγραμματισμός Τσαγκατάκης Ιωάννης

Transcript of Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C)...

Page 1: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

Εισαγωγή στο TDDTest Driven

Development

Δομημένος ΠρογραμματισμόςΤσαγκατάκης Ιωάννης

Page 2: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

2

Πως λύνουμε ένα πρόβλημα ;

ΣχεδιασμόςΑλγορίθμου

Κώδικας (υλοποίηση)

Profit !

Page 3: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

3

Άσκηση 4Γράψτε ένα πρόγραμμα το οποίο θα βρίσκει και θα εμφανίζει στη οθόνη όλους τους τετραψήφιους αριθμούς που είναι ίσοι με το άθροισμα των ψηφίων τους στη τέταρτη δύναμη.

Α Β C D

0...9

1...9

Ένα κόμμα κάνει την διαφορά

#include <math.h>

int a, b, c, d, x;

int sum1 = pow(a, 4) + pow(b, 4) + pow(c, 4) + pow(d, 4);

int sum2 = pow(a + b + c + d, 4);

Page 4: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

4

undefined reference to `pow'● Χρειάζεται την βιβλιοθήκη libm

gcc -Wall -Wconversion -o ex4 -lm ex4.c

● cmake cmake_minimum_required(VERSION 3.15 )project(Ergasia1 C)add_compile_options(-Wall -Wextra -Wconversion -Wpedantic)

add_executable(ex1 ex1.c)add_executable(ex4 ex4.c)target_link_libraries(ex4 m)

Page 5: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

5

undefined reference to `pow'● Περιφραστικά

● Συνάρτηση

int sum3= a*a*a*a + b*b*b*b + c*c*c*c + d*d*d*d;

int pow4(int num) { int result = num * num * num * num; return result;}

Page 6: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

6

Μια απλή λύσηint main() { for (int a = 1; a <= 9; a++) { for (int b = 0; b <= 9; b++) { for (int c = 0; c <= 9; c++) { for (int d = 0; d <= 9; d++) {

// Horner method int x = (((a * 10) + b) * 10 + c) * 10 + d;

int sum = pow(a, 4) + pow(b, 4) + pow(c, 4) + pow(d, 4); if (sum == x) { printf("Solution found %d\n", x); } } } } }}

Solution found 1634Solution found 8208Solution found 9474

Είναι σωστά;

Page 7: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

7

Μια (αυστηρή) κριτική της λύσης● Δουλεύει μόνο για 4ψήφιους αριθμούς

– Αν αύριο μας ζητήσουν για 5-ψήφιους αριθμούς;● Κάνει πολλά πράγματα μπλεγμένα μεταξύ τους

– Παραγωγή 4-ψήφιων αριθμών – Έλεγχος της συνθήκης φιλτραρίσματος. Αν αύριο αλλάξει;

● Πάντα αναζητούμε ποιο γενικές λύσεις● Αυτά δεν είναι προβλήματα στο επίπεδο που είμαστε,

αλλά καλό να το έχουμε υπόψιν μας

Page 8: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

8

Μια συνήθης λύση#include <math.h>#include <stdbool.h>#include <stdio.h>

int main() { bool isFound = false; int a, b, c, d; for (int x = 1000; x <= 9999; x++) { a = 0; b = 0; c = 0; d = 0; int sum = pow(a, 4) + pow(b, 4) + pow(c, 4) + pow(d, 4); if (sum == x) { printf("Solution found %d\n", x); isFound = true; } }

if (isFound == false) { puts("No solutions found"); }}

Page 9: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

9

Ο λογικός τύπος bool // Old Ctypedef int bool;#define true 1#define false 0

// C99#include <stdbool.h>

Page 10: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

10

Μια συνήθης λύση (μικρά προβλήματα)

#include <math.h>#include <stdbool.h>#include <stdio.h>

int main() { bool isFound = false; int a, b, c, d; for (int x = 1000; x <= 9999; x++) { a = 0; b = 0; c = 0; d = 0; double sum = pow(a, 4) + pow(b, 4) + pow(c, 4) + pow(d, 4); if (sum == x) { printf("Solution found %d\n", x); isFound = true; } }

if (isFound == false) { puts("No solutions found"); }}

warning: conversion to ‘int’ from ‘double’ mayalter its value [-Wfloat-conversion]

Αυτά θέλουν σκέψη,ας το καθυστερήσουμε λιγάκι

Έτσι θα ξέρω και πως αυτό θα δουλέψει !

Page 11: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

11

Test Driven Development● Σπάω το πρόβλημα

σε μικρότερα και απλούστερα

● Βεβαιώνομε πως κάθε τι είναι σωστό

● Ο αλγόριθμος θα προκύψει

Page 12: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

12

Τα assertions● Το TDD του φτωχού● Μια συνθήκη που αν δεν είναι αληθής

– Σε Release mode δεν υπάρχουν● δεν θα κάνουν τίποτα, ούτε θα παραχθεί κώδικας

– Σε Debug mode● Θα σταματήσουν βίαια την εκτέλεση του προγράμματος● Με ένα Debugger θα δούμε την λάθος τιμή.

Page 13: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

13

Εισαγωγή στα assertions#include <assert.h>

int main() { int x = 4712; int a, b, c, d; a = 0; b = 0; c = 0; d = 0;

assert(a == 4); assert(b == 7); assert(c == 1); assert(d == 2);

puts("All assertions passed !");}

main: Assertion `a == 4' failed.

Ας το φτιάξουμε

Page 14: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

14

Εισαγωγή στα assertions#include <assert.h>

int main() { int x = 4712; int a, b, c, d; a = 4; b = 7; c = 1; d = 2;

assert(a == 4); assert(b == 7); assert(c == 1); assert(d == 2);

puts("All assertions passed !");}

Ας το φτιάξουμεστα αλήθεια

Page 15: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

15

Βήμα 2: Assertion pass● Ο κώδικας δουλεύει● Υπάρχει κάποια κρυμμένη δομή; ● Μπορεί να γίνει ποιο γενικός;

int x = 4712;

int d = x % 10;int a = x / 1000;

int b = (x / 100) % 10;int c = (x / 10) % 10;

assert(a == 4);assert(b == 7);assert(c == 1);assert(d == 2); int a = x / 1000; // 3

int b = (x / 100) % 10; // 2 int c = (x / 10) % 10; // 1int d = x % 10; // 0

Page 16: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

16

Αναζητώντας ένα γενικό τύπο● Ο κώδικας δουλεύει● Υπάρχει κάποια κρυμμένη δομή; ● Μπορεί να γίνει ποιο γενικός;

int a = x / 1000; // 3int b = (x / 100) % 10; // 2 int c = (x / 10) % 10; // 1int d = x % 10; // 0

// 1st passint a = (x / 1000) % 10; // 3int b = (x / 100) % 10; // 2 int c = (x / 10) % 10; // 1int d = (x / 1) % 10; // 0

// 2nd passint a = (x / 10^3) % 10; // 3int b = (x / 10^2) % 10; // 2 int c = (x / 10^1) % 10; // 1int d = (x / 10^0) % 10; // 0

Page 17: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

17

Βήμα 3 : Refactoringint ipow(int num, int to) { double result = pow(num, to); return (int)result;}

int main() { int x = 4712;

int a = (x / ipow(10, 3)) % 10; // 3 int b = (x / ipow(10, 2)) % 10; // 2 int c = (x / ipow(10, 1)) % 10; // 1 int d = (x / ipow(10, 0)) % 10; // 0

assert(a == 4); assert(b == 7); assert(c == 1); assert(d == 2);

int sum = ipow(a, 4) + ipow(b, 4) + ipow(c, 4) + ipow(d, 4); assert(sum == pow(4, 4) + pow(7, 4) + pow(1, 4) + pow(2, 4)); // 2674

puts("All assertions passed !");}

Page 18: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

18

Βήμα 3.1 : Refactoring with forint ipow(int num, int to) { double result = pow(num, to); return (int)result;}

int main() { int x = 4712; int digits = 4;

int sum = 0; for(int i=0; i< digits; i++) { int digit = (x / ipow(10, i)) % 10; sum = sum + ipow(digit,4); }

assert(sum == pow(4, 4) + pow(7, 4) + pow(1, 4) + pow(2, 4)); // 2674 puts("All assertions passed !");}

Page 19: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

19

Βήμα 3.2 : Refactoring no doublesint ipow(int num, int to) { int result = 1; for (int i = 0; i < to; i++) result *= num; return result;}

int main() { int x = 4712; int digits = 4;

int sum = 0; for(int i=0; i< digits; i++) { int digit = (x / ipow(10, i)) % 10; sum += ipow(digit,4); }

assert(sum == pow(4, 4) + pow(7, 4) + pow(1, 4) + pow(2, 4)); // 2674 puts("All assertions passed !");}

Page 20: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

20

Βήμα 3.3int ipow(int num, int to) { int result = 1; for (int i = 0; i < to; i++) result *= num; return result;}

int main() { int x = 4712; int digits = 4;

int sum = 0; for(int i=0; i< digits; i++) { int digit = (x / ipow(10, i)) % 10; sum += ipow(digit,4); }

assert(sum == pow(4, 4) + pow(7, 4) + pow(1, 4) + pow(2, 4)); // 2674 puts("All assertions passed !");}

Χωρίςαυτό;

Page 21: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

21

Βήμα 3.3 : Refactoring do..whileint main() { int x = 4712;

...

int sum2 = 0; int num = x; do { int digit = num % 10; sum2 = sum2 + ipow(digit, 4); num = num / 10; } while ( num != 0 );

assert(sum2==sum);

...}

ΟΚ

Page 22: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

22

Βήμα 3.4 int main() { int x = 4712;

...

int sum2 = 0; int num = x; do { int digit = num % 10; sum2 = sum2 + ipow(digit, 4); num = num / 10; } while ( num != 0 );

assert(sum2==sum);

...}

Συνάρτηση;

Page 23: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

23

Βήμα 3.4 : Refactoring to functionsint ipow(int num, int to);int calculateSquare4(int num);

int calculateSquare4(int num) { int sum = 0; do { int digit = num % 10; sum += ipow(digit, 4); num = num / 10; } while ( num != 0 ); return sum;}

int main() { int x = 4712; int sum = calculateSquare4(x);

assert(sum == pow(4, 4) + pow(7, 4) + pow(1, 4) + pow(2, 4)); // 2674 puts("All assertions passed !");}

Page 24: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

24

Βήμα 3.5 : Βελτιστοποιώντας την ipow

● Εφόσον τα πάντα είναι στην θέση τους μπορώ να κάνω με ασφάλεια μικρές πινελιές απόδοσης

int ipow4(int num);

int ipow4(int num) { int temp = num * num; return temp *temp;}

Page 25: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

25

Το τελικό πρόγραμμαint main() { bool isFound = false;

for (int x = 1000; x <= 9999; x++) { int sum = calculateSquare4(x); if (sum == x) { printf("A solution found %d\n", x); isFound = true; } }

if (isFound == false) { puts("No solutions found"); }}

Page 26: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

26

Συμπεράσματα● Καταλήξαμε (σχεδόν αυτόματα!) σε ένα κομψό αλγόριθμο● Εύκολα κατανοητός και με ευκολία αλλαγής

– Τα assertions μας προστάτευαν από τα λάθη μας– Πόσο εύκολα αλλάζει αν κάναμε λάθος στο “,” της εκφώνησης;

● Ποιο γενικός κώδικας– Δουλεύει με αριθμούς οποιουδήποτε μεγέθους.– Δεν χρησιμοποιεί αριθμούς κινητής υποδιαστολής

Page 27: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

27

Μικροβελτιστοποιήσεις● Μια μοντέρνα CPU είναι πολύπλοκη.● Δεν είναι όλες οι πράξεις ίδιες.● Δεν είναι όλες οι προσβάσεις στην μνήμη ίδιες● Η κλίμακα είναι λογαριθμική● Η πρόσβαση στην μνήμη συχνά ποιο σημαντική

από τον αλγόριθμο● Μια απλή αλλαγή μπορεί να αλλάξει την ταχύτητα

Χ100 φορές.● Μόνο με μετρήσεις μπορούμε να ξτο

τεκμηριώσουμε,● Δεν θα ασχοληθούμε με αυτό περαιτέρω

Page 28: Εισαγωγή στο TDD Test Driven Development · project(Ergasia1 C) add_compile_options(-Wall -Wextra -Wconversion -Wpedantic) add_executable(ex1 ex1.c) add_executable(ex4

28

Ήταν δύσκολο;

“Πονάει πάντα η πρώτη φορά”Γιάννης Αγγελάκας, Τρύπες