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
4 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
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
5 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
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
8 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
9. Dokumentation
• API-Dokumentation veröffentlichen
– Source-Jars <plugin>
erzeugen, <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
z. B. mit Maven <inherited>true</inherited>
<executions>
<execution>
<id>attach-sources</id>
– ermöglicht Unter- <phase>verify</phase>
<goals>
stützung durch <goal>jar-no-fork</goal>
</goals>
die IDE </execution>
</executions>
</plugin>
9 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
10. 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 + ")");
10 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
11. 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
11 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
12. 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
(was wäre wohl der Präfix für Map<String, Lok> ?)
– werden durch IDE-Unterstützung mehr als ersetzt
– this. ist aussagekräftiger (OO) als m_
– Unterscheidung Klasse vs. Interface zweitrangig
12 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
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
–…
13 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
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
14 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
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
15 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
16. 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
{
…
16 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
17. switch
• Regeln:
– default nicht vergessen
– kein Fall Through
• CS: Missing Switch Default, Fall Through
17 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
18. Protokollierung
• keine Protokollausgabe auf stdout, stderr
• "Mal schnell 'ne Ausgabe"
• Achtung: IDE-Templates!
• CS: Regexp… mit passendem Pattern
18 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
19. Exception-Verwendung
• Werfen und Fangen von Throwable,
Exception, RuntimeException i. A. fehlerhaft
• CS: Illegal Catch, Illegal Throws
19 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
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!)
21 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
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
23 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
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
24 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
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
25 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
26. Klassen sparen lohnt nicht
• Anschauungsbeispiel "Wachdienst"
– Besser: Zusätzliche Ebene für Etagen
– Klares Konzept
Real World Klasse
26 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
27. Wohin mit der Logik?
27 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
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
28 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
29. Wohin mit der Logik?
• Anschauungsbeispiel "Modellbahnsteuerung":
– 1. Ansatz: Iteration über Fahrstraßenelemente im
Webservice @POST
@Path("/fahrstrasse/{bereich}/{name}/reserviert")
public Response setFahrstrassenreservierung(...)
{
– Nachteile: Fahrstrasse fahrstrasse = …
for (FahrstrassenElement fe
• nicht wieder- : fahrstrasse.getElemente())
verwendbar, da {
Fahrwegelement fwe = fe.getFahrwegelement();
im Webservice if (fwe instanceof Weiche)
• "Polymorphie {
Weiche w = (Weiche) fwe;
für Arme" w.setStellung(…);
}
…
29 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
30. 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);
30 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
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
31 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
32. In Objekten denken
• Anschauungsbeispiel: 1:n-Relation (JPA)
@Entity
public class Book
{
@Entity @Id @GeneratedValue Integer id;
public class Publisher @ManyToOne Publisher 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();
32 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de