Date post: | 25-Jan-2015 |
Category: |
Technology |
Upload: | gfu-cyrus-ag |
View: | 3,120 times |
Download: | 0 times |
Java Code Quality
Regeln für gute Java-Programme
Treffpunkt Semicolon, 22.02.2011, GFU Cyrus AG
Jens Seekamp, GEDOPLAN GmbH
Java Code Quality – ein ganzheitlicher Ansatz
Agenda
Software-Qualität
Regel 1: System-Dekomposition und Build-ProzessRegel 1: System-Dekomposition und Build-Prozess
Regel 2: Schichten-Architektur
Regel 3: Modell-getriebene Entwicklung
Regel 4: inkrementelle Entwicklung
Regel 5: Richtlinien und statische Code-Analyse
Regel 6: integrierter, automatisierter Test
Regel 7: Refactoring und Regressionstest
2
Software-Qualität
Strukturierung (System, Komponente, Schicht, Paket, Klasse, Methode, Anweisung)
Einheitlichkeit (Generierung, Muster)
Richtlinien-Konformität (statische Programm-Analyse)
Verständlichkeit (Funktionalität / Logik der Software-Elemente)
Lesbarkeit (Bezeichner, Formatierung, ...)
Dokumentation, Kommentare (JavaDoc)
Korrektheit und Stabilität (funktionaler Programm-Test)
Leistungsfähigkeit (Performanz, Last), Benutzerfreundlichkeit
Wartbarkeit (Fehlerbehebung, Change Requests)
Erweiterbarkeit (neue Anforderungen)
3
Regel 1: System-Dekomposition und Build-Prozess
System-Dekomposition
Zerlegung des Software-Systems in Komponenten
eine Komponente kapselt einen Funktionsbereich (Schnittstelle vs. Rumpf)vs. Rumpf)
eine Komponente basiert oftmals auf einer Implementierungs-Technologie (z. B. EJB)
eine Komponente ist i. d. R. ausführbar
4
Architektur einer „kleinen“ Java-EE-Anwendung
Projekt PRAGSYS:Prüfsystem für Statistiken der GKV
5
Architektur einer „großen“ Java-EE-Anwendung
Projekt BDE:Betriebsdatenerfassung für Fertigungsindustrie
6
Regel 1: System-Dekomposition und Build-Prozess
Build-Prozess
„Bauen“ des Software-Systems aus seinen kompilierten Komponenten
dabei wird je Komponente ein Build-Artefakt erstelltdabei wird je Komponente ein Build-Artefakt erstellt
Werkzeuge für den Build-Prozess
Build-Prozess wird vollständig mit Maven 3.x durchgeführtJava-Compiler der IDE ist (theoretisch) überflüssig
Continuous Integration wird mit Hudson realisiert (z. B. NightlyBuild)
7
Maven-Multi-Projekt für Java-EE-Anwendung
<project>
<parent><groupId>de.gedoplan.bde</groupId><artifactId>bde</artifactId><version>1.0.0</version>
</parent>
<project>
<groupId>de.gedoplan.bde</groupId><artifactId>bde</artifactId><version>1.0.0</version>
<modules><module>bde-common</module><module>bde-comp-mitarbeiter</module><module >bde- comp- zeiterfassung </ module >
8
<artifactId>bde-comp-mitarbeiter</artifactId><packaging>ejb</packaging>
<module >bde- comp- zeiterfassung </ module ><module>bde-web</module><module>bde-ear</module>
</modules>
<project>
<parent> ...
<artifactId>bde-web</artifactId><packaging>war</packaging>
<project>
<parent> ...
<artifactId>bde-ear</artifactId><packaging>ear</packaging>
<dependencies>... <artifactId>bde-comp-mitarbeiter ...... <artifactId>bde-web ...
Regel 2: Schichten-Architektur
Zerlegung in 3-Schichten-Architektur
Präsentations-Schicht (GUI)
Fachlogik-Schicht (Geschäftsfälle, Dienste, Fachklassen)
Datenhaltungs-Schicht (Speicherung der Objekte, RDBMS)Datenhaltungs-Schicht (Speicherung der Objekte, RDBMS)
zusätzlich oftmals „übergreifende“ Schichten
fachliches Klassenmodell (Entitäten)
Basis-Dienste und –Klassen (z. B. Ausnahmen, Meldungen)
Schichten-Zerlegung ist möglich
auf Ebene des Software-Systems
auf Ebene der Komponenten
9
Schichten-Architektur einer Java-EE-Anwendung
10
Sicherstellung der Schichten-Architektur
häufige Verletzungen der Schichten-Architektur
„Überspringen“ einer Schicht (Präsentation � Datenhaltung)
„umgekehrte“ benutzt-Beziehung (Datenhaltung � Fachlogik)
falsche Zuordnung von Implementierungfalsche Zuordnung von ImplementierungRealisierung von fachlicher Logik in Dialogklassen
erkennbar in Benutzung von Fachklassen anstelle von Dienst-Schnittstelle
Sicherstellung durch Spezifikation von
erlaubten benutzt-Beziehungen
nicht erlaubten benutzt-Beziehungen
11
Sicherstellung mit Checkstyle-Modul „Import Control“
12
Regel 3: Modell-getriebene Entwicklung
aus einem „Modell“ generierter Java-Code ist
strukturiert
einheitlich
korrekt und stabilkorrekt und stabil
Code-Generierung steigert außerdem
die Effizienz der Software-Entwicklung
die Wartbarkeit des Software-Systems
13
„klassische“ Modell-getriebene Entwicklung
@Entitypublic class Land{
@Idprivate String isoCode;private String name;
public Land()
Generierung
des fachlichen Klassenmodells (Entitäten)
als POJO-Klassen mit JPA-
14
public Land(){}
public String getIsoCode(){ return this.isoCode; }
public void setIsoCode(String code){ this.isoCode = code; }
public String getName(){ return this.name; }
public void setName(String name){ this.name = name; }
}
als POJO-Klassen mit JPA-Annotationen
aus UML-Klassenmodell (z. B. Enterprise Architect)
Generierung von XML-Zugriffsklassen (1)
Generierung
für die Umwandlung Java-Objekte �� XML-Dokumente (Marshalling / Unmarshalling)
als POJO-Klassen mit JAXB-Annotationenals POJO-Klassen mit JAXB-Annotationen
aus XML-Schema (z. B. XMLSPY)mit dem JAXB-Schema-Compiler (Java Architecture for XML Binding)
15
Generierung von XML-Zugriffsklassen (2)
XJC
16
@XmlAccessorType(XmlAccessType.FIELD)@XmlType(name = "Satzart_Ctp", propOrder =
{"verfahren", "zeitraumAb", "zeitraumBis"})
public class Satzart implements Serializable{
@XmlElement(name = "Verfahren", required = true)private String verfahren;
public String getVerfahren(){ return verfahren; }
public void setVerfahren(String daten){ verfahren = daten; }
Generierung eines Formel-Parser
Generierung
eines Parser für arithmetisch-logische Formeln
aus einer kontextfreien Grammatik
mit dem Parser-Generator JavaCC (Java Compiler Compiler)mit dem Parser-Generator JavaCC (Java Compiler Compiler)
17
12 * x + 5 ...TOKEN: {| < PLUS: "+" >| < MINUS: "-" >}
void Addition():{ Token t = null;
StringBuilder sb = new StringBuilder();}{ Multiplikation()
( ( t = <PLUS> Multiplikation() ) { sb.append(t.ima ge); }| ( t = <MINUS> Multiplikation() ) { sb.append(t.im age); }
)*{ jjtThis.jjtSetValue(sb.toString()); }
}
5
+
*
x12
Regel 4: inkrementelle Entwicklung - Randbedingungen
18
package de.aoksystems.pragsys.service.pruefkern;
import de.aoksystems.pragsys.bo.statistik.Statistik;import de.aoksystems.pragsys.bo.pruefung.Pruefergebn is;
@Statelesspublic class PruefServiceBean implements PruefService{
/*** Diese Methode prüft eine Statistik, die an das Pr üfsystem* übergeben wurde, und liefert das Prüfergebnis zur ück.*/
public Pruefergebnis pruefeStatistik(Statistik s){...}
}
Regel 4: inkrementelle Entwicklung - Tipps
Implementierung: konkret beginnen und schrittweise verfeinern
erst „in die Tiefe“, später „in die Breite“ implementieren (Prototyping, depth-first)
möglichst frühe Rückkopplung
gleichzeitige Erstellung von Unit-Tests
Review durch Projekt-Kollegen
Demonstration für Benutzer
Grundsätze beachten (vgl. http://www.clean-code-developer.de)
immer objektorientiert und „sauber“
möglichst einfach (KISS), redundanzfrei (DRY), ...
„Software ist (fast) nie fertig.“ (evolutionäre Entwicklung, TODOs)
19
Regel 5: Richtlinien und statische Code-Analyse
ein Team von SW-Entwicklern ist heterogen (Berufs-/Projekterfahrung, Programmierstil)
für einheitlichen, lesbaren, kommentierten usw. Java-Code sind Entwicklungs-Richtlinien unabdingbar
Richtlinien-Katalog zusammengefasst im Entwickler-HandbuchRichtlinien-Katalog zusammengefasst im Entwickler-Handbuch
Beschreibung der Richtlinie (ggf. mit Motivation, Zielsetzung)
Positiv- und ggf. Negativ-Beispiele (Do‘s and Dont‘s)
Umfang des Programm-Code und Anzahl der Richtlinien erfordern automatisierte Überwachung
Werkzeuge für die statische Code-Analyse
z. B. Checkstyle, FindBugs, SonarJ
20
Regel 5: Richtlinien-Katalog (Beispiele)
Standard-Konventionen für Java der Firma Sun
deutsche Bezeichner für Klassen, Attribute, Methoden etc. verwenden
Konstanten bestehen nur aus Großbuchstaben, Ziffern und dem Konstanten bestehen nur aus Großbuchstaben, Ziffern und dem Unterstrich "_"
anstatt null ein Array der Länge 0 zurück geben
falls eine Exception geworfen wird, muss sie protokolliert werden
mehrmals benötigte Programmlogik wird in eine separate Methode bzw. Klasse ausgelagert
Reflection darf nicht verwendet werden
21
Regel 5: Werkzeuge für statische Code-Analyse
Idealfall: für jede Richtlinie gibt es eine aktivierte Analyse-Regel und umgekehrt
für „kleine“ Projekte sollte ein Code-Analyse-Werkzeug reichen
für „große“ Projekte und Vollständigkeit müssen ggf. mehrere Code-für „große“ Projekte und Vollständigkeit müssen ggf. mehrere Code-Analyse-Werkzeuge parallel eingesetzt werden
erhöhter Konfigurationsaufwand
Problem der Mehrfach-Meldung von Verletzungen
Standardisierung / Wiederverwendung des Richtlinien-Kataloges und der Werkzeug-Konfiguration (über Projekt- und Abteilungsgrenzen)
Werkzeuge machen Reviews durch Software-Architekten oder erfahrene Entwickler nicht überflüssig
22
Beispiel: Code-Bereinigung mittels Checkstyle / Review
(5) Import-Organisation, Formatierung
(4) Namenskonventionen, Bezeichner, for
(3) JavaDoc, Anweisungs-Struktur, Kommentare
(2) try - catch , Parameterprüfung
23
(2) try - catch , Parameterprüfung
(1) Ausnahmebehandlung, Logging
� „Nice“
Regel 6: integrierter, automatisierter Test
Software-Test hat zwei Zielsetzungen
im Java-Code möglichst viele Fehler aufdecken
Korrektheit der Anwendung demonstrieren
Test ist integraler Bestandteil der Software-Entwicklung, und nicht Test ist integraler Bestandteil der Software-Entwicklung, und nicht nur nachgelagert (vgl. testgetriebene Entwicklung, test-first)
Test dient zum Nachweis der dynamischen, funktionalen Korrektheit des Java-Code (dies ist mit statischer Code-Analyse nicht möglich)
Fokus liegt auf der Realisierung von automatisierten Tests
dafür Einsatz von Java-Test-Frameworks und –Werkzeugen
24
Regel 6: Test-Konzeption für Java-(EE)-Anwendungen
Schritt 1: Entwicklertest für wichtige Klassen und Methoden„Standard“-Framework JUnit 4.x
Schritt 2: Realisierung einer Testdaten-VerwaltungNutzung dedizierter Test-Datenbank(en)
explizite Testdaten-Erzeugung mittels Java (DBUnit, XMLUnit)
Schritt 3: Integrationstest der Service-Schichtper JUnit-Testclient gegen den Application-Server (remote)
mittels z. B. OpenEJB innerhalb der IDE (embedded)
Schritt 4: „automatisierter Abnahmetest“ der GUI-ClientsWerkzeug abhängig von GUI-Technologie und –Bibliothek
z. B. QF-Test (alle), Selenium (Web), Abbot (Swing)
Schritt 5: Test nicht-funktionaler Anforderungen (Performanz, Last)
25
Regel 6: Bibliothek der automatisierten Testfälle
Zusammenfassung aller automatisierten Testfälle aus Schritt 1 bis 5 zu einer Test-Bibliothek
� als Test-Suites gemäß JUnit(JUnit-Integration aller Werkzeuge /
26
(JUnit-Integration aller Werkzeuge / Frameworks vorausgesetzt)
� hierarchische Strukturierung der Test-Suites
� gesamte Test-Bibliothek auf Entwicklungsrechner lokal ausführbar
Regel 7: Refactoring und Regressionstest
Fehler und Qualitätsmängel des Java-Code werden laufend festgestellt durch
werkzeuggestützte, automatisierte Tests
werkzeuggestützte, statische Code-Analyse
direkte Notwendigkeit für Fehlerbehebung und Mängelbeseitigungdirekte Notwendigkeit für Fehlerbehebung und Mängelbeseitigung
bedingt oftmals Refactoring, d. h. weitergehende, strukturelle „Umbau-Arbeiten“
nach einem Refactoring
ist der Java-Code fehlerbereinigt und / oder qualitativ besser
ist die Gesamt-Funktionalität unverändert
27
Beispiel: Redundanz-Beseitigung und Kapselung
� Aufdecken von redundantem Java-Code mit Checkstyle-Modul „Strict Duplicate Code“
� Auslagern der Code-Redundanz in eine separate Klasse
� dadurch gleichzeitig Kapselung der Verwendung
28
� dadurch gleichzeitig Kapselung der Verwendung des JAXB-Framework
Regel 7: Regressionstest im Rahmen der CI
Wahrung der funktionalen Korrektheit nach Refactorings wird durch den Regressionstest sichergestellt
Regressionstest ist der Test des gesamten Java-Code auf Basis der Test-Bibliothek
Zusammenfassung aller automatisierten, qualitätssichernden Maßnahmen in der Continuous Integration (Hudson):
Integrations-Build (Subversion, Maven)Generierung der Programm-Dokumentation (JavaDoc)statische Code-Analyse (Checkstyle, ...)Regressionstest (JUnit, ...) auf Basis der Test-BibliothekMessung der Test-Überdeckung (Cobertura)Deployment auf QS-Umgebung (für manuelle Tests)
29