Die verschiedenen Programmierparadigmen von C++ © Helmke Clicker-“Abstimmung“ Kennen Sie testbasierte Software-Entwicklung/test-first? 1. Häh??? 2. Habe ich schon mal gehört, aber im Moment nicht präsent. 3. Ja und lassen Sie mich kurz denken, dann erkläre ich es der gesamten Vorlesung 4. Ja, das machen wir in unserer Gruppe schon seit Jahren 5. Ja bin ich mit vertraut, aber ich sehe die Vorteile nicht. WS 2015/16 V 4.01; © Hon. Prof. Helmke 1 Die verschiedenen Programmierparadigmen von C++ © Helmke Clicker-“Abstimmung“ Sagt, Ihnen „Think, Red-Bar, Green-Bar, Refactor“ im Sinne von testbasierter Softwareentwicklung etwas? 1. Häh??? 2. Habe ich schon mal gehört, aber im Moment nicht präsent. 3. Ja und lassen Sie mich kurz denken, dann erkläre ich es der gesamten Vorlesung WS 2015/16 V 4.01; © Hon. Prof. Helmke 2 Die verschiedenen Programmierparadigmen von C++ © Helmke Lernziele • • WS 2015/16 Was bedeutet „Test first“? Was bedeuten „Think, Red Bar, Green Bar, Think“? V 4.01; © Hon. Prof. Helmke 3 Die verschiedenen Programmierparadigmen von C++ © Helmke Testbasierte Software-Entwicklung Think Red Bar Green Bar Refactor WS 2015/16 V 4.01; © Hon. Prof. Helmke 4 Die verschiedenen Programmierparadigmen von C++ © Helmke Beispiel bzw. Wiederholung: Funktion, die auf Primzahl testet Think Red Bar Green Bar Aufgabe: Implementierung einer Funktion „istPrim“, die ermittelt, ob das Argument eine Primzahl ist oder nicht. bool istPrim(int zahl); Refactor /** 2 und 3 sind Primzahlen, 4 nicht. Bei den größeren Zahlen gilt: Zahlen, die durch 2 und 3 teilbar sind, sind keine Primzahlen. */ bool istPrim(int zahl); WS 2015/16 V 4.01; © Hon. Prof. Helmke 5 Die verschiedenen Programmierparadigmen von C++ © Helmke Red Bar: Einfacher Testfall /** istPrim wird für 2 und 3 aufgerufen, true wird jeweils erwartet istPrim wird für 4 aufgerufen, false wird erwartet */ bool testPrim234() { bool testPrim234(); bool result = true; result = (true == istPrim(2)) && result; result = (true == istPrim(3)) && result; result = (false == istPrim(4)) && result; bool istPrim(int zahl){ return result; return false; } } WS 2015/16 V 4.01; © Hon. Prof. Helmke 6 Die verschiedenen Programmierparadigmen von C++ © Helmke Red Bar: Hauptprogramm int main() { Noch scheitert der Test. if (true== testPrim234 ()) { cout << "Alle Tests erfolgreich.\n"; } else { cout << "Tests gescheitert.\n"; } } WS 2015/16 V 4.01; © Hon. Prof. Helmke 7 Die verschiedenen Programmierparadigmen von C++ © Helmke Green Bar: bool istPrim(int zahl){ if (2== zahl) {return true;} if (3== zahl) {return true;} Tests laufen nun return false; (green bar). } WS 2015/16 V 4.01; © Hon. Prof. Helmke 8 Die verschiedenen Programmierparadigmen von C++ © Helmke Hauptprogramm: Komplexerer Fall int main() { Noch scheitert der Test. if ((true== testPrim234 ()) && (true== testPrim56Etc ()) { { cout << "Alle Tests erfolgreich.\n"; } else { cout << "Tests gescheitert.\n"; } } WS 2015/16 V 4.01; © Hon. Prof. Helmke 9 Die verschiedenen Programmierparadigmen von C++ © Helmke Red Bar: Testfälle 5 bis 10 /** istPrim wird für 5 bis 10 aufgerufen, true, false, true, false, false, false wird erwartet */ bool testPrim56Etc(); bool testPrim56Etc() { bool result = true; result = (true == istPrim(5)) && result; result = (false == istPrim(6)) && result; result = (true == istPrim(7)) && result; result = (false == istPrim(8)) && result; bool istPrim(int zahl){ result = (false == istPrim(9)) && result; if (2== zahl) {return true;} result = (false == istPrim(10)) && result; if (3== zahl) {return true;} return result; return false; } } WS 2015/16 V 4.01; © Hon. Prof. Helmke 10 Die verschiedenen Programmierparadigmen von C++ © Helmke Green Bar:? /** Teile zahl durch alle Zahlen 2, 3, 5, 7, 9, 11, ... bis Wurzel(zahl). Wenn eine davon Teiler von Zahl ist, dann ist zahl keine Primzahl, sonst Rückgabe true \param[in] zahl \return true, wenn zahl Primzahl Notizen: */ • 3 mit for-Schleife zusammenfassen bool istPrim(int zahl){ if (2== zahl) {return true;} • für -1, 0, 1 prüfen if (3== zahl) {return true;} • für große Zahlen auch Tests bauen if (0== (zahl%2)) {return false;} int wurzel = static_cast<int>( sqrt(static_cast<double>(zahl))); for (int i=3; i < wurzel; i=i+2) { if ( 0== (zahl%i)) { return false; } Tests scheitern noch beim Wert 9! }// for i return true; } WS 2015/16 V 4.01; © Hon. Prof. Helmke 11 Die verschiedenen Programmierparadigmen von C++ © Helmke Green Bar: /** Teile zahl durch alle Zahlen 2, 3, 5, 7, 9, 11, ... bis Wurzel(zahl). Wenn eine davon Teiler von Zahl ist, dann ist zahl keine Primzahl, sonst Rückgabe true \param[in] zahl \return true, wenn zahl Primzahl */ Tests laufen nun bool istPrim(int zahl){ (green bar). if (2== zahl) {return true;} if (3== zahl) {return true;} if (0== (zahl%2)) {return false;} int ende = 1 + static_cast<int>( sqrt(static_cast<double>(zahl))); for (int i=3; i < ende; i=i+2) { if ( 0== (zahl%i)) { return false; Notizen: } • 3 mit for-Schleife zusammenfassen }// for i • für -1, 0, 1 prüfen return true; • für große Zahlen auch Tests bauen } WS 2015/16 V 4.01; © Hon. Prof. Helmke 12 Die verschiedenen Programmierparadigmen von C++ © Helmke Refactoring: 3 mit for-Schleife zusammenfassen /** Teile zahl durch alle Zahlen 2, 3, 5, 7, 9, 11, ... bis Wurzel(zahl). Wenn eine davon Teiler von Zahl ist, dann ist zahl keine Primzahl, sonst Rückgabe true \param[in] zahl \return true, wenn zahl Primzahl */ bool istPrim(int zahl){ if (2== zahl) {return true;} if (0== (zahl%2)) {return false;} int ende = 1 + static_cast<int>( sqrt(static_cast<double>(zahl))); for (int i=3; i < ende; i=i+2) { if ( 0== (zahl%i)) { return false; } Notizen: }// for i • für -1, 0, 1 prüfen return true; • für große Zahlen auch Tests bauen } WS 2015/16 V 4.01; © Hon. Prof. Helmke 13 Die verschiedenen Programmierparadigmen von C++ © Helmke Red Bar: Testfälle Zahlen bis einschließlich 1 /* Es wird für -2, -1, 0, 1 auf prim geprüft.*/ bool testPrimLess2() { bool result = true; result = (false == istPrim(-2)) && result; result = (false == istPrim(-1)) && result; result = (false == istPrim(0)) && result; result = (false == istPrim(1)) && result; return result; bool istPrim(int zahl){ } if (2== zahl) {return true;} if (0== (zahl%2)) {return false;} int ende = 1 + static_cast<int>(sqrt(static_cast<double>(zahl))); for (int i=5; i < wurzel; i=i+2) { if ( 0== (zahl%i)) { return false; } }// for i return true; } WS 2015/16 V 4.01; © Hon. Prof. Helmke 14 Die verschiedenen Programmierparadigmen von C++ © Helmke Green Bar: bool istPrim(int zahl){ if (zahl < 2) {return false;} if (2== zahl) {return true;} if (0== (zahl%2)) {return false;} int ende = 1 + static_cast<int>(sqrt(static_cast<double>(zahl))); for (int i=3; i < ende; i=i+2) { if ( 0== (zahl%i)) { return false; Tests laufen nun } (green bar). }// for i return true; } Notizen: •für große Zahlen prüfen WS 2015/16 V 4.01; © Hon. Prof. Helmke 15 Die verschiedenen Programmierparadigmen von C++ © Helmke Hauptprogramm: Komplexerer Fall int main() { if ( (true== testPrim234 ()) && (true== testPrim56Etc ()) && (true== testPrimLess2 ()) && (true== testPrimBig ()) ){ cout << "Alle Tests erfolgreich.\n"; } else { cout << "Tests gescheitert.\n"; } } WS 2015/16 V 4.01; © Hon. Prof. Helmke 16 Die verschiedenen Programmierparadigmen von C++ © Helmke Noch ein Test: Test für ausgewählte große Zahlen /* Es wird für 961, 8191, 10011001 auf prim geprüft.*/ bool testPrimBig() { bool result = true; result = (false == istPrim(961)) && result; result = (true == istPrim(8191)) && result; result = (false == istPrim(1001001)) && result; return result; } bool istPrim(int zahl){ if (zahl < 2) {return false;} if (2== zahl) {return true;} if (0== (zahl%2)) {return false;} int ende = 1 + static_cast<int>(sqrt(static_cast<double>(zahl))); for (int i=3; i < ende; i=i+2) { if ( 0== (zahl%i)) { return false; } }// for i return true; } WS 2015/16 V 4.01; © Hon. Prof. Helmke 17 Die verschiedenen Programmierparadigmen von C++ © Helmke Noch ein Beispiel: Funktion „istPalindrom“ WS 2015/16 V 4.01; © Hon. Prof. Helmke 18 Die verschiedenen Programmierparadigmen von C++ © Helmke Testbasierte Software-Entwicklung Think Red Bar Green Bar Refactor WS 2015/16 V 4.01; © Hon. Prof. Helmke 19 Die verschiedenen Programmierparadigmen von C++ © Helmke Refactoring Von Refactoring spricht man allgemein, wenn man Änderungen am Code vornimmt, ohne seine Funktionalität zu verändern. Refactoring dient somit lediglich dazu, Code übersichtlicher, wartungsfreundlicher und damit weniger fehleranfällig zu machen. Refactoring wird aber meist einer Erweiterung der Funktionalität vorgeschaltet.Es gibt neben der Aufspaltung einer großen Funktion in kleinere Funktionen weitere Refactoring-Techniken. Wir werden im Folgenden noch einige kennen lernen. Details können aber dem Lehrbuch von Fowler zum Refactoring entnommen werden. Martin Fowler: Refactoring -- Improving the Design of Existing Code, Addison Wesley, 2002 WS 2015/16 V 4.01; © Hon. Prof. Helmke 20 Die verschiedenen Programmierparadigmen von C++ © Helmke Refactoring und Erweiterung von Programmen „Never change a running system“ gilt nicht. Wir haben automatisch ablaufende Tests. Wir dokumentieren eine neue Funktionalität zuerst. Dann schreiben wir noch einen Test für die neue Funktionalität oder auch mehrere. Anschließend implementieren wir die Funktionalität. Wir führen die Tests aus --- und hoffen --- !!! Nein, es ist ein systematisches Vorgehen, was zwar auch nicht fehlerfrei ist, aber ziemlich sicher die Fehler aufdeckt. WS 2015/16 V 4.01; © Hon. Prof. Helmke 21 Die verschiedenen Programmierparadigmen von C++ © Helmke Beispiel Getränkemarkt Sie geben im Getränkemarkt Ihre leeren Flaschen in Kisten ab. Implementieren Sie eine Funktion BerechnePfand, die Ihnen ermittelt, wie viel Pfand Sie für B abgegebene Bierflaschen und S abgegebene Saftflaschen erhalten. Für eine Bierflasche gibt es 8 Cent Pfand und für eine Saftflasche 15 Cent. Bedenken Sie, dass jeweils 6 Saftflaschen bzw. 24 Bierflaschen in einen Kasten passen und Sie für jeden abgegebenen Kasten dann auch zusätzlich zum Flaschenpfand 1 Euro 50 Cent erhalten. Gehen Sie bei der Lösung der Aufgabe in den Schritten vor • Konkretisierung des Problems • Entwicklung der Lösung • Implementierung von Test und Lösung • (Testen, Fehlersuche und Funktionserweiterung) WS 2015/16 V 4.01; © Hon. Prof. Helmke 23 Die verschiedenen Programmierparadigmen von C++ © Helmke Beispiel Bäcker Sie kaufen in der Bäckerei normale Brötchen und Vollkornbrötchen sowie die dazu erforderlichen Tüten. Implementieren Sie eine BerechnePreis, die Ihnen ermittelt, wie viel Sie für N normale Brötchen und V Vollkornbrötchen bezahlen. 10 Brötchen passen jeweils (maximal) in eine Tüte. Ein normales Brötchen kostet 25 Cent, ein Vollkornbrötchen kostet 50 Cent. Die Tüte kostet jeweils 5 Cent. Wie viel müssen Sie somit insgesamt bezahlen? Gehen Sie bei der Lösung der Aufgabe in den Schritten vor • Konkretisierung des Problems • Entwicklung der Lösung • Implementierung von Test und Lösung • (Testen, Fehlersuche und Funktionserweiterung) WS 2015/16 V 4.01; © Hon. Prof. Helmke 29