"Code-Smell"?

Alles, was nicht direkt mit Python-Problemen zu tun hat. Dies ist auch der perfekte Platz für Jobangebote.
heiliga horsd

Moin!

Ich lese hier immer wieder ein paar Threads durch und stoße häufig auf Hinweise wie "foo ist ein CodeSmell, mach lieber bar" oder so ähnlich. Ich hab mir vorhin nochmal PEP8 durchgelesen und darin stand nichts von solchen "CodeSmells". Daher wollte ich hier mal kurz fragen: Warum sind das "CodeSmell"s, wenn es in anderen Programmiersprachen anscheinend durchaus legitime Prozeduren sind, und wo sind alle aufgelistet damit man sich das anschauen und zukünftig auch vermeiden kann?

Lg HH
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Also nummerieren von Variablen ist in keiner Sprache die ich kenne eine legitime Prozedur. Oder worauf spielst du genau an?

Mir ist eine Auflistung nicht bekannt, für mich sind das Erfahrungswerte. Du kannst natürlich einen passenden Artikel im Wiki starten.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

rads
User
Beiträge: 153
Registriert: Freitag 26. März 2010, 15:51

Mir wurde von BlackJack pylint und pyflakes ans Herz gelegt, um unschönen und so auch oft inperformanten Code mittels Tools in Programmcode aufzuspüren.

CodeSmells, ohne jetzt auf Wikipedia zurück zu greifen, sind Codeteile, Programmabschnitte welche zwar durch
den Compiler übersetzt werden könnten (alternativ Interpreter bei anderen Sprachen) aber schlichtweg eine
schlechte Lösung darstellen.

Beispiel gibt es hier unendlich viele

z.B.
- würdest du ja auch nie auf die Idee kommen die Fakultät über eine Schleife zu berechen
- In C objekte nicht zu "zerstören" wenn sie nicht mehr benötigt werden
- auf Classevariablen direkt, anstatt mit Getter/Setter zuzugreifen
- Mehrfach iterative Schleifen anstatt Rekursion zu nutzen
- Variablenbezeichnung mit a, b , c wählen

Im groben und ganzen läuft das für mich unter Codingstyle und Softwaredesign. Sowas fängt wie gesagt schon darin an
die variablen mit vernünftigen Namen zu versehen und endet darin das man anstatt "bla" + "Bla" einen StringBuffer verwenden. Ebenfalls gehört es für mich dazu definierte Design Patterns zu verwenden und nicht jedesmal das Rad neu zu erfinden (z.b. Observer Pattern).
Dies sorgt schlussendlich für einen performanten, wartbaren und auch durch andere Personen lesbaren Code

Grüße

p.s. ja ich gebs zu, bisl weit ausgeholt
heiliga horsd

Leonidas hat geschrieben:Also nummerieren von Variablen ist in keiner Sprache die ich kenne eine legitime Prozedur. Oder worauf spielst du genau an?

Mir ist eine Auflistung nicht bekannt, für mich sind das Erfahrungswerte. Du kannst natürlich einen passenden Artikel im Wiki starten.
Konkret:
http://www.python-forum.de/viewtopic.ph ... 19#p170519

Es gibt doch sicherlich Programmiersprachen, in denen sowasa Gang und Gäbe ist, oder?


@cofi: Danke, aber der Hinweis von BlackJack den ich oben verlinkt habe wird da ja auch nicht aufgeführt - also ist das eher so etwas inoffizielles wie "jeder weiß es aber es steht nirgends geschrieben" oder kocht da jeder sein eigenes Süppchen?

@rads: Fakultät mit einer Schleife wäre ja dann die iterative Version oder? Also bei Python bin ich schon aufdie Idee gekommen, nachdem es da ein recursion-limit gibt.
pylint und pyflakes werde ich trotzdem mal googlen, danke dir!
rads
User
Beiträge: 153
Registriert: Freitag 26. März 2010, 15:51

@rads: Fakultät mit einer Schleife wäre ja dann die iterative Version oder? Also bei Python bin ich schon aufdie Idee gekommen, nachdem es da ein recursion-limit gibt.
Ein recursions-limit gibt es quasi in jeder Sprache, man könnte sie anpassen bei bedarf. Aber für Fakultät würde ich math.factorial() verwenden. Ich behaupte besser als diese Standardfunktion kann ich es auch nicht. Ansonsten sehe ich als Software Entwicklung Tutor i den Erstsemestlern oft Programmteile, in welchen Mathematischen Ergebnisse manuell errechnet werden (Summe von 1 bis 10.000) anstatt die mathematische Formel dafür zu verwenden. Wie gesagt, war nur eines von vielen Beispielen.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

heiliga horsd hat geschrieben:@cofi: Danke, aber der Hinweis von BlackJack den ich oben verlinkt habe wird da ja auch nicht aufgeführt - also ist das eher so etwas inoffizielles wie "jeder weiß es aber es steht nirgends geschrieben" oder kocht da jeder sein eigenes Süppchen?
Nunja, es sind Bestandteil der offiziellen Doku, also wuerde ich es nicht unbedingt "inoffiziell" nennen, aber die Aufzaehlungen hatte keinen Anspruch auf Vollstaendigkeit und beschaeftigt sich auch eher mit Python-spezifischen Sachen.

Es gibt aber auch Sachen, die generell schlecht sind (durchnummerierte Variablen), schlecht in OO-Stil/Funktionaler Programmierung/etc.

Zu dem konkreten Problem: Das ist IMO schon ein OO-Codesmell, aber man muss das auch pragmatisch sehen, da es sich nicht unbedingt lohnt die Typhierarchie aufzublasen. Bzw in Python kommt man um Typtests nicht herum (wenn man das _so_ machen will), da es kein typbasiertes Dispatching gibt, aber Ducktyping und EAFP sind sowieso gelaeufiger.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

rads hat geschrieben:z.B.
- würdest du ja auch nie auf die Idee kommen die Fakultät über eine Schleife zu berechen
- In C objekte nicht zu "zerstören" wenn sie nicht mehr benötigt werden
- auf Classevariablen direkt, anstatt mit Getter/Setter zuzugreifen
- Mehrfach iterative Schleifen anstatt Rekursion zu nutzen
- Variablenbezeichnung mit a, b , c wählen

Im groben und ganzen läuft das für mich unter Codingstyle und Softwaredesign. Sowas fängt wie gesagt schon darin an
die variablen mit vernünftigen Namen zu versehen und endet darin das man anstatt "bla" + "Bla" einen StringBuffer verwenden.
Das ist jetzt aber tatsächlich recht Java-spezifisch. Natürlich würde ich in Python auf Instanzvariablen direkt zugreifen und natürlich würde ich Iteration der Rekursion vorziehen wenn ich mit großen Daten arbeite die das Rekursionslimit überschreiten (in Java eigentlich auch, fwiw).

Ich weiß gar nicht ob ich das Codesmell nennen würde...
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
heiliga horsd

@rads: Ich denke das Zusammenzählen (dein Beispiel mit der Summe) würde ich auch machen, da ich keine solche Formel/Funktion kenne.
@cofi: Den letzten Abschnitt habe ich nicht wirklich verstanden.

Solche Code-Smells haben ja anscheinend durchaus Hand und Fuß wenn ich mir die Erläuterungen so ansehe, aber allzuviel davon verstehe ich wiederum auch nicht, da ich einfach noch wenig Erfahrung habe. Hat sich denn noch niemand auf dieser Welt die Arbeit gemacht, diese Dinge mal fragmentartig zusammen zu suchen und auch für noch nicht so erfahrene Programmierer aufzuarbeiten?
rads
User
Beiträge: 153
Registriert: Freitag 26. März 2010, 15:51

Die Summenformel gabs vom kleinen Gauß aus seiner Schulzeit Summe von 0 bis N ist die Formel n(n+1)/2.
Sind dann nur noch 2 mul 1 invert 1 sum und nicht n add befehle.

An sich gibt gibt es wohl kaum ein Dokument welch alle möglichen Fehler festhällt. gut wird das wie gesagt durch die genannten Tools festgehalten.
Es sind schlichtweg zu viele Regeln. Man lässt sich ein solches Tool drüberlaufen, dann wertet man den Report aus und überlegt was sinnvoll sein könnte und was nicht. Hierfür ist an sich aber schon etwas Erfahrung notwendig um wichtige Codesmells von unwichtigen zu unterscheiden.

Am besten empfehle ich als echter Beginner ein klassisches Einführungsbuch. die Starter-Bücher gehen typischerweise auf verwendete Notationen und dos an nots ein.

Leonidas kann dir hier sicherlich ein gutes Python Buch empfehlen, welches genau das beschreibt. Ich fand das Galileo Python OpenBook ganz gut, vielleicht zu umfangreich. http://openbook.galileocomputing.de/python/
rads
User
Beiträge: 153
Registriert: Freitag 26. März 2010, 15:51

Was ich gerade gesehen habe,

falls Pep auf englisch jemandem zu anstrengend ist, ich unterstelle das natürlich jetzt niemanden, gibts das auch mehr oder wenig gut übersetzt unter:

http://wiki.python.de/PEP%208%20%28%C3%9Cbersetzung%29
heiliga horsd

Ein Einsteigerbuch hab ich schon durchgearbeitet und inzwischen hab ich mich auch schon bei Python 3 eingefunden, aber wenn das Buch gegen die PEP8 verstößt habe ich nicht wirklich hohe Erwartungen außer als dass es mich einführt und mir etwas Gespühr verleiht.
(Einstieg in Python 3, auch von Galileo Computing)

Da es hier wohl nicht viel zu lernen, sondern nur zu erfahren gibt, werd ich damit wohl weiter machen: erfahrungen sammeln. Vielen Dank an alle die sich gemeldet haben und die hilfreichen Tipps.

Zu deinem Hinweis: PEP 8 habe ich inzwischen ca. 10x durchgearbeitet, das letzte Mal heute weil ich nochmal auf Nummer sicher gehen wollte bevor ich den thread eröffne. Aber trotzdem Danke ;)
BlackJack

@heiliga horsd: Wichtig bei "code smells" ist, dass der Code erst einmal nur unschön "riecht". Das heisst es kann durchaus legitim sein so etwas in seinem Programm zu haben, solange man begründen kann warum man das so gemacht hat. Beispiel Typtests und darauf basierende Entscheidungen mit `instanceof()` oder `type()`: Man sollte die vermeiden, weil man damit das "duck typing" aushebelt und es dem OOP-Paradigma zuwiederlaufen kann. Letzteres ist der Grund warum ``instanceof``-Tests auch in Java ein "code smell" sind. Aber manchmal muss man halt doch darauf zurückgreifen weil die Alternative nicht sauber möglich oder *wesentlich* aufwändiger ist.

Dass nicht alle "code smells" universell für alle Sprachen gelten, sieht man hier an dem Beispiel mit Attributzugriffen über Getter/Setter ganz gut. In Sprachen die berechnete Attributzugriffe a.k.a. Properties kennen, sind Getter/Setter nicht notwendig um für Clientcode eine unveränderte API zu bieten wenn man irgendwann aus normalen Attributen berechnete machen möchte. Bei Sprachen die keine Properties kennen müsste man ohne Getter/Setter nicht nur die veränderte Klasse, sondern auch allen Code der die jetzt veränderte API verwendet, anpassen.

Und auch Rekursion vs. Iteration: Python ist eher auf Iteration ausgelegt, mit einem relativ niedrigen Rekursionslimit und ohne garantierte "tail call optimization". Zusätzlich ist der Funktionsaufruf von der Laufzeit her verhältnismässig teuer. Bei funktionalen Programmiersprachen sieht das anders aus.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Noch ein Beispiel wäre vielleicht jemand, der nicht weiß, dass man bei Python direkt über die Elemente eine Sequenz (a.k.a. Array) iterieren kann und Code wie diesen schreibt:

Code: Alles auswählen

>>> mystring = 'code smell'
>>> for i in range(len(mystring)): print mystring[i]
... 
c
o
d
e
 
s
m
e
l
l
Das klappt zwar, aber ist halt total kompliziert und unpythonisch. Wenn ich persönlich irgendwelche Python-Projekte angucke und relativ schnell stark riechenden Code entdecke, ist das ein guter Grund für mich, die Finger davon zu lassen.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

rads hat geschrieben:Leonidas kann dir hier sicherlich ein gutes Python Buch empfehlen, welches genau das beschreibt. Ich fand das Galileo Python OpenBook ganz gut, vielleicht zu umfangreich. http://openbook.galileocomputing.de/python/
Der Rest des Forums hat sich recht einstimmig auf das Buch eingeschossen, BlackJack hat sogar eine (sehr negative) Kritik verfasst, ich bin mir da auch sehr sicher, dass es nicht empfehlenswert ist.
Wie Leonidas schon gesagt hat, ist der direkte Zugriff auf Instanzvariablen kein Problem, schliesslich kann man Aenderungen an der Implementierung mit Properties fuer den Anwender abstrahieren.

@heiliga horsd: In C++/Java kann man eine Methode ueberladen, sodass je nach Typ der Argumente etwas anderes ausgefuehrt wird. Das ist typbasiertes Dispatching.
Ducktyping heisst, dass man Objekte, die sich gleich verhalten (lingua python: diesselben Protokolle implementieren) auch gleich behandelt.
EAFP: "it's Easier to Ask Forgiveness than Permission", im Allgeinen ein auf Exceptions ausgerichteter Programmierstil.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

cofi hat geschrieben:Ducktyping heisst, dass man Objekte, die sich gleich verhalten (lingua python: diesselben Protokolle implementieren) auch gleich behandelt.
Oder anders gesagt: Man guckt nicht so sehr auf den Typ sondern versucht, die-und-die Methode auszuführen. Existiert die Methode nicht, gibt es einen Fehler und es wird wohl das falsche Objekt übergeben worden sein. Den Fehler hätte man ja bei expliziter Typprüfung genau so, nur dass man sich a) die Zeilen dafür sparen kann und b) eben auch alternative Typen behandeln kann.

@heiliga horsd: Schau dir zum Beispiel mal den Code vom Modul StringIO an. Damit kann man Funktionen, die eine Datei erwarten, einfach eine solche vorgaukeln. Die `.read()`-Methode wird sich genau so verhalten, wie die Funktion es erwartet - außer natürlich, sie testet es vorher explizit und merkt, dass sie nichts vom Typ `file` bekommen hat...
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

rads hat geschrieben:Leonidas kann dir hier sicherlich ein gutes Python Buch empfehlen, welches genau das beschreibt. Ich fand das Galileo Python OpenBook ganz gut, vielleicht zu umfangreich. http://openbook.galileocomputing.de/python/
Wie cofi schrieb führt eben dieses Buch zu "code smells" da die Autoren versuchen Konzepte aus Java nach Python bringen die in Pyhton eben keine gute Idee sind. Wenns um idiomatischen Code geht ist "Expert Python Programming" besser geeignet - auch wenn nicht direkt für Einsteiger.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
heiliga horsd

Also, ich versuch das jetzt mal in eigenen Worten zusammenzufassen:

Als CodeSmell ist in Python Code gemeint, der entweder gegen "pythonische Philosophie" verstößt, wie Beispielsweise Typprüfungen beim in Python verwendeten Duck Typing, oder eben Dinge unnötig verkompliziert, wie zum Beispiel das ermitteln der Länge einer Liste um dann darüber zu iterieren anstatt gleich über die Liste zu iterieren. CodeSmell ist jedoch durchaus legitim, wenn sich eine äquivalente Funktion nur mit deutlichem Mehraufwand entwickeln ließe.

Kann man das so stehen lassen?
Zuletzt geändert von heiliga horsd am Donnerstag 27. Mai 2010, 20:26, insgesamt 1-mal geändert.
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Ja. Aber ich muss hinzufügen, dass ich die Formulierung "… nicht ohne …" hasse; macht den Satz nur unnötig kompliziert! :evil:
heiliga horsd

derdon hat geschrieben:Ja. Aber ich muss hinzufügen, dass ich die Formulierung "… nicht ohne …" hasse; macht den Satz nur unnötig kompliziert! :evil:
Als CodeSmell ist in Python Code gemeint, der entweder gegen "pythonische Philosophie" verstößt, wie Beispielsweise Typprüfungen beim in Python verwendeten Duck Typing, oder eben Dinge unnötig verkompliziert, wie zum Beispiel das ermitteln der Länge einer Liste um dann darüber zu iterieren anstatt gleich über die Liste zu iterieren. CodeSmell ist jedoch durchaus legitim, wenn sich eine äquivalente Funktion nur mit deutlichem Mehraufwand entwickeln ließe.
Besser?
Antworten