Wie kommentiert ihr?
-
Ohne zu wissen auf welchem Target, welchem Umfeld, welcher Sprache etc. man sich bewegt _irgendwas_ zu postulieren ist... ach ich halt mich raus. 13 Wahrheiten reichen fürs erste...
-
-fricky- schrieb:
Also ich finde es nie gut, performance gegen 'schönen code' zu tauschen.
o_0 Ernsthaft? Dann schreibst du also nur Performance-Kritische Anwendungen, die auf 8-Bit-Microprozessoren ausfuehren sind und starke Echtzeitbedingungen stellen. Falls dem nicht so ist: bitte erklaer warum du das findest
Schoener Code ist leichter wartbar/lesbar/verstehbar (und damit vermutlich irgendwann auch bugfreier). Auf heutigen X Ghx-Prozessoren mit X GB RAM kommts auf virtuelle Methodenaufrufe statt switches einfach so gut wie nie an.
Uebrigens kommen wir stark vom Thema ab. Mal eine Frage an die "Vieldokumentierer", die auch getSize dokumentieren: dokumentiert ihr auch alle private-Variablen?
-
tfa schrieb:
Bashar schrieb:
Da er nicht mehr Informationen hat, als dass da eine Funktion ein längliches Switch enthält, ist das unwahrscheinlich.
Und aus diesen wenigen Informationen kannst du ableiten, dass OO hier böse ist und er lieber ein Spaghetti-Switch machen soll? Respekt! Ich trau mir das nicht zu.
Nochmal für dich zum mitmeißeln: Das switch besteht schon, der Vorschlag war, es zu beseitigen, indem man "Polymorphie anwendet". Es steht nicht zur Debatte, für ein vorliegendes Problem zwischen den Designalternativen switch und "OO" zu entscheiden.
BTW was soll ein "Spaghetti"-Switch sein? Von Spaghetti-Code spricht man bei verschlungenem, nicht nachvollziehbarem Kontrollfluss. Dazu eignet sich wilder goto-Einsatz besonders gut. Wer den Kontrollfluss eines switch-Statements nicht nachvollziehen kann, sollte m.E. den Beruf wechseln.Hast du schonmal was vom State Pattern gehört? Wer es nicht kennt läuft Gefahr, das eine oder andere überflüsse switch in seinen Code einzubauen, statt ein wartbares Entwurfsmuster zu verwenden. Das soll natürlich nicht heißen, dass switch völlig überflüssig und immer zu ersetzen ist. Aber nachdenken sollte man schon drüber.
Was willst du mir damit sagen? Dass das State-Pattern dazu da ist, switches zu ersetzen? Das kann ja wohl nicht dein Ernst sein. Oder dass man switch durch State ersetzen sollte?
Bashar schrieb:
Reflexartig irgendwelche Patentrezepte auf nichtexistente Probleme anzuwenden ist eigentlich eher das, was unwartbare Designs erst erzeugt.
Ich finde reflexarte Ablehnung von OO-Mustern viel gefährlicher. Außerdem würde ich ein überlanges switch nicht als "nichtexistentes" Problem ansehen.
Jetzt fang nicht an mir irgendwas zu unterstellen, was ich nicht gesagt habe. Was das Problem an einem switch sein soll hast du immernoch nicht gesagt.
-
Bashar schrieb:
[...]
BTW was soll ein "Spaghetti"-Switch sein? Von Spaghetti-Code spricht man bei verschlungenem, nicht nachvollziehbarem Kontrollfluss. Dazu eignet sich wilder goto-Einsatz besonders gut. Wer den Kontrollfluss eines switch-Statements nicht nachvollziehen kann, sollte m.E. den Beruf wechseln.
[...]
Was willst du mir damit sagen? Dass das State-Pattern dazu da ist, switches zu ersetzen? Das kann ja wohl nicht dein Ernst sein. Oder dass man switch durch State ersetzen sollte?
[...] Was das Problem an einem switch sein soll hast du immernoch nicht gesagt.Am besten liest du diesen Thread nochmal durch, besonders, was ich geschrieben habe. Dann klickt du auf den State-Pattern-Link und liest dir das durch. Aber auch ganz nach unten scrollen (wichtig)!
Vielleicht wird's dann Licht. Nimm dir ruhig soviel Zeit wie du brauchst.
-
tfa schrieb:
Am besten liest du diesen Thread nochmal durch, besonders, was ich geschrieben habe.
Soviel war das ja nicht.
Dann klickt du auf den State-Pattern-Link und liest dir das durch. Aber auch ganz nach unten scrollen (wichtig)!
Vielleicht wird's dann Licht. Nimm dir ruhig soviel Zeit wie du brauchst.Wie man Arroganz stilvoll anbringt musst du aber noch lernen.
-
Bashar einfach davon auszugehen, dass irgendein switch mit 30 cases optimal ist und deinem Fall entspricht ist schon extrem unrealistisch.
-
Bashar schrieb:
Nochmal für dich zum mitmeißeln: Das switch besteht schon, der Vorschlag war, es zu beseitigen, indem man "Polymorphie anwendet". Es steht nicht zur Debatte, für ein vorliegendes Problem zwischen den Designalternativen switch und "OO" zu entscheiden.
So hab ich das nie geschrieben oder gemeint. Vielmehr ist in den meisten Fällen schon einiges schief gelaufen, wenn Du überhaupt an den Punkt kommst, ein Switch mit 30 Cases am Stück zu schreiben. Wenn Du konsequent objektorientiert strukturierst, wirst Du in den meisten Fällen gar nicht erst in diese Verlegenheit kommen, solche Monolithen zu implementieren.
Natürlich mag es auch (seltene) Fälle geben, wo man nicht drum herum kommt. Aber auch da ist ein 30er Switch imo eher die schlechtere Wahl. Da wird es sich wohl meistens eher anbieten, diesen Monolith aufzubrechen und z.B. als Chain of Responsibility (siehe GOF) zu implementieren.
Naja, aber wahrscheinlich irre ich, die GOF und alle anderen und Du hast Recht.
SWITCH++
-
Bashar schrieb:
tfa schrieb:
Am besten liest du diesen Thread nochmal durch, besonders, was ich geschrieben habe.
Soviel war das ja nicht.
OK, hier kommt der Vorlese-Service:
tfa schrieb:
Vielleicht hat er auch unwartbaren Spaghetticode zu einem vernünftigen OO-Design gemacht.
...State Pattern... Das soll natürlich nicht heißen, dass switch völlig überflüssig und immer zu ersetzen ist. Aber nachdenken sollte man schon drüber.
Wikipedia schrieb:
State Pattern - As opposed to using switch
The state pattern can be used to replace switch() statements and if {} statements which can be difficult to maintain and are less type-safe.
-
Bei einer fixen Anzahl von Faellen ziehe ich switch vor. Auch wenns 30 Faelle sind. Es sei denn, sie sind wirklich tabellierbar.
-
tfa schrieb:
OK, hier kommt der Vorlese-Service:
Weil das, was ich sage, dir nicht gefällt, gehst du davon aus, dass ich das nicht gelesen hätte.
tfa schrieb:
Vielleicht hat er auch unwartbaren Spaghetticode zu einem vernünftigen OO-Design gemacht.
Das hatten wir schon (vielleicht selbst auch mal lesen?) ... Wir wissen nicht, was dieses konkrete switch tut oder warum es existiert. Vielleicht hat es seinen guten Grund, und davon sollte man zuerst mal ausgehen, es sei denn es gibt guten Grund, das anzuzweifeln. Allein die Zahl der Cases ist es nicht.
Schlechte switches erkennt man zum Beispiel daran, dass dieselbe Fallunterscheidung an mehreren Stellen vorgenommen wird. Erst dann hat man ein Wartungsproblem, weil bei Änderungen an einer Stelle die anderen Stellen vergessen werden können.
...State Pattern... Das soll natürlich nicht heißen, dass switch völlig überflüssig und immer zu ersetzen ist. Aber nachdenken sollte man schon drüber.
Nachdenken sollte man immer, gut dass wir uns da einig sind. Deine sonstigen Äußerungen stehen zu dieser Aussage aber im Widerspruch...
Wikipedia schrieb:
State Pattern - As opposed to using switch
The state pattern can be used to replace switch() statements and if {} statements which can be difficult to maintain and are less type-safe.
Hast du dein Wissen über das State-Pattern eigentlich aus Wikipedia? Der Einsatz von Polymorphie statt Type-Switches, wie es in einem prozeduralen Stil üblich wäre, ist eine grundlegende OO-Technik, die natürlich auch bei vielen Patterns zum Einsatz kommt. Das heißt aber erstens nicht, dass diese Ersetzung Gegenstand des State-Patterns ist, und zweitens heißt es nicht, dass es für jedes switch angewendet werden kann oder sollte.
-
byto schrieb:
Natürlich mag es auch (seltene) Fälle geben, wo man nicht drum herum kommt. Aber auch da ist ein 30er Switch imo eher die schlechtere Wahl. Da wird es sich wohl meistens eher anbieten, diesen Monolith aufzubrechen und z.B. als Chain of Responsibility (siehe GOF) zu implementieren.
Wenn man die Kosten der 30 sich ergebenden Klassen im Vergleich zum Wartungsaufwand bei dem switch im Griff hat. Wenn es sich herausstellt, dass diese Klassen auch abgesehen von diesem switch-Aspekt im Gesamtsystem Sinn ergeben. Dann wurden sie wohl bei der Analyse übersehen. Aber nur für dieses eine Refactoring? Niemals.
Naja, aber wahrscheinlich irre ich, die GOF und alle anderen und Du hast Recht.
Du magst mir gerne Zitate der GOF bringen, in denen sie sagen, dass man jegliches switch, evtl. ab einer bestimmten Zahl von Cases, durch Polymorphie ersetzen sollte. (Edit: Aber erst nach dem Urlaub
bis dann)
-
Wo die Wartung angesprochen wurde, kann ein etwas längerer Switch durchaus wartungsfreundlicher sein als eine Map auf Funktionen oder ein komplettes OO Konzept.
Die Grausamste switch-Anweisung die ich in dem Unternehmen in dem ich derzeit aktiv bin, kenne besteht auf 67 Zweigen und 32 Bildschirmseiten Code. (Wobei die Sprache und die vielen globalen Variablen für die Seiteneffekte viel schlimmer sind.) Ich kenne also auch Bereiche, in denen es dringenst Nötig gewesen wäre, das Konstrukt durch etwas Sinnvolles zu ersetzen.
Aber oft wachsen Projekte - und verschiedenste Entwickler mit unterschiedlichsten Qualifikationen müssen an der SW arbeiten.
Nehmen wir aber mal ein einfaches Menü - 4 Menüpunkte. An sich ok für ein switch Statement, schnell erweitert und jeder sieht um was es geht.
Natürlich lässt sich das jetzt auch in eine Zuordnung Wert -> Funktion packen. Das schaut super raffiniert aus an der Stelle an der man die Menüaufrufe bedient. Einfach nur ein map[value].doIt(); Aber was ist denn der Preis für diesen Einzeiler ?
a) Fehlerbehandlung auf nicht vorhandene Elemente.
b) Seiteneffekte durch Manipulation der Map
c) Nun hab ich keine 30 Zeilen mehr durch einen Casezweig - nun hab ich 30 Zeilen die die Map initialisieren
d) Nicht alles was in dem Switch vorkommen würde passt in die Map. Also endet es irgendwo in einem Code, der ohne Debugger oder längerem Lesen nicht nachvollzogen werden kann
e) Für das einfügen eines einfachen Menüpunktes muss ich nun deutlich höher Qualifiziertes Personal beschäftigen. Das einfügen eines Punktes kann nun durchaus länger benötigen als ein case: neueFunktion(); break;
f) Ich kann nicht mehr mit einem Blick sagen welche Fälle behandelt werden - die Map kann an verschiedensten Orten befüllt werdenDas System ist insgesamt nun schöner, eleganter und - vorallem - komplexer und dadurch teurer in der Wartung. Kritisch wird es dann, wenn ein schlampiger Entwickler - oder ein Entwickler oder enormen Zeidruck (z.B. vor Ort beim Kunden) schnell eine Lösung dazwischenfummelt. Dann unterläuft es das ganze System das zuvor elegant alles erledigt und die Seiteneffekte sind nicht vorhersehbar.
Sicherlich stimme ich mit den Aussagen, kleine Funktionen -> Übersichtlicher und einfacher überein*, aber nicht in allen Fällen ist die eleganteste oder "schönste" Lösung die beste und Wartungsfreundlichste. Gerade im Bereich, bei den die Zeit für eine Softwareerstellung in Stunden bis max. Tage gemessen wird kann man nicht 2 Stunden für die schönste Lösung verbraten. Da wird eine Funktion, vor allem durch Änderungen, einfach mal länger wie eine 1/2 Bildschirmseite.
Ich habe hier durchaus Entwickler im Unternehmen gehabt, die bei der Erweiterung einer kleinen 600€ Software erst einmal 2 Tage mit Umbauen verbracht haben. Die Argumente waren denen, die man hier im Forum immer wieder lesen kann sehr ähnlich. (Die Wirtschaftlichkeit hat sich dem Problem jedoch angenommen.)
Ohne zu wissen auf welchem Target, welchem Umfeld, welcher Sprache etc. man sich bewegt _irgendwas_ zu postulieren ist..
Der Satz spricht mir aus der Seele. Ich finde es immer wieder erstaunlich was alles im Namen des "sauberen" oder "eleganten" Codes gepostet und als "die" Lösung verteidigt wird. Immer öfter bekomme ich dabei das Gefühl, das da aus reiner Theorie geschrieben wird und keinerlei Praxiserfahrung vorhanden ist. Erst recht nicht in Bereichen, in denen man den Zeitrahmen eines Projektes in Stunden bis 5 Tage bemisst, nicht in Monaten oder gar Jahren.
Interpretiere ich die Meinung mancher Forennutzer richtig, muss eine Software zwangsläufig Plattformübergreifende Bibliotheken verwenden, alles andere ist nicht haltbar. Das fängt beim UI an und hört bei Klassen für Netzwerkzugriffe nicht auf.
Noch schlimmer sind die Leute, die für jedes Problem erst einmal eine eigene Sprache erzeugen wollen die speziell für die Aufgabenlösung zugeschneidert ist und einen
einfachen wartbaren Code erzeugen. Erstaunlicherweise werden solche Ideen mit der Zunahme von praktischen Erfahrungen geringer.* Jeder, der Code erzeugt, bei dem man nur den Kopf schütteln kann, muss man einfach mal zu seinem Glück zwingen es mit kleinen Funktionen zu versuchen. Er wird irgendwann einsehen, das es deutliche Vorteile hat, auch wenn man von Natur aus zum schlampen neigt.
-
Knuddlbaer schrieb:
a) Fehlerbehandlung auf nicht vorhandene Elemente.
b) Seiteneffekte durch Manipulation der Map
c) Nun hab ich keine 30 Zeilen mehr durch einen Casezweig - nun hab ich 30 Zeilen die die Map initialisieren
d) Nicht alles was in dem Switch vorkommen würde passt in die Map. Also endet es irgendwo in einem Code, der ohne Debugger oder längerem Lesen nicht nachvollzogen werden kann
e) Für das einfügen eines einfachen Menüpunktes muss ich nun deutlich höher Qualifiziertes Personal beschäftigen. Das einfügen eines Punktes kann nun durchaus länger benötigen als ein case: neueFunktion(); break;
f) Ich kann nicht mehr mit einem Blick sagen welche Fälle behandelt werden - die Map kann an verschiedensten Orten befüllt werdenDiese Punkte gelten doch alle nicht, weis nicht was du damit willst.
a) das gleiche bei Switch-Caste.
b) kann man umgehen, indem man eine Readonly-Map hat.
c)switch foo { case a: doA(); break; case b: doB(); break; // ... case z: doZ(); break; } // versus map.put(a, doA); map.put(b, doB); //... map.put(z, doZ); // ist also das gleiche
d) verstehe ich nicht
e) vielleicht braucht mal wirklich einen hoeheren Abschluss fuer ein map.put(z, doZ);
f) readonly-mapDas System ist insgesamt nun schöner, eleganter und - vorallem - komplexer und dadurch teurer in der Wartung. Kritisch wird es dann, wenn ein schlampiger Entwickler - oder ein Entwickler oder enormen Zeidruck (z.B. vor Ort beim Kunden) schnell eine Lösung dazwischenfummelt. Dann unterläuft es das ganze System das zuvor elegant alles erledigt und die Seiteneffekte sind nicht vorhersehbar.
Das bezweifle ich. Je eleganter der Code ist, desto einfach kann man ihn warten und erweitern. Ein schlampiger Programmierer wird dir jedes System unterlaufen. Ein eleganter Code macht es einem nur leichter, wenn der Programmierer es aber nicht will, dann hilft einem auch nichts mehr.
-
Bashar schrieb:
Weil das, was ich sage, dir nicht gefällt, gehst du davon aus, dass ich das nicht gelesen hätte.
Nein. Wenn einer Blödsinn schreibt und Fragen stellt wie "Was willst du mir damit sagen? Dass das State-Pattern dazu da ist, switches zu ersetzen? Das kann ja wohl nicht dein Ernst sein." - Fragen, die sich nach Lesen meiner Aussagen und des Links überhaupt nicht stellen dürften - dann unterstelle ich, dass du nicht gelesen hast oder es nicht kapiert hast.
Das hatten wir schon (vielleicht selbst auch mal lesen?) ... Wir wissen nicht, was dieses konkrete switch tut oder warum es existiert. Vielleicht hat es seinen guten Grund, und davon sollte man zuerst mal ausgehen, es sei denn es gibt guten Grund, das anzuzweifeln. Allein die Zahl der Cases ist es nicht.
Siehe oben.
Hast du dein Wissen über das State-Pattern eigentlich aus Wikipedia? Der Einsatz von Polymorphie statt Type-Switches, wie es in einem prozeduralen Stil üblich wäre, ist eine grundlegende OO-Technik, die natürlich auch bei vielen Patterns zum Einsatz kommt. Das heißt aber erstens nicht, dass diese Ersetzung Gegenstand des State-Patterns ist, und zweitens heißt es nicht, dass es für jedes switch angewendet werden kann oder sollte.
Siehe oben!
Langsam wird mir das echt zu blöd.
-
DEvent schrieb:
Diese Punkte gelten doch alle nicht, weis nicht was du damit willst.
DEvent schrieb:
d) verstehe ich nicht
-
Bashar schrieb:
Wenn man die Kosten der 30 sich ergebenden Klassen im Vergleich zum Wartungsaufwand bei dem switch im Griff hat. Wenn es sich herausstellt, dass diese Klassen auch abgesehen von diesem switch-Aspekt im Gesamtsystem Sinn ergeben. Dann wurden sie wohl bei der Analyse übersehen. Aber nur für dieses eine Refactoring? Niemals.
Du hast meine Aussage, dass man durch Polymorphie häufig so riesige Switch-Monolithen vermeiden kann, erfolgreich mißverstanden. Es ging nie darum, aus einem 30er Switch - oh pardon Du hattest ja schon auf jeden Switch generalisiert, obwohl das hier nie Thema war
- 30 Klassen zu refaktorieren.
-
Blue-Tiger schrieb:
-fricky- schrieb:
Also ich finde es nie gut, performance gegen 'schönen code' zu tauschen.
o_0 Ernsthaft? Dann schreibst du also nur Performance-Kritische Anwendungen, die auf 8-Bit-Microprozessoren ausfuehren sind und starke Echtzeitbedingungen stellen.
manchmal schon. die 'stärksten' prozessoren, mit denen ich's zur zeit zu tun habe, laufen mit 72 Mhz. aber ganz davon abgesehen: ich achte immer darauf, dass ich mir keine unnötigen 'bremsklötze' einbaue und alles so simpel wie möglich halte. zwar sagt man so schön, dass die geschwindigkeit von 20% des codes abhängt, aber wenn man zu arglos jeden kleinkram abstrahiert, dann kann schnell mehr daraus werden.
Blue-Tiger schrieb:
Falls dem nicht so ist: bitte erklaer warum du das findest
Schoener Code ist leichter wartbar/lesbar/verstehbar (und damit vermutlich irgendwann auch bugfreier).
ich finde einfacher code ist verständlicher und leichter wartbar. bei 'schönem code' freut man sich darüber, was man für sich 'ne tolle abkürzung ausgedacht hat, aber das müssen andere erstmal nachvollziehen können. d.h. mehraufwand durch doku usw. ein langes switch-statement finde ich gar nicht so schlimm. wenn man's gut formatiert ist es auch gut lesbar. nur die funktion, in der es steckt, wird eben länger als normal. aber das ist kein wirkliches problem.
DEvent schrieb:
Je eleganter der Code ist, desto einfach kann man ihn warten und erweitern.
das ist ein trugschluss. was für dich eleganz ist, kann für andere völlig verwirrend sein.
-
byto schrieb:
Bashar schrieb:
Wenn man die Kosten der 30 sich ergebenden Klassen im Vergleich zum Wartungsaufwand bei dem switch im Griff hat. Wenn es sich herausstellt, dass diese Klassen auch abgesehen von diesem switch-Aspekt im Gesamtsystem Sinn ergeben. Dann wurden sie wohl bei der Analyse übersehen. Aber nur für dieses eine Refactoring? Niemals.
Du hast meine Aussage, dass man durch Polymorphie häufig so riesige Switch-Monolithen vermeiden kann, erfolgreich mißverstanden. Es ging nie darum, aus einem 30er Switch - oh pardon Du hattest ja schon auf jeden Switch generalisiert, obwohl das hier nie Thema war
- 30 Klassen zu refaktorieren.
Na dann -- gut, dass wir drüber gesprochen haben