Software Engineering II Refactoring, Style, Software Metriken

Ähnliche Dokumente
SE2-6. Übung Johannes Bürdek

Software-Refactoring. 29. Mai 2013

4. Vererbung Die Klasse Object. Die Klasse Object

Software-Refactoring. 27. Mai 2015

Software Engineering. 13. Automatische Code Analyse. Franz-Josef Elmer, Universität Basel, WS 2005/06

Programmieren in Java

Info B VL 11: Innere Klassen/Collections

Software-Metriken. Dipl.-Ing.(BA) Henning Sievert Seminar Software-Entwurf WS 2004/05

Kapitel 3 Software Quality III

Die Klasse java.lang.object. Thorsten Treffer

Javakurs FSS Lehrstuhl Stuckenschmidt. Tag 3 - Objektorientierung

Einstieg in die Informatik mit Java

Graphalgorithmen. Graphen

3. Übungsbesprechung Programmkonstruktion

Refactoring. Uschi Beck

Werkzeuggestützte Softwareprüfungen Statische Analyse und Metriken

Softwaremetriken verstehen und nutzen

Einführung in die Programmierung I. 2.0 Einfache Java Programme. Thomas R. Gross. Department Informatik ETH Zürich

Programmiermethodik 3. Klausur Lösung

Programmieren 2 Java Überblick

Qualitätsmanagement im Projekt

Javakurs zu Informatik I. Henning Heitkötter

Einstieg in die Informatik mit Java

Refactoring von Legacy Systemen. Jochen Winzen andrena objects ag

JAVA BASICS. 2. Primitive Datentypen. 1. Warum Java? a) Boolean (logische Werte wahr & falsch)

Codequalitätskontrolle mit SonarQube

Javakurs 2013 Objektorientierung

Javadoc. Programmiermethodik. Eva Zangerle Universität Innsbruck

Algorithmen und Datenstrukturen

Übergang von funktionaler zu OOP. Algorithmen und Datenstrukturen II 1

Erzeugungsmuster. Kapselung der Objekt-Erzeugung

Software Entwicklung 1

Anweisungen zur Ablaufsteuerung

Programmieren I. Kapitel 8. Vererbung

Softwaremetriken verstehen und nutzen

12 Abstrakte Klassen, finale Klassen und Interfaces

II.4.2 Abstrakte Klassen und Interfaces - 1 -

Objektorientierung II & die Java Klassenbibliothek. Kristian Bergmann und Arthur Lochstampfer

Objektorientierte Programmierung Studiengang Medieninformatik

Vererbung. Gerd Bohlender. Institut für Angewandte und Numerische Mathematik. Vorlesung: Einstieg in die Informatik mit Java 23.5.

Web-Anwendungen mit Arquillian testen

Konzepte der Programmiersprachen

Property Based Testing

Dynamische Datentypen. Destruktor, Copy-Konstruktor, Zuweisungsoperator, Dynamischer Datentyp, Vektoren

Vererbung, Polymorphie

Java Kurs für Anfänger Einheit 5 Methoden

AuD-Tafelübung T-B5b

Interfaces und Generics

Java-Schulung Grundlagen

Beispiele für Ausdrücke. Der imperative Kern. Der imperative Kern. Imperativer Kern - Kontrollstrukturen. Deklarationen mit Initialisierung

Objektorientierte Programmierung. Kapitel 22: Aufzählungstypen (Enumeration Types)

Programmieren I. Kapitel 5. Kontrollfluss

Institut für Programmierung und Reaktive Systeme. Java 6. Markus Reschke

Interface. So werden Interfaces gemacht

Informatik II Prüfungsvorbereitungskurs

Große Übung Praktische Informatik 1

! 1. Unterklassen und Vererbung! 2. Abstrakte Klassen und Interfaces! 3. Modularität und Pakete. II.4.2 Abstrakte Klassen und Interfaces - 1 -

Wie kann man es verhindern das Rad immer wieder erneut erfinden zu müssen?

Bean-Mapping mit MapStruct

Tag 4 Repetitorium Informatik (Java)

Einstieg in die Informatik mit Java

Theorie zu Übung 8 Implementierung in Java

Objektorientierung (OO)

7. Metriken. Idee von Maßsystemen Halstead live Variables Variablenspanne McCabe-Zahl LCOM*

Algorithmen und Datenstrukturen. Übersicht. Interfaces und Generics. InsertionSort für Punkte. InsertionSort für Punkte

ALP II Dynamische Datenmengen Datenabstraktion

Wie entwerfe ich ein Programm?

Arbeitsblätter für die Lehrveranstaltung OOP JAVA 1

JAVA BASICS. 2. Primitive Datentypen. 1. Warum Java? a) Boolean (logische Werte wahr & falsch)

Programmieren in Java

Refactoring. Programmiermethodik. Eva Zangerle Universität Innsbruck

II.4.4 Exceptions - 1 -

Girls Day 2017 Programmierung

Datenstrukturen / Container in Java

Schwerpunkte. 10. Felder (Arrays) Grundprinzip von Arrays. Klassifikation von Typen in Programmiersprachen

Softwaretechnik WS 16/17. Übungsblatt 01

Methoden und Wrapperklassen

Modularisierung in Java: Pakete Software Entwicklung 1

Softwaretechnik (Allgemeine Informatik) Überblick

Projekt AGB-10 Fremdprojektanalyse

Programmieren lernen mit Groovy Objektorientierung Typen

Algorithmen und Datenstrukturen

Probeklausur: Programmierung WS04/05

Java - Programmierung - Prozedurale Programmierung 1

Javakurs für Anfänger

Transkript:

Software Engineering II Refactoring, Style, Software Metriken Prof. Dr. Axel Böttcher 16. Dezember 2012

Wiederholung Technische Schulden geek & poke, http://geek-and-poke.com/2011/12/keynesian-based-coding.html (Creative Commons Attribution 3.0 Unported License)

Wiederholung Technische Schulden geek & poke, http://geek-and-poke.com/2011/12/keynesian-based-coding.html (Creative Commons Attribution 3.0 Unported License)

Wiederholung Technische Schulden geek & poke, http://geek-and-poke.com/2011/12/keynesian-based-coding.html (Creative Commons Attribution 3.0 Unported License)

Refactoring

Was ist hier faul?

Definition Refactoring ist ein Vorgang, der die Struktur von Software verändert, ohne das externe Verhalten (Funktion) zu ändern.

Definition Refactoring ist ein Vorgang, der die Struktur von Software verändert, ohne das externe Verhalten (Funktion) zu ändern. Mühevolle Detailarbeit (minimalinvasiv).

Definition Refactoring ist ein Vorgang, der die Struktur von Software verändert, ohne das externe Verhalten (Funktion) zu ändern. Mühevolle Detailarbeit (minimalinvasiv). Grundlage sind Unit Tests, mit denen kontinuierlich die Funkion überprüft werden kann.

Definition Refactoring ist ein Vorgang, der die Struktur von Software verändert, ohne das externe Verhalten (Funktion) zu ändern. Mühevolle Detailarbeit (minimalinvasiv). Grundlage sind Unit Tests, mit denen kontinuierlich die Funkion überprüft werden kann. Ausgangspunkt sind üble Gerüche (smells), für die eine gewisse Sensibilität erforderlich ist.

Definition Refactoring ist ein Vorgang, der die Struktur von Software verändert, ohne das externe Verhalten (Funktion) zu ändern. Mühevolle Detailarbeit (minimalinvasiv). Grundlage sind Unit Tests, mit denen kontinuierlich die Funkion überprüft werden kann. Ausgangspunkt sind üble Gerüche (smells), für die eine gewisse Sensibilität erforderlich ist. Es gibt Standard-Techniken, die teilweise von IDEs unterstützt werden. Eine gute Übersicht steht unter http://www.refactoring.com/catalog

Extremfall Wie refaktorisiert man solche Software:

Ausgabe

Code Smells Eine Übersicht Code-Duplizierung Lange Methode Große Klasse Klasse zu umfangreich Faule Klasse Klasse leistet zu wenig Lange Parameterliste mehr Parameter übergeben als nötig Nichtssagender Name Kommentare Wo notwendig, ist häufig der Code schlecht... Eine umfangreiche Liste weiterer Smells: http://www.codinghorror.com/blog/2006/05/code-smells.html

Duplicated Code Der absolute Klassiker! Abhilfe: Methode extrahieren Klasse extrahieren Methode nach oben (d.h. in Basisklasse) verschieben Template-Methode bilden

Duplicated Code: Extract Method

Schlechte, nichtssagende Namen Abhilfe: Umbenennen (Rename) Gute Namen sind sehr wichtig Mit fortschreitender Arbeit ändern sich Namen und werden angepasst Umbenennung kann gut automatisiert werden; ist ein syntax-sensitiver Vorgang Automatisierung klappt auch Klassenübergreifend

Kommentare geek & poke, http://geek-and-poke.com/2012/04/sometimes-its-that-simple.html (Creative Commons Attribution 3.0 Unported License)

Kommentare geek & poke, http://geek-and-poke.com/2012/04/sometimes-its-that-simple.html (Creative Commons Attribution 3.0 Unported License)

Kommentare geek & poke, http://geek-and-poke.com/2012/04/sometimes-its-that-simple.html (Creative Commons Attribution 3.0 Unported License)

Code Smells Kommentare (I) 1 private int a = 0; // a wird mit 0 i n i t i a l i s i e r t Der Kommentar beschreibt exakt, was auch im Code steht Es benötigt mehr Zeit, den Kommentar zu lesen als den Code Redundanter Kommentar entfernt 1 private int a = 0;

Code Smells Kommentare (II) 1 private int i ; // Enthaelt den Fehlercode Hier erklärt der Kommentar die Bedeutung der Variablen i Doppelter Code Smell: Nichtssagender Name + unötiger Kommentar Aussagekräftige Variable verwendet 1 private int errorcode ;

Beispiel Beispiel aus java.lang. Integer. tostring (): 1 // I use the i n v a r i a n t d i v i s i o n by m u l t i p l i c a t i o n t r i c k to 2 // a c c e l e rate Integer. tostring. In p a r t i c u l a r we want to 3 // avoid d i v i s i o n by 10. 4 // 5 // The t r i c k has roughly the same performance c h a r a c t e r i s t i 6 // as the c l a s s i c Integer. tostring code on a non JIT VM. 7 // The t r i c k avoids. rem and. div c a l l s but has a longer code 8 // path and i s thus dominated by dispatch overhead. In the 9 // JIT case the dispatch overhead doesn t e x i s t and the 10 // t r i c k i s considerably f a s t e r than the c l a s s i c code. 11 // 12 // TODO FIXME : convert ( x 52429) into the equiv s h ift add 13 // sequence. 14 // 15 // RE: Division by I n varia nt Integers using M u l t i p l i c a t i o n 16 // T Gralund, P Montgomery 17 // ACM PLDI 1994 18 //

Lange Methode Nachteile langer Methoden: lassen sich schwer testen erledigen häufig verschiedene Dinge es lassen sich schwer spezialisierte Subklassen bilden sind potenzielle Quellen für Fehler, da wenig transparent

Code Smell Lange Methode 1 (I) 1 public void debit ( fl o at amount ) { 2 // deduct amount from balance 3 balance = amount ; 4 5 // record transaction 6 transactions. add (new Transaction ( true, amount ) ) ; 7 8 // update l a s t debit date 9 Calendar calendar = Calendar. getinstance ( ) ; 10 11 lastdebitdate = calendar. get ( Calendar.DATE) + / + 12 calendar. get ( Calendar.MONTH) + / + 13 calendar. get ( Calendar.YEAR ) ; 14 } Extract Method dreifach 1 Code smell of the week, http://www.youtube.com/watch?v=u4hipntxwyc

Code Smell Lange Methode (II) 1 public void debit ( fl o at amount ) { 2 deductamountfrombalance ( amount ) ; 3 recordtransaction (amount, true ) ; 4 updatelastdebitdate ( ) ; 5 } 6 7 private void deductamountfrombalance ( f loat amount ) { 8 balance = amount ; 9 } 10 11 private void recordtransaction ( f loat amount, boolean isdebit ) { 12 transactions. add (new Transaction ( isdebit, amount ) ) ; 13 } 14 15 private void updatelastdebitdate () { 16 Calendar calendar = Calendar. getinstance ( ) ; 17 18 lastdebitdate = calendar. get ( Calendar.DATE) + / + 19 calendar. get ( Calendar.MONTH) + / + 20 calendar. get ( Calendar.YEAR ) ; 21 }

Magic Numbers 1 mins = t o t a l /60; 2 secs = t o t a l 60 mins ; 3 4 hours = mins /60; 5 mins = mins 60 hours ; 6 7 days = hours /24; 8 hours = hours 24 days ; Abhilfe: durch static final Konstante ersetzen (Extract constant):

Änderungen am API Änderungen an öffentlichen Methoden eines API sind dann gefährlich, wenn bereits Kunden dieses API verwenden. Besser: deprecaten.

Änderungen am API Änderungen an öffentlichen Methoden eines API sind dann gefährlich, wenn bereits Kunden dieses API verwenden. Besser: deprecaten. Ansonsten: Kein Problem ein API zu verbessern.

Weitere Smells Smell: Datenklassen (mangelnde Kapselung) Feld Kapseln: Public Felder mit Getter und setter kapseln (diese können beispielsweis ein Eclipse eutomatisch erzeugt werden)

Siehe http://worsethanfailure.com 1 public int hightemp ( int Temp1, i nt Temp2, int Temp3, int Temp4, 2 i nt Temp5) { 3 int HighTemp = 0; 4 i f ((Temp1 >= Temp2) && (Temp1 >= Temp3) && (Temp1 >= Temp4) && (Temp1 >= Temp5)) 5 HighTemp = Temp1; 6 else i f ((Temp2 >= Temp1) && (Temp2 >= Temp3) && (Temp2 >= Temp4) && (Temp2 >= Temp5 7 HighTemp = Temp2; 8 else i f ((Temp3 >= Temp1) && (Temp3 >= Temp2) && (Temp3 >= Temp4) && (Temp3 >= Temp5 9 HighTemp = Temp3; 10 else i f ((Temp4 >= Temp1) && (Temp4 >= Temp3) && (Temp4 >= Temp2) && (Temp4 >= Temp5 11 HighTemp = Temp4; 12 else i f ((Temp5 >= Temp1) && (Temp5 >= Temp3) && (Temp5 >= Temp4) && (Temp5 >= Temp2 13 HighTemp = Temp5; 14 return HighTemp ; 15 }

Frage Welcher der folgenden Begriffe beschreibt keinen Code Smell? 1. Code-Duplizierung 2. Rename 3. Lange Methode 4. Magic Number

Smell Detection: Programmierstil Code Guarding Wartbarkeit

Wartbarkeit ist ein nicht-funktionales Qualitätsmerkmal der Software(-Architektur). Dieser Abschnitt beschäftigt sich damit, welche Hilfsmittel es gibt, Smells automatisiert zu entdecken Smells schon beim Entwickeln zu vermeiden verstehbaren Code zu schreiben wartbaren Code zu schreiben

Stil-Richtlinien Stell dir vor es gibt Programmierrichtlinien und keiner hält sich dran. Viele Firmen nutzen interne Richtlinien für den Programmierstil. Bekanntester (wahrscheinlich) Style Guide:

Vorteile Vermindert die Fehleranfälligkeit. Verbessert die Lesbarkeit. Erleichtert das Verständnis fremden Codes. Beispiel: Was stimmt an folgendem C-Programm nicht? void calc(int *i, int*j) { *i = *i/*j; }

IDE-Integration Es gibt Eclipse-Plugins, um den Programmierstil zu überprüfen, z.b.: (Checkstyle) Das Tool ist weitgehend konfigurierbar:

Fehlermuster Neben Entwurfsmustern (Design Patterns) gibt es typische Fehlermuster (Bug Patterns). Echtes Beispiel aus dem Eclipse Code der Verion 3.0 (siehe findbugs.sf.net): 1 i f ( in == null ) 2 try { 3 in. close ( ) ; 4 } Alleine das Verständnis der Bug Patterns bringt großen Erkenntnisgewinn. Teilweise nahe Verwandtschaft zwischen Bug Patterns und Style Rules.

Fehlerkategorien Korrektheit auch im Hinblick auf Multithreading. Z.B. String- oder Objektvergleich durch == und!=. Angreifbarkeit durch Schadprogramme. Z.B. durch Rückgabe von Referenzen auf interne Arrays. Effizienz und Design.

Weitere Beispiele if(name!= null name.length > 0) log(x.y()); if(x == null) throw new XyzException("x is null"); public Object execute(handler h, Node n){ return execute(h, n); }

boolean equals(object o){ Frame f = (Frame)o; return f.getx() == this.x; } C d; if(d instanceof D)...

if ( (str.charat(i)>57 str.charat(i)<48) &&!(str.charat(i)==. ) )

Eclipse Findbugs Plugin Integriert sich nahtlos in den Mechanismus zum Anzeigen von Fehlern: Je entdecktem potenziellem Bug wird eine Warnung angezeigt:

Software Metriken

Software Metriken warum und wozu Wer misst, misst Mist Grundsätzliche Schwierigkeit, die Komplexität eines Stück Programms durch eine Zahl (oder mehrere Zahlen) zu messen. Das klassische Maß ist Lines of Code (LOC); dieses ist allerdings wenig aussagekräftig.

Cyclomatic Complexity, kurz CC Thomas McCabe, 1976 Sprach- und formatunabhängiges Ist ein Maß für die voneinander unabhängigen Pfade durch ein Programmmodul. Ausgangspunkt: Der Kontrollfluss eines Programms kann durch einen gerichteten Graphen dargestellt werden. Zur Erinnerung: Ein gerichteter Graph besteht aus Knoten (node) und gerichteten Kanten (edge, arc). dabei: Cyclomatic complexity (CC) = E N + 2 E: Anzahl der Kanten des Graphen N: Anzahl der Knoten des Graphen

Beispiel für CC=2 1 public Singleton getinstance (){ 2 i f ( theinstance == null ) 3 theinstance = new Singleton ( ) ; 4 return theinstance ; 5 }

Beispiel für CC=4 1 public void execcommand( int cmd){ 2 switch (cmd) 3 { 4 case 0: sendcommand (LEFTREV) ; break ; 5 case 1: sendcommand (LEFTSTOP) ; break ; 6 c a se 2: sendcommand (LEFTFWD) ; break ; 7 default : sendcommand (EMERGENCYSTOP) ; br 8 } 9 return ; 10 }

Programme mit niedriger zyklomatischer Komplexität sind leichter zu lesen, zu warten und zu testen. Studien belegen einen Zusammenhang zwischen zyklomatischer Komplexität und der Fehleranfälligkeit von Code.: Cyclomatic Complexity Risiko 1-10 einfaches Programm, kaum Risiko 11-20 etwas komplexer, moderates Risiko 21-50 komplexes Programm mit hohem Risiko > 50 nicht mehr testbar: Sehr hohes Risiko

Tools zur Bestimmung der CC

Stabilität Abstractness (Generality) A eines Pakets p: A = Anzahl abstrakter Klassen im Paket Gesamtzahl Klassen im Paket Wertebereich 0 (vollständig konkretes Paket) bis 1 (vollständig abstraktes Paket).

Stabilität Abstractness (Generality) A eines Pakets p: A = Anzahl abstrakter Klassen im Paket Gesamtzahl Klassen im Paket Wertebereich 0 (vollständig konkretes Paket) bis 1 (vollständig abstraktes Paket). Afferent Couplings C a eines Pakets p: Die Anzahl an Paketen außerhalb des Pakets p, die von Klassen innerhalb des Pakets abhängen (Vererbung, Assoziation). Efferent Couplings C e eines Pakets p: Die Anzahl an Klassen außerhalb des Pakets, von denen Klassen innerhalb des Pakets p abhängen.

Stabilität Abstractness (Generality) A eines Pakets p: A = Anzahl abstrakter Klassen im Paket Gesamtzahl Klassen im Paket Wertebereich 0 (vollständig konkretes Paket) bis 1 (vollständig abstraktes Paket). Afferent Couplings C a eines Pakets p: Die Anzahl an Paketen außerhalb des Pakets p, die von Klassen innerhalb des Pakets abhängen (Vererbung, Assoziation). Efferent Couplings C e eines Pakets p: Die Anzahl an Klassen außerhalb des Pakets, von denen Klassen innerhalb des Pakets p abhängen. Instability I: I = C a + C e Wertebereich 0... 1. Paket mit I = 0 ist maximal stabil und mit I = 1 maximal unstabil. C e

) > I J H =? J A I I 1 I J = > E E J O K J I A H * A H A E? D 0 = K F J E E A I? D A H D = B J A H * A H A E? D

Frage Folgende Informationen liegen Ihnen zur Stabilität Ihres Codes vor: C e = 3, C a = 0, Ihr Paket besteht aus 100 Klassen, davon 30 abstrakt. Welcher Punkt im Diagramm beschreibt am besten die Stabilität Ihres Codes?

Frage Folgender Kontrollfluss eines Programms ist gegeben. Wie hoch ist das Risiko für die Fehleranfälligkeit des Codes? 1. Kaum Risiko 2. Moderates Risiko 3. Hohes Risiko 4. Sehr hohes Risiko