SlideShare ist ein Scribd-Unternehmen logo
Quelle: Johannes Hofmeister, http://empathic.herokuapp.com
Unter Code-Smell, kurz Smell (deutsch ‚[schlechter] Geruch‘) oder
deutsch übelriechender Code versteht man in der Programmierung ein Konstrukt, das
eine Überarbeitung des Programm-Quelltextes nahelegt. Dem Vernehmen nach stammt
die Metapher Smell von Kent Beck und erlangte weite Verbreitung durch das
Buch Refactoring von Martin Fowler. Unter dem Begriff sollten handfestere Kriterien
für Refactoring beschrieben werden, als das durch den vagen Hinweis auf
Programmästhetik geschehen würde.
Bei Code-Smell geht es nicht um Programmfehler, sondern um funktionierenden
Programmcode, der aber schlecht strukturiert ist. Das größte Problem liegt darin, dass
der Code für den Programmierer schwer verständlich ist, so dass sich bei Korrekturen und
Erweiterungen häufig wieder neue Fehler einschleichen. Code-Smell kann auch auf ein
tieferes Problem hinweisen, das in der schlechten Struktur verborgen liegt und erst durch
eine Überarbeitung erkannt wird.
Quelle: https://de.wikipedia.org/wiki/Smell_(Programmierung)
Add Parameter Introduce Class Annotation Replace Conditional with Polymorphism
Change Bidirectional Association to Unidirectional Introduce Expression Builder Replace Constructor with Factory Method
Change Reference to Value Introduce Foreign Method Replace Data Value with Object
Change Unidirectional Association to Bidirectional Introduce Gateway Replace Delegation With Hierarchy
Change Value to Reference Introduce Local Extension Replace Delegation with Inheritance
Collapse Hierarchy Introduce Named Parameter Replace Dynamic Receptor with Dynamic Method Definition
Consolidate Conditional Expression Introduce Null Object Replace Error Code with Exception
Consolidate Duplicate Conditional Fragments Introduce Parameter Object Replace Exception with Test
Decompose Conditional Isolate Dynamic Receptor Replace Hash with Object
Duplicate Observed Data Lazily Initialized Attribute Replace Inheritance with Delegation
Dynamic Method Definition Move Eval from Runtime to Parse Time Replace Loop with Collection Closure Method
Eagerly Initialized Attribute Move Field Replace Magic Number with Symbolic Constant
Encapsulate Collection Move Method Replace Method with Method Object
Encapsulate Downcast Parameterize Method Replace Nested Conditional with Guard Clauses
Encapsulate Field Preserve Whole Object Replace Parameter with Explicit Methods
Extract Class Pull Up Constructor Body Replace Parameter with Method
Extract Interface Pull Up Field Replace Record with Data Class
Extract Method Pull Up Method Replace Subclass with Fields
Extract Module Push Down Field Replace Temp with Chain
Extract Subclass Push Down Method Replace Temp with Query
Extract Superclass Recompose Conditional Replace Type Code with Class
Extract Surrounding Method Remove Assignments to Parameters Replace Type Code with Module Extension
Extract Variable Remove Control Flag Replace Type Code With Polymorphism
Form Template Method Remove Middle Man Replace Type Code with State/Strategy
Hide Delegate Remove Named Parameter Replace Type Code with Subclasses
Hide Method Remove Parameter Self Encapsulate Field
Inline Class Remove Setting Method Separate Query from Modifier
Inline Method Remove Unused Default Parameter Split Temporary Variable
Inline Module Rename Method Substitute Algorithm
Inline Temp Replace Abstract Superclass with Module
Introduce Assertion Replace Array with Object
refactoring.com
Bloaters
Change
Preventers
Dispensables
Couplers
Object-Orientation Abusers
2000
Zeien
500
Zeilen
π •👍
Klasse < 500 LoC
Methode < 50 LoC
= 187 LoC
✄
public LicenseInformationViewModel(string licenseID, string name, string description,
bool isLicensed, bool isEnabled, ModuleScope moduleScope, long expireDays, bool
isOptional)
{
…
}
public LicenseInformationViewModel(Module module)
{
…
}
private string command;
private void connect(object sender, EventArgs e)
{
inputField.Visibility = Visibility.Hidden;
string user = cStgring1.Text;
string pass = cStgring2.Text;
string cStr = cStgring3.Text;
Properties.Settings.Default.DBUsername = user;
Properties.Settings.Default.DBPassword = pass;
Properties.Settings.Default.ConnectionString = cStr;
inputField.Visibility = Visibility.Collapsed;
if (command == "Import")
{
ImportDB1();
} else if (command == "Export")
{
ExPorterDB1();
}
}
private void ImportDB(object sender, EventArgs e)
{
inputField.Visibility = Visibility.Visible;
cStgring1.Text = Properties.Settings.Default.DBUsername ?? "";
cStgring2.Text = Properties.Settings.Default.DBPassword ?? "";
cStgring3.Text = Properties.Settings.Default.ConnectionString ?? "";
this.command = "Import";
}
new NLogFacade(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Trace.log"));
Service Zugriffe in eine Initialisierungsmethode
Auslagern und diese gezielt nach der Instanziierung
aufrufen.
„Util“ Klassen oder Namespace enthalten eigentlich nur Funktionalität die allgemeingültig und frei von jeglichem
Fachkontext sind. Entwickler verschieben dorthin aber auch gern Dinge bei denen Sie nicht wissen wo sie sonst hin
sollen. Dadurch entsteht ungewollte Kopplung.
Userinterface
Controller
Großanwendungen
Datenhaltung
Geschäftslogik
Userinterface
Controller
Großanwendungen
Datenhaltung
Geschäftslogik
Kleinanwendungen
Datenhaltung
Userinterface
Controller
Großanwendungen
Datenhaltung
Geschäftslogik
IST
Datenhaltung
Userinterface
Controller
Soll
Datenhaltung
Geschäftslogik
Utils
Datenhaltung
ACHTUNG: Durch strikte Schichtentrennung kann der
Eindruck von faulen Klassen entstehen!
Wrapper und andere Pattern sehen ebenfalls danach aus.
class ProjectRepoInstance
{
public List<Project> Projects { get; set; }
}
public class PublicationManager
{
private IPublicationRepository publicationRepository;
public PublicationManager(IPublicationRepository publicationRepository)
{
this.publicationRepository = publicationRepository;
}
public void Save(Publication publication)
{
this.publicationRepository.Save(publication);
}
}
Code der nichts tut:
Code der unnötige Aktionen ausführt:
.
public class MediaData
{
public List<Publication> Media { get; set; }
}
public class Publisher
{
public int Id { get; set; }
public string Name { get; set; }
public string Link { get; set; }
}
ACHTUNG: Gillt nicht unbedingt als Smell...
public interface ILogger
{
void Log(string message, LogLevel level);
}
public interface ILog2
{
void Error(string message);
void Warning(string message);
void Debug(string message);
}
public interface IPublicationRepository
{
Publication[] Load();
}
public interface IPublicationStore
{
IEnumerable<Publication> GetAll();
}
Bequest -> Vermächtnis
„Replace inheritance with delegation“
Eigenständige Klasse die nur eine Aufgabe hat.
„Method Object“
private string command;
private void connect(object sender, EventArgs e)
{
inputField.Visibility = Visibility.Hidden;
string user = cStgring1.Text;
string pass = cStgring2.Text;
string cStr = cStgring3.Text;
Properties.Settings.Default.DBUsername = user;
Properties.Settings.Default.DBPassword = pass;
Properties.Settings.Default.ConnectionString = cStr;
inputField.Visibility = Visibility.Collapsed;
if (command == "Import")
{
ImportDB1();
} else if (command == "Export")
{
ExPorterDB1();
}
}
private void ImportDB(object sender, EventArgs e)
{
inputField.Visibility = Visibility.Visible;
cStgring1.Text = Properties.Settings.Default.DBUsername ?? "";
cStgring2.Text = Properties.Settings.Default.DBPassword ?? "";
cStgring3.Text = Properties.Settings.Default.ConnectionString ?? "";
this.command = "Import";
}
Envy = Neid
public class Invoice
{
public Order Order { get; set; }
public double VAT { get; set; }
public double CalculatePrice()
{
var price = this.Order.Article.Sum(x => x.Quantity * x.Price);
return price * this.VAT;
}
}
public class Invoice
{
public Order Order { get; set; }
public double VAT { get; set; }
public double CalculatePrice()
{
var price = this.Order.GetPrice();
return price * this.VAT;
}
}
[TestMethod]
public void PublicationDataMustBeSavedInRepository()
{
var repoFake = A.Fake<IPublicationRepository>();
var sut = new PublicationManager(repoFake);
sut.Save(new Publication());
A.CallTo(() => repoFake.Save(A<Publication>.Ignored)).MustHaveHappened();
}
((ComboBox)((StackPanel)((StackPanel)((Page1)((Frame)((TabItem)e.AddedItems[0])
.Content).Content).Content).Children[3]).Children[1]).ItemsSource = x;
class ProjectViewModel
{
private readonly IProjectRepository projectRepository;
public ProjectViewModel(IProjectRepository projectRepository)
{
this.projectRepository = projectRepository;
}
public Project SelectedProject { get; set; }
public void Save()
{
this.projectRepository.Save(this.SelectedProject);
}
}
https://en.wiktionary.org/wiki/yak_shaving
public interface IPublicationStorage
{
bool Store(Publication publication);
}
public class PublicationDatabaseStorage : IPublicationStorage
{
public bool Store(Publication publication)
{
// ...
return true;
}
}
public class PublicationJsonStorage : IPublicationStorage
{
public bool Store(Publication publication)
{
// ...
return true;
}
}
public class PublicationStorage
{
public bool StoreInDatabase(Publication publication)
{
…
return true;
}
public bool StoreAsJson(Publication publication)
{
…
return true;
}
}
Codesmells
Codesmells

Weitere ähnliche Inhalte

Ähnlich wie Codesmells

Agiles Modellieren mit Domain Specific Languages
Agiles Modellieren mit Domain Specific LanguagesAgiles Modellieren mit Domain Specific Languages
Agiles Modellieren mit Domain Specific LanguagesDominik Hirt
 
JPA the Versant Way
JPA the Versant WayJPA the Versant Way
JPA the Versant Wayjubecker
 
Camunda@1&1
Camunda@1&1Camunda@1&1
Camunda@1&1
1&1
 
TYPO3 coding guidelines
TYPO3 coding guidelinesTYPO3 coding guidelines
TYPO3 coding guidelines
Alex Kellner
 
Abläufe mit PHP und Phing automatisieren
Abläufe mit PHP und Phing automatisierenAbläufe mit PHP und Phing automatisieren
Abläufe mit PHP und Phing automatisieren
Christian Münch
 
Go - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare SystemeGo - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare Systeme
Frank Müller
 
javaPersistenceInActionFeaturesJenseitsDesEntryLevels
javaPersistenceInActionFeaturesJenseitsDesEntryLevelsjavaPersistenceInActionFeaturesJenseitsDesEntryLevels
javaPersistenceInActionFeaturesJenseitsDesEntryLevels
gedoplan
 
Typescript
TypescriptTypescript
Typescript
Sebastian Springer
 
TYPO3 5.0 - Der aktuelle Stand der Zukunft
TYPO3 5.0 - Der aktuelle Stand der ZukunftTYPO3 5.0 - Der aktuelle Stand der Zukunft
TYPO3 5.0 - Der aktuelle Stand der ZukunftJochen Rau
 
Prototype 1.7
Prototype 1.7Prototype 1.7
Prototype 1.7
msebel
 
Interprozesskommunikation mit PHP
Interprozesskommunikation mit PHPInterprozesskommunikation mit PHP
Interprozesskommunikation mit PHP
Stephan Schmidt
 
XML-Socket-Server zur Kommunikation mit Flash
XML-Socket-Server zur Kommunikation mit FlashXML-Socket-Server zur Kommunikation mit Flash
XML-Socket-Server zur Kommunikation mit Flash
Stephan Schmidt
 
Wicket Kurzübersicht
Wicket KurzübersichtWicket Kurzübersicht
FMK2014: FileMaker Plugin erzeugen by Christian Schmitz
FMK2014: FileMaker Plugin erzeugen by Christian SchmitzFMK2014: FileMaker Plugin erzeugen by Christian Schmitz
FMK2014: FileMaker Plugin erzeugen by Christian Schmitz
Verein FM Konferenz
 
Metaprogrammierung und Reflection
Metaprogrammierung und ReflectionMetaprogrammierung und Reflection
Metaprogrammierung und ReflectionStefan Marr
 
Lösungsorientierte Fehlerbehandlung
Lösungsorientierte FehlerbehandlungLösungsorientierte Fehlerbehandlung
Lösungsorientierte Fehlerbehandlung
roskakori
 
Celery - eine asynchrone Task Queue (nicht nur) für Django
Celery - eine asynchrone Task Queue (nicht nur) für DjangoCelery - eine asynchrone Task Queue (nicht nur) für Django
Celery - eine asynchrone Task Queue (nicht nur) für Django
Markus Zapke-Gründemann
 
Python builds mit ant
Python builds mit antPython builds mit ant
Python builds mit ant
roskakori
 
dotnet Cologne 2013 - Windows Azure Mobile Services
dotnet Cologne 2013 - Windows Azure Mobile Servicesdotnet Cologne 2013 - Windows Azure Mobile Services
dotnet Cologne 2013 - Windows Azure Mobile ServicesSascha Dittmann
 

Ähnlich wie Codesmells (20)

Agiles Modellieren mit Domain Specific Languages
Agiles Modellieren mit Domain Specific LanguagesAgiles Modellieren mit Domain Specific Languages
Agiles Modellieren mit Domain Specific Languages
 
JPA the Versant Way
JPA the Versant WayJPA the Versant Way
JPA the Versant Way
 
Camunda@1&1
Camunda@1&1Camunda@1&1
Camunda@1&1
 
MVVM Pattern
MVVM Pattern MVVM Pattern
MVVM Pattern
 
TYPO3 coding guidelines
TYPO3 coding guidelinesTYPO3 coding guidelines
TYPO3 coding guidelines
 
Abläufe mit PHP und Phing automatisieren
Abläufe mit PHP und Phing automatisierenAbläufe mit PHP und Phing automatisieren
Abläufe mit PHP und Phing automatisieren
 
Go - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare SystemeGo - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare Systeme
 
javaPersistenceInActionFeaturesJenseitsDesEntryLevels
javaPersistenceInActionFeaturesJenseitsDesEntryLevelsjavaPersistenceInActionFeaturesJenseitsDesEntryLevels
javaPersistenceInActionFeaturesJenseitsDesEntryLevels
 
Typescript
TypescriptTypescript
Typescript
 
TYPO3 5.0 - Der aktuelle Stand der Zukunft
TYPO3 5.0 - Der aktuelle Stand der ZukunftTYPO3 5.0 - Der aktuelle Stand der Zukunft
TYPO3 5.0 - Der aktuelle Stand der Zukunft
 
Prototype 1.7
Prototype 1.7Prototype 1.7
Prototype 1.7
 
Interprozesskommunikation mit PHP
Interprozesskommunikation mit PHPInterprozesskommunikation mit PHP
Interprozesskommunikation mit PHP
 
XML-Socket-Server zur Kommunikation mit Flash
XML-Socket-Server zur Kommunikation mit FlashXML-Socket-Server zur Kommunikation mit Flash
XML-Socket-Server zur Kommunikation mit Flash
 
Wicket Kurzübersicht
Wicket KurzübersichtWicket Kurzübersicht
Wicket Kurzübersicht
 
FMK2014: FileMaker Plugin erzeugen by Christian Schmitz
FMK2014: FileMaker Plugin erzeugen by Christian SchmitzFMK2014: FileMaker Plugin erzeugen by Christian Schmitz
FMK2014: FileMaker Plugin erzeugen by Christian Schmitz
 
Metaprogrammierung und Reflection
Metaprogrammierung und ReflectionMetaprogrammierung und Reflection
Metaprogrammierung und Reflection
 
Lösungsorientierte Fehlerbehandlung
Lösungsorientierte FehlerbehandlungLösungsorientierte Fehlerbehandlung
Lösungsorientierte Fehlerbehandlung
 
Celery - eine asynchrone Task Queue (nicht nur) für Django
Celery - eine asynchrone Task Queue (nicht nur) für DjangoCelery - eine asynchrone Task Queue (nicht nur) für Django
Celery - eine asynchrone Task Queue (nicht nur) für Django
 
Python builds mit ant
Python builds mit antPython builds mit ant
Python builds mit ant
 
dotnet Cologne 2013 - Windows Azure Mobile Services
dotnet Cologne 2013 - Windows Azure Mobile Servicesdotnet Cologne 2013 - Windows Azure Mobile Services
dotnet Cologne 2013 - Windows Azure Mobile Services
 

Mehr von Hendrik Lösch

Why (most) softwareprojects fail silently
Why (most) softwareprojects fail silentlyWhy (most) softwareprojects fail silently
Why (most) softwareprojects fail silently
Hendrik Lösch
 
We (don't) need a software architect!?!
We (don't) need a software architect!?!We (don't) need a software architect!?!
We (don't) need a software architect!?!
Hendrik Lösch
 
Restrukturierung einer industriellen Großapplikation
Restrukturierung einer industriellen GroßapplikationRestrukturierung einer industriellen Großapplikation
Restrukturierung einer industriellen Großapplikation
Hendrik Lösch
 
Vom Monolith zum Modulith
Vom Monolith zum ModulithVom Monolith zum Modulith
Vom Monolith zum Modulith
Hendrik Lösch
 
Der Software auf den Zahn gefühlt - Einstieg in die Architekturbewertung
Der Software auf den Zahn gefühlt - Einstieg in die ArchitekturbewertungDer Software auf den Zahn gefühlt - Einstieg in die Architekturbewertung
Der Software auf den Zahn gefühlt - Einstieg in die Architekturbewertung
Hendrik Lösch
 
„Wie reden Sie denn mit mir?!?“ – Stakeholder überzeugen als Softwarearchitekt
„Wie reden Sie denn mit mir?!?“ – Stakeholder überzeugen als Softwarearchitekt„Wie reden Sie denn mit mir?!?“ – Stakeholder überzeugen als Softwarearchitekt
„Wie reden Sie denn mit mir?!?“ – Stakeholder überzeugen als Softwarearchitekt
Hendrik Lösch
 
Software ist was du draus machst!
Software ist was du draus machst!Software ist was du draus machst!
Software ist was du draus machst!
Hendrik Lösch
 
Modular mit .NET
Modular mit .NETModular mit .NET
Modular mit .NET
Hendrik Lösch
 
.NET zu .NET Core
.NET zu .NET Core.NET zu .NET Core
.NET zu .NET Core
Hendrik Lösch
 
Workshop Vue js
Workshop Vue jsWorkshop Vue js
Workshop Vue js
Hendrik Lösch
 
Migrationsstrategien
MigrationsstrategienMigrationsstrategien
Migrationsstrategien
Hendrik Lösch
 
Einstieg in das Vueniverse
Einstieg in das VueniverseEinstieg in das Vueniverse
Einstieg in das Vueniverse
Hendrik Lösch
 
Survivalkit für Codehausmeister
Survivalkit für CodehausmeisterSurvivalkit für Codehausmeister
Survivalkit für Codehausmeister
Hendrik Lösch
 
Confessions of a Codehausmeister
Confessions of a CodehausmeisterConfessions of a Codehausmeister
Confessions of a Codehausmeister
Hendrik Lösch
 
Hey, wie geht es dir?
Hey, wie geht es dir?Hey, wie geht es dir?
Hey, wie geht es dir?
Hendrik Lösch
 
WPF Dos n Don'ts - der WPF Rundumschlag
WPF Dos n Don'ts - der WPF RundumschlagWPF Dos n Don'ts - der WPF Rundumschlag
WPF Dos n Don'ts - der WPF Rundumschlag
Hendrik Lösch
 
Clean mit visual studio
Clean mit visual studioClean mit visual studio
Clean mit visual studio
Hendrik Lösch
 
Der Healthcheck für Softwareprojekte
Der Healthcheck für SoftwareprojekteDer Healthcheck für Softwareprojekte
Der Healthcheck für Softwareprojekte
Hendrik Lösch
 
MVVM mit WPF
MVVM mit WPFMVVM mit WPF
MVVM mit WPF
Hendrik Lösch
 
Ionic 3
Ionic 3Ionic 3

Mehr von Hendrik Lösch (20)

Why (most) softwareprojects fail silently
Why (most) softwareprojects fail silentlyWhy (most) softwareprojects fail silently
Why (most) softwareprojects fail silently
 
We (don't) need a software architect!?!
We (don't) need a software architect!?!We (don't) need a software architect!?!
We (don't) need a software architect!?!
 
Restrukturierung einer industriellen Großapplikation
Restrukturierung einer industriellen GroßapplikationRestrukturierung einer industriellen Großapplikation
Restrukturierung einer industriellen Großapplikation
 
Vom Monolith zum Modulith
Vom Monolith zum ModulithVom Monolith zum Modulith
Vom Monolith zum Modulith
 
Der Software auf den Zahn gefühlt - Einstieg in die Architekturbewertung
Der Software auf den Zahn gefühlt - Einstieg in die ArchitekturbewertungDer Software auf den Zahn gefühlt - Einstieg in die Architekturbewertung
Der Software auf den Zahn gefühlt - Einstieg in die Architekturbewertung
 
„Wie reden Sie denn mit mir?!?“ – Stakeholder überzeugen als Softwarearchitekt
„Wie reden Sie denn mit mir?!?“ – Stakeholder überzeugen als Softwarearchitekt„Wie reden Sie denn mit mir?!?“ – Stakeholder überzeugen als Softwarearchitekt
„Wie reden Sie denn mit mir?!?“ – Stakeholder überzeugen als Softwarearchitekt
 
Software ist was du draus machst!
Software ist was du draus machst!Software ist was du draus machst!
Software ist was du draus machst!
 
Modular mit .NET
Modular mit .NETModular mit .NET
Modular mit .NET
 
.NET zu .NET Core
.NET zu .NET Core.NET zu .NET Core
.NET zu .NET Core
 
Workshop Vue js
Workshop Vue jsWorkshop Vue js
Workshop Vue js
 
Migrationsstrategien
MigrationsstrategienMigrationsstrategien
Migrationsstrategien
 
Einstieg in das Vueniverse
Einstieg in das VueniverseEinstieg in das Vueniverse
Einstieg in das Vueniverse
 
Survivalkit für Codehausmeister
Survivalkit für CodehausmeisterSurvivalkit für Codehausmeister
Survivalkit für Codehausmeister
 
Confessions of a Codehausmeister
Confessions of a CodehausmeisterConfessions of a Codehausmeister
Confessions of a Codehausmeister
 
Hey, wie geht es dir?
Hey, wie geht es dir?Hey, wie geht es dir?
Hey, wie geht es dir?
 
WPF Dos n Don'ts - der WPF Rundumschlag
WPF Dos n Don'ts - der WPF RundumschlagWPF Dos n Don'ts - der WPF Rundumschlag
WPF Dos n Don'ts - der WPF Rundumschlag
 
Clean mit visual studio
Clean mit visual studioClean mit visual studio
Clean mit visual studio
 
Der Healthcheck für Softwareprojekte
Der Healthcheck für SoftwareprojekteDer Healthcheck für Softwareprojekte
Der Healthcheck für Softwareprojekte
 
MVVM mit WPF
MVVM mit WPFMVVM mit WPF
MVVM mit WPF
 
Ionic 3
Ionic 3Ionic 3
Ionic 3
 

Codesmells

  • 1.
  • 2.
  • 3.
  • 4.
  • 5. Quelle: Johannes Hofmeister, http://empathic.herokuapp.com
  • 6. Unter Code-Smell, kurz Smell (deutsch ‚[schlechter] Geruch‘) oder deutsch übelriechender Code versteht man in der Programmierung ein Konstrukt, das eine Überarbeitung des Programm-Quelltextes nahelegt. Dem Vernehmen nach stammt die Metapher Smell von Kent Beck und erlangte weite Verbreitung durch das Buch Refactoring von Martin Fowler. Unter dem Begriff sollten handfestere Kriterien für Refactoring beschrieben werden, als das durch den vagen Hinweis auf Programmästhetik geschehen würde. Bei Code-Smell geht es nicht um Programmfehler, sondern um funktionierenden Programmcode, der aber schlecht strukturiert ist. Das größte Problem liegt darin, dass der Code für den Programmierer schwer verständlich ist, so dass sich bei Korrekturen und Erweiterungen häufig wieder neue Fehler einschleichen. Code-Smell kann auch auf ein tieferes Problem hinweisen, das in der schlechten Struktur verborgen liegt und erst durch eine Überarbeitung erkannt wird. Quelle: https://de.wikipedia.org/wiki/Smell_(Programmierung)
  • 7. Add Parameter Introduce Class Annotation Replace Conditional with Polymorphism Change Bidirectional Association to Unidirectional Introduce Expression Builder Replace Constructor with Factory Method Change Reference to Value Introduce Foreign Method Replace Data Value with Object Change Unidirectional Association to Bidirectional Introduce Gateway Replace Delegation With Hierarchy Change Value to Reference Introduce Local Extension Replace Delegation with Inheritance Collapse Hierarchy Introduce Named Parameter Replace Dynamic Receptor with Dynamic Method Definition Consolidate Conditional Expression Introduce Null Object Replace Error Code with Exception Consolidate Duplicate Conditional Fragments Introduce Parameter Object Replace Exception with Test Decompose Conditional Isolate Dynamic Receptor Replace Hash with Object Duplicate Observed Data Lazily Initialized Attribute Replace Inheritance with Delegation Dynamic Method Definition Move Eval from Runtime to Parse Time Replace Loop with Collection Closure Method Eagerly Initialized Attribute Move Field Replace Magic Number with Symbolic Constant Encapsulate Collection Move Method Replace Method with Method Object Encapsulate Downcast Parameterize Method Replace Nested Conditional with Guard Clauses Encapsulate Field Preserve Whole Object Replace Parameter with Explicit Methods Extract Class Pull Up Constructor Body Replace Parameter with Method Extract Interface Pull Up Field Replace Record with Data Class Extract Method Pull Up Method Replace Subclass with Fields Extract Module Push Down Field Replace Temp with Chain Extract Subclass Push Down Method Replace Temp with Query Extract Superclass Recompose Conditional Replace Type Code with Class Extract Surrounding Method Remove Assignments to Parameters Replace Type Code with Module Extension Extract Variable Remove Control Flag Replace Type Code With Polymorphism Form Template Method Remove Middle Man Replace Type Code with State/Strategy Hide Delegate Remove Named Parameter Replace Type Code with Subclasses Hide Method Remove Parameter Self Encapsulate Field Inline Class Remove Setting Method Separate Query from Modifier Inline Method Remove Unused Default Parameter Split Temporary Variable Inline Module Rename Method Substitute Algorithm Inline Temp Replace Abstract Superclass with Module Introduce Assertion Replace Array with Object refactoring.com
  • 9.
  • 11.
  • 12. π •👍 Klasse < 500 LoC Methode < 50 LoC = 187 LoC ✄
  • 13.
  • 14. public LicenseInformationViewModel(string licenseID, string name, string description, bool isLicensed, bool isEnabled, ModuleScope moduleScope, long expireDays, bool isOptional) { … } public LicenseInformationViewModel(Module module) { … }
  • 15.
  • 16. private string command; private void connect(object sender, EventArgs e) { inputField.Visibility = Visibility.Hidden; string user = cStgring1.Text; string pass = cStgring2.Text; string cStr = cStgring3.Text; Properties.Settings.Default.DBUsername = user; Properties.Settings.Default.DBPassword = pass; Properties.Settings.Default.ConnectionString = cStr; inputField.Visibility = Visibility.Collapsed; if (command == "Import") { ImportDB1(); } else if (command == "Export") { ExPorterDB1(); } } private void ImportDB(object sender, EventArgs e) { inputField.Visibility = Visibility.Visible; cStgring1.Text = Properties.Settings.Default.DBUsername ?? ""; cStgring2.Text = Properties.Settings.Default.DBPassword ?? ""; cStgring3.Text = Properties.Settings.Default.ConnectionString ?? ""; this.command = "Import"; }
  • 17.
  • 18.
  • 20. Service Zugriffe in eine Initialisierungsmethode Auslagern und diese gezielt nach der Instanziierung aufrufen.
  • 21. „Util“ Klassen oder Namespace enthalten eigentlich nur Funktionalität die allgemeingültig und frei von jeglichem Fachkontext sind. Entwickler verschieben dorthin aber auch gern Dinge bei denen Sie nicht wissen wo sie sonst hin sollen. Dadurch entsteht ungewollte Kopplung.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30. ACHTUNG: Durch strikte Schichtentrennung kann der Eindruck von faulen Klassen entstehen! Wrapper und andere Pattern sehen ebenfalls danach aus. class ProjectRepoInstance { public List<Project> Projects { get; set; } } public class PublicationManager { private IPublicationRepository publicationRepository; public PublicationManager(IPublicationRepository publicationRepository) { this.publicationRepository = publicationRepository; } public void Save(Publication publication) { this.publicationRepository.Save(publication); } }
  • 31. Code der nichts tut: Code der unnötige Aktionen ausführt:
  • 32. .
  • 33. public class MediaData { public List<Publication> Media { get; set; } } public class Publisher { public int Id { get; set; } public string Name { get; set; } public string Link { get; set; } } ACHTUNG: Gillt nicht unbedingt als Smell...
  • 34.
  • 35.
  • 36. public interface ILogger { void Log(string message, LogLevel level); } public interface ILog2 { void Error(string message); void Warning(string message); void Debug(string message); } public interface IPublicationRepository { Publication[] Load(); } public interface IPublicationStore { IEnumerable<Publication> GetAll(); }
  • 37. Bequest -> Vermächtnis „Replace inheritance with delegation“
  • 38. Eigenständige Klasse die nur eine Aufgabe hat.
  • 40. private string command; private void connect(object sender, EventArgs e) { inputField.Visibility = Visibility.Hidden; string user = cStgring1.Text; string pass = cStgring2.Text; string cStr = cStgring3.Text; Properties.Settings.Default.DBUsername = user; Properties.Settings.Default.DBPassword = pass; Properties.Settings.Default.ConnectionString = cStr; inputField.Visibility = Visibility.Collapsed; if (command == "Import") { ImportDB1(); } else if (command == "Export") { ExPorterDB1(); } } private void ImportDB(object sender, EventArgs e) { inputField.Visibility = Visibility.Visible; cStgring1.Text = Properties.Settings.Default.DBUsername ?? ""; cStgring2.Text = Properties.Settings.Default.DBPassword ?? ""; cStgring3.Text = Properties.Settings.Default.ConnectionString ?? ""; this.command = "Import"; }
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48. Envy = Neid public class Invoice { public Order Order { get; set; } public double VAT { get; set; } public double CalculatePrice() { var price = this.Order.Article.Sum(x => x.Quantity * x.Price); return price * this.VAT; } } public class Invoice { public Order Order { get; set; } public double VAT { get; set; } public double CalculatePrice() { var price = this.Order.GetPrice(); return price * this.VAT; } }
  • 49. [TestMethod] public void PublicationDataMustBeSavedInRepository() { var repoFake = A.Fake<IPublicationRepository>(); var sut = new PublicationManager(repoFake); sut.Save(new Publication()); A.CallTo(() => repoFake.Save(A<Publication>.Ignored)).MustHaveHappened(); }
  • 51. class ProjectViewModel { private readonly IProjectRepository projectRepository; public ProjectViewModel(IProjectRepository projectRepository) { this.projectRepository = projectRepository; } public Project SelectedProject { get; set; } public void Save() { this.projectRepository.Save(this.SelectedProject); } }
  • 52.
  • 54.
  • 55. public interface IPublicationStorage { bool Store(Publication publication); } public class PublicationDatabaseStorage : IPublicationStorage { public bool Store(Publication publication) { // ... return true; } } public class PublicationJsonStorage : IPublicationStorage { public bool Store(Publication publication) { // ... return true; } } public class PublicationStorage { public bool StoreInDatabase(Publication publication) { … return true; } public bool StoreAsJson(Publication publication) { … return true; } }

Hinweis der Redaktion

  1. Bloater sind üblicherweise Methoden oder Klassen die eine schwer zu überblickende Größe erreicht haben und meist unterschiedlichen Zwecken dienen. Die Größe wächst mit der Zeit an, da zu wenig refaktorisiert wird und vorrangig bestehende Strukturen genutzt statt neue geschaffen werden.
  2. Methoden haben sehr viele Parameter wodurch sie schwer zu verwenden sind und die Bedeutung einzelner Parameter nicht klar ist.
  3. Es werden vor allem primitive Datentypen eingesetzt statt Objekte. Dadurch geht der Kontext der Daten verloren, was zu Verständnisschwierigkeiten und Programmierfehlern führt.
  4. Es werden vor allem primitive Datentypen eingesetzt statt Objekte. Dadurch geht der Kontext der Daten verloren, was zu Verständnisschwierigkeiten und Programmierfehlern führt.
  5. Der Kontext verlangt, dass gewisse Daten gemeinsam zur Verfügung stehen. Diese werden aber immer als eigene Objekte behandelt, wodurch der Kontext verloren geht und Fehler entstehen können weil nur ein Teil der Daten vorhanden bzw. valide ist.
  6. Der Kontext verlangt, dass gewisse Daten gemeinsam zur Verfügung stehen. Diese werden aber immer als eigene Objekte behandelt, wodurch der Kontext verloren geht und Fehler entstehen können weil nur ein Teil der Daten vorhanden bzw. valide ist.
  7. Methodenaufrufe werden aneinander gekoppelt wie Waggons. Wenn in einem Aufruf ein Fehler auftritt kann dieser schwer geprüft werden da Debugging kaum möglich ist. Zusätzlich kann die Codezeile nur schwer verstanden werden.
  8. Konstruktoren die zu viele Aufgaben übernehmen und daher zu Problemen bei der Instanziierung führen können. Probleme entstehen bspw. durch den Zugriff auf andere Dienste während der Instanziierung.
  9. Bei Dispensables handelt es sich um Code oder Strukturen, die keinem Zweck (mehr) dienen. Diese Dinge werden eigentlich nicht mehr benötigt und erhöhen nur die Komplexität da sie das Volumen der zu beachtenden Strukturen erhöhen und oft nicht zu erkennen ist ob sie noch benötigt werden.
  10. Umfangreiche Kommentare altern schnell, sie sind nicht Refaktorisierungssicher und können den Blick auf den eigentlichen Code verstellen.
  11. Geclonter Code ist sich vom Verhalten oder der Struktur sehr ähnlich. Dies behindert die Übersicht über die tatsächliche Funktionalität und macht Anpassungen schwierig, da ggf. mehrere Stellen angepasst warden müssen.
  12. “Faule Klassen” tun eigentlich kaum etwas. Meist haben sie nur eine Methode, wenige Eigenschaften und delegieren alle Funktionalität an andere Klassen.
  13. Toter Code wird zur Laufzeit nicht ausgeführt. Er erhöht nur die Komplexität und das Volumen des Codebasis. Es ist teilweise sehr schwer zu ermitteln ob Code tatsächlich verwendet wird oder nicht.
  14. Hierbei handelt es sich um Code der auf Verdacht umgesetzt wurde um sich gegen evtl. zukünftige Anforderungen abzusichern. Dadurch ist er komplexer als notwendig, behindert das Verständnis und erhöht den Wartungsaufwand
  15. Data Classes enthalten nur Datenfelder und evtl. getter und setter. Sie sind nur Container ohne Funktionalität und haben keine Möglichkeit selbst auf den Daten zu operieren.
  16. Nicht alles was uns die objektorientierte Programmierung erlaubt ist auch gut. Falsch angewendet können Objekte und ihre Vererbungshierarchien den Code unleserlich machen und zusätzliche Komplexität verursachen.
  17. Zwei Klassen machen nahezu das Gleiche aber mit unterschiedlichen Schnittstellen. Bei Repos könnte die unterschiedliche Ausgestalltung aber auch an unterschiedlichen Kontexten liegen -> DDD! Immer auf die Namensgebung achten.
  18. Abgeleitete Klassen stellen nur einen Teil der Funktionalität ihrer Elternklasse bereit. Auf die Weise verletzen sie das Liskowsche Substitutions Prinzip, wonach sich alle Elemente einer Vererbungshierarchie erwartungsgemäß gleich darstellen müssen.
  19. Felder von Klassen werden als „Zwischenspeicher“ innerhalb eines komplexen Workflows genutzt. Teilweise sind sie leer, Teilweise aber nicht. Sie koppeln die Methoden aneinander und definieren einen Status der Klasse der zu Fehlern führt, wenn der Status unvorhergesehen geändert wird.
  20. Felder von Klassen werden als „Zwischenspeicher“ innerhalb eines komplexen Workflows genutzt. Teilweise sind sie leer, Teilweise aber nicht. Sie koppeln die Methoden aneinander und definieren einen Status der Klasse der zu Fehlern führt, wenn der Status unvorhergesehen geändert wird.
  21. Sehr ähnliche Fallunterscheidungen werden an unterschiedlichen Stellen im Code vorgenommen. Wird eine vergessen, kommt es zu Problemen.
  22. Sehr ähnliche Fallunterscheidungen werden an unterschiedlichen Stellen im Code vorgenommen. Wird eine vergessen, kommt es zu Problemen.
  23. Fallunterscheidungen werden innerhalb einer Methode vorgenommen um einen Workflow zu realisieren.
  24. Guardclauses prüfen an vielen Stellen im Code ob der übergebene Wert Null ist da Null im Fehlerfall zurück gegeben wird. Kann durch das Try-Pattern verhindert werden.
  25. Guardclauses prüfen an vielen Stellen im Code ob der übergebene Wert Null ist da Null im Fehlerfall zurück gegeben wird. Kann durch das Null-Object Pattern verhindert werden.
  26. Couplers führen zu unnötiger Kopplung innerhalb des Codes. Dadurch warden Änderungen schwierig, automatisierte Tests behindert und Änderungen können unerwartete Auswirkungen haben.
  27. Wenn sich eine Methode theoretisch in der falschen Klasse befindet und deshalb mehr auf den Daten einer anderen Klasse arbeitet. Dies lässt sich auf falsch gestaltete Separation of Concernce zurück führen.
  28. Eine Klasse nutzt interne Funktionen einer anderen Klasse oder zieht Rückschlüsse auf die internen Strukturen einer anderen. Sollten sich diese interna ändern kommt es zu Fehlern. Zusätzlich machen Änderungen an der einen Klasse meist auch Änderungen an der anderen notwendig.
  29. Bei einer Message Chain wird ein Aufruf entlang einer Objekthierarchie weitergereicht. Der Aufrufer ist damit nicht nur an ein Objekt gebunden, sondern an die gesamte Hierarchie.
  30. Ein Middle Man hat selbst keine Logik und reicht Aufgaben eigentlich nur an andere Klassen weiter. Dies erhöht nur das Volumen des Codes und sorgt dafür, dass Aufgaben schwieriger zu verstehen sind.
  31. Change preventers behindern Änderungen da Anpassungen an einer Stelle des Codes direkt oder indirekt Änderungen an anderen Stellen notwendig machen. Sind die notwendigen Änderungen nicht sofort sichtbar kommt es zu unerwarteten Fehlern.
  32. Vererbungshierarchien sind so komplex geworden, dass die gleichen Objekte in unterschiedlichen Vererbungszweigen gebraucht werden oder zwei Vererbungshierarchien sind so stark von einander abhängig, dass sie sich gegenseitig zur Vererbung zwingen.
  33. Es sind Änderungen an einer Klasse notwendig, die nichts mit dem eigentlich Änderungsgrund zu tun haben sollten. Entsteht häufig durch Verletzung des Single Responsibility Principle, wodurch eine Klasse mehrere Aufgaben hat.
  34. Es ist eine Vielzahl von kleinen Änderungen an vielen einzelnen Klasse notwendig. Entsteht häufig durch Verletzung des Single Responsibility Principle, wodurch mehrere Klassen die gleiche Aufgabe haben, zum Beispiel durch Code Clones.