Skip to main content
swissICT Booster  |  M&F Academy  |  M&F Events   |  +41 44 747 44 44  | 
4 Minuten Lesezeit (814 Worte)

Software Refactoring und Design Patterns

In der agilen Softwareentwicklung kommt man an kontinuierlichem Refactoring nicht vorbei. Das Wichtigste, was ein Softwareentwickler zu Refactoring und Design Patterns wissen muss, habe ich euch hier zusammengefasst. Die Inputs dazu lieferte Prof. Oliver Augenstein. Er ist Dozent an der Hochschule für Technik in Rapperswil und kennt sich im Bereich Software Architektur und insbesondere bei Themen wie Code Refactoring und Patterns bestens aus. 

 

Was ist Refactoring?

Unter Refactoring versteht man einen Prozess welcher Code so verändert, dass das Verhalten des Codes äusserlich gleich bleibt. Unit Tests beispielsweise sollen vor und nach dem Refactoring denselben Output haben.

Das Ziel des Refactorings ist eine Umstrukturierung von Code, um den inneren Aufbau zu verbessern, z.B. durch Einführen von Design Patterns. Jedes Refactoring soll den Code "besser" machen. Generell kann man sagen, das Refactoring ist entweder eine Umstrukturierung des bestehenden Codes, um ihn verständlicher zu machen oder um neue Funktionalitäten einbauen zu können. Ein Refactoring Prozess besteht aus möglichst kleinen, zielgerichteten aber auch in sich abgeschlossenen Schritten, nach welchen die ursprüngliche Funktionalität wieder hergestellt ist. Ein Refactoring ist kein Bugfix, kann aber die Grundlage für einen Bugfix sein.

 

Refactoring-Primitiven

Refactoring basiert auf sehr einfachen Konzepten, den Refactoring-Primitiven.

  •   Renaming: also Umbenennen von Variablen, Methoden, Klassen und so weiter.
  •   Move: das Verschieben von Code an eine andere Stelle oder in ein anderes File.
  •   Add oder Remove von Klassen, Methoden und Variablen, ohne die ursprüngliche Funktion zu verändern.

Durch Kombination dieser simplen Schritte können z.B. Design Patterns angewandt werden.

 

Arten von Refactoring

Generell wird zwischen zwei Arten von Refactorings unterschieden: kleine und grosse Refactorings. Kleine Refactorings sind ein wichtiger Bestandteil vom normalen Arbeitsprozess. Sie fördern das Code-Verständnis, erlauben einem inkrementelles Erarbeiten von neuen Funktionalitäten und ermöglichen ein sicheres Abarbeiten von Review-Findings. Man spricht von kleinen Refactorings wenn sich der Aufwand im Rahmen von Minuten bis Stunden befindet.

Grosse Refactorings ziehen sich hingegen über Wochen bis zu Jahren. Sie erlauben grössere Projekte schrittweise neu zu gestalten. Die Ziele eines solchen Refactorings müssen dabei dem ganzen Team bekannt sein und es braucht eine langfristige Strategie mit Unterstützung des Managements. Zudem ist es dabei erlaubt, auch parallel neue Funktionalität zu entwickeln. Beispiele dazu wären das Beheben einer systematischen Fehlerquelle oder «Modernisierung» einer alten Codebasis.

 

Softwaredesign

In der Praxis ist es nahezu unmöglich, eine Software so zu planen, dass alle Schnittstellen in Zukunft allen Anforderungen genügen. Oft sind Anforderungen noch nicht klar bekannt oder z.T. treten sie erst nach einem anderen Ereignis auf. Refactoring ermöglicht ein inkrementelles Softwaredesign. Code wird laufend den bekannten Anforderungen angepasst und umstrukturiert.

Software Design

 

Best Practice beim Refactoring

  • Klare Trennung von Arbeitsschritten: Entweder Fix, Entwicklung oder Refactoring, nicht mischen!
  • Markieren von allen notwendigen Schritten (am besten mit einem Marker, welcher noch nicht im Projekt vorkommt und einfach zu Finden ist). Die einzelnen Schritte sollten wenn möglich klein und in sich abgeschlossen sein.
  • Jeder dieser Schritte wird einzeln bearbeitet.
  • Nach Beenden eines Schrittes sollte die Funktionalität wiederhergestellt sein.
  • Das Refactoring ist abgeschlossen, wenn alle Marker entfernt wurden, die Funktionalität sich nicht verändert hat, die Änderungen zum gewünschten Ziel geführt haben und der Code ins Versionskontrollsystem eingecheckt wurde.

 

Design Patterns

Extract Class

Wenn der Zuständigkeitsbereich einer Klasse sehr weit gedehnt ist, lohnt es sich meistens, eine oder mehrere Klassen zu extrahieren. Denn eine kleine Klassen mit spezifischer Zuständigkeit lässt sich leichter testen und wiederverwenden. Beispiel: Bei einer Klasse eines Spieles wird Spiellogik mit GUI vermischt.

Vorgehen:

  1.   Markieren aller zu extrahierenden Methoden und Attribute
  2.   Erstellen der neuen Klasse
  3.   Kopieren der markierten Methoden in neue Klasse
  4.   Verschieben der markierten Attribute in die neue Klasse
  5.   Neue Klasse an sich lauffähig machen
  6.   Abhängigkeit erstellen zwischen der alten und der neuen Klasse (am besten unidirektional)
  7.   Alle Kopierten Methoden der alten Klasse in delegate Methoden umwandeln.
  8.   Alle delegate Methoden nach und nach entfernen

Das Programm müsste nach Abschluss jedes Schrittes lauffähig sein.

Design Patterns Delegation

 

Observer Pattern

Das Observer Pattern wird dann angewandt, wenn Änderungen an einem Objekt irgendetwas in anderen Objekten auslösen soll. Es hilft dabei Objekte über Änderungen zu Informieren und die Koppelung lose zu behalten.

Observer Pattern

Dazu ein kleines Beispielprogramm in Java in welchem die beiden Observer benachrichtigt werden wenn sich der Status des Subject ändert. 

Simple Observer
import java.util.HashSet;


abstract class Observer {
protected Subject subject;
public abstract void update();
}

class Subject {
private HashSet myObservers = new HashSet();
private String state;

public void add(Observer o) {
myObservers.add(o);
}

public String getState() {
return state;
}

public void setState(String value) {
this.state = value;
notifyObserver();
}

private void notifyObserver() {
for (Observer observer : myObservers) {
observer.update();
}
}
}

class ConcreteObserver extends Observer {
public ConcreteObserver(Subject subject) {
this.subject = subject;
this.subject.add(this);
}

public void update() {
System.out.print(" " + subject.getState());
}
}

public class ObserverDemo {
public static void main( String[] args ) {
Subject sub = new Subject();

new ConcreteObserver(sub);
new ConcreteObserver(sub);
sub.setState("I'm getting printed twice, once for each ConcreteObserver\n");
}
}

 

Und jetzt: viel Spass beim Refactoring! Wenn Fragen auftauchen, können Sie jederzeit unser Experten-Team kontaktieren. 

0
Interview mit der ersten Frau im Trainee-Programm
Der neue Trainee Dominik stellt sich vor

Ähnliche Beiträge

 

Kommentare 1

Gäste - Reto am Dienstag, 12. November 2019 17:43

Sehr cool, Fabio. Danke für den tollen Blog!

Sehr cool, Fabio. Danke für den tollen Blog!
Mittwoch, 15. Mai 2024

Sicherheitscode (Captcha)