Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger [email protected].

24
Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger [email protected]

Transcript of Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger [email protected].

Page 1: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Seminar aus Softwareentwicklung: Programmierstile

Christian [email protected]

Page 2: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Übersicht

• Einführung und Beispiele von Softwarefehler

• Was bedeutet „Defensives Programmieren“

• Design by Contract

• Erfolgreiches Verwalten von Resourcen

• Self-Describing Data

• Die Kunst des Testens

Robustheit, Christian Zeilinger ([email protected]) Folie 2/23

Page 3: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Einführung

Es gibt keine perfekte Software!! !

Leider Tatsache:

Also, was tun?

Sich damit abfinden, oder gar verzweifeln?

Robustheit, Christian Zeilinger ([email protected]) Folie 3/23

Page 4: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Robustheit, Christian Zeilinger ([email protected]) Folie 4/23

Die schlimmsten Softwarefehler

• 1985: Software-Fehler in einem Röntgenapparat

• 1996: Explosion der Ariane 5 am 4. Juni

• 1999: Verglühen eines Mars Climate Orbiters

• Rechtzeitig gefundener Fehler: F-16

T+36: Fehler im Inertial Reference System

Hauptcomputer weist Triebwerke an, eine große Korrektur durchzuführen

Rakete bricht aufgrund aerodynamischer Kräfte auseinander (Selbstzerstörung)

SO NICHT!!!

Page 5: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Defensives Programmieren

Definition Robustheit: Fähigkeit von Softwaresystemen, auch unter außergewöhnlichen Bedingungen zu funktionieren

Defensiv zu programmieren bedeutet, die Programme in Hinblick auf Robustheit zu gestalten

Deshalb: Alle Annahme über Eingaben, Systemzustände usw. prüfen und bei Fehlern handeln (Assertions, Exceptions,…)

Zum Beispiel:„Die Variable x muss hier positiv sein“„Dieser Zeiger darf hier (eigentlich) nicht NULL sein“

Robustheit, Christian Zeilinger ([email protected]) Folie 5/23

Page 6: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Design by Contract

• Bedingungen, die gelten müssen, damit ein System funktionieren kann

• Beispiel im realen Leben: PaketzustelldienstBedingungen der Zustellfirma:

- maximale Größe und Gewicht des Paketes- Bezahlung der Dienstleistung im Voraus

Bedingungen von Seiten des Klienten:- Sorgfältiger Umgang mit der Fracht (keine Beschädigungen,…)- Ankunft des Gutes am gewünschten Zielort innerhalb einer gewissen Zeitspanne

Robustheit, Christian Zeilinger ([email protected]) Folie 6/23

Page 7: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Design by Contract

• PreconditionsBedingungen, die gelten müssen, damit eine Methode (Komponente) ausgeführt werden kann

• PostconditionsBedingungen, die nach dem Ausführen einer Methode gelten müssen (impliziert auch Resultate)

• InvariantenBedingungen, die aus Sicht des Rufers immer erfüllt sein müssen

Beispiele: Class-Invarianten, Loop-Invarianten

„Lazy Code“

Robustheit, Christian Zeilinger ([email protected]) Folie 7/23

Page 8: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Design by Contract/* class invariant: * count enspricht der Anzahl der gesetzten Integer-Werte array ist ein Feld von Werten * die gesetzt werden können, wobei jeder noch nicht gesetzter Wert -1 entspricht. */public class IntegerArray {

…………………public int Max { get { int max = -1;

/* Loop-Invariante: * Vor jedem Durchlauf gilt: max = max(array[0:i-1]) (auch nach dem Ende der Schleife)*/for(int i=0; i < array.Length; i++) if(array[i] > max) max = array[i];return max;

} }public int this[int index] {

get { return array[index]; }// Precondition: 0 <= index < sizeset {

array[index] = value; /* Nach der Ausführung dieser Anweisung ist die Klasseninvariante * verletzt, da count ungleich der der Anzahl der gesetzten Werte*/

count++; //Erst jetzt gilt die Klasseninvariante wieder}// Postcondition: Wert gesetzt

}……………………

}

Robustheit, Christian Zeilinger ([email protected]) Folie 8/23

Page 9: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Design by Contract

Überprüfung der Kontrakte

• Mit Hilfe von ToolsTool für Java: iContract (im Kommentar: @pre, @post, @invariant)

• AssertionenMethodenaufruf mit Übergabe der Bedingung - Beispiel: assert(x > 0);

Bedingung erfüllt: okay

Bedingung verletzt: Fehler -> Programmabbruch

• ExceptionsSprachliche Unterstützung, um mit einfachen Mitteln:

- dem Rufer einen Ausnahmefall mitzuteilen (throw)- ein (kollektives) Errorhandling zu bewerkstelligen (try …… catch)

Robustheit, Christian Zeilinger ([email protected]) Folie 9/23

Page 10: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Design by Contract

using System.Diagnostics.Debug;

public class IntegerArray {…………………public int this[int index] {

get { Debug.Assert(index >0 && index < array.Length); //Prüfung der Preconditionreturn array[index];

}

set {Debug.Assert(index >0 && index < array.Length); //Prüfung der Preconditionarray[index] = value;count++;

}}

public IntegerArray(int size) {Debug.Assert(size > 0); //Prüfung der Preconditionarray = new int[size]; for(int i=0; i<size; i++) array[i] = -1;

}}

Assertions

Robustheit, Christian Zeilinger ([email protected]) Folie 10/23

Page 11: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Design by ContractExceptions

#include <stdio.h> //without Exceptionsint main() {

int xMin, xMax, yMin, yMax, error = 0;FILE *file = fopen("file.cfg", "rb");if (f != NULL) {

error = 1; } else if(xMin = fgetc(file) == EOF) {

error = 1; } else if(xMax = fgetc(file) == EOF) {

error = 1; } else if(yMin = fgetc(file) == EOF) {

error = 1; } else if(yMax = fgetc(file) == EOF) {

error = 1; return -1;

}if (error == 0) {

printf("%d,%d,%d,%d",xMin,xMax,yMin,yMax);

} else printf("Error reading file.cfg");fclose(file);

}

using System; //using Exceptions using System.IO;class Test {

static void Main() {int xMin, xMax, yMin, yMax;try {

FileStream str = new FileStream("file.cfg",

FileMode.Open);xMin = str.ReadByte();xMax = str.ReadByte();yMin = str.ReadByte();yMax = str.ReadByte();Console.WriteLine("{0},{1},{2},{3}",

xMin,xMax,yMin,yMax);} catch(IOException) {

Console.WriteLine("Error reading file.cfg");} finally {

//Code der in jedem Fall ausgeführt wirdstr.Close();

}}

}Robustheit, Christian Zeilinger ([email protected]) Folie 11/23

Page 12: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Resource-Balancing

• Hauptspeicher, Threads, Dateien, Timer,… sind limitiertVerhaltensmuster: allocate – use – deallocate

using System.IO;class Budget {

FileStream fileStr = null;void ReadBudget(string fileName, out int budget) {

fileStr = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite);budget = (new BinaryReader(fileStr)).ReadInt32();

}void WriteBudget(int budget) {

fileStr.Seek(0, SeekOrigin.Begin);(new BinaryWriter(fileStr)).Write(budget);fileStr.Close();

}public virtual int Update(string fileName, int newBudget) {

int oldBudget;ReadBudget(fileName, out oldBudget); //Altes auslesenWriteBudget(newBudget); //Neues schreibenreturn newBudget;

} }

class NewBudget : Budget {public override int Update(string fileName, int newBudget)

{int oldBudget;ReadBudget(fileName, out oldBudget);if (newBudget > 0) {

//nur mit positiven neuem Budget überschreiben!WriteBudget(newBudget);return newBudget;

}return oldBudget;

}}

Robustheit, Christian Zeilinger ([email protected]) Folie 12/23

Page 13: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Resource-Balancing

Finish What You Start! using System.IO;class Budget {

protected void ReadBudget(FileStream fileStr, out int budget) {budget = (new BinaryReader(fileStr)).ReadInt32();

}protected void WriteBudget(FileStream fileStr, int budget) {

fileStr.Seek(0, SeekOrigin.Begin);(new BinaryWriter(fileStr)).Write(budget);

}public virtual int Update(string fileName, int newBudget) {

int budget;FileStream fileStr = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite);ReadBudget(fileStr, out budget); //Altes Budget auslesenif (newBudget > 0) {

WriteBudget(fileStr, newBudget); //eventuell mit neuem Budget überschreibenbudget = newBudget;

}fileStr.Close();return budget;

} }

Robustheit, Christian Zeilinger ([email protected]) Folie 13/23

Page 14: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Kundendaten:

Hans Maier, 03/04/1976, 02/07/2001, 01/12/2002, 20

Christoph Huber, 01/02/1979, 01/01/2000, 11/02/2002, 10

Hannes Dorfer, 09/09/1958, 01/01/2000, 01/01/2002, 5

Self-Describing Data

Problem: Mysteriöse Daten!

Linux-Verzeichnisausgabe mittels „dir“:

total 44-rw-r--r--   1 pr17     pr          4810 Dec  4 14:37 ETRC-rw-r--r--   1 pr17     pr          4810 Dec  4 14:36 ETRC.BAKdrwxr-xr-x   2 root     root         512 Oct 24  2001 TT_DB-rw-r--r--   1 pr17     pr             0 Dec  4 17:02 out.txtdrwxr-xr-x   3 pr17     pr           512 Dec  4 14:19 rounddrwxr-xr-x   2 pr17     pr           512 Nov  7 15:12 testdrwxr-xr-x   2 pr17     pr           512 Dec  4 14:25 traces1drwxr-xr-x   2 pr17     pr           512 Dec  4 14:29 traces2drwxr-xr-x   2 pr17     pr           512 Dec  4 14:33 traces3drwxr-xr-x   2 pr17     pr           512 Nov 12 17:35 ueb13drwxr-xr-x   2 pr17     pr           512 Nov 20 16:51 ueb24drwxr-xr-x   2 pr17     pr           512 Dec  3 15:35 ueb32drwxr-xr-x   2 pr17     pr           512 Dec  3 17:43 ueb33drwxr-xr-x   2 pr17     pr           512 Dec  4 12:30 ueb42drwxr-xr-x   3 pr17     pr           512 Dec  4 12:17 ueb43

Linux-Prozessübersicht mittels: ps –ef | grep pr17

pr17 26763     1  0 17:00:58 ?        0:00 /system/apps/gup/bin/lamd -H 140.78.91.1 -P 59246 -n 0 -o 0pr17 26809 26739  0 17:04:16 pts/2    0:00 -tcshpr17 26802 26801  0 17:03:19 ?        0:00 /usr/local/bin/tcsh -c sftp-serverpr17 26739 26737  0 17:00:48 pts/2    0:00 -tcshpr17 26804 26802  0 17:03:19 ?        0:00 sftp-server ???

Robustheit, Christian Zeilinger ([email protected]) Folie 14/23

Page 15: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Self-Describing Data

• Name-Value Pairs: Daten + SchemaBeispiel: Kundendaten

%name „Hans Maier“

%birthday „03/04/1976“

%firstTransaction „02/07/2001“

%discountStartDate „01/12/2002“

%discountPercent 20

%name „Christoph Huber“

………

Speichereffizienz?

Robustheit, Christian Zeilinger ([email protected]) Folie 15/23

Page 16: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Self-Describing Data

• Komprimierte Speicherung von Name-Value PairsBeispiel: Kundendaten

naHans Maier|bi03/04/1976|ft02/07/2001|ds01/12/2002|di20

naChristoph Huber| .........

Zusatzinformationen in einem Data Dictionary:ABBREVIATION NAME UNIT

na name text

bi birthday date

ft firstTransaction date

ds discountStartDate date

di discount percent

• Herkunft der Daten und Geschichte von VeränderungenWer? Wann? Wieso?

Robustheit, Christian Zeilinger ([email protected]) Folie 16/23

Page 17: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Self-Describing Data

• Name-Value Pairs in der ProgrammierungBsp.: AddProduct(1001, „C# and .NET Reference“, 5, 29.90, 20, 10);

Was bedeuten die einzelnen Werte?

• Programmierdisziplin (Kommentare):AddProduct( 1001, //Produktnummer

„C# and .NET Reference“, //Bezeichnung

5, //Stückzahl

29.90, //Verkaufspreis netto

20, //Mehrwertsteuer (in %)

10); //maximaler Rabatt

• Sprachliche UnterstützungAddProduct(pNr = 1001, name = „C# and .NET Reference“, count = 5, price = 29.90,

MWSt = 20, discount = 10);

Robustheit, Christian Zeilinger ([email protected]) Folie 17/23

Page 18: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Die Kunst des Testens

• Fehler gefunden -> Test war erfolgreich

• Ging alles gut -> Erfolgloser Test

Testen bedeutet: Ein Programm mit der Absicht auszuführen,

Fehler zu finden!

Testen kann NICHT zeigen, dass ein Programm fehlerfrei ist.

Robustheit, Christian Zeilinger ([email protected]) Folie 18/23

Page 19: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Die Kunst des Testens

• Testen im Software-Lebenszyklus– Test der Spezifikation

– Modultest

– Integrationstest

– Systemtest

– Abnahmetest

• Systematisch Testen– inkrementelles Testen

– beginnend mit den einfachen und grundlegenden Teilen

– Welchen Output erwartet man sich?

– Vergleich verschiedener Implementierungen

– Coverage?

Teste während der Codeerstellung

Robustheit, Christian Zeilinger ([email protected]) Folie 19/23

Page 20: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Die Kunst des Testens

White-Box-Testing

vs.

Black-Box-Testing

?

?

Robustheit, Christian Zeilinger ([email protected]) Folie 20/23

Page 21: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Die Kunst des Testens• Abklären, was getestet werden soll

z.B.: Methode: String ToUpperCase(String str, int startIndex, boolean unicode);

• Wahl geeigneter Inputs– Äquivalenzklassen

str: null, im ASCII-Code, im Unicode; unicode: true, falsestartIndex < 0, 0 <= startIndex < N, startIndex >=N

– RandbereichestartIndex: -1, 0, 1, N-2, N-1, N; str: null, 1-Zeichen, 2-Z., N-

Zeichen

– Reduktion der Testeingaben„unmögliche“ Kombinationen: str.length == 0 und unicode == truenur für einen Parameter eine ungültige Äquivalenzklasse wählen

• Festlegen der erwarteten Ausgabe• Durchführen des Test• Vergleich der Ausgabe mit der erwarteten

Robustheit, Christian Zeilinger ([email protected]) Folie 21/23

Page 22: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Die Kunst des Testens

• Testautomation– Code-Review

– Erzeugung von Eingabewerten• Generische Daten• Intelligente Daten

– Stress-Tests

– Regressionstesten

• Testabbruch– wenn bestimmte Anzahl von Fehlern entdeckt wurde

• 1 Fehler / 10-25 Anweisungen• Es bleiben immer Restfehler!!!

– wenn bei gleichmäßiger Testanstrengung die Fehlerentdeckungsrate deutlich abnimmt

Robustheit, Christian Zeilinger ([email protected]) Folie 22/23

Page 23: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.

Zusammenfassung

Robustheit, Christian Zeilinger ([email protected]) Folie 23/23

• Defensives Programmieren steigert die Robustheit von Softwareprodukten

• Design by Contract trifft Aussagen über notwendige Bedingungen zur Ausführung von Software

• Korrektes Resource-Balancing ist von hoher Notwendigkeit

• Selbstbeschreibende Daten helfen bei der Analyse und tragen zum allgemeinen Verständnis bei

• Ausreichende Tests sind der Schlüssel zu robusten Programmen

Page 24: Seminar aus Softwareentwicklung: Programmierstile Christian Zeilinger ch.zeilinger@gmx.at.