Wikipedia · einfach zusammengefasst · Stand
Code-Smell
Unter dem Begriff sollten handfestere Kriterien für Refactoring beschrieben werden, als das durch den vagen Hinweis auf Programmästhetik geschehen würde. Bei …
Inhalt4 Abschnitte
Bedeutung von Code-Smells
Ein Code-Smell („übelriechender Code“) ist in der Programmierung ein Konstrukt, das nahelegt, den Quelltext zu überarbeiten (Refactoring). Es handelt sich nicht um Programm- oder Syntaxfehler: Der Code funktioniert, ist aber schlecht strukturiert. Dadurch wird er für Programmierer schwer verständlich; bei Korrekturen und Erweiterungen können leichter neue Fehler entstehen. Ein Smell kann außerdem auf ein tiefer liegendes Strukturproblem hinweisen, das erst bei der Überarbeitung sichtbar wird.
Der Begriff sollte handfestere Hinweise für Refactoring liefern als der vage Maßstab der Programmästhetik.
Häufige Probleme im Quelltext
Verbreitete Smells sind Code-Duplizierung, also gleicher Code an mehreren Stellen, sowie lange Methoden und große Klassen mit zu vielen Instanzvariablen oder dupliziertem Code. Eine lange Parameterliste entsteht, wenn Attribute eines Objekts einzeln statt das Objekt selbst übergeben werden.
Bei divergierenden Änderungen muss eine Klasse für eine einzelne Änderung an mehreren Stellen angepasst werden. Bei „Shotgun Surgery“ sind Änderungen sogar in vielen Klassen nötig. „Feature Envy“ liegt vor, wenn eine Methode stärker die Daten einer anderen als die ihrer eigenen Klasse nutzt. Datenklumpen sind Gruppen von Objekten, die wiederholt gemeinsam als Felder oder Parameter auftreten.
Weitere Hinweise sind die Neigung zu elementaren Typen, obwohl Klassen und Objekte aussagekräftiger wären, sowie Switch-Case-Anweisungen in objektorientiertem Code, wo Polymorphismus sie weitgehend ersetzen und duplizierten Code vermeiden kann. Parallele Vererbungshierarchien bedeuten, dass zu jeder Unterklasse einer Hierarchie stets eine Unterklasse einer anderen gehört.
Eine faule Klasse leistet zu wenig für ihre Existenz. Spekulative Allgemeinheit deckt unbenötigte Spezialfälle ab und verursacht Pflegeaufwand ohne Nutzen. Temporäre Felder werden nur unter bestimmten Umständen verwendet und erschweren das Verstehen und Debuggen. Nachrichtenketten verletzen das Gesetz von Demeter. Ein „Middle Man“ delegiert alle Methodenaufrufe an eine andere Klasse; bei unangebrachter Intimität sind zwei Klassen zu eng miteinander verflochten.
Auch alternative Klassen mit unterschiedlichen Schnittstellen für dieselbe Aufgabe, unvollständige Bibliotheksklassen, reine Datenklassen mit Feldern und Zugriffsmethoden ohne Funktionalität sowie ausgeschlagenes Erbe sind Smells. Beim ausgeschlagenen Erbe benötigt eine Unterklasse geerbte Methoden und Daten nicht; dies betrifft auch das Liskovsche Substitutionsprinzip. Kommentare sind grundsätzlich hilfreich, können aber dort gehäuft nötig sein, wo Code schlecht verständlich ist, und damit auf schlechten Code hinweisen.
Weitere Anti-Pattern
Weitere Smells werden oft als Programmierungs-Anti-Pattern bezeichnet. Nichtssagende Namen erklären Eigenschaften oder Verwendung nicht; aussagekräftige Namen sind für das Verständnis wesentlich. Redundanter Code bezeichnet mehrfach identische Quellcodeteile. Bei „Indecent Exposure“ werden interne Details einer Klasse unnötig Teil ihrer äußeren Schnittstelle.
„Contrived complexity“ ist die erzwungene Verwendung von Entwurfsmustern, obwohl ein einfacheres Design genügte. Zu lange Namen enthalten insbesondere Architektur- oder Designbestandteile; zu kurze Namen wie „x“, „i“ oder Abkürzungen beschreiben die Funktion einer Variable nicht. Ein Über-Callback versucht, alles zu erledigen. Komplexe Verzweigungen prüfen viele Bedingungen, die nichts mit der Funktionalität des Codeblocks zu tun haben. Tiefe Verschachtelungen von if/else/for/do/while-Anweisungen machen Code unlesbar.
Smells in der Softwarearchitektur
Smells treten nicht nur im Quelltext, sondern auch in der Architektur von Softwaresystemen auf. Als Architektur-Smells gelten unter anderem zyklische Benutzungsbeziehungen zwischen Paketen, Schichten und Subsystemen sowie Probleme bei Größe und Aufteilung von Paketen oder Subsystemen.