Gute zeilen, schlechte zeilen - Regeln für wartbare Software

50 %
50 %
Information about Gute zeilen, schlechte zeilen - Regeln für wartbare Software
Technology

Published on February 17, 2014

Author: gedoplan

Source: slideshare.net

Description

GEDOPLAN-Vortrag zum Thema Qualität von (Java-)Software: Clean Code, Code-Analyse, Architektur, Qualitätssicherung. (www.gedoplan.de)

Gute Zeilen, schlechte Zeilen Regeln für wartbare Programme Dirk Weil, GEDOPLAN GmbH

Dirk Weil GEDOPLAN GmbH, Bielefeld Java EE seit 1998 Konzeption und Realisierung Vorträge Seminare Veröffentlichungen Gute Zeilen, schlechte Zeilen 2

GUTE ZEILEN SCHLECHTE ZEILEN Gute Zeilen, schlechte Zeilen 3

Gibt es guten und schlechten Code? Software muss funktional korrekt sein Software muss effizient bearbeitbar sein Ist (fast) nie fertig Wird (meist) im Team entwickelt Teams ändern sich über die Zeit unterschiedliche Berufserfahrung, Programmierstile, … Software muss verständlich sein Gute Zeilen, schlechte Zeilen 4

Richtlinien … helfen bei der Einarbeitung in fremde Software bei der (Weiter-) Entwicklung Low Level: Namen, Formatierung … Grundlegendes Klassendesign Code-Komplexität Anwendungsstruktur Gute Zeilen, schlechte Zeilen 5

Statische Code-Analyse Matching des Codes gegen Regelsätze Einfache (Text-)Pattern … strukturelle Pattern Checkstyle Gute Zeilen, schlechte Zeilen 6

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 Gute Zeilen, schlechte Zeilen 7

Dokumentation API-Dokumentation veröffentlichen Source-Jars erzeugen, z. B. mit Maven ermöglicht Unterstützung durch die IDE Gute Zeilen, schlechte Zeilen <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> 8

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 + ")"); Gute Zeilen, schlechte Zeilen 9

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 Gute Zeilen, schlechte Zeilen 10

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 this. ist aussagekräftiger (OO) als m_ Unterscheidung Klasse vs. Interface zweitrangig werden durch IDE-Unterstützung mehr als ersetzt Gute Zeilen, schlechte Zeilen 11

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 … Gute Zeilen, schlechte Zeilen 12

Formatierung Code sollte im Team einheitlich formatiert sein Einrückung (Tab/Blanks, wie viele?) Platzierung von { … Vorteile Code liest sich leichter kleinere Change Sets im SCM Lässt sich mit IDE-Komfort leicht erreichen Save action: Format code Überprüfung durch Code Checker eher zweitrangig Gute Zeilen, schlechte Zeilen 13

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 { … Gute Zeilen, schlechte Zeilen 14

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 Gute Zeilen, schlechte Zeilen 15

switch Regeln: default nicht vergessen kein Fall Through CS: Missing Switch Default, Fall Through Gute Zeilen, schlechte Zeilen 16

Protokollierung keine Protokollausgabe auf stdout, stderr "Mal schnell 'ne Ausgabe" Achtung: IDE-Templates! CS: Regexp… mit passendem Pattern Gute Zeilen, schlechte Zeilen 17

Exception-Verwendung Werfen und Fangen von Throwable, Exception, RuntimeException i. A. fehlerhaft CS: Illegal Catch, Illegal Throws Gute Zeilen, schlechte Zeilen 18

DRY Keine Copy&Paste-Programmierung CS: Strict Duplicate Code (nicht wirklich empfehlenswert) PMD: Copy Paste Detection Gute Zeilen, schlechte Zeilen 19

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!) Gute Zeilen, schlechte Zeilen 20

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 Gute Zeilen, schlechte Zeilen 21

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 Gute Zeilen, schlechte Zeilen 22

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 Gute Zeilen, schlechte Zeilen 23

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 Gute Zeilen, schlechte Zeilen 24

Klassen sparen lohnt nicht Anschauungsbeispiel "Wachdienst" Besser: Zusätzliche Ebene für Etagen Klares Konzept Real World  Klasse Gute Zeilen, schlechte Zeilen 25

Wohin mit der Logik? Gute Zeilen, schlechte Zeilen 26

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 Gute Zeilen, schlechte Zeilen 27

Wohin mit der Logik? Anschauungsbeispiel "Modellbahnsteuerung": 1. Ansatz: Iteration über Fahrstraßenelemente im Webservice Nachteile: nicht wiederverwendbar, da im Webservice "Polymorphie für Arme" (instanceof ~ goto der OO) Gute Zeilen, schlechte Zeilen @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(…); } … 28

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); Gute Zeilen, schlechte Zeilen 29

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 Gute Zeilen, schlechte Zeilen 30

In Objekten denken Anschauungsbeispiel: 1:n-Relation (JPA) @Entity public class Book { @Id @GeneratedValue Integer id; @ManyToOne Publisher publisher; @Entity public class 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(); Gute Zeilen, schlechte Zeilen 31

Packages Zwei Anti-Beispiele Gute Zeilen, schlechte Zeilen 32

Anekdoten Offensichtlich komplett falsche Vorstellung von Objekten und Referenzen darauf String name = new String(); name = "Hugo"; instanceof if (val != null && ("" + val.getClass().getName()).equals("java.lang.String")) Sind die Labels nicht Texte? Warum dann Set<Object>? Wenn unterschiedliche Typen erlaubt: Set<?> Set<String> texte = …; Set<Object> labels = new TreeSet<>(); labels.addAll(texte); Integer.toString(adr) int adr = …; String adrAsString = new Integer(adr).toString(); Gute Zeilen, schlechte Zeilen 33

Anekdoten setRueckwaerts(!isRueckwaerts()) public static final Anlagenstatus public void changeRichtung() = new Anlagenstatus() { if (isRueckwaerts()) Noch besser: enum-Singleton 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; } Gute Zeilen, schlechte Zeilen 34

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) { int menge Auto car1 = ...; Auto car2 = ...; if (car1.getId().getValue().equals(car2.getId().getValue())) { ... if (car1.equals(car2)) Gute Zeilen, schlechte Zeilen 35

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); } Gute Zeilen, schlechte Zeilen 36

Unit Tests Test der funktionalen Korrektheit auf Unit-Ebene einzelne Klasse isoliert von ihrer Umgebung, ggf. mittels Mock-Objekten als Integrationstests während der Entwicklung als nachträglich Absicherung oder als Vorgehensweise (Test Driven Development) als Qualitätssicherungsmaßnahme automatisiert regelmäßig Gute Zeilen, schlechte Zeilen 37

Unit Tests nicht aufwändiger als Main-Programm zum „Ausprobieren“ public class WaehrungServiceUnitTest { private static WaehrungService WAEHRUNG_SERVICE = new WaehrungService(); @Test public void testUmrechnenUSD() { double actual = WAEHRUNG_SERVICE.umrechnen(100.0, "USD"); assertThat("Euro-Betrag", actual, is(83.41)); } public class WaehrungServiceMain { private static WaehrungService WAEHRUNG_SERVICE = new WaehrungService(); public static void main(String [] args) { BigDecimal actual = WAEHRUNG_SERVICE.umrechnen(100.0, "USD"); System.out.println("100 USD = " + actual + " EUR"); } Gute Zeilen, schlechte Zeilen 38

Unit Tests Testwissen wird explizit gemacht als Einstiegsdokumentation / Tutorial geeignet automatisch, unbedient ausführbar Continuous Integration (Hudson, Jenkins, …) regelmäßige Ausführung aller Tests effizient möglich dauerhafte Qualitätssicherung unverzichtbar für Refactoring und Weiterentwicklung Absicherung gegen „Verschlimmbesserung“ Gute Zeilen, schlechte Zeilen 39

Continuous Integration Manuelle Ausführung reicht nicht belastet den Entwicklungsprozess keine (einheitliche) Veröffentlichung der Ergebnisse keine (einheitliche) Eskalation bei Fehlern An dem Teil habe ich nichts gemacht! Bei mir läuft's! Gute Zeilen, schlechte Zeilen Oh, sorry – das habe ich noch nicht eingecheckt. 40

Continuous Integration Voraussetzung: Projekt enthält ausführbare Tests Junit, TestNG, … Build selbst ist auch ein Test! Gute Zeilen, schlechte Zeilen 41

Continuous Integration Anforderungen an eine Build- und Test-Umgebung Regelmäßige, automatische Ausführung zeitgesteuert ("Daily Build") durch Check-In getriggert … Kompletter Build Ausführung aller Tests Qualitätsprüfung (Style, Coverage, …) Reporting Benachrichtigung Gute Zeilen, schlechte Zeilen 42

Continuous Integration Plan Feedback Test Archiv CI-Umgebung Entw.Umgebung SCM Gute Zeilen, schlechte Zeilen Build 43

Continuous Integration Gute Zeilen, schlechte Zeilen 44

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 Gute Zeilen, schlechte Zeilen 45

More Seminare zum Thema, z. B. Java Effective Java Software Testing http://javaeeblog.wordpress.com/ http://expertenkreisjava.blogspot.de/  dirk.weil@gedoplan.de @dirkweil Gute Zeilen, schlechte Zeilen 46 dirk.weil@gedoplan.de

Add a comment

Related presentations

Related pages

Gute Zeilen, schlechte Zeilen – Regeln für wartbare ...

... Gute Zeilen, schlechte Zeilen – Regeln für ... guten Programmiersprache kann man schlechte ... wartbaren Code ausmacht, welche Regeln man ...
Read more

Gute Zeilen, schlechte Zeilen – Regeln für wartbare ...

... schlechte Zeilen – Regeln für wartbare Programme interessiert sind, ... Gute Zeilen, schlechte Zeilen – Regeln für wartbare Programme ...
Read more

Gute Zeilen, schlechte Zeilen – Regeln für wartbare ...

... schlechte Zeilen – Regeln für wartbare ... guten Programmiersprache kann man schlechte ... wartbaren Code ausmacht, welche Regeln man ...
Read more

gedoplan-it-consulting :: Veranstaltungen

Gute Zeilen, schlechte Zeilen - Regeln für wartbare Programme 19.4.2012, 14:30 ... Thema: Gute Zeilen, schlechte Zeilen - Regeln für wartbare Programme .
Read more

Lars Adler - Softwareentwickler - visionera GmbH | XING

(Der Unternehmensname ist nur für eingeloggte Mitglieder sichtbar.) Impressum von Lars Adler Anmelden ...
Read more

John Boyd-Rainey - Clean Code Consultant & Trainer ...

Clean Code Consultant & Trainer ... Anmelden und ganzes Profil ansehen Anmelden und Profil ansehen
Read more

GFU - Semicolon: Die nächsten Termine - GFU Cyrus AG: IT ...

... Entwicklung sicherer Software ISO 27034 in ... Gute Zeilen, schlechte Zeilen – Regeln für wartbare ... Regeln für verständliche und wartbare Java ...
Read more

Regeln für Leichte Sprache

Die Regeln für Leichte Sprache ... Schlecht: GENEHMIGEN Gut: ERLAUBEN Beispiel ... Lassen Sie genug Abstand zwischen den Zeilen. Gut: $IESER3ATZHAT3CHRIFT
Read more

Gute Zeiten, schlechte Zeiten - RTL.de - Willkommen zuhause

Gute Zeiten, schlechte Zeiten: ... Für Dieter Bach fällt bei GZSZ die letzte Klappe Gastrolle als Dr. Frederic Riefflin zu Ende . Der exklusive GZSZ ...
Read more

Tagebuch - für gute und schlechte Tage: - Zum Ankreuzen ...

Tagebuch - für gute und schlechte Tage: - Zum Ankreuzen und Ausfüllen Gebundene Ausgabe – 28. März 2011. ... Tolles Tagebuch. Leider etwas enge Zeilen.
Read more