SlideShare ist ein Scribd-Unternehmen logo
Gute Zeilen, schlechte Zeilen
Regeln für wartbare Programme

Dirk Weil, GEDOPLAN GmbH
Dirk Weil
GEDOPLAN GmbH, Bielefeld
Java EE seit 1998
Konzeption und
Realisierung
Vorträge
Seminare
Veröffentlichungen

Gute Zeilen, schlechte Zeilen

2
GUTE

ZEILEN
SCHLECHTE

ZEILEN
Gute Zeilen, schlechte Zeilen

3
Gibt es guten und schlechten Code?
Software muss funktional korrekt sein
Software muss effizient bearbeitbar sein
Ist (fast) nie fertig
Wird (meist) im Team entwickelt
Teams ändern sich über die Zeit
unterschiedliche Berufserfahrung, Programmierstile, …

Software muss verständlich sein

Gute Zeilen, schlechte Zeilen

4
Richtlinien
… helfen
bei der Einarbeitung in fremde Software
bei der (Weiter-) Entwicklung
Low Level: Namen, Formatierung …
Grundlegendes Klassendesign
Code-Komplexität
Anwendungsstruktur
Gute Zeilen, schlechte Zeilen

5
Statische Code-Analyse
Matching des Codes gegen Regelsätze
Einfache (Text-)Pattern … strukturelle Pattern

Checkstyle

Gute Zeilen, schlechte Zeilen

6
Dokumentation
Javadoc für API
Klassen, Interfaces,
Methoden, Variablen
public, protected
Kontrolle bspw. per Checkstyle
Javadoc Comments
Prüft per Default auch private
 scope = protected
Getter/Setter-Doku meist überflüssig
 allowMissingPropertyJavadoc = true

Gute Zeilen, schlechte Zeilen

7
Dokumentation
API-Dokumentation
veröffentlichen
Source-Jars erzeugen,
z. B. mit Maven
ermöglicht Unterstützung durch
die IDE

Gute Zeilen, schlechte Zeilen

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<inherited>true</inherited>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>

8
Dokumentation
Erklärungsbedürftige Codesequenzen
/*
* Fahrstrassen innerhalb von Fahrstrassen expandieren, d. h. durch ihre Elemente
* ersetzen. Dies geschieht in einer Schleife solange, bis alle Expansionen
* erledigt sind oder kein Fortschritt mehr erzielt wird.
*/
int letzteAnzahlFahrstrassenFahrstrassen = 0;
int anzahlFahrstrassenFahrstrassen = 0;
while (true)
{
for (Fahrstrasse fahrstrasse : this.fahrstrassen)
…

Trivialdokumentation ist überflüssig
// Neue Weichenstellung protokollieren
this.logger.trace(this + ": setStellung(" + stellung + ")");

Gute Zeilen, schlechte Zeilen

9
Namen
Klassen, Variablen, Methoden entsprechend ihrer Aufgabe benennen
spart umfangreiche Dokumentation
Well-Known Names nicht umdeuten!
Anschauungsbeispiel: "Nothalt-Funktion"
public void setAnlagenstatus()
{
Anlagenstatus.getInstance().changeAnlagenstatus();

Anlagenstatus ist zu generell
Methode setzt den Status nicht, sondern toggelt
setXyz ist well-known mit anderer Bedeutung

Gute Zeilen, schlechte Zeilen

10
Namen
Keine Präfixnotation für Typen, Sichtbarkeit etc.:
Instanzvariable

Name beginnt mit m_

Variable vom Typ List<Integer>

Name beginnt mit lI_

Interface

Name beginnt mit I

…

…

Präfixnamen tendieren zur Unlesbarkeit
this. ist aussagekräftiger (OO) als m_
Unterscheidung Klasse vs. Interface zweitrangig
werden durch IDE-Unterstützung mehr als ersetzt

Gute Zeilen, schlechte Zeilen

11
Namen
CS kann Namenskonventionen prüfen
(Module group Naming Conventions)
IDE-Komfort nutzen!
Quick fix: Namensvorschläge (Variablen, Konstanten ..)
Save actions: Member mit this. qualifizieren
…

Gute Zeilen, schlechte Zeilen

12
Formatierung
Code sollte im Team einheitlich formatiert sein
Einrückung (Tab/Blanks, wie viele?)
Platzierung von {
…
Vorteile
Code liest sich leichter
kleinere Change Sets im SCM
Lässt sich mit IDE-Komfort leicht erreichen
Save action: Format code
Überprüfung durch Code Checker eher zweitrangig
Gute Zeilen, schlechte Zeilen

13
equals, hashCode
Jedes Geschäftsobjekt sollte equals und hashCode definieren
IDEs bieten gute Unterstützung
Achtung bei equals in Basisklassen
public class BadEquals
{
public boolean equals(Object obj)
{
…
if (getClass() != obj.getClass())
// if (!(obj instanceof BadEquals)) // unsymmetrisch, wenn Subklasse überschreibt
// if (obj.getClass() != BadEquals.class) // funktioniert nicht für Subklassen
{
…

Gute Zeilen, schlechte Zeilen

14
equals, hashCode
equals definieren  hashCode definieren
nicht nur equals(MyType)
Codeanalyse:
CS: Equals and Hashcode, Covariant Equals
FB: Class defines equals and uses Object.hashCode

Gute Zeilen, schlechte Zeilen

15
switch
Regeln:
default nicht vergessen
kein Fall Through
CS: Missing Switch Default, Fall Through

Gute Zeilen, schlechte Zeilen

16
Protokollierung
keine Protokollausgabe auf stdout, stderr
"Mal schnell 'ne Ausgabe"
Achtung: IDE-Templates!
CS: Regexp… mit passendem Pattern

Gute Zeilen, schlechte Zeilen

17
Exception-Verwendung
Werfen und Fangen von Throwable, Exception,
RuntimeException i. A. fehlerhaft
CS: Illegal Catch, Illegal Throws

Gute Zeilen, schlechte Zeilen

18
DRY
Keine Copy&Paste-Programmierung
CS: Strict Duplicate Code
(nicht wirklich empfehlenswert)
PMD: Copy Paste Detection

Gute Zeilen, schlechte Zeilen

19
Komplexität
Klassen / Methoden nicht zu lang
Anzahl Methodenparameter nicht zu groß
CS: Maximum Method Length, Maximum Parameters,
Maximum File Length,
Cyclomatic Complexity
(Anwendung im
Team diskutieren!)

Gute Zeilen, schlechte Zeilen

20
Einfach machen
Einfache Lösungen sind gute Lösungen
Vorsicht bei:
Reflection
extrem schlecht lesbar
Refactoring problematisch

hochgradig konfigurierbaren Klassen
schwer nutzbar (bspw. GridBagConstraints)

übermäßigem Einsatz von Typparametern

Gute Zeilen, schlechte Zeilen

21
Einfach machen
Anschauungsbeispiel: Entity Editor
Generischer Editor für Geschäftsobjekte
Steuerung per Annotation @Editable
Remote funktionsfähig ( kein EntityManager)
Hochgradige Nutzung von Reflection
Umfangreiche Konfiguration von Services etc.
Einsatzfall BDE-System
ca. 35 Entities
Gute Zeilen, schlechte Zeilen

22
Klassen sparen lohnt nicht
Anschauungsbeispiel "Wachdienst":
Gebäudekontrolle durch Prüfung aller Räume
Räume sind auf Etagen verteilt
Kontrollierte Räume
werden abgehakt

Gute Zeilen, schlechte Zeilen

23
Klassen sparen lohnt nicht
Anschauungsbeispiel "Wachdienst"
1. Ansatz: Keine Klasse für Etage
Dialogaufbau unnötig kompliziert
(~ Gruppenwechsel)
Kein Platz für zukünftige Erweiterung
um Etagen-Daten

Gute Zeilen, schlechte Zeilen

24
Klassen sparen lohnt nicht
Anschauungsbeispiel "Wachdienst"
Besser: Zusätzliche Ebene für Etagen
Klares Konzept
Real World  Klasse

Gute Zeilen, schlechte Zeilen

25
Wohin mit der Logik?

Gute Zeilen, schlechte Zeilen

26
Wohin mit der Logik?
Anschauungsbeispiel "Modellbahnsteuerung":
Reservieren einer Fahrstraße
=Stellen der betroffenen
Weichen und Signale
Fahrstrasse liegt als
Geschäftsobjekt vor
Anforderung als Webservice

Gute Zeilen, schlechte Zeilen

27
Wohin mit der Logik?
Anschauungsbeispiel "Modellbahnsteuerung":
1. Ansatz: Iteration über Fahrstraßenelemente im Webservice
Nachteile:
nicht wiederverwendbar, da
im Webservice
"Polymorphie
für Arme"
(instanceof
~ goto der OO)

Gute Zeilen, schlechte Zeilen

@POST
@Path("/fahrstrasse/{bereich}/{name}/reserviert")
public Response setFahrstrassenreservierung(...)
{
Fahrstrasse fahrstrasse = …
for (FahrstrassenElement fe
: fahrstrasse.getElemente())
{
Fahrwegelement fwe = fe.getFahrwegelement();
if (fwe instanceof Weiche)
{
Weiche w = (Weiche) fwe;
w.setStellung(…);
}
…

28
Wohin mit der Logik?
Anschauungsbeispiel "Modellbahnsteuerung":
Besser: Platzierung der Logik in Fahrstrasse,
abstrakte Methode statt expliziter Typabfrage
@Path("{bereich}/{name}/reserviert")
@POST
public Response setReserviert(…)
{
Fahrstrasse fahrstrasse = …
fahrstrasse.setReserviert(reserviert);
}
public void setReserviert(boolean reserviert)
{
for (FahrstrassenElement element : this.elemente)
element.setReserviert(reserviert);
public abstract void setReserviert(boolean reserviert);
Gute Zeilen, schlechte Zeilen

29
Wohin mit der Logik?
Geschäftslogik in Geschäftslogik-Schicht
CDI, EJB, JPA, …
Präsentationslogik bspw. in JSF-Beans
CDI-Models, Managed Beans
Boundary-Code in EJBs, Webservices etc.
Saubere Schichtung
erhöht Wiederverwendbarkeit
macht den Code übersichtlicher

Gute Zeilen, schlechte Zeilen

30
In Objekten denken
Anschauungsbeispiel: 1:n-Relation (JPA)
@Entity
public class Book
{
@Id @GeneratedValue Integer
id;
@ManyToOne
Publisher publisher;

@Entity
public class Publisher
{
@Id @GeneratedValue
Integer
id;
@OneToMany(mappedBy = "publisher") List<Book> books;
…

Query "Suche Books eines Publishers"
(Warum so kompliziert?):
Publisher publisher = …;
… em.createQuery("select b from Book b where b.publisher.id=:publisherId", Book.class)
.setParameter("publisherId", publisher.getId())
.getResultList();

Gute Zeilen, schlechte Zeilen

31
Packages
Zwei Anti-Beispiele

Gute Zeilen, schlechte Zeilen

32
Anekdoten

Offensichtlich komplett falsche Vorstellung
von Objekten und Referenzen darauf

String name = new String();
name = "Hugo";
instanceof
if (val != null && ("" + val.getClass().getName()).equals("java.lang.String"))

Sind die Labels nicht Texte? Warum dann Set<Object>?
Wenn unterschiedliche Typen erlaubt: Set<?>
Set<String> texte = …;
Set<Object> labels = new TreeSet<>();
labels.addAll(texte);
Integer.toString(adr)
int adr = …;
String adrAsString = new Integer(adr).toString();
Gute Zeilen, schlechte Zeilen

33
Anekdoten

setRueckwaerts(!isRueckwaerts())

public static final Anlagenstatus
public void changeRichtung()
= new Anlagenstatus()
{
if (isRueckwaerts())
Noch besser: enum-Singleton
setRueckwaerts(false);
else
setRueckwaerts(true);
}
public class Anlagenstatus
{
private static Anlagenstatus anlagenstatus = null;
private Anlagenstatus() { }

public static Anlagenstatus getInstance()
{
if (anlagenstatus == null)
anlagenstatus = new Anlagenstatus();
return anlagenstatus;
}

Gute Zeilen, schlechte Zeilen

34
Anekdoten
@POST
@Path("artikel/{artNr}/menge")
public Response setSpeed(@PathParam("artNr") String adrNr,
@FormParam("menge") String menge)
{
try
{
int mengeInt = Integer.parseInt(menge);
…
}
catch (NumberFormatException e)
{

int menge

Auto car1 = ...;
Auto car2 = ...;
if (car1.getId().getValue().equals(car2.getId().getValue()))
{
...
if (car1.equals(car2))
Gute Zeilen, schlechte Zeilen

35
Anekdoten
if (this.kommPunkt.isTurnText()) {
g2.setFont(system.getKommPunktFont());
g2.translate(kommPunktBreite / 2 + 2, 0 * kommPunktBreite / 2 - 1);
g2.rotate(Math.toRadians(this.kommPunkt.getDisplayWinkel() - 90),
this.kommPunkt.getDisplayX(), this.kommPunkt.getDisplayY());
g2.setColor(system.getColor(system.PROPERTY_KOMMPUNKT_TEXT_COLOR));
g2.drawString(this.kommPunkt.getId().getValue(), this.kommPunkt.getDisplayX() - 3,
this.kommPunkt.getDisplayY() + 2);
g2.setTransform(this.father.baseTransform);
} else {
g2.setFont(system.getKommPunktFont());
g2.translate(kommPunktBreite / 2 + 2, 0 * kommPunktBreite / 2 - 1);
g2.rotate(Math.toRadians(this.kommPunkt.getDisplayWinkel() - 90),
this.kommPunkt.getDisplayX(), this.kommPunkt.getDisplayY());
g2.setColor(system.getColor(system.PROPERTY_KOMMPUNKT_TEXT_COLOR));
g2.drawString(this.kommPunkt.getId().getValue(), this.kommPunkt.getDisplayX() - 24,
this.kommPunkt.getDisplayY() + 2);
g2.setTransform(this.father.baseTransform);
}

Gute Zeilen, schlechte Zeilen

36
Unit Tests
Test der funktionalen Korrektheit
auf Unit-Ebene
einzelne Klasse
isoliert von ihrer Umgebung, ggf. mittels Mock-Objekten

als Integrationstests
während der Entwicklung
als nachträglich Absicherung
oder als Vorgehensweise (Test Driven Development)
als Qualitätssicherungsmaßnahme
automatisiert
regelmäßig
Gute Zeilen, schlechte Zeilen

37
Unit Tests
nicht aufwändiger als Main-Programm zum „Ausprobieren“
public class WaehrungServiceUnitTest
{
private static WaehrungService WAEHRUNG_SERVICE = new WaehrungService();
@Test
public void testUmrechnenUSD()
{
double actual = WAEHRUNG_SERVICE.umrechnen(100.0, "USD");
assertThat("Euro-Betrag", actual, is(83.41));
}
public class WaehrungServiceMain
{
private static WaehrungService
WAEHRUNG_SERVICE = new WaehrungService();
public static void main(String [] args)
{
BigDecimal actual = WAEHRUNG_SERVICE.umrechnen(100.0, "USD");
System.out.println("100 USD = " + actual + " EUR");
}

Gute Zeilen, schlechte Zeilen

38
Unit Tests
Testwissen wird explizit gemacht
als Einstiegsdokumentation / Tutorial geeignet
automatisch, unbedient ausführbar
Continuous Integration (Hudson, Jenkins, …)
regelmäßige Ausführung aller Tests effizient möglich
dauerhafte Qualitätssicherung
unverzichtbar für Refactoring und Weiterentwicklung
Absicherung gegen „Verschlimmbesserung“
Gute Zeilen, schlechte Zeilen

39
Continuous Integration
Manuelle Ausführung reicht nicht
belastet den Entwicklungsprozess
keine (einheitliche) Veröffentlichung der Ergebnisse
keine (einheitliche) Eskalation bei Fehlern
An dem Teil habe ich
nichts gemacht!
Bei mir läuft's!

Gute Zeilen, schlechte Zeilen

Oh, sorry – das habe
ich noch nicht
eingecheckt.

40
Continuous Integration
Voraussetzung: Projekt enthält ausführbare Tests
Junit, TestNG, …
Build selbst ist auch ein Test!

Gute Zeilen, schlechte Zeilen

41
Continuous Integration
Anforderungen an eine Build- und Test-Umgebung
Regelmäßige, automatische Ausführung
zeitgesteuert ("Daily Build")
durch Check-In getriggert
…

Kompletter Build
Ausführung aller Tests
Qualitätsprüfung (Style, Coverage, …)
Reporting
Benachrichtigung

Gute Zeilen, schlechte Zeilen

42
Continuous Integration
Plan

Feedback

Test
Archiv

CI-Umgebung
Entw.Umgebung

SCM
Gute Zeilen, schlechte Zeilen

Build
43
Continuous Integration

Gute Zeilen, schlechte Zeilen

44
Qualitäts-Schulden
Schlechte Code-Qualität = Kredit
Code-Review + Korrektur = Rückzahlung
Weiterentwicklung trotz Schwächen
= Zinszahlungen
können überwältigend werden!

Nichts tun = "absaufen"
Ad-hoc-Maßnahmen sind
keine Dauerlösung

Gute Zeilen, schlechte Zeilen

45
More
Seminare zum Thema, z. B.
Java Effective
Java Software Testing

http://javaeeblog.wordpress.com/
http://expertenkreisjava.blogspot.de/
 dirk.weil@gedoplan.de
@dirkweil
Gute Zeilen, schlechte Zeilen

46
dirk.weil@gedoplan.de

Weitere ähnliche Inhalte

Ähnlich wie Gute zeilen, schlechte zeilen - Regeln für wartbare Software

Workshop: Besseres C#
Workshop: Besseres C#Workshop: Besseres C#
Workshop: Besseres C#
Rainer Stropek
 
Oracle Forms: How to create a Framework
Oracle Forms: How to create a FrameworkOracle Forms: How to create a Framework
Oracle Forms: How to create a Framework
OPITZ CONSULTING Deutschland
 
Puppet - Module entwickeln - Von der Planung bis zur Umsetzung
Puppet - Module entwickeln - Von der Planung bis zur UmsetzungPuppet - Module entwickeln - Von der Planung bis zur Umsetzung
Puppet - Module entwickeln - Von der Planung bis zur Umsetzung
inovex GmbH
 
Metaprogrammierung und Reflection
Metaprogrammierung und ReflectionMetaprogrammierung und Reflection
Metaprogrammierung und Reflection
Stefan Marr
 
Fundamentale Muster in Java
Fundamentale Muster in JavaFundamentale Muster in Java
Fundamentale Muster in Java
tutego
 

Ähnlich wie Gute zeilen, schlechte zeilen - Regeln für wartbare Software (20)

Workshop: Besseres C#
Workshop: Besseres C#Workshop: Besseres C#
Workshop: Besseres C#
 
Einführung in Clean Code mit .NET - Teil 1
Einführung in Clean Code mit .NET - Teil 1Einführung in Clean Code mit .NET - Teil 1
Einführung in Clean Code mit .NET - Teil 1
 
Oracle Forms: How to create a Framework
Oracle Forms: How to create a FrameworkOracle Forms: How to create a Framework
Oracle Forms: How to create a Framework
 
Puppet: Designing modules & repositories
Puppet: Designing modules & repositoriesPuppet: Designing modules & repositories
Puppet: Designing modules & repositories
 
Java Code Quality: Gute Software braucht guten Code - Regeln für verständlich...
Java Code Quality: Gute Software braucht guten Code - Regeln für verständlich...Java Code Quality: Gute Software braucht guten Code - Regeln für verständlich...
Java Code Quality: Gute Software braucht guten Code - Regeln für verständlich...
 
IfN Studienarbeit Abschlusspres 18.9.2007
IfN Studienarbeit Abschlusspres 18.9.2007IfN Studienarbeit Abschlusspres 18.9.2007
IfN Studienarbeit Abschlusspres 18.9.2007
 
FH Wedel - SS11 - Seminar - Marcus Riemer - LEDA
FH Wedel - SS11 - Seminar - Marcus Riemer - LEDAFH Wedel - SS11 - Seminar - Marcus Riemer - LEDA
FH Wedel - SS11 - Seminar - Marcus Riemer - LEDA
 
Bit WiSe 2013 | Basisinformationstechnologie I - 08: Programmiersprachen I
Bit WiSe 2013 | Basisinformationstechnologie I - 08: Programmiersprachen IBit WiSe 2013 | Basisinformationstechnologie I - 08: Programmiersprachen I
Bit WiSe 2013 | Basisinformationstechnologie I - 08: Programmiersprachen I
 
#SpeakRoslyn - Die Microsoft .NET Compiler Plattform
#SpeakRoslyn - Die Microsoft .NET Compiler Plattform#SpeakRoslyn - Die Microsoft .NET Compiler Plattform
#SpeakRoslyn - Die Microsoft .NET Compiler Plattform
 
Puppet - Module entwickeln - Von der Planung bis zur Umsetzung
Puppet - Module entwickeln - Von der Planung bis zur UmsetzungPuppet - Module entwickeln - Von der Planung bis zur Umsetzung
Puppet - Module entwickeln - Von der Planung bis zur Umsetzung
 
An Introduction to Ruby
An Introduction to RubyAn Introduction to Ruby
An Introduction to Ruby
 
Metaprogrammierung und Reflection
Metaprogrammierung und ReflectionMetaprogrammierung und Reflection
Metaprogrammierung und Reflection
 
The Lotus Code Cookbook
The Lotus Code CookbookThe Lotus Code Cookbook
The Lotus Code Cookbook
 
Java 8, mit Lambdas das hohe Lied des Functional Programming singen
Java 8, mit Lambdas das hohe Lied des Functional Programming singenJava 8, mit Lambdas das hohe Lied des Functional Programming singen
Java 8, mit Lambdas das hohe Lied des Functional Programming singen
 
Dart (Teil I der Tour de Dart)
Dart (Teil I der Tour de Dart)Dart (Teil I der Tour de Dart)
Dart (Teil I der Tour de Dart)
 
Design OOA OOD
Design OOA OODDesign OOA OOD
Design OOA OOD
 
Clean Coding - Theorie und Praxis Guide.pptx
Clean Coding - Theorie und Praxis Guide.pptxClean Coding - Theorie und Praxis Guide.pptx
Clean Coding - Theorie und Praxis Guide.pptx
 
Drupal inside out
Drupal inside outDrupal inside out
Drupal inside out
 
Fundamentale Muster in Java
Fundamentale Muster in JavaFundamentale Muster in Java
Fundamentale Muster in Java
 
Advanced Refactoring Patterns
Advanced Refactoring PatternsAdvanced Refactoring Patterns
Advanced Refactoring Patterns
 

Gute zeilen, schlechte zeilen - Regeln für wartbare Software

  • 1. Gute Zeilen, schlechte Zeilen Regeln für wartbare Programme Dirk Weil, GEDOPLAN GmbH
  • 2. Dirk Weil GEDOPLAN GmbH, Bielefeld Java EE seit 1998 Konzeption und Realisierung Vorträge Seminare Veröffentlichungen Gute Zeilen, schlechte Zeilen 2
  • 4. Gibt es guten und schlechten Code? Software muss funktional korrekt sein Software muss effizient bearbeitbar sein Ist (fast) nie fertig Wird (meist) im Team entwickelt Teams ändern sich über die Zeit unterschiedliche Berufserfahrung, Programmierstile, … Software muss verständlich sein Gute Zeilen, schlechte Zeilen 4
  • 5. Richtlinien … helfen bei der Einarbeitung in fremde Software bei der (Weiter-) Entwicklung Low Level: Namen, Formatierung … Grundlegendes Klassendesign Code-Komplexität Anwendungsstruktur Gute Zeilen, schlechte Zeilen 5
  • 6. Statische Code-Analyse Matching des Codes gegen Regelsätze Einfache (Text-)Pattern … strukturelle Pattern Checkstyle Gute Zeilen, schlechte Zeilen 6
  • 7. Dokumentation Javadoc für API Klassen, Interfaces, Methoden, Variablen public, protected Kontrolle bspw. per Checkstyle Javadoc Comments Prüft per Default auch private  scope = protected Getter/Setter-Doku meist überflüssig  allowMissingPropertyJavadoc = true Gute Zeilen, schlechte Zeilen 7
  • 8. Dokumentation API-Dokumentation veröffentlichen Source-Jars erzeugen, z. B. mit Maven ermöglicht Unterstützung durch die IDE Gute Zeilen, schlechte Zeilen <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <inherited>true</inherited> <executions> <execution> <id>attach-sources</id> <phase>verify</phase> <goals> <goal>jar-no-fork</goal> </goals> </execution> </executions> </plugin> 8
  • 9. Dokumentation Erklärungsbedürftige Codesequenzen /* * Fahrstrassen innerhalb von Fahrstrassen expandieren, d. h. durch ihre Elemente * ersetzen. Dies geschieht in einer Schleife solange, bis alle Expansionen * erledigt sind oder kein Fortschritt mehr erzielt wird. */ int letzteAnzahlFahrstrassenFahrstrassen = 0; int anzahlFahrstrassenFahrstrassen = 0; while (true) { for (Fahrstrasse fahrstrasse : this.fahrstrassen) … Trivialdokumentation ist überflüssig // Neue Weichenstellung protokollieren this.logger.trace(this + ": setStellung(" + stellung + ")"); Gute Zeilen, schlechte Zeilen 9
  • 10. Namen Klassen, Variablen, Methoden entsprechend ihrer Aufgabe benennen spart umfangreiche Dokumentation Well-Known Names nicht umdeuten! Anschauungsbeispiel: "Nothalt-Funktion" public void setAnlagenstatus() { Anlagenstatus.getInstance().changeAnlagenstatus(); Anlagenstatus ist zu generell Methode setzt den Status nicht, sondern toggelt setXyz ist well-known mit anderer Bedeutung Gute Zeilen, schlechte Zeilen 10
  • 11. Namen Keine Präfixnotation für Typen, Sichtbarkeit etc.: Instanzvariable Name beginnt mit m_ Variable vom Typ List<Integer> Name beginnt mit lI_ Interface Name beginnt mit I … … Präfixnamen tendieren zur Unlesbarkeit this. ist aussagekräftiger (OO) als m_ Unterscheidung Klasse vs. Interface zweitrangig werden durch IDE-Unterstützung mehr als ersetzt Gute Zeilen, schlechte Zeilen 11
  • 12. Namen CS kann Namenskonventionen prüfen (Module group Naming Conventions) IDE-Komfort nutzen! Quick fix: Namensvorschläge (Variablen, Konstanten ..) Save actions: Member mit this. qualifizieren … Gute Zeilen, schlechte Zeilen 12
  • 13. Formatierung Code sollte im Team einheitlich formatiert sein Einrückung (Tab/Blanks, wie viele?) Platzierung von { … Vorteile Code liest sich leichter kleinere Change Sets im SCM Lässt sich mit IDE-Komfort leicht erreichen Save action: Format code Überprüfung durch Code Checker eher zweitrangig Gute Zeilen, schlechte Zeilen 13
  • 14. equals, hashCode Jedes Geschäftsobjekt sollte equals und hashCode definieren IDEs bieten gute Unterstützung Achtung bei equals in Basisklassen public class BadEquals { public boolean equals(Object obj) { … if (getClass() != obj.getClass()) // if (!(obj instanceof BadEquals)) // unsymmetrisch, wenn Subklasse überschreibt // if (obj.getClass() != BadEquals.class) // funktioniert nicht für Subklassen { … Gute Zeilen, schlechte Zeilen 14
  • 15. equals, hashCode equals definieren  hashCode definieren nicht nur equals(MyType) Codeanalyse: CS: Equals and Hashcode, Covariant Equals FB: Class defines equals and uses Object.hashCode Gute Zeilen, schlechte Zeilen 15
  • 16. switch Regeln: default nicht vergessen kein Fall Through CS: Missing Switch Default, Fall Through Gute Zeilen, schlechte Zeilen 16
  • 17. Protokollierung keine Protokollausgabe auf stdout, stderr "Mal schnell 'ne Ausgabe" Achtung: IDE-Templates! CS: Regexp… mit passendem Pattern Gute Zeilen, schlechte Zeilen 17
  • 18. Exception-Verwendung Werfen und Fangen von Throwable, Exception, RuntimeException i. A. fehlerhaft CS: Illegal Catch, Illegal Throws Gute Zeilen, schlechte Zeilen 18
  • 19. DRY Keine Copy&Paste-Programmierung CS: Strict Duplicate Code (nicht wirklich empfehlenswert) PMD: Copy Paste Detection Gute Zeilen, schlechte Zeilen 19
  • 20. Komplexität Klassen / Methoden nicht zu lang Anzahl Methodenparameter nicht zu groß CS: Maximum Method Length, Maximum Parameters, Maximum File Length, Cyclomatic Complexity (Anwendung im Team diskutieren!) Gute Zeilen, schlechte Zeilen 20
  • 21. Einfach machen Einfache Lösungen sind gute Lösungen Vorsicht bei: Reflection extrem schlecht lesbar Refactoring problematisch hochgradig konfigurierbaren Klassen schwer nutzbar (bspw. GridBagConstraints) übermäßigem Einsatz von Typparametern Gute Zeilen, schlechte Zeilen 21
  • 22. Einfach machen Anschauungsbeispiel: Entity Editor Generischer Editor für Geschäftsobjekte Steuerung per Annotation @Editable Remote funktionsfähig ( kein EntityManager) Hochgradige Nutzung von Reflection Umfangreiche Konfiguration von Services etc. Einsatzfall BDE-System ca. 35 Entities Gute Zeilen, schlechte Zeilen 22
  • 23. Klassen sparen lohnt nicht Anschauungsbeispiel "Wachdienst": Gebäudekontrolle durch Prüfung aller Räume Räume sind auf Etagen verteilt Kontrollierte Räume werden abgehakt Gute Zeilen, schlechte Zeilen 23
  • 24. Klassen sparen lohnt nicht Anschauungsbeispiel "Wachdienst" 1. Ansatz: Keine Klasse für Etage Dialogaufbau unnötig kompliziert (~ Gruppenwechsel) Kein Platz für zukünftige Erweiterung um Etagen-Daten Gute Zeilen, schlechte Zeilen 24
  • 25. Klassen sparen lohnt nicht Anschauungsbeispiel "Wachdienst" Besser: Zusätzliche Ebene für Etagen Klares Konzept Real World  Klasse Gute Zeilen, schlechte Zeilen 25
  • 26. Wohin mit der Logik? Gute Zeilen, schlechte Zeilen 26
  • 27. Wohin mit der Logik? Anschauungsbeispiel "Modellbahnsteuerung": Reservieren einer Fahrstraße =Stellen der betroffenen Weichen und Signale Fahrstrasse liegt als Geschäftsobjekt vor Anforderung als Webservice Gute Zeilen, schlechte Zeilen 27
  • 28. Wohin mit der Logik? Anschauungsbeispiel "Modellbahnsteuerung": 1. Ansatz: Iteration über Fahrstraßenelemente im Webservice Nachteile: nicht wiederverwendbar, da im Webservice "Polymorphie für Arme" (instanceof ~ goto der OO) Gute Zeilen, schlechte Zeilen @POST @Path("/fahrstrasse/{bereich}/{name}/reserviert") public Response setFahrstrassenreservierung(...) { Fahrstrasse fahrstrasse = … for (FahrstrassenElement fe : fahrstrasse.getElemente()) { Fahrwegelement fwe = fe.getFahrwegelement(); if (fwe instanceof Weiche) { Weiche w = (Weiche) fwe; w.setStellung(…); } … 28
  • 29. Wohin mit der Logik? Anschauungsbeispiel "Modellbahnsteuerung": Besser: Platzierung der Logik in Fahrstrasse, abstrakte Methode statt expliziter Typabfrage @Path("{bereich}/{name}/reserviert") @POST public Response setReserviert(…) { Fahrstrasse fahrstrasse = … fahrstrasse.setReserviert(reserviert); } public void setReserviert(boolean reserviert) { for (FahrstrassenElement element : this.elemente) element.setReserviert(reserviert); public abstract void setReserviert(boolean reserviert); Gute Zeilen, schlechte Zeilen 29
  • 30. Wohin mit der Logik? Geschäftslogik in Geschäftslogik-Schicht CDI, EJB, JPA, … Präsentationslogik bspw. in JSF-Beans CDI-Models, Managed Beans Boundary-Code in EJBs, Webservices etc. Saubere Schichtung erhöht Wiederverwendbarkeit macht den Code übersichtlicher Gute Zeilen, schlechte Zeilen 30
  • 31. In Objekten denken Anschauungsbeispiel: 1:n-Relation (JPA) @Entity public class Book { @Id @GeneratedValue Integer id; @ManyToOne Publisher publisher; @Entity public class Publisher { @Id @GeneratedValue Integer id; @OneToMany(mappedBy = "publisher") List<Book> books; … Query "Suche Books eines Publishers" (Warum so kompliziert?): Publisher publisher = …; … em.createQuery("select b from Book b where b.publisher.id=:publisherId", Book.class) .setParameter("publisherId", publisher.getId()) .getResultList(); Gute Zeilen, schlechte Zeilen 31
  • 33. Anekdoten Offensichtlich komplett falsche Vorstellung von Objekten und Referenzen darauf String name = new String(); name = "Hugo"; instanceof if (val != null && ("" + val.getClass().getName()).equals("java.lang.String")) Sind die Labels nicht Texte? Warum dann Set<Object>? Wenn unterschiedliche Typen erlaubt: Set<?> Set<String> texte = …; Set<Object> labels = new TreeSet<>(); labels.addAll(texte); Integer.toString(adr) int adr = …; String adrAsString = new Integer(adr).toString(); Gute Zeilen, schlechte Zeilen 33
  • 34. Anekdoten setRueckwaerts(!isRueckwaerts()) public static final Anlagenstatus public void changeRichtung() = new Anlagenstatus() { if (isRueckwaerts()) Noch besser: enum-Singleton setRueckwaerts(false); else setRueckwaerts(true); } public class Anlagenstatus { private static Anlagenstatus anlagenstatus = null; private Anlagenstatus() { } public static Anlagenstatus getInstance() { if (anlagenstatus == null) anlagenstatus = new Anlagenstatus(); return anlagenstatus; } Gute Zeilen, schlechte Zeilen 34
  • 35. Anekdoten @POST @Path("artikel/{artNr}/menge") public Response setSpeed(@PathParam("artNr") String adrNr, @FormParam("menge") String menge) { try { int mengeInt = Integer.parseInt(menge); … } catch (NumberFormatException e) { int menge Auto car1 = ...; Auto car2 = ...; if (car1.getId().getValue().equals(car2.getId().getValue())) { ... if (car1.equals(car2)) Gute Zeilen, schlechte Zeilen 35
  • 36. Anekdoten if (this.kommPunkt.isTurnText()) { g2.setFont(system.getKommPunktFont()); g2.translate(kommPunktBreite / 2 + 2, 0 * kommPunktBreite / 2 - 1); g2.rotate(Math.toRadians(this.kommPunkt.getDisplayWinkel() - 90), this.kommPunkt.getDisplayX(), this.kommPunkt.getDisplayY()); g2.setColor(system.getColor(system.PROPERTY_KOMMPUNKT_TEXT_COLOR)); g2.drawString(this.kommPunkt.getId().getValue(), this.kommPunkt.getDisplayX() - 3, this.kommPunkt.getDisplayY() + 2); g2.setTransform(this.father.baseTransform); } else { g2.setFont(system.getKommPunktFont()); g2.translate(kommPunktBreite / 2 + 2, 0 * kommPunktBreite / 2 - 1); g2.rotate(Math.toRadians(this.kommPunkt.getDisplayWinkel() - 90), this.kommPunkt.getDisplayX(), this.kommPunkt.getDisplayY()); g2.setColor(system.getColor(system.PROPERTY_KOMMPUNKT_TEXT_COLOR)); g2.drawString(this.kommPunkt.getId().getValue(), this.kommPunkt.getDisplayX() - 24, this.kommPunkt.getDisplayY() + 2); g2.setTransform(this.father.baseTransform); } Gute Zeilen, schlechte Zeilen 36
  • 37. Unit Tests Test der funktionalen Korrektheit auf Unit-Ebene einzelne Klasse isoliert von ihrer Umgebung, ggf. mittels Mock-Objekten als Integrationstests während der Entwicklung als nachträglich Absicherung oder als Vorgehensweise (Test Driven Development) als Qualitätssicherungsmaßnahme automatisiert regelmäßig Gute Zeilen, schlechte Zeilen 37
  • 38. Unit Tests nicht aufwändiger als Main-Programm zum „Ausprobieren“ public class WaehrungServiceUnitTest { private static WaehrungService WAEHRUNG_SERVICE = new WaehrungService(); @Test public void testUmrechnenUSD() { double actual = WAEHRUNG_SERVICE.umrechnen(100.0, "USD"); assertThat("Euro-Betrag", actual, is(83.41)); } public class WaehrungServiceMain { private static WaehrungService WAEHRUNG_SERVICE = new WaehrungService(); public static void main(String [] args) { BigDecimal actual = WAEHRUNG_SERVICE.umrechnen(100.0, "USD"); System.out.println("100 USD = " + actual + " EUR"); } Gute Zeilen, schlechte Zeilen 38
  • 39. Unit Tests Testwissen wird explizit gemacht als Einstiegsdokumentation / Tutorial geeignet automatisch, unbedient ausführbar Continuous Integration (Hudson, Jenkins, …) regelmäßige Ausführung aller Tests effizient möglich dauerhafte Qualitätssicherung unverzichtbar für Refactoring und Weiterentwicklung Absicherung gegen „Verschlimmbesserung“ Gute Zeilen, schlechte Zeilen 39
  • 40. Continuous Integration Manuelle Ausführung reicht nicht belastet den Entwicklungsprozess keine (einheitliche) Veröffentlichung der Ergebnisse keine (einheitliche) Eskalation bei Fehlern An dem Teil habe ich nichts gemacht! Bei mir läuft's! Gute Zeilen, schlechte Zeilen Oh, sorry – das habe ich noch nicht eingecheckt. 40
  • 41. Continuous Integration Voraussetzung: Projekt enthält ausführbare Tests Junit, TestNG, … Build selbst ist auch ein Test! Gute Zeilen, schlechte Zeilen 41
  • 42. Continuous Integration Anforderungen an eine Build- und Test-Umgebung Regelmäßige, automatische Ausführung zeitgesteuert ("Daily Build") durch Check-In getriggert … Kompletter Build Ausführung aller Tests Qualitätsprüfung (Style, Coverage, …) Reporting Benachrichtigung Gute Zeilen, schlechte Zeilen 42
  • 44. Continuous Integration Gute Zeilen, schlechte Zeilen 44
  • 45. Qualitäts-Schulden Schlechte Code-Qualität = Kredit Code-Review + Korrektur = Rückzahlung Weiterentwicklung trotz Schwächen = Zinszahlungen können überwältigend werden! Nichts tun = "absaufen" Ad-hoc-Maßnahmen sind keine Dauerlösung Gute Zeilen, schlechte Zeilen 45
  • 46. More Seminare zum Thema, z. B. Java Effective Java Software Testing http://javaeeblog.wordpress.com/ http://expertenkreisjava.blogspot.de/  dirk.weil@gedoplan.de @dirkweil Gute Zeilen, schlechte Zeilen 46 dirk.weil@gedoplan.de