Johannes Link. jl@johanneslink.net



Ähnliche Dokumente
Java: Vererbung. Teil 3: super()

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Klassenentwurf. Wie schreiben wir Klassen, die leicht zu verstehen, wartbar und wiederverwendbar sind? Objektorientierte Programmierung mit Java

Was meinen die Leute eigentlich mit: Grexit?

Client-Server-Beziehungen

Fortgeschrittenes Programmieren mit Java. Test Driven Development

Java Kurs für Anfänger Einheit 5 Methoden

Informationsblatt Induktionsbeweis

Programmieren in Java

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Welchen Weg nimmt Ihr Vermögen. Unsere Leistung zu Ihrer Privaten Vermögensplanung. Wir machen aus Zahlen Werte

SEP 114. Design by Contract

6 Beiträge zum Platz "Steuerberater Kanzlei Schelly - Hamburg Nord" auf Deutsch. robzim Hamburg 1 Beitrag. Kommentieren 1 Kommentar zu diesem Beitrag

Programmierkurs Java

Statuten in leichter Sprache

Das Leitbild vom Verein WIR

Welche Gedanken wir uns für die Erstellung einer Präsentation machen, sollen Ihnen die folgende Folien zeigen.

5. Abstrakte Klassen. Beispiel (3) Abstrakte Klasse. Beispiel (2) Angenommen, wir wollen die folgende Klassenhierarchie implementieren:

Objektorientierte Programmierung

Catherina Lange, Heimbeiräte und Werkstatträte-Tagung, November

Testen mit JUnit. Motivation

Gründe für fehlende Vorsorgemaßnahmen gegen Krankheit

Was ich als Bürgermeister für Lübbecke tun möchte

Große Übung Praktische Informatik 1

Regeln für das Qualitäts-Siegel

Objektorientierte Programmierung. Kapitel 12: Interfaces

Test-Driven Design: Ein einfaches Beispiel

Das Persönliche Budget in verständlicher Sprache

SharePoint Workspace 2010 Installieren & Konfigurieren

Operationalisierbare Qualitätskriterien für die Programmierung mit Erfahrungen aus PRÜ1 und PRÜ2

40-Tage-Wunder- Kurs. Umarme, was Du nicht ändern kannst.

TESTEN SIE IHR KÖNNEN UND GEWINNEN SIE!

Java Einführung Abstrakte Klassen und Interfaces

5. Abstrakte Klassen

Nicht über uns ohne uns

Übungen Programmieren 1 Felix Rohrer. Übungen

Programmieren I. Strategie zum Entwurf von Klassen. Beispiele. Design von Klassen. Dr. Klaus Höppner. Beispiel: Bibliothek

Win 7 sinnvoll einrichten

PowerPoint vertonen. by H.Schönbauer 1

Alle gehören dazu. Vorwort

1. Weniger Steuern zahlen

Win 7 optimieren. Unser Thema heute: Meine erstellten Daten in eine andere Partition verschieben.

Software Engineering Klassendiagramme Assoziationen

Gesetz für die Gleichstellung von Menschen mit Behinderungen. Erklärt in leichter Sprache

Internet Explorer Version 6

Wichtig ist die Originalsatzung. Nur was in der Originalsatzung steht, gilt. Denn nur die Originalsatzung wurde vom Gericht geprüft.

Objektorientierte Programmierung für Anfänger am Beispiel PHP

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = Euro ergeben.

Einführung in die Java- Programmierung

Fachgebiet Informationssysteme Prof. Dr.-Ing. N. Fuhr. Programmierung Prof. Dr.-Ing. Nobert Fuhr. Übungsblatt Nr. 6

50. Mathematik-Olympiade 2. Stufe (Regionalrunde) Klasse Lösung 10 Punkte

Babeș-Bolyai Universität Cluj Napoca Fakultät für Mathematik und Informatik Grundlagen der Programmierung MLG5005. Modulare Programmierung

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Algorithmen und Datenstrukturen

WAS finde ich WO im Beipackzettel

Einführung in die Informatik Tools

2.1 Erstellung einer Gutschrift über den vollen Rechnungsbetrag

Memeo Instant Backup Kurzleitfaden. Schritt 1: Richten Sie Ihr kostenloses Memeo-Konto ein

Und im Bereich Lernschwächen kommen sie, wenn sie merken, das Kind hat Probleme beim Rechnen oder Lesen und Schreiben.

1 Vom Problem zum Programm

Leichte-Sprache-Bilder

Impulse Inklusion 2014 Beteiligungskulturen - Netzwerke - Kooperationen (Leichte Sprache Version)

Professionelle Seminare im Bereich MS-Office

das usa team Ziegenberger Weg Ober-Mörlen Tel Fax: mail: lohoff@dasusateam.de web:

Adobe Photoshop. Lightroom 5 für Einsteiger Bilder verwalten und entwickeln. Sam Jost

5. Tutorium zu Programmieren

Tipps & Tricks im CRM

Kapitalerhöhung - Verbuchung

Säuglingsanfangsnahrung und Folgenahrung Was ändert sich? Was bleibt?

Objektorientierte Programmierung

Software Engineering. Zur Architektur der Applikation Data Repository. Franz-Josef Elmer, Universität Basel, HS 2015

Tutorial. Wie kann ich meinen Kontostand von meinen Tauschpartnern in. übernehmen? Zoe.works - Ihre neue Ladungsträgerverwaltung

Geld Verdienen im Internet leicht gemacht

Klassendefinitionen verstehen

Beschreibung Regeln z.b. Abwesenheitsmeldung und Weiterleitung

ZIELE erreichen WERTSTROM. IDEEN entwickeln. KULTUR leben. optimieren. KVP und Lean Management:

Wichtige Forderungen für ein Bundes-Teilhabe-Gesetz

Schritte 4. Lesetexte 13. Kosten für ein Girokonto vergleichen. 1. Was passt? Ordnen Sie zu.

Hilfe, mein SCRUM-Team ist nicht agil!

Objektbasierte Entwicklung

Welches Übersetzungsbüro passt zu mir?

Persönliche Zukunftsplanung mit Menschen, denen nicht zugetraut wird, dass sie für sich selbst sprechen können Von Susanne Göbel und Josef Ströbl

Datenbank-Verschlüsselung mit DbDefence und Webanwendungen.

Glaube an die Existenz von Regeln für Vergleiche und Kenntnis der Regeln

Die Post hat eine Umfrage gemacht

Prüfung Computation, Programming

Festplatte defragmentieren Internetspuren und temporäre Dateien löschen

Online Newsletter III

! " # $ " % & Nicki Wruck worldwidewruck

Übungsaufgaben Prozentrechnung und / oder Dreisatz

Der Gabelstapler: Wie? Was? Wer? Wo?

Die Industrie- und Handelskammer arbeitet dafür, dass Menschen überall mit machen können

Webseiten sind keine Gemälde. Webstandards für ein besseres Web. Webstandards für ein besseres Web

Einführung in die Programmierung

Die Beitrags-Ordnung vom Verein

Europäischer Fonds für Regionale Entwicklung: EFRE im Bundes-Land Brandenburg vom Jahr 2014 bis für das Jahr 2020 in Leichter Sprache

Software-Engineering und Optimierungsanwendungen in der Thermodynamik

PFÄNDUNGSSCHUTZ AB 1. JANUAR 2012 NUR NOCH ÜBER DAS P-KONTO

Elternzeit Was ist das?

Dieser PDF-Report kann und darf unverändert weitergegeben werden.

Transkript:

Johannes Link jl@johanneslink.net

Bevor ich es vergesse... Dank an Malte Finsterwalder Dank an Jens Coldewey (coldewey.com) Ich suche einen studentischen Mitarbeiter

Refactoring anhand von Beispielen

Evolutionäres Design Geplantes Design versucht, heutige und mögliche zukünftige Anforderungen auf einen Schlag abzudecken. Viele Annahmen treten jedoch nicht ein, so dass der Code unnötig komplex wird. Unvorhergesehene Anforderungen kommen trotzdem Mit evolutionärem Design können wir die heutigen Anforderungen in kleinen Schritten erfüllen. Wir vermeiden den vorausplanenden Blick in die unsichere Zukunft. Refactoring hält das Design für zukünftige Anforderungen offen.

Test / Code / Refactor 1) Neuer Test Tests Fail 2) Neues Feature Tests OK 3) Refactoring

Refactoring? Eine Änderung an der internen Struktur eines Programms, um es leichter verständlich und besser modifizierbar zu machen, ohne dabei sein beobachtbares Verhalten zu ändern. [Fowler 99]

If you want to refactor, the essential precondition is having solid tests. Martin Fowler

Umformung mathematischer Formeln: Umformung von Code: (a + b)² = void foo() { x = foo(); (a + b)(a + b) = a² + ab + ba + b² = a² + ab + ab + b² = void gutername() { x = gutername(); a² + 2ab + b² Mathematische Umformungen: Die Formel verändern, und den Wert der Formel unverändert lassen Refaktorisieren: Den Code ändern, ohne sein Verhalten (Semantik) zu ändern

Größere Refaktorisierungen kann man mit mathematischen Beweisen vergleichen Vom Start zum Ziel braucht man viele kleine (oft triviale) Zwischenschritte Jeder einzelne Schritt erhält die Semantik Zwischenschritte sind oft komplexer als der Start Es gibt Strategien für mittelgroße Schritte Gelegentlich läuft man in Sackgassen Gelegentlich macht man Fehler Unterschied: Beim Refaktorisieren kann man mit Unit-Tests zu jedem Zeitpunkt feststellen, ob man Fehler gemacht hat

Refactoring erhält strukturelle Qualität Wir refaktorisieren, um das Design zu verbessern um das Programm leichter verständlich zu machen um zukünftige Änderungen am Code zu erleichtern um der Entropie entgegen zu wirken

In einem abgeschlossenen System nimmt die Unordnung nicht ab. 2. Hauptsatz der Thermodynamik Das gilt auch für Software

Der Komplexitätstod eines Softwaresystems Ohne Gegenmaßnahmen nimmt die Komplexität eines Systems immer mehr zu und senkt die Produktivität bis die Wartung irgendwann unwirtschaftlich wird Refaktorisieren nimmt Komplexität aus dem bestehenden System

Refactoring-Ziel: Das einfachste Design Design ist einfach, wenn der Code...... alle seine Tests erfüllt.... jede Intention der Programmierer ausdrückt.... keine duplizierte Logik enthält.... möglichst wenig Klassen und Methoden umfasst. Reihenfolge entscheidend!

Refactoring - Vorgehen Refactoring findet ständig statt. Klein(st)e Schritte Entweder Refactoring oder neue Funktionalität Unit Tests sind das Fangnetz des Refactoring. Oft ist auch ein Refactoring der Tests notwendig.

Warum ständiges Refactoring? Nicht optimales Design zu dulden, ist wie Schulden machen Große Refactorings bremsen das ganze Team Refactoring-Phasen lassen sich nur schwer verkaufen Refactoring gehört zum professionellen Entwickeln und sollte nicht zur Verhandlungsmasse gehören

Übelriechender Code Code Smells: Indizien für (eventuell) notwendiges Refactoring duplizierte Logik lange Funktionen Kommentare switch-ketten, verschachtelte if-then-else Code, der seine Intention nicht ausdrückt Neid auf die Features einer anderen Klasse Datenklassen ohne wirkliches Verhalten Eigentlich......

Refactorings Rename Extract Method / Variable Inline Method / Variable Encapsulate Field Change Method Signature Move Method Introduce Null Object Replace Conditional with Polymorphism Replace Inheritance with Delegation... http://refactoring.com/catalog/index.html

Was tut dieser Code? public class A { private int b = 0; public int gb() { return b; public void d(int a) { c(a); b += a; private void c(int a) { if (a <= 0.0) { throw new IAE();

Namen sind mehr als Schall und Rauch: Das Rename-Refactoring public class Konto { private int saldo = 0; Der Thesaurus ist mein wichtigstes ProgrammierWerkzeug public int getsaldo() { return saldo; public void zahleein(int betrag) { ueberpruefedassbetragnichtnegativ(betrag); saldo += betrag; private void ueberpruefedassbetragnichtnegativ(int amount) { if (betrag <= 0.0) { throw new IllegalArgumentException(); Ward Cunningham

Suchen und Ersetzen genügen nicht! public class Foo { int foo; int foo(int b) { int foo = b * this.foo; return foo; public class FooUser { Foo foo; void foo(int c) { foo.foo(c); Sichtbarkeit und Verschattung müssen berücksichtigt werden Nötig: Auswertung interner Informationen des Compilers Brauchbare Refactoring-Browser sind eng mit dem Compiler verbunden

Gute Namen machen viele Kommentare überflüssig Vorher: /** * Ueberweise betrag in Euro * auf anderes konto */ public void ueberweise(double betrag, Konto konto) { konto.saldo += betrag; this.saldo -= betrag; Nachher: public void ueberweiseauf(double betragineuro, Konto zielkonto) { zielkonto.saldo += betragineuro; this.saldo -= betragineuro; Kommentare sieht man nur in der Deklaration, gute Namen überall Um gute Namen zu finden braucht man oft mehrere Versuche Kann ich aus diesem Kommentar einen Namen machen?

Wann ist Umbenennen sinnvoll? Um die Verständlichkeit des Codes zu erhöhen Wenn sich das eigene Verständnis des Codes verbessert hat Wenn sich die Zuständigkeiten der Klasse verändert haben (z.b. Generalisierung) Um Redundanz sichtbar zu machen Um APIs zu vereinheitlichen Um Verschattungen zu eliminieren

Divide and Conquer: Extract Method

Parameter und Rückgabetypen werden automatisch bestimmt private void paintcard(graphics g) { Image image = null; if (card.gettype().equals("problem")) { image = explanations.getgameui().problem; else if (card.gettype().equals("solution")) { image = explanations.getgameui().solution; else if (card.gettype().equals("value")) { image = explanations.getgameui().value; g.drawimage(image, 0, 0, explanations.getgameui()); if (shouldhighlight()) paintcardhighlight(g); paintcardtext(g); private void paintcard(graphics g) { paintcardimage(g); if (shouldhighlight()) paintcardhighlight(g); paintcardtext(g);

Auch Ausdrücke können extrahiert werden if (card.gettype().equals("problem")) { Extract Method private String problem() { return "Problem";... if (card.gettype().equals(problem())) { Extract Local Variable String problem = "Problem"; if (card.gettype().equals(problem)) { Extract Constant private static final String PROBLEM = "Problem";... if (card.gettype().equals(problem())) {

Wann ist es sinnvoll, zu extrahieren? Um die Lesbarkeit zu verbessern und Kommentare loszuwerden Um alle Aufrufe auf der gleichen Detailstufe zu haben Um redundante Abschnitte zusammen zu fassen Zur Vorbereitung weiterer Umstellungen: Um Codestücke zu extrahieren, die alle an ein (anderes) Objekt gehen Um Teile an der API bereit zu stellen Um abweichendes Verhalten in Subklassen überschreiben zu können

Die Umkehroperation zu Extract ist Inline if (card.gettype().equals("problem")) { Inline private String problem() { return "Problem";... if (card.gettype().equals(problem())) { String problem = "Problem"; if (card.gettype().equals(problem)) { private static final String PROBLEM = "Problem";... if (card.gettype().equals(problem())) {

Wann ist Inline sinnvoll? Um überflüssige Variablen zu eliminieren Um reine Durchreich-Methoden zu eliminieren Um alle Methoden auf der gleichen Detailebene zu haben Wenn viele Aufrufer gleichzeitig umgestellt werden müssen Für API-Änderungen: deprecated Aufrufe eliminieren Änderungen der Signatur automatisieren

Feature Envy: Ich bin nicht zuständig Wenn alle (oder die meisten) Aufrufe innerhalb einer Methode an ein anderes Objekt gehen, dann sollte die Methode auch dort angesiedelt sein: private Storage storage; protected void appendwithstoragecheck(elementtype element) { if (storage.nomorespaceleft()) { if (storage.compactingmakessense()) storage.compactstoragearray(); else storage.extendstoragearray(); storage.append(element); Diese Methode gehört in die Klasse Storage

Zuständigekeiten verschieben: Move Method private Storage storage; protected void appendwithstoragecheck(elementtype element) { if (storage.nomorespaceleft()) {... storage.append(element); protected void appendwithstoragecheck(elementtype element) { storage.appendwithcheck(element); class Storage... public void appendwithcheck(elementtype element) { if (nomorespaceleft()) {... append((elementtype) element);

Wann kann man Move einsetzen? Um Zuständigkeiten an einer Stelle zu sammeln ( Eine Klasse, ein Konzept ) Um Klassen aufzuspalten Um überfettete Klassen aufzuräumen Teilschritt zahlreicher komplexer Refactorings, z.b.: Replace Inheritance with Delegation Replace Conditional with Polymorphism

Replace Conditional with Polymorphism public class Konto... private boolean istbetraggedeckt(double betrag) { switch (kontotyp) { case GIRO: return betrag <= saldo + dispo; case SPAR: return betrag <= saldo; throw new RuntimeException("Unbekannter Kontotyp"); public abstract class Konto... abstract protected boolean istbetraggedeckt(double betrag); public class Sparkonto extends Konto... protected boolean istbetraggedeckt(double betrag) { return betrag <= saldo; public class Girokonto extends Konto... protected boolean istbetraggedeckt(double betrag) { return betrag <= saldo + dispo;

Tipps zum Refaktorisieren Aufräumen geht ad hoc, strukturelle Änderungen sollte man diskutieren Zwischenprodukte über (Verstoß gegen) Namenskonvention oder deprecated kennzeichnen Nicht alles auf einmal machen: Brauchbare Zwischenstände synchronisieren und einchecken Mut zum Rückschritt: Manchmal verrennt man sich Ehrgeiz: Das Design sollte nur aktuellen Anforderungen widerspiegeln, weder die Historie noch (Annahmen über) die Zukunft

Technische Grenzen des automatischen Refactorings Es kann nur Code geändert werden, der auch geladen ist Nur wo der Compiler Abhängigkeiten erkennt, kann er konsistent ändern: Vorsicht mit Reflection! Es gibt noch kaum sprachübergreifenden Ansätze, z.b. Java/SQL, Java/JavaScript, Java/ XML Viele nennenswerte Refactorings sind nicht automatisierbar, weil sie Wissen über die Absicht des Codes verlangen

Organisatorische Grenzen des Refactorings Besitzdenken über Code verhindert oft notwendige Umbauten Verteilte Entwicklung verhindert notwendige Abstimmungen Refactoring braucht manchmal Mut der muss auch in die Kultur passen Wenn Produktivität zu feingranular gemessen wird, ist keine Zeit mehr für unproduktives Refaktorisieren und die Produktivität sinkt Wenn Sie es gleich richtig gemacht hätten, müssten Sie jetzt keine Zeit für Umbauten verschwenden! Conway s Law: Architecture follows organization

Große Umbauten erfordern Planung Je größer ein Umbau ist, umso schwerer ist er zu schätzen Unvollendetes Refactoring hinterlässt den Code oft schlimmer, als vorher Temporäre Behelfsbrücken, um konsistente Zwischenstände zu haben Zunächst auf Entkopplung von Systemteilen konzentrieren (Interfaces!) Große Umbauten möglichst durch frühes und ständiges Refactoring vermeiden

Referenzen Kent Beck: Test-Driven Development By Example. Addison-Wesley, 2003. Martin Fowler: Refactoring Improving the Design of Existing Code. AddisonWesley, 1999. Joshua Kerievsky: Refactoring to Patterns. Addison-Wesley, 2004. Stefan Roock & Martin Lippert: Refactorings in großen Softwareprojekten. dpunkt, 2004.