gute zeilen schlechte zeilen, jug ostfalen 29.8.2013

39
Gute Zeilen, schlechte Zeilen Regeln für wartbare Programme Java User Group Ostfalen, 29.08.2013 Dirk Weil, GEDOPLAN GmbH

Upload: gedoplan

Post on 19-Jun-2015

235 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Gute Zeilen, schlechte Zeilen

Regeln für wartbare Programme

Java User Group Ostfalen, 29.08.2013

Dirk Weil, GEDOPLAN GmbH

Page 2: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Dirk Weil

GEDOPLAN GmbH, Bielefeld

Java EE seit 1998

Konzeption undRealisierung

Vorträge

Seminare

Veröffentlichungen

2Gute Zeilen, schlechte Zeilen

Page 3: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

3

GUTE

SCHLECHTE

ZEILEN

ZEILEN

Gute Zeilen, schlechte Zeilen

Page 4: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 5: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 6: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Richtlinien

6

Low Level: Namen, Formatierung …

Grundlegendes Klassendesign

Code-Komplexität

Anwendungsstruktur

Gute Zeilen, schlechte Zeilen

Page 7: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Statische Code-Analyse

Matching des Codes gegen Regelsätze

Einfache (Text-)Pattern … strukturelle Pattern

7

Checkstyle

Gute Zeilen, schlechte Zeilen

Page 8: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Dokumentation

Javadoc für API

Klassen, Interfaces,Methoden, Variablen

public , protected

Kontrolle bspw. per CheckstyleJavadoc Comments

Prüft per Default auch private� scope = protected

Getter/Setter-Doku meist überflüssig� allowMissingPropertyJavadoc = true

8Gute Zeilen, schlechte Zeilen

Page 9: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Dokumentation

API-Dokumentationveröffentlichen

Source-Jars erzeugen,z. B. mit Maven

ermöglicht Unter-stützung durchdie 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

Page 10: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 11: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 12: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 13: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 14: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 15: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 16: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 17: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

switch

Regeln:

default nicht vergessen

kein Fall Through

CS: Missing Switch Default, Fall Through

17Gute Zeilen, schlechte Zeilen

Page 18: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Protokollierung

keine Protokollausgabe auf stdout , stderr

"Mal schnell 'ne Ausgabe"

Achtung: IDE-Templates!

CS: Regexp…mit passendem Pattern

18Gute Zeilen, schlechte Zeilen

Page 19: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Exception-Verwendung

Werfen und Fangen von Throwable , Exception , RuntimeException i. A. fehlerhaft

CS: Illegal Catch , Illegal Throws

19Gute Zeilen, schlechte Zeilen

Page 20: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

DRY

Keine Copy&Paste-Programmierung

CS: Strict Duplicate Code(nicht wirklich empfehlenswert)

20Gute Zeilen, schlechte Zeilen

Page 21: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Komplexität

Klassen / Methoden nicht zu lang

Anzahl Methodenparameter nicht zu groß

CS: Maximum Method Length , Maximum Parameters , Maximum File Length , Cyclomatic Complexity(Anwendung imTeam diskutieren!)

21Gute Zeilen, schlechte Zeilen

Page 22: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Einfach machen

Einfache Lösungen sind gute Lösungen

Vorsicht bei:

Reflectionextrem schlecht lesbar

Refactoring problematisch

hochgradig konfigurierbaren Klassenschwer nutzbar (bspw. GridBagConstraints )

übermäßigem Einsatz von Typparametern

22Gute Zeilen, schlechte Zeilen

Page 23: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 24: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Klassen sparen lohnt nicht

Anschauungsbeispiel "Wachdienst":

Gebäudekontrolle durch Prüfung aller Räume

Räume sind auf Etagen verteilt

Kontrollierte Räumewerden abgehakt

24Gute Zeilen, schlechte Zeilen

Page 25: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Klassen sparen lohnt nicht

Anschauungsbeispiel "Wachdienst"

1. Ansatz: Keine Klasse für Etage

Dialogaufbau unnötig kompliziert(~ Gruppenwechsel)

Kein Platz für zukünftige Erweiterungum Etagen-Daten

25Gute Zeilen, schlechte Zeilen

Page 26: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Klassen sparen lohnt nicht

Anschauungsbeispiel "Wachdienst"

Besser: Zusätzliche Ebene für Etagen

Klares KonzeptReal World � Klasse

26Gute Zeilen, schlechte Zeilen

Page 27: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Wohin mit der Logik?

27Gute Zeilen, schlechte Zeilen

Page 28: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Wohin mit der Logik?

Anschauungsbeispiel "Modellbahnsteuerung":

Reservieren einer Fahrstraße=Stellen der betroffenen

Weichen und Signale

Fahrstrasse liegt alsGeschäftsobjekt vor

Anforderung als Webservice

28Gute Zeilen, schlechte Zeilen

Page 29: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Wohin mit der Logik?

Anschauungsbeispiel "Modellbahnsteuerung":

1. Ansatz: Iteration über Fahrstraßenelemente im Webservice

Nachteile:nicht wieder-verwendbar, daim Webservice

"Polymorphiefü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

Page 30: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 31: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 32: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 33: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

Packages

Zwei Anti-Beispiele

33Gute Zeilen, schlechte Zeilen

Page 34: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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 Vorstellungvon 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

Page 35: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 36: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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))

Page 37: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 38: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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

Page 39: Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

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!

[email protected]

39Gute Zeilen, schlechte Zeilen