Your SlideShare is downloading. ×
Java Code Quality: Gute Software braucht guten Code - Regeln für verständliche und wartbare Java-Programme
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Saving this for later?

Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime - even offline.

Text the download link to your phone

Standard text messaging rates apply

Java Code Quality: Gute Software braucht guten Code - Regeln für verständliche und wartbare Java-Programme

3,194
views

Published on

Kurzbeschreibung …

Kurzbeschreibung

Softwarequalität ist keine Spracheigenschaft. In jeder noch so guten Programmiersprache kann man schlechte Programme schreiben – sogar in Java. Herr Seekamp, Senior Consultant bei der GEDOPLAN GmbH, macht in diesem Vortrag anhand von Fallbeispielen aus seinen Projekten deutlich, was verständlichen und wartbaren Code ausmacht, welche Regeln man dafür beherzigen sollte und welche Analysewerkzeuge dabei unterstützen können.

Inhalt
Regeln für guten Java-Code
Statische Code-Analyse
Refactoring
Werkzeuge zur Sicherung der Qualität

Published in: Technology

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
3,194
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
35
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Java Code QualityRegeln für gute Java-ProgrammeTreffpunkt Semicolon, 22.02.2011, GFU Cyrus AGJens Seekamp, GEDOPLAN GmbH
  • 2. Java Code Quality – ein ganzheitlicher AnsatzAgenda Software-Qualität Regel 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
  • 3. 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
  • 4. Regel 1: System-Dekomposition und Build-Prozess System-Dekomposition Zerlegung des Software-Systems in Komponenten eine Komponente kapselt einen Funktionsbereich (Schnittstelle vs. Rumpf) eine Komponente basiert oftmals auf einer Implementierungs- Technologie (z. B. EJB) eine Komponente ist i. d. R. ausführbar 4
  • 5. Architektur einer „kleinen“ Java-EE-Anwendung Projekt PRAGSYS: Prüfsystem für Statistiken der GKV 5
  • 6. Architektur einer „großen“ Java-EE-Anwendung Projekt BDE: Betriebsdatenerfassung für Fertigungsindustrie 6
  • 7. Regel 1: System-Dekomposition und Build-Prozess Build-Prozess „Bauen“ des Software-Systems aus seinen kompilierten Komponenten dabei wird je Komponente ein Build-Artefakt erstellt Werkzeuge für den Build-Prozess Build-Prozess wird vollständig mit Maven 3.x durchgeführt Java-Compiler der IDE ist (theoretisch) überflüssig Continuous Integration wird mit Hudson realisiert (z. B. Nightly Build) 7
  • 8. Maven-Multi-Projekt für Java-EE-Anwendung<project><groupId>de.gedoplan.bde</groupId> <project><artifactId>bde</artifactId><version>1.0.0</version> <parent> <groupId>de.gedoplan.bde</groupId><modules> <artifactId>bde</artifactId> <module>bde-common</module> <version>1.0.0</version> <module>bde-comp-mitarbeiter</module> </parent> <module>bde-comp-zeiterfassung</module> <module>bde-web</module> <artifactId>bde-comp-mitarbeiter</artifactId> <module>bde-ear</module> <packaging>ejb</packaging></modules> <project> <project> <parent> ... <parent> ... <artifactId>bde-web</artifactId> <artifactId>bde-ear</artifactId> <packaging>war</packaging> <packaging>ear</packaging> <dependencies> ... <artifactId>bde-comp-mitarbeiter ... ... <artifactId>bde-web ... 8
  • 9. 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) 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
  • 10. Schichten-Architektur einer Java-EE-Anwendung 10
  • 11. Sicherstellung der Schichten-Architektur häufige Verletzungen der Schichten-Architektur „Überspringen“ einer Schicht (Präsentation Datenhaltung) „umgekehrte“ benutzt-Beziehung (Datenhaltung Fachlogik) falsche Zuordnung von Implementierung Realisierung 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
  • 12. Sicherstellung mit Checkstyle-Modul „Import Control“ 12
  • 13. Regel 3: Modell-getriebene Entwicklung aus einem „Modell“ generierter Java-Code ist strukturiert einheitlich korrekt und stabil Code-Generierung steigert außerdem die Effizienz der Software-Entwicklung die Wartbarkeit des Software-Systems 13
  • 14. „klassische“ Modell-getriebene EntwicklungGenerierung @Entity public class Land des fachlichen Klassenmodells { @Id (Entitäten) private String isoCode; private String name; als POJO-Klassen mit JPA- public Land() Annotationen {} public String getIsoCode() aus UML-Klassenmodell (z. B. { return this.isoCode; } Enterprise Architect) public void setIsoCode(String code) { this.isoCode = code; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } } 14
  • 15. Generierung von XML-Zugriffsklassen (1)Generierung für die Umwandlung Java-Objekte XML-Dokumente (Marshalling / Unmarshalling) als POJO-Klassen mit JAXB-Annotationen aus XML-Schema (z. B. XMLSPY) mit dem JAXB-Schema-Compiler (Java Architecture for XML Binding) 15
  • 16. Generierung von XML-Zugriffsklassen (2) XJC @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; } 16
  • 17. Generierung eines Formel-ParserGenerierung eines Parser für arithmetisch-logische Formeln aus einer kontextfreien Grammatik mit dem Parser-Generator JavaCC (Java Compiler Compiler) TOKEN: { | < PLUS: "+" > 12 * x + 5 ... | < MINUS: "-" > } void Addition(): { Token t = null; StringBuilder sb = new StringBuilder(); } + { Multiplikation() ( ( t = <PLUS> Multiplikation() ) { sb.append(t.image); } | ( t = <MINUS> Multiplikation() ) { sb.append(t.image); } * 5 )* { jjtThis.jjtSetValue(sb.toString()); } } 12 x 17
  • 18. Regel 4: inkrementelle Entwicklung - Randbedingungen package de.aoksystems.pragsys.service.pruefkern; import de.aoksystems.pragsys.bo.statistik.Statistik; import de.aoksystems.pragsys.bo.pruefung.Pruefergebnis; @Stateless public 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) {...} } 18
  • 19. 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
  • 20. 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-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
  • 21. 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 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
  • 22. 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- 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
  • 23. Beispiel: Code-Bereinigung mittels Checkstyle / Review (5) Import-Organisation, Formatierung (4) Namenskonventionen, Bezeichner, for (3) JavaDoc, Anweisungs-Struktur, Kommentare (2) try-catch, Parameterprüfung (1) Ausnahmebehandlung, Logging „Nice“ 23
  • 24. 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 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
  • 25. 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-Verwaltung Nutzung dedizierter Test-Datenbank(en) explizite Testdaten-Erzeugung mittels Java (DBUnit, XMLUnit) Schritt 3: Integrationstest der Service-Schicht per JUnit-Testclient gegen den Application-Server (remote) mittels z. B. OpenEJB innerhalb der IDE (embedded) Schritt 4: „automatisierter Abnahmetest“ der GUI-Clients Werkzeug 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
  • 26. 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 / Frameworks vorausgesetzt) hierarchische Strukturierung der Test-Suites gesamte Test-Bibliothek auf Entwicklungsrechner lokal ausführbar 26
  • 27. 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ä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
  • 28. 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 des JAXB-Framework 28
  • 29. 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-Bibliothek Messung der Test-Überdeckung (Cobertura) Deployment auf QS-Umgebung (für manuelle Tests) 29