Gute Zeilen, schlechte ZeilenRegeln für wartbare Programme       Dirk Weil | GEDOPLAN
Dirk Weil    • GEDOPLAN GmbH, Bielefeld    • Java EE seit 1998    • Konzeption und      Realisierung    • Vorträge    • Se...
GUTE           ZEILEN           SCHLECHTE           ZEILEN3   Gute Zeilen, schlechte Zeilen   dirk.weil@gedoplan.de
Gibt es guten und schlechten Code?    • Software ist (fast) nie fertig    • Software wird (meist) im Team entwickelt    • ...
Gibt es guten und schlechten Code?    • Entwicklerteams sind meist heterogen      – Berufserfahrung      – Programmierstil...
Richtlinien    Low Level: Namen, Formatierung …      Grundlegendes Klassendesign            Code-Komplexität          Anwe...
Statische Code-Analyse    • Matching des Codes gegen Regelsätze    • Einfache (Text-)Pattern … strukturelle Pattern       ...
Dokumentation    • Javadoc für API      – Klassen, Interfaces,        Methoden, Variablen      – public, protected      – ...
Dokumentation    • API-Dokumentation veröffentlichen      – Source-Jars                <plugin>        erzeugen,          ...
Dokumentation     • Erklärungsbedürftige Codesequenzen       /*        * Fahrstrassen innerhalb von Fahrstrassen expandier...
Namen     • Klassen, Variablen, Methoden entsprechend ihrer       Aufgabe benennen       – spart umfangreiche Dokumentatio...
Namen     • Keine Präfixnotation für Typen, Sichtbarkeit etc.:        Instanzvariable                                   Na...
Namen     • CS kann Namenskonventionen prüfen       (Module group Naming Conventions)     • IDE-Komfort nutzen!       – Qu...
Formatierung     • Code sollte im Team einheitlich formatiert sein       – Einrückung (Tab/Blanks, wie viele?)       – Pla...
equals, hashCode     • equals definieren   hashCode definieren     • nicht nur equals(MyType)     • Codeanalyse:       – C...
equals, hashCode      • Jedes Geschäftsobjekt sollte equals und        hashCode definieren      • IDEs bieten gute Unterst...
switch     • Regeln:       – default nicht vergessen       – kein Fall Through     • CS: Missing Switch Default, Fall Thro...
Protokollierung     • keine Protokollausgabe auf stdout, stderr     • "Mal schnell ne Ausgabe"     • Achtung: IDE-Template...
Exception-Verwendung     • Werfen und Fangen von Throwable,       Exception, RuntimeException i. A. fehlerhaft     • CS: I...
DRY     • Keine Copy&Paste-Programmierung     • CS: Strict Duplicate Code       (nicht wirklich empfehlenswert)20         ...
Komplexität     • Klassen / Methoden nicht zu lang     • Anzahl Methodenparameter nicht zu groß     • CS: Maximum Method L...
Einfach machen     • Einfache Lösungen sind gute Lösungen     • Vorsicht bei:       – Reflection          • extrem schlech...
Einfach machen     • Anschauungsbeispiel: Entity Editor       – Generischer Editor für Geschäftsobjekte       – Steuerung ...
Klassen sparen lohnt nicht     • Anschauungsbeispiel "Wachdienst":       – Gebäudekontrolle durch Prüfung aller Räume     ...
Klassen sparen lohnt nicht     • Anschauungsbeispiel "Wachdienst"       – 1. Ansatz: Keine Klasse für Etage       – Dialog...
Klassen sparen lohnt nicht     • Anschauungsbeispiel "Wachdienst"       – Besser: Zusätzliche Ebene für Etagen       – Kla...
Wohin mit der Logik?27     Gute Zeilen, schlechte Zeilen   dirk.weil@gedoplan.de
Wohin mit der Logik?     • Anschauungsbeispiel "Modellbahnsteuerung":       – Reservieren einer Fahrstraße         = Stell...
Wohin mit der Logik?     • Anschauungsbeispiel "Modellbahnsteuerung":       – 1. Ansatz: Iteration über Fahrstraßenelement...
Wohin mit der Logik?      • Anschauungsbeispiel "Modellbahnsteuerung":           – Besser:               • Platzierung der...
Wohin mit der Logik?     • Geschäftslogik in Geschäftslogik-Schicht       – CDI, EJB, JPA, …     • Präsentationslogik bspw...
In Objekten denken      • Anschauungsbeispiel: 1:n-Relation (JPA)                                         @Entity         ...
Packages     • Zwei Anti-Beispiele33                 Gute Zeilen, schlechte Zeilen   dirk.weil@gedoplan.de
Anekdoten     String name = new String();     name = "Hugo";         if (val != null && ("" + val.getClass().getName()).eq...
Anekdoten     public void changeRichtung()     {       if (isRueckwaerts())         setRueckwaerts(false);       else     ...
Anekdoten     @POST     @Path("artikel/{artNr}/menge")     public Response setSpeed(@PathParam("artNr") String adrNr,     ...
Anekdoten     if (this.kommPunkt.isTurnText())     {       g2.setFont(system.getKommPunktFont());       g2.translate(kommP...
Gute Zeilen, schlechte Zeilen   dirk.weil@gedoplan.de
Nächste SlideShare
Wird geladen in …5
×

Vortrag Dirk Weil Gute zeilen, schlechte Zeilen auf der JAX 2012

1.445 Aufrufe

Veröffentlicht am

Gute zeilen, schlechte Zeilen - Vortrag Dirk Weil auf der JAX 2012. IPS Stand JAX 2012.

0 Kommentare
0 Gefällt mir
Statistik
Notizen
  • Als Erste(r) kommentieren

  • Gehören Sie zu den Ersten, denen das gefällt!

Keine Downloads
Aufrufe
Aufrufe insgesamt
1.445
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
400
Aktionen
Geteilt
0
Downloads
15
Kommentare
0
Gefällt mir
0
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie

Vortrag Dirk Weil Gute zeilen, schlechte Zeilen auf der JAX 2012

  1. 1. Gute Zeilen, schlechte ZeilenRegeln für wartbare Programme Dirk Weil | GEDOPLAN
  2. 2. Dirk Weil • GEDOPLAN GmbH, Bielefeld • Java EE seit 1998 • Konzeption und Realisierung • Vorträge • Seminare • Veröffentlichungen2 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  3. 3. GUTE ZEILEN SCHLECHTE ZEILEN3 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  4. 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 sein4 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  5. 5. Gibt es guten und schlechten Code? • Entwicklerteams sind meist heterogen – Berufserfahrung – Programmierstil –… • Richtlinien helfen – bei der Einarbeitung in fremde Software – bei der (Weiter-) Entwicklung5 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  6. 6. Richtlinien Low Level: Namen, Formatierung … Grundlegendes Klassendesign Code-Komplexität Anwendungsstruktur6 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  7. 7. Statische Code-Analyse • Matching des Codes gegen Regelsätze • Einfache (Text-)Pattern … strukturelle Pattern Checkstyle7 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  8. 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 = true8 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  9. 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. 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. 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 Bedeutung11 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  12. 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 zweitrangig12 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  13. 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. 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 code14 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  15. 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.hashCode15 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  16. 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. 17. switch • Regeln: – default nicht vergessen – kein Fall Through • CS: Missing Switch Default, Fall Through17 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  18. 18. Protokollierung • keine Protokollausgabe auf stdout, stderr • "Mal schnell ne Ausgabe" • Achtung: IDE-Templates! • CS: Regexp… mit passendem Pattern18 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  19. 19. Exception-Verwendung • Werfen und Fangen von Throwable, Exception, RuntimeException i. A. fehlerhaft • CS: Illegal Catch, Illegal Throws19 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  20. 20. DRY • Keine Copy&Paste-Programmierung • CS: Strict Duplicate Code (nicht wirklich empfehlenswert)20 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  21. 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
  22. 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 Typparametern22 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  23. 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 Entities23 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  24. 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 abgehakt24 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  25. 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-Daten25 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  26. 26. Klassen sparen lohnt nicht • Anschauungsbeispiel "Wachdienst" – Besser: Zusätzliche Ebene für Etagen – Klares Konzept Real World Klasse26 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  27. 27. Wohin mit der Logik?27 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  28. 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 Webservice28 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  29. 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. 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. 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 übersichtlicher31 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  32. 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
  33. 33. Packages • Zwei Anti-Beispiele33 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  34. 34. Anekdoten 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();34 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  35. 35. Anekdoten 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; }35 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  36. 36. 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) { Auto car1 = ...; Auto car2 = ...; if (car1.getId().getValue().equals(car2.getId().getValue())) { ...36 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  37. 37. 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); }37 Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de
  38. 38. Gute Zeilen, schlechte Zeilen dirk.weil@gedoplan.de

×