Software Engineering 13. Automatische Code Analyse Franz-Josef Elmer, Universität Basel, WS 2005/06 Software Engineering: 13. Automatische Code Analyse 2 Code Analyse: Manuell versus Automatisch – Manuelle Code Analyse = Code Review ● ● Unterstützung durch ein Tool (z.B. IDE) möglich. Vorteile: – – ● Nachteile: – – – Der Mensch kann Probleme besser erkennen als ein automatische Analyse. Flexibler in der Fokusierung auf das Wesentliche. Der Mensch übersieht leicht Probleme. Langsam und grosser Aufwand. Automatische Code Analyse: ● ● ● ● Software Tools analysieren den (Quell)-Code, erzeugen Reports und verschicken eventuell E-Mails. Online: Interaktive z.B. intergriert in IDE Offline: Automatisch angeworfene Analyse (z.B. jede Nacht). Vorteile: – – ● Schnell. Die ganze Code-Basis kann analysiert werden. Nachteile: – – Universität Basel, WS 2005/06 Problemerkennung sehr schwierig. Erkennt Probleme, die keine sind. © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 3 Arten der automatischen Analyse – Code Metriken: ● Berechnung von Masszahlen, die (vielleicht) etwas über die Qualität des Codes aussagen. – ● Verschiedene Typen von Metriken: – – – ● Prozedurale Metriken Objektorientierte Metriken etc Report: – – – IEEE 1061: A function whose inputs are software data and whose output is a single numerical value that can be interpreted as the degree to which software possesses a given attribute that affects its quality. Tabelle: Jede Zeile enthält alle gemessenen Metriken für eine Einheit des Codes. Granularität: Einheiten sind Module, Pakete, Klassen, Methoden, Funktionen etc. Überprüfung des Codes (engl. auditing): ● ● ● Aufspüren von Verstössen gegen Regeln. Kombiniert mit Code Metriken: Masszahl über- bzw. unterschreitet einen kritischen Wert. Report: Liste der Verstösse. Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 4 Einsatz automatischer Code Analysen – Für die einzelnen Entwickler: ● ● – Für den Chefentwickler oder das Entwicklerteam: ● ● – Web Site mit den Reports. Integriert in IDE: Sofortige Warnung bei Regelverstössen. Übersicht Schnelles Auffinden von potentiellen Problemfeldern im Code. Für QA und Management: ● ● Status der aktuellen Codequalität im Projekt. – Aber: Ergebnis muss korrekt interpretiert werden. Teil einer Analyse durch unabhängiger Gutachter. Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 5 Code Metriken – Problem: Geeigneten Algorithmus finden, der es erlaubt aus dem (Quell-)Code eine Zahl zu berechnen, die die Qualität des Codes misst. – Beispiel: ● ● Lines of Code (LOC): Zahl der Zeilen in Quellcode minus Zahl der Leerzeilen und Zeilen, die nur Kommentar enthalten. Fokus: Gesamtprojekt: – – ● Keine Qualitätsaussage möglich. Schätzung bzw. Validierung des Aufwands für Coding bzw. Testing. ● Voraussetzung: Erfahrung mit demselben Team, derselben Entwicklungsmethodologie und derselben Technologie. Fokus: Klasse, Methode: – – Universität Basel, WS 2005/06 Hinweis auf Bad Smells „grosse Klasse“ und „lange Methode“. Code Review ● der längsten Klassen und Methoden oder ● aller Klassen und Methoden für die LOC einen kritischen Wert überschreitet. © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 6 Prozedurale Metriken – – LOC: Lines of Code NCSS: Non-Commenting Source Statements: ● ● ● Zahl der Statements die keine Kommentare sind. Im Gegensatz zu LOC unabhängig von der Formatierung des Quellcodes. Beispiel: LOC: 7, NCSS: 4 LOC: 9, NCSS: 4 /** Removes and returns the element * on the top of the stack. * @throws IllegalStateException * if the stack is empty. */ public Object pop() { if (isEmpty()) { throw new IllegalStateException( "Empty stack."); } return _stack.remove(_stack.size()­1); } /** Removes and returns the element * on the top of the stack. * @throws IllegalStateException */ public Object pop() { if (isEmpty()) { throw new IllegalStateException( "Empty stack."); } return _stack.remove(_stack.size()­1); } ● Refactoring: Extract Method, Extract Class Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 7 Cyclomatic Complexity Number – CCN: McCabe's Cyclomatic Complexity Number: ● ● ● Versuch, die prozedurale Komplexität einer Prozedur/Funktion/Methode zu messen. CCN = Zahl der Verzweigungen in Kontrollfluss Java: Jedes der folgenden Statements erhöht CCN um 1: – – – – – ● ● if for while case catch Variante: CCN =Zahl der Verzweigungen + Zahl der Exit-Points Java: Jedes der folgendes Statements erhöht CCN auch um 1: – – Universität Basel, WS 2005/06 return (auch implizites return beim Verlassen einer void Methode) throw © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 8 Cyclomatic Complexity Number: Beispiele – CCN Variante in allen Beispielen LOC: 3, NCSS: 2, CCN: 1 void printHelloWorld() { System.out.println("hello world"); } ←1: implizites return LOC: 15, NCSS: 19, CCN: 7 LOC: 7, NCSS: 5, CCN: 2 void printHello(String name) { if (name == null) { 1→ System.out.println("hello"); } else { System.out.println("hello " + name); } } ←2: implizites return String[] getOperators(int[] codes) { String[] operators = new String[codes.length]; 1→ for (int i = 0; i < codes.length; i++) { switch (codes[i]) { case ADD: operators[i] = "add"; break; 2→ case SUB: operators[i] = "sub"; break; 3→ case MUL: operators[i] = "mul"; break; 4→ case DIV: operators[i] = "div"; break; 5→ default: throw new IllegalArgumentException( 6→ "unkown code: " + codes[i]); } } 7→ return operators; } Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 9 Cyclomatic Complexity Number – Keine Aussage über Verständlichkeit des Codes ● Zwei Beispiele beide CCN = 9 String getOperator(int code) { switch (code) { case ADD: return "add"; case SUB: return "sub"; case MUL: return "mul"; case DIV: return "div"; default: throw new IllegalArgumentException( "unkown code: " + code); } } ● ● Regel: Auf alle Methoden mit CCN ≥ 10 sollte man einen Blick darauf werfen. Refactoring: Extract Method Universität Basel, WS 2005/06 void execute(String text) { if (text == null) { throw new IllegalArgumentException( "Missing text"); } StringTokenizer tokenizer = new StringTokenizer(text); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); if (token.equals(BAQ)) { int n = _borders.length; for (int i = 0; i < n; i++) { _borders[i].increment(); } } else if (token.equals(ZOP)) { if (_zone != null) { _zone.reset(); } else { _list.clear(); } } else if (_zone.isActive()) { _list.add(token); } } } © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 10 Objektorientierte Metriken – – – Problem: Es ist schwierig geeignete Metriken zu den bekannten Design Prinzipien zu finden. Konsequenz: Es gibt eine grosse Zahl von verschiedenen Metriken für objektorientierte Programme. Am bekanntesten: Chidamber-Kemerer (CK) Metriken für Klassen: ● WMC: Weighted Methods per Class ● LCOM: Lack of Cohesion in Methods ● DIT: Depth of Inheritance Tree ● NOC: Number of Children ● CBO: Coupling between Object Classes ● RFC: Response for a Class Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 11 Weighted Methods per Class (WMC) – – Definition: Die Summe der CCN aller Methoden (inkl. Konstruktoren) oder Zahl der Methoden. Interpretation: ● ● Grosse WMC lassen auf applikationsspezifische Klasse mit geringen Wiederverwendungspotential schliessen. Je grösser WMC einer Klasse desto grösser die Abhängigkeit ihrer Unterklassen von ihr. Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 12 Lack of Cohesion in Methods (LCOM) – Definition: LCOM = max(0, P-Q) mit P ist die Zahl der Methodenpaare, die auf kein gemeinsames Attribute zugreifen, und Q die Zahl der Paare, die auf mindestens ein gemeinsames Attribute zugreifen. – Beispiel: class ABC { int a; int b; int c; int sum() { return a + b; } int diff() { return a ­ b; } int square() { return c * c; } } Universität Basel, WS 2005/06 Paare sum:diff sum:square diff:square Gemeinsame Attribute a, b keine keine P = 2, Q = 1 ⇒ LCOM = 1 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 13 LCOM: Kritik – Lack of Cohesion möglich trotz LCOM = 0. – Beispiel: class AB { int a; int b; int a() { return a; } int b() { return b; } int bb() { return b * b; } int bbb() { return b * b * b; } } Universität Basel, WS 2005/06 Paare a:b a:bb a:bbb b:bb b:bbb bb:bbb Gemeinsame Attribute keine keine keine b b b P = 3, Q = 3 ⇒ LCOM = 0 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 14 LCOM: Definition nach Li und Henry – – LCOM = Zahl von disjunkten Mengen von Methoden, die wie folgt definiert sind: Je zwei Methoden einer solchen Menge greifen auf gemeinsames Attribute zu. Beispiel: class AB { int a; int b; int a() { return a; } int b() { return b; } int bb() { return b * b; } int bbb() { return b * b * b; } } Universität Basel, WS 2005/06 M1 = {a}, M2 = {b, bb, bb} ⇒ LCOM = 2 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 15 LCOM: Kritik – LCOM > 0 trotzdem kein Lack of Cohesion: ● ● Idirekter Attributenzugriff durch Aufruf von Methoden derselben Klasse. Beispiel: class AB { int a; int b; int a() { return a; } int b() { return b * a(); } } – Koppelt b() an a() LCOM ≫ 1 trotzdem kein Problem: Data Transfer Objects enthalten typischerweise nur Setters und Getters. ● n Attribute: LCOM (nach CK): n⋅(2n-3), für n > 1 LCOM (nach Li & Henry): n Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 16 Depth of Inheritance Tree (DIT) – – Definition: Maximale Länge des Vererbungspfads einer Klasse. Beispiele: DIT:2 – Object DIT:0 Number DIT:1 Integer Float A DIT:1 DIT:2 DIT:2 DIT:0 B C DIT:0 D Interpretation: Je kleiner DIT desto besser (Prinzip Komposition vor Vererbung). Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 17 Number Of Children (NOC) – – Definition: Zahl der direkten Unterklassen. Beispiel: DIT:0 A DIT:1 NOC:0 B NOC:2 C DIT:1 NOC:1 DIT:2 NOC:2 D DIT:3 NOC:0 – E F DIT:3 NOC:0 Interpretation: Je grösser NOC desto wichtiger ist die Klasse und desto mehr sollte man darauf achten, dass das Liskovsche Substitutionsprinzip eingehalten wird. Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 18 Coupling between Object Classes (CBO) – Definition: Zahl der Klassen von denen die Klasse direkt abhängt. Mögliche Abhängigkeiten sind: ● ● ● – Vererbung und Interface Implementation Typen der Attribute, Parameter, lokalen Variablen, und Rückgabewerte. Klassen, deren Konstruktoren/Methoden/Attribute benutzt werden. Beispiel: 3: Dummy 4: Integer – CBO: 6 1: SampleClass 2: MyInterface class MyClass extends SampleClass implements MyInterface { Dummy dummy; 5: Number Integer getNumberOfCharacters(Number number) { return new Integer(number.toString().length()); } 6:String } Interpretation: Je grösser CBO desto wahrscheinlicher wird das Prinzip der schwachen Kopplung verletzt. ● Erlaubte Ausnahme: Alle Klassen gehören zum selben Modul/Paket (Prinzip der maximalen Kohäsion) Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 19 Response for a Class (RFC) – Definition: Anzahl Klassenmethoden + Zahl der verschiedenen direkt aufgerufenen Methoden in anderen Klassen. – Beispiel: RFC: 10 public class Stack { 1 private final List _stack = new ArrayList(); 2: default constructor public void push(Object element) { 3 _stack.add(element); 4 } public boolean isEmpty() { 5 return _stack.isEmpty(); } 6 public Object pop() { 7 if (isEmpty()) { throw new IllegalStateException("Empty stack."); } 8 return _stack.remove(_stack.size() ­ 1); } 9 10 } – Interpretation: Analog zu CBO: Je grösser desto wahrscheinlicher die Verletzung des Prinzips der schwachen Kopplung. Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 20 Open Source Tools für Code Metriken – CCCC: ● ● ● – JavaNCSS: ● ● ● – Tool in C geschrieben analysiert C, C++, Java Quellcode. Reports in XML und HTML Metriken: LOC, CCN, WMC, DIT, NOC, CBO und andere http://cccc.sourceforge.net Tool in Java geschrieben analysiert Java Quellcode. Reports als Text, XML oder HTML. Metriken: NCSS, CCN, WMC und andere http://www.kclee.de/clemens/java/javancss/ ckjm: ● ● ● Tool in Java geschrieben analysiert Java Quellcode. Reports als Text. Metriken: WMC, LCOM, DIT, NOC, CBO, RFC und andere http://www.spinellis.gr/sw/ckjm/ Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 21 Classycle – Open Source Tool Suite zur Analyse der Abhängigkeiten zwischen Java Klassen und Paketen: ● ● – In Java geschrieben analysiert kompilierte Java Klassen. http://classycle.sourceforge.net Analyser: ● ● ● Analyse der Klassen/Paket Abhängigkeiten. Reports in XML und HTML. Reports enthalten (unter anderem): – – – Tabelle aller Klassen/Pakete: ● Grösse ● Zahl der Klassen/Pakete die dieses benutzen ● Zahl der Klassen/Pakete die von diesem benutzt werden (=CBO) Tabelle aller Zyklen (strong components) DependencyChecker: ● ● ● Findet unerwünschte direkte und indirekte Abhängigkeiten zwischen Klassen. Überprüft Schichtarchitektur. Regelbasiert Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 22 Classycle: Gerichteter Abhängigkeitsgraph – Classycle ermittelt die Anhängigkeiten durch die Analyse des sogenannten Constant Pools der .class Dateien. – Classycle baut einen gerichteten Graphen (engl. digraph): ● Knoten: Klassen/Pakete ● Kanten: Klasse/Paket X hängt von Y ab: X→Y B interne Klasse A externe Klasse D C E Universität Basel, WS 2005/06 F G © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 23 Classycle: Zyklen = strong components – Definition: ● ● – Strongly connected: Von jedem Knoten in der strong component gibt es einen Pfad zu jedem anderen Knoten der strong component. Vollständigkeit: Das Hinzufügen einer oder mehrerer Konten zerstört obige Eigenschaft. Ein gerichtete Graph kann zu einem azyklischen gerichteten Graphen seiner strong components kondensiert werden c a b Layer d 3 A B C D E F G Kondensation H d Universität Basel, WS 2005/06 I strong component a 2 b 1 c 0 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 24 Classycle: Eigenschaften von Zyklen – Classycle ermittelt für jede strong component: ● ● ● ● ● ● – Exzentrizität: ● ● – Zahl der Knoten. Beste Fragmentgrösse: Minimum der maximalen Fragmentgrösse Radius: Minimum der Exzentrizität Durchmesser: Maximum der Exzentrizität Girth: Länge des kürzesten Zyklus Layer Index Eigenschaft eines Knoten in einem gerichteten Graphen. Definition: – Finde die kürzesten Pfade zu jedem anderen Knoten. – Exzentrizität = Maximum der Länge aller kürzesten Pfade Beispiel: A B C Universität Basel, WS 2005/06 Von A A B B C C Nach Kürzester Pfad B 1 2 C 1 A C 1 A 1 B 2 Knoten Exzentrizität A 2 B 1 C 2 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 25 Classycle: Maximale Fragmentgrösse – Maximale Fragmentgrösse ist die Eigenschaft eines Knotens einer strong component: ● Definition: – – – – Entferne den Knoten Mache eine strong component Analyse des Rest Maximale Fragmentgrösse ist das Maximum über Zahl der Knoten der strong components (Fragmente) aus dieser Analyse. Beispiel: 5 A 5 2 B 2 C E D 4 F 5 beste Fragmentierer Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 26 Classycle: Refactoring von Zyklen – Klassenzyklen: Kriterium: Zyklus > 10 ● Häufigstes Refactoring: Extract Interface implementiert Interface A ⇒ Typen Referenzen – I A Interface Paketzyklen: Kriterium: Keine Paketzyklen zulassen. ● Mögliche Refactorings: – – – ● Verschieben von Klassen in andere Pakete Einführung eines neuen Pakets Zusammenlegung eines Pakets Bei paketübergreifendem Klassenzyklus: Eventuell erst Klassenzyklus zerlegen. Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 27 Classycle: Dependency Checker – Überprüfung ob definierte Subgraphen voneinander direkt oder indirekt unabhängig sind. [set1] direkte Abhängigkeit [set2] indirekte Abhängigkeit – Regeln (festgelegt in dependency definition files): check [set1] directlyIndependentOf [set2] check [set1] independetOf [set2] Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 28 Classycle: Dependency Checker – Überprüfung von Schichtarchitekturen: Layer C – erlaubte direkte Abhängigkeit [set5] Layer B [set3] [set4] Layer A [set1] [set2] verbotene direkte Abhängigkeit bei strikter Schichtung Regeln: layer A = [set1] [set2] layer B = [set3] [set4] layer C = [set4] check layeringOf A B C check strictLayeringOf A B C Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005 Software Engineering: 13. Automatische Code Analyse 29 Open Source Auditing Tools für Java FindBugs http://findbugs.sourceforge.net PMD mit CPD (Copy-Paste Detector) http://pmd.sourceforge.net Universität Basel, WS 2005/06 © Franz­Josef Elmer 2005