SlideShare ist ein Scribd-Unternehmen logo
1 von 39
Downloaden Sie, um offline zu lesen
Gute Zeilen, schlechte Zeilen
Regeln für wartbare Programme
Java User Group Ostfalen, 29.08.2013
Dirk Weil, GEDOPLAN GmbH
Dirk Weil
GEDOPLAN GmbH, Bielefeld
Java EE seit 1998
Konzeption und
Realisierung
Vorträge
Seminare
Veröffentlichungen
2Gute Zeilen, schlechte Zeilen
3
GUTE
SCHLECHTE
ZEILEN
ZEILEN
Gute Zeilen, schlechte Zeilen
Gibt es guten und schlechten Code?
Software ist (fast) nie fertig
Software wird (meist) im Team entwickelt
Teams ändern sich über die Zeit
Software muss verständlich sein
4Gute Zeilen, schlechte Zeilen
Gibt es guten und schlechten Code?
Entwicklerteams sind meist heterogen
Berufserfahrung
Programmierstil
…
Richtlinien helfen
bei der Einarbeitung in fremde Software
bei der (Weiter-) Entwicklung
5Gute Zeilen, schlechte Zeilen
Richtlinien
6
Low Level: Namen, Formatierung …
Grundlegendes Klassendesign
Code-Komplexität
Anwendungsstruktur
Gute Zeilen, schlechte Zeilen
Statische Code-Analyse
Matching des Codes gegen Regelsätze
Einfache (Text-)Pattern … strukturelle Pattern
7
Checkstyle
Gute Zeilen, schlechte Zeilen
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
8Gute Zeilen, schlechte Zeilen
Dokumentation
API-Dokumentation
veröffentlichen
Source-Jars erzeugen,
z. B. mit Maven
ermöglicht Unter-
stützung durch
die IDE
9
<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>
Gute Zeilen, schlechte Zeilen
Dokumentation
Erklärungsbedürftige Codesequenzen
Trivialdokumentation ist überflüssig
10
/*
* 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)
…
// Neue Weichenstellung protokollieren
this.logger.trace(this + ": setStellung(" + stellung + ")");
Gute Zeilen, schlechte Zeilen
Namen
Klassen, Variablen, Methoden entsprechend ihrer Aufgabe benennen
spart umfangreiche Dokumentation
Well-Known Names nicht umdeuten!
Anschauungsbeispiel: "Nothalt-Funktion"
Anlagenstatus ist zu generell
Methode setzt den Status nicht, sondern toggelt
setXyz ist well-known mit anderer Bedeutung
11
public void setAnlagenstatus()
{
Anlagenstatus.getInstance().changeAnlagenstatus();
Gute Zeilen, schlechte Zeilen
Namen
Keine Präfixnotation für Typen, Sichtbarkeit etc.:
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
12
Instanzvariable Name beginnt mit m_
Variable vom Typ List<Integer> Name beginnt mit lI_
Interface Name beginnt mit I
… …
Gute Zeilen, schlechte Zeilen
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
…
13Gute Zeilen, schlechte Zeilen
Formatierung
Code sollte im Team einheitlich formatiert sein
Einrückung (Tab/Blanks, wie viele?)
Platzierung von {
Zeilenumbruch
…
Vorteile
Code liest sich leichter
kleinere Change Sets im SCM
Lässt sich mit IDE-Komfort leicht erreichen
Save action: Format code
14Gute Zeilen, schlechte Zeilen
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
15Gute Zeilen, schlechte Zeilen
equals, hashCode
Jedes Geschäftsobjekt sollte equals und hashCode definieren
IDEs bieten gute Unterstützung
Achtung bei equals in Basisklassen
16
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
switch
Regeln:
default nicht vergessen
kein Fall Through
CS: Missing Switch Default, Fall Through
17Gute Zeilen, schlechte Zeilen
Protokollierung
keine Protokollausgabe auf stdout, stderr
"Mal schnell 'ne Ausgabe"
Achtung: IDE-Templates!
CS: Regexp… mit passendem Pattern
18Gute Zeilen, schlechte Zeilen
Exception-Verwendung
Werfen und Fangen von Throwable, Exception,
RuntimeException i. A. fehlerhaft
CS: Illegal Catch, Illegal Throws
19Gute Zeilen, schlechte Zeilen
DRY
Keine Copy&Paste-Programmierung
CS: Strict Duplicate Code
(nicht wirklich empfehlenswert)
20Gute Zeilen, schlechte Zeilen
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!)
21Gute Zeilen, schlechte Zeilen
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
22Gute Zeilen, schlechte Zeilen
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
23Gute Zeilen, schlechte Zeilen
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
24Gute Zeilen, schlechte Zeilen
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
25Gute Zeilen, schlechte Zeilen
Klassen sparen lohnt nicht
Anschauungsbeispiel "Wachdienst"
Besser: Zusätzliche Ebene für Etagen
Klares Konzept
Real World Klasse
26Gute Zeilen, schlechte Zeilen
Wohin mit der Logik?
27Gute Zeilen, schlechte Zeilen
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
28Gute Zeilen, schlechte Zeilen
Wohin mit der Logik?
Anschauungsbeispiel "Modellbahnsteuerung":
1. Ansatz: Iteration über Fahrstraßenelemente im Webservice
Nachteile:
nicht wieder-
verwendbar, da
im Webservice
"Polymorphie
für Arme"
(instanceof
~ goto der OO)
29
@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(…);
}
…
Gute Zeilen, schlechte Zeilen
Wohin mit der Logik?
Anschauungsbeispiel "Modellbahnsteuerung":
Besser: Platzierung der Logik in Fahrstrasse,
abstrakte Methode statt expliziter Typabfrage
30
@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
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
31Gute Zeilen, schlechte Zeilen
In Objekten denken
Anschauungsbeispiel: 1:n-Relation (JPA)
Query "Suche Books eines Publishers"
(Warum so kompliziert?):
32
@Entity
public class Publisher
{
@Id @GeneratedValue Integer id;
@OneToMany(mappedBy = "publisher") List<Book> books;
…
@Entity
public class Book
{
@Id @GeneratedValue Integer id;
@ManyToOne Publisher publisher;
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
Packages
Zwei Anti-Beispiele
33Gute Zeilen, schlechte Zeilen
Anekdoten
34
String name = new String();
name = "Hugo";
if (val != null && ("" + val.getClass().getName()).equals("java.lang.String"))
Set<String> texte = …;
Set<Object> labels = new TreeSet<>();
labels.addAll(texte);
int adr = …;
String adrAsString = new Integer(adr).toString();
Offensichtlich komplett falsche Vorstellung
von Objekten und Referenzen darauf
instanceof
Sind die Labels nicht Texte? Warum dann Set<Object>?
Wenn unterschiedliche Typen erlaubt: Set<?>
Integer.toString(adr)
Gute Zeilen, schlechte Zeilen
Anekdoten
35
public void changeRichtung()
{
if (isRueckwaerts())
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;
}
setRueckwaerts(!isRueckwaerts())
public static final Anlagenstatus
= new Anlagenstatus()
Noch besser: enum-Singleton
Gute Zeilen, schlechte Zeilen
Anekdoten
36
@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)
{
Auto car1 = ...;
Auto car2 = ...;
if (car1.getId().getValue().equals(car2.getId().getValue()))
{
...
Gute Zeilen, schlechte Zeilen
int menge
if (car1.equals(car2))
Anekdoten
37
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
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
38 Gute Zeilen, schlechte Zeilen
Mehr?
Seminare zum Thema Java SE und Java EE, z. B.
Java Effective
Power Workshop Java EE
http://ips-it-schulungen.de/Kurse/Java
Fragen!
dirk.weil@gedoplan.de
39Gute Zeilen, schlechte Zeilen

Weitere ähnliche Inhalte

Andere mochten auch

Ms 05 management of machines and materials
Ms 05 management of machines and materialsMs 05 management of machines and materials
Ms 05 management of machines and materialssmumbahelp
 
Mit4022 network security
Mit4022  network securityMit4022  network security
Mit4022 network securitysmumbahelp
 
Bca2010 – operating system
Bca2010 – operating systemBca2010 – operating system
Bca2010 – operating systemsmumbahelp
 
Mh0056 – public relations & marketing for healthcare organizations
Mh0056 – public relations & marketing for healthcare organizationsMh0056 – public relations & marketing for healthcare organizations
Mh0056 – public relations & marketing for healthcare organizationssmumbahelp
 
International business
International businessInternational business
International businesssmumbahelp
 
Ib0014 certificate in export import management
Ib0014   certificate in export import managementIb0014   certificate in export import management
Ib0014 certificate in export import managementsmumbahelp
 
Bt0082, visual basic
Bt0082, visual basicBt0082, visual basic
Bt0082, visual basicsmumbahelp
 
Construction management
Construction managementConstruction management
Construction managementsmumbahelp
 
Ma0044 & institutional banking
Ma0044 & institutional bankingMa0044 & institutional banking
Ma0044 & institutional bankingsmumbahelp
 

Andere mochten auch (11)

Ms 05 management of machines and materials
Ms 05 management of machines and materialsMs 05 management of machines and materials
Ms 05 management of machines and materials
 
Mit4022 network security
Mit4022  network securityMit4022  network security
Mit4022 network security
 
Bca2010 – operating system
Bca2010 – operating systemBca2010 – operating system
Bca2010 – operating system
 
Mh0056 – public relations & marketing for healthcare organizations
Mh0056 – public relations & marketing for healthcare organizationsMh0056 – public relations & marketing for healthcare organizations
Mh0056 – public relations & marketing for healthcare organizations
 
International business
International businessInternational business
International business
 
Ib0014 certificate in export import management
Ib0014   certificate in export import managementIb0014   certificate in export import management
Ib0014 certificate in export import management
 
Bt0082, visual basic
Bt0082, visual basicBt0082, visual basic
Bt0082, visual basic
 
Construction management
Construction managementConstruction management
Construction management
 
5 Digital Marketing Strategies
5 Digital Marketing Strategies5 Digital Marketing Strategies
5 Digital Marketing Strategies
 
Ma0044 & institutional banking
Ma0044 & institutional bankingMa0044 & institutional banking
Ma0044 & institutional banking
 
alpaEOS Flyer
alpaEOS FlyeralpaEOS Flyer
alpaEOS Flyer
 

Ähnlich wie Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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 1Gregor Biswanger
 
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...GFU Cyrus AG
 
Puppet: Designing modules & repositories
Puppet: Designing modules & repositoriesPuppet: Designing modules & repositories
Puppet: Designing modules & repositoriesinovex GmbH
 
Advanced Refactoring Patterns
Advanced Refactoring PatternsAdvanced Refactoring Patterns
Advanced Refactoring PatternsHendrik Lösch
 
Advanced Refactoring Patterns - Dev Day 2018
Advanced Refactoring Patterns - Dev Day 2018Advanced Refactoring Patterns - Dev Day 2018
Advanced Refactoring Patterns - Dev Day 2018Hendrik Lösch
 
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 - LEDAMarcus Riemer
 
Fundamentale Muster in Java
Fundamentale Muster in JavaFundamentale Muster in Java
Fundamentale Muster in Javatutego
 
Metaprogrammierung und Reflection
Metaprogrammierung und ReflectionMetaprogrammierung und Reflection
Metaprogrammierung und ReflectionStefan Marr
 
IfN Studienarbeit Abschlusspres 18.9.2007
IfN Studienarbeit Abschlusspres 18.9.2007IfN Studienarbeit Abschlusspres 18.9.2007
IfN Studienarbeit Abschlusspres 18.9.2007derDoc
 
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 singengedoplan
 
The Lotus Code Cookbook
The Lotus Code CookbookThe Lotus Code Cookbook
The Lotus Code CookbookUlrich Krause
 
TYPO3 coding guidelines
TYPO3 coding guidelinesTYPO3 coding guidelines
TYPO3 coding guidelinesAlex Kellner
 
Domain Driven Design in Rails
Domain Driven Design in RailsDomain Driven Design in Rails
Domain Driven Design in RailsAngelo Maron
 
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 Umsetzunginovex GmbH
 
Neue Features der Java EE 6
Neue Features der Java EE 6Neue Features der Java EE 6
Neue Features der Java EE 6GFU Cyrus AG
 

Ähnlich wie Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013 (20)

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
 
Workshop: Besseres C#
Workshop: Besseres C#Workshop: Besseres C#
Workshop: Besseres C#
 
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...
 
Puppet: Designing modules & repositories
Puppet: Designing modules & repositoriesPuppet: Designing modules & repositories
Puppet: Designing modules & repositories
 
Advanced Refactoring Patterns
Advanced Refactoring PatternsAdvanced Refactoring Patterns
Advanced Refactoring Patterns
 
Advanced Refactoring Patterns - Dev Day 2018
Advanced Refactoring Patterns - Dev Day 2018Advanced Refactoring Patterns - Dev Day 2018
Advanced Refactoring Patterns - Dev Day 2018
 
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
 
Fundamentale Muster in Java
Fundamentale Muster in JavaFundamentale Muster in Java
Fundamentale Muster in Java
 
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
 
Metaprogrammierung und Reflection
Metaprogrammierung und ReflectionMetaprogrammierung und Reflection
Metaprogrammierung und Reflection
 
IfN Studienarbeit Abschlusspres 18.9.2007
IfN Studienarbeit Abschlusspres 18.9.2007IfN Studienarbeit Abschlusspres 18.9.2007
IfN Studienarbeit Abschlusspres 18.9.2007
 
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
 
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
 
The Lotus Code Cookbook
The Lotus Code CookbookThe Lotus Code Cookbook
The Lotus Code Cookbook
 
Drupal inside out
Drupal inside outDrupal inside out
Drupal inside out
 
Web Entwicklung mit PHP - Teil 3 Beta
Web Entwicklung mit PHP - Teil 3 BetaWeb Entwicklung mit PHP - Teil 3 Beta
Web Entwicklung mit PHP - Teil 3 Beta
 
TYPO3 coding guidelines
TYPO3 coding guidelinesTYPO3 coding guidelines
TYPO3 coding guidelines
 
Domain Driven Design in Rails
Domain Driven Design in RailsDomain Driven Design in Rails
Domain Driven Design in Rails
 
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
 
Neue Features der Java EE 6
Neue Features der Java EE 6Neue Features der Java EE 6
Neue Features der Java EE 6
 

Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

  • 1. Gute Zeilen, schlechte Zeilen Regeln für wartbare Programme Java User Group Ostfalen, 29.08.2013 Dirk Weil, GEDOPLAN GmbH
  • 2. Dirk Weil GEDOPLAN GmbH, Bielefeld Java EE seit 1998 Konzeption und Realisierung Vorträge Seminare Veröffentlichungen 2Gute Zeilen, schlechte Zeilen
  • 4. Gibt es guten und schlechten Code? Software ist (fast) nie fertig Software wird (meist) im Team entwickelt Teams ändern sich über die Zeit Software muss verständlich sein 4Gute Zeilen, schlechte Zeilen
  • 5. Gibt es guten und schlechten Code? Entwicklerteams sind meist heterogen Berufserfahrung Programmierstil … Richtlinien helfen bei der Einarbeitung in fremde Software bei der (Weiter-) Entwicklung 5Gute Zeilen, schlechte Zeilen
  • 6. Richtlinien 6 Low Level: Namen, Formatierung … Grundlegendes Klassendesign Code-Komplexität Anwendungsstruktur Gute Zeilen, schlechte Zeilen
  • 7. Statische Code-Analyse Matching des Codes gegen Regelsätze Einfache (Text-)Pattern … strukturelle Pattern 7 Checkstyle Gute Zeilen, schlechte Zeilen
  • 8. 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 8Gute Zeilen, schlechte Zeilen
  • 9. Dokumentation API-Dokumentation veröffentlichen Source-Jars erzeugen, z. B. mit Maven ermöglicht Unter- stützung durch die IDE 9 <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> Gute Zeilen, schlechte Zeilen
  • 10. Dokumentation Erklärungsbedürftige Codesequenzen Trivialdokumentation ist überflüssig 10 /* * 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) … // Neue Weichenstellung protokollieren this.logger.trace(this + ": setStellung(" + stellung + ")"); Gute Zeilen, schlechte Zeilen
  • 11. Namen Klassen, Variablen, Methoden entsprechend ihrer Aufgabe benennen spart umfangreiche Dokumentation Well-Known Names nicht umdeuten! Anschauungsbeispiel: "Nothalt-Funktion" Anlagenstatus ist zu generell Methode setzt den Status nicht, sondern toggelt setXyz ist well-known mit anderer Bedeutung 11 public void setAnlagenstatus() { Anlagenstatus.getInstance().changeAnlagenstatus(); Gute Zeilen, schlechte Zeilen
  • 12. Namen Keine Präfixnotation für Typen, Sichtbarkeit etc.: 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 12 Instanzvariable Name beginnt mit m_ Variable vom Typ List<Integer> Name beginnt mit lI_ Interface Name beginnt mit I … … Gute Zeilen, schlechte Zeilen
  • 13. 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 … 13Gute Zeilen, schlechte Zeilen
  • 14. Formatierung Code sollte im Team einheitlich formatiert sein Einrückung (Tab/Blanks, wie viele?) Platzierung von { Zeilenumbruch … Vorteile Code liest sich leichter kleinere Change Sets im SCM Lässt sich mit IDE-Komfort leicht erreichen Save action: Format code 14Gute Zeilen, schlechte Zeilen
  • 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 15Gute Zeilen, schlechte Zeilen
  • 16. equals, hashCode Jedes Geschäftsobjekt sollte equals und hashCode definieren IDEs bieten gute Unterstützung Achtung bei equals in Basisklassen 16 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
  • 17. switch Regeln: default nicht vergessen kein Fall Through CS: Missing Switch Default, Fall Through 17Gute Zeilen, schlechte Zeilen
  • 18. Protokollierung keine Protokollausgabe auf stdout, stderr "Mal schnell 'ne Ausgabe" Achtung: IDE-Templates! CS: Regexp… mit passendem Pattern 18Gute Zeilen, schlechte Zeilen
  • 19. Exception-Verwendung Werfen und Fangen von Throwable, Exception, RuntimeException i. A. fehlerhaft CS: Illegal Catch, Illegal Throws 19Gute Zeilen, schlechte Zeilen
  • 20. DRY Keine Copy&Paste-Programmierung CS: Strict Duplicate Code (nicht wirklich empfehlenswert) 20Gute Zeilen, schlechte Zeilen
  • 21. 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!) 21Gute Zeilen, schlechte Zeilen
  • 22. 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 22Gute Zeilen, schlechte Zeilen
  • 23. 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 23Gute Zeilen, schlechte Zeilen
  • 24. 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 24Gute Zeilen, schlechte Zeilen
  • 25. 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 25Gute Zeilen, schlechte Zeilen
  • 26. Klassen sparen lohnt nicht Anschauungsbeispiel "Wachdienst" Besser: Zusätzliche Ebene für Etagen Klares Konzept Real World Klasse 26Gute Zeilen, schlechte Zeilen
  • 27. Wohin mit der Logik? 27Gute Zeilen, schlechte Zeilen
  • 28. 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 28Gute Zeilen, schlechte Zeilen
  • 29. Wohin mit der Logik? Anschauungsbeispiel "Modellbahnsteuerung": 1. Ansatz: Iteration über Fahrstraßenelemente im Webservice Nachteile: nicht wieder- verwendbar, da im Webservice "Polymorphie für Arme" (instanceof ~ goto der OO) 29 @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(…); } … Gute Zeilen, schlechte Zeilen
  • 30. Wohin mit der Logik? Anschauungsbeispiel "Modellbahnsteuerung": Besser: Platzierung der Logik in Fahrstrasse, abstrakte Methode statt expliziter Typabfrage 30 @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
  • 31. 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 31Gute Zeilen, schlechte Zeilen
  • 32. In Objekten denken Anschauungsbeispiel: 1:n-Relation (JPA) Query "Suche Books eines Publishers" (Warum so kompliziert?): 32 @Entity public class Publisher { @Id @GeneratedValue Integer id; @OneToMany(mappedBy = "publisher") List<Book> books; … @Entity public class Book { @Id @GeneratedValue Integer id; @ManyToOne Publisher publisher; 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
  • 34. Anekdoten 34 String name = new String(); name = "Hugo"; if (val != null && ("" + val.getClass().getName()).equals("java.lang.String")) Set<String> texte = …; Set<Object> labels = new TreeSet<>(); labels.addAll(texte); int adr = …; String adrAsString = new Integer(adr).toString(); Offensichtlich komplett falsche Vorstellung von Objekten und Referenzen darauf instanceof Sind die Labels nicht Texte? Warum dann Set<Object>? Wenn unterschiedliche Typen erlaubt: Set<?> Integer.toString(adr) Gute Zeilen, schlechte Zeilen
  • 35. Anekdoten 35 public void changeRichtung() { if (isRueckwaerts()) 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; } setRueckwaerts(!isRueckwaerts()) public static final Anlagenstatus = new Anlagenstatus() Noch besser: enum-Singleton Gute Zeilen, schlechte Zeilen
  • 36. Anekdoten 36 @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) { Auto car1 = ...; Auto car2 = ...; if (car1.getId().getValue().equals(car2.getId().getValue())) { ... Gute Zeilen, schlechte Zeilen int menge if (car1.equals(car2))
  • 37. Anekdoten 37 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
  • 38. 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 38 Gute Zeilen, schlechte Zeilen
  • 39. Mehr? Seminare zum Thema Java SE und Java EE, z. B. Java Effective Power Workshop Java EE http://ips-it-schulungen.de/Kurse/Java Fragen! dirk.weil@gedoplan.de 39Gute Zeilen, schlechte Zeilen