Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

342 views
312 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
342
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
8
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Gute Zeilen schlechte Zeilen, JUG Ostfalen 29.8.2013

  1. 1. Gute Zeilen, schlechte Zeilen Regeln für wartbare Programme Java User Group Ostfalen, 29.08.2013 Dirk Weil, GEDOPLAN GmbH
  2. 2. Dirk Weil GEDOPLAN GmbH, Bielefeld Java EE seit 1998 Konzeption und Realisierung Vorträge Seminare Veröffentlichungen 2Gute Zeilen, schlechte Zeilen
  3. 3. 3 GUTE SCHLECHTE ZEILEN ZEILEN Gute Zeilen, schlechte Zeilen
  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 sein 4Gute Zeilen, schlechte Zeilen
  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-) Entwicklung 5Gute Zeilen, schlechte Zeilen
  6. 6. Richtlinien 6 Low Level: Namen, Formatierung … Grundlegendes Klassendesign Code-Komplexität Anwendungsstruktur Gute Zeilen, schlechte Zeilen
  7. 7. Statische Code-Analyse Matching des Codes gegen Regelsätze Einfache (Text-)Pattern … strukturelle Pattern 7 Checkstyle Gute Zeilen, schlechte Zeilen
  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 = true 8Gute Zeilen, schlechte Zeilen
  9. 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. 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. 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. 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. 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. 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. 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. 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. 17. switch Regeln: default nicht vergessen kein Fall Through CS: Missing Switch Default, Fall Through 17Gute Zeilen, schlechte Zeilen
  18. 18. Protokollierung keine Protokollausgabe auf stdout, stderr "Mal schnell 'ne Ausgabe" Achtung: IDE-Templates! CS: Regexp… mit passendem Pattern 18Gute Zeilen, schlechte Zeilen
  19. 19. Exception-Verwendung Werfen und Fangen von Throwable, Exception, RuntimeException i. A. fehlerhaft CS: Illegal Catch, Illegal Throws 19Gute Zeilen, schlechte Zeilen
  20. 20. DRY Keine Copy&Paste-Programmierung CS: Strict Duplicate Code (nicht wirklich empfehlenswert) 20Gute Zeilen, schlechte Zeilen
  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!) 21Gute Zeilen, schlechte Zeilen
  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 Typparametern 22Gute Zeilen, schlechte Zeilen
  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 Entities 23Gute Zeilen, schlechte Zeilen
  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 abgehakt 24Gute Zeilen, schlechte Zeilen
  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-Daten 25Gute Zeilen, schlechte Zeilen
  26. 26. Klassen sparen lohnt nicht Anschauungsbeispiel "Wachdienst" Besser: Zusätzliche Ebene für Etagen Klares Konzept Real World Klasse 26Gute Zeilen, schlechte Zeilen
  27. 27. Wohin mit der Logik? 27Gute Zeilen, schlechte Zeilen
  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 Webservice 28Gute Zeilen, schlechte Zeilen
  29. 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. 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. 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. 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
  33. 33. Packages Zwei Anti-Beispiele 33Gute Zeilen, schlechte Zeilen
  34. 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. 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. 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. 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. 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. 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

×