Performance Aware Programming

Entwickelt ihr "Performance-Aware"?

  • Ja, ich nutzte Cachefreundliche Datenstrukten und nutze die CPU effizient aus

    Stimmen: 7 25,0%
  • Ja ist mir bekannt, kann ich aber aus bestimmten Gründen nicht umsetzen

    Stimmen: 11 39,3%
  • Ja ist mir bekannt, aber ich verstehe es nicht

    Stimmen: 2 7,1%
  • Nein, klingt aber interessant und würde gerne mehr darüber erfahren

    Stimmen: 2 7,1%
  • Nein, denn Performance spielt keine Rolle in meinen Codes

    Stimmen: 6 21,4%

  • Umfrageteilnehmer
    28
  • Umfrage geschlossen .
BeBur schrieb:
Dann lies mal auch die kommentare dazu.
Hab ich, und zwar nicht nur die populärsten

BeBur schrieb:
Bitte nicht Performance-Aware entwickeln, sondern Maintenance-Aware.
Ich denke, dass sich das nicht ausschließen muss und ohne Maintenance Einbußen auch viel an Performance rausholen kann.

BeBur schrieb:
Es gibt im Allgemeinen nur ein Performance Problem, wenn man komplexe Zwischenlayer einsetzt (z.B. Electron oder React Native)
Sehe ich auch anders. Merkt man z.B. ältere oder günstigere Smartphones/Laptops/Tablets nutzt. Achja, Browser würde ich zu den komplexen Zwischenlayer dazuzählen.

Aber da kommt es wieder drauf an:
KitKat::new() schrieb:
irrelevant für den Entwickler, aber am Ende kaufen Leute doch neue HW, weil Software zu träge wird oder der Arbeitsspeicher ausgeht
Ergänzung ()

Piktogramm schrieb:
An solchen Stellen sollte man Warbarkeit und Erweiterbarkeit bzw. die Prinzipien von "Clean Code" nicht ohne (akute) Not einer Performanceoptimierung opfern.
Und switch case opfert inwiefern Wartbarkeit, wie z.B. Erweiterbarkeit?
Man könnte sogar dahingegen argumentieren, dass sich diese erhöht, weil ein spezifischer Teil der Businesslogik gesammelt wird statt über mehrere Klassen verstreut wird:
I prefer to have those 104 cases all in one place (as is the case, when it is a switch statement) rather than each in a separate file, that I need to jump around between now (as is the case with polymorphism). This situation is a bit analogous to organising things column-wise vs row-wise. And in practice I find that I need to jump around a lot less with code that uses switches than with code that uses polymorphism. Tangentially, the latter is also more prone to turning into spaghetti, as the whole is obscured by indirection levels between the parts, but you don't see the spaghetti until you try to step through the code, when debugging an issue or just trying to familiarise yourself with a new codebase.
https://news.ycombinator.com/item?id=34980045

In der Pauschalität würde ich definitiv nicht mitgehen.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: BeBur
So ich als TE werde mich jetzt auch mal zu Wort melden, denn tatsächlich war der "Clean Code" Artikel eines der Gründe warum ich diesen gestartet habe.

Grundsätzlich bin ich sehr für OOP und Abtraktion, aber ich sehe oft Codes die nur wegen S.O.L.I.D oder anderen Prinzipien unnötig Abstraktionen erzeugen, welche enorm die Performance verringern - teilweise sogar um Faktor 100!

Ich habe tatsächlich erst vor kurzem ein Realbeispiel aus der Arbeit gehabt, bei dem wir von hunderten Signalen mit einer Länge von 50.000 - 500.000 das Minimum und das Maximum abfragen musstem - der Code vom Dienstleister aber so katastrophal langsam war, das wir das abbrechen mussten und ich diesen einen Teil neu geschrieben habe und es dadurch um Faktor 10-20 schneller wurde.

Datenbasis:

  • Jedes Signal hat N-Werte - typischerweise float, kann aber auch nen anderer Datentyp sein
  • Signale sind abstrakt implementiert, damit jeder Datentyp damit abbildbar ist
  • Werte sind in der Zeit idealerweise sortiert, gibt aber keine Garantie dafür
  • Nicht jeder Wert ist gültig, deshalb gibt es ein einen State für jeden einzelnen Wert der beschreibt ob dieser Gültig oder Ungültig ist (Enum/Bitmaske).
  • Die Anzahl an States ist identisch mit der Anzahl an Werten
  • Direkter Zugriff auf die Daten ist nicht möglich, nur Getter sind erlaubt im spezialierten Interface für den jeweiligen Datentyp

Warum war es langsam?

  • Weil unnötig Speicher auf dem Heap angelegt wurde, für Arrays, für Listen, usw.
  • Weil (lock) verwendet wurde um Ergebnisse aus Threads zu Synchronisieren
  • Overhead von Multithreading und Tasks (Parallel.For)
  • Kein direkter Zugriff auf die Daten möglich war, wegen Abstraktion
  • Millionen Aufrufe von virtuellen Funktionen, weil für jeden einzelnen Wert
  • Mind. 3 Schichten Abstraktion bevor überhaupt der tatsächliche Code ausgeführt wurde
  • Ineffiziente Datenstrukturen

Was habe ich gemacht?

  • Aufs wesentliche reduziert
  • Komplett auf Multithreading verzichtet
  • Sichergestellt das nur Stackallokierter Speicher verwendet wird
  • Vector<> aka SIMD verwendet mit ConditionalSelect() und Masken, um ungültige Werte auszuschließen
  • IPC erhöht mit manuellem Loop-Unrolling, damit die CPU mehr Instruktionen parallel starten kann

Alleine schon das hat mind. 10x und mehr an Performance gebracht, aber das war tatsächlich nicht das Ende der Fahnenstangen, denn schlussendlich habe ich sogar erreicht dass der jeweilige Dienstleister die Datenstrukturen soweit verändert hat, damit wir diesen Code noch effizienter verwenden können, wie z.b. States sind Bitmasken anstatt Enum, direkter Zugriff auf Daten und States möglich.

Ich habe mittlerweile auch den ganzen Kram mal privat nachgebaut und anonymisiert und werd dies die Tage mal auf Github hochladen.
 
  • Gefällt mir
Reaktionen: andy_m4 und BeBur
KitKat::new() schrieb:
Und switch case opfert inwiefern Wartbarkeit, wie z.B. Erweiterbarkeit?
Man könnte sogar dahingegen argumentieren, dass sich diese erhöht, weil ein spezifischer Teil der Businesslogik gesammelt wird statt über mehrere Klassen verstreut wird:
Na hoffentlich programmiert Niemand so, dass großartig Logik in einem Switchstatement enthalten ist. Normalerweise sollten da schon Aufrufe auf Funktionen/Methoden erfolgen und wenn diese komplex werden, werden innerhalb dieser weitere Aufrufe fällig. Da verteilt sich die Definition des Programms dann entsprechend ebenso auf zig Subdefinitionen der Funktionen, Datenstrukturen etc. pp.
In der Regel das keinen Deut besser, je nach genauem Fall ist es meist nicht schneller und weil der gemeinsame "Standard" von Clean Code fehlt wird es grandiose Scheiße wenn da mehrere Entwickler(-generationen) dran gearbeitet haben.
 
  • Gefällt mir
Reaktionen: Aduasen und JP-M
Piktogramm schrieb:
Normalerweise sollten da schon Aufrufe auf Funktionen/Methoden erfolgen und wenn diese komplex werden, werden innerhalb dieser weitere Aufrufe fällig. Da verteilt sich die Definition des Programms dann entsprechend ebenso auf zig Subdefinitionen der Funktionen, Datenstrukturen etc. pp.
und wo ist jetzt das Problem?

Piktogramm schrieb:
In der Regel das keinen Deut besser, je nach genauem Fall ist es meist nicht schneller
ja kann man sicher einfach mal behaupten. Ob das weiter hilft, gerade in den indviduellen Fällen, ist fraglich

Piktogramm schrieb:
und weil der gemeinsame "Standard" von Clean Code fehlt wird es grandiose Scheiße wenn da mehrere Entwickler(-generationen) dran gearbeitet haben.
Es fällt echt schwer das ernst zu nehmen.
Code, der mal switch statements statt Klassenpolymorphismus nutzt, soll grandiose Scheisse werden, weil man dadurch nicht strikt einem Stil aus einem Buch folgt, das selbst nicht einmal diesen Anspruch verfolgt?
 
@KitKat::new()
Ich bin mir gerade nicht sicher, ob wir wirklich aneinander vorbeireden, oder ob es absichtliches nicht verstehen wollen ist..

Du selbst hast einen englischen Text zitiert, bei dem jemand das "im Code Herumspringen" negativ dargestellt wird. Worauf meine Erwiderung ist, dass das bei so oder so der Fall ist. Egal ob Switch zum Einsatz kommt oder Polymorphie genutzt wird. Die Unterschiede in der Übersichtlichkeit sind eher klein, vor allem mit modernen IDEs. Persönliche Präferenz lass ich durchgehen, ein $foo ist übersichtlicher als $bar kann ich an der Stelle nicht mitgehen.

KitKat::new() schrieb:
ja kann man sicher einfach mal behaupten. Ob das weiter hilft, gerade in den indviduellen Fällen, ist fraglich
Ja was, das Beispiel aus dem Video holt bei einem Minimalbeispiel des Code und Daten komplett in L1I und L1D passen dürften 10Takte je Verzweigung heraus bei tendenziell guter Trefferquote der Sprungvorhersage. Ein paar Daten, zufällige Verzweigung, mehr Verzweigungsmöglichkeiten sowie komplexere Berechnungen und das sieht alles anders aus.
Naja und dann zeigt der Herr auch noch selber, dass wenn der Teil vom Code ein kritischer Pfad ist, man am aller besten an der Struktur der Daten arbeiten, damit man den Kram in größeren Blöcken vektorisieren kann.

KitKat::new() schrieb:
Code, der mal switch statements statt Klassenpolymorphismus nutzt, soll grandiose Scheisse werden, weil man dadurch nicht strikt einem Stil aus einem Buch folgt, das selbst nicht einmal diesen Anspruch verfolgt?
Das steht so nicht da. Da steht, dass Code der von verschiedenen Leuten (zu verschiedenen Zeiten aka. "Generationen") ohne gemeinsamen, klar definierten Standard geschrieben wird, bei Zeiten "grandiose Scheiße" wird. Da hilft es ungemein, wenn man allen entweder die Lektüre des Buches auferlegt, oder aber wenigstens eigene, klare Regeln definiert.
 
  • Gefällt mir
Reaktionen: Aduasen
Piktogramm schrieb:
Du selbst hast einen englischen Text zitiert, bei dem jemand das "im Code Herumspringen" negativ dargestellt wird. Worauf meine Erwiderung ist, dass das bei so oder so der Fall ist. Egal ob Switch zum Einsatz kommt oder Polymorphie genutzt wird.
Selbst, wenn einige Subfunktionen nötig sind, kann es noch ein signifikanter Vorteil sein diese spezifische Funktionalität in einer Datei zu haben, da es ja weiter eine höhere Kohärenz für diesen logischen Bereich gibt.
Ich denke davon bleibt selbst noch etwas übrig, wenn mehrere Dateien draus werden.

Piktogramm schrieb:
Ja was, das Beispiel aus dem Video holt bei einem Minimalbeispiel des Code und Daten komplett in L1I und L1D passen dürften 10Takte je Verzweigung heraus bei tendenziell guter Trefferquote der Sprungvorhersage. Ein paar Daten, zufällige Verzweigung, mehr Verzweigungsmöglichkeiten sowie komplexere Berechnungen und das sieht alles anders aus
Sicher kann man sich Szenarien ausdenken, in denen der Performancenutzen genau dieser einer Technik gegen 0 geht... und nun? Deswegen nie so nutzen?

Piktogramm schrieb:
Da steht, dass Code der von verschiedenen Leuten (zu verschiedenen Zeiten aka. "Generationen") ohne gemeinsamen, klar definierten Standard geschrieben wird, bei Zeiten "grandiose Scheiße" wird.
Wenn du das wirklich so meinst, ist das eher unabhängig vom konkreten Stil.
Aber ich sehe das weitaus weniger kritisch und sprachenabhängig inwiefern man da etwas vorgeben muss, sh. z.B. C++ vs go, wobei man beim ersteren so programmieren könnte, dass ein anderer C++ Programmierer den Code nicht mehr lesen kann.
Ob da jemand nun einmal Switch case statt klassenpolymorphie nutzt, geschenkt. Man nutzt die Tools der Sprache und schaut was am besten passt, und statt gegenüber Performance völlig zu vernachlässigen, berücksichtigt man eben jene ebenso bei der Entscheidungsfindung.
 
KitKat::new() schrieb:
Man nutzt die Tools der Sprache und schaut was am besten passt, und statt gegenüber Performance völlig zu vernachlässigen, berücksichtigt man eben jene ebenso bei der Entscheidungsfindung.

Falls beruflich genutzt, gibt hoffentlich die Firma entsprechende Entwicklungs- und Dokumentationsrichtlinien raus, an die sich dann bitte alle Entwickler zu halten haben.
Allein schon aus dem Grund, weil nie eine Person allein an einem Projekt arbeitet.
Wie willst Du sonst in 10 Jahren noch durch etwas durchsteigen, was die letzten 20 Deiner Vorgänger entwickelt haben - bei einem zeitkritischen Projekt.
 
  • Gefällt mir
Reaktionen: Piktogramm
hamju63 schrieb:
Ich finde es unnötig zum dritten mal darauf hinzuweisen.
Entweder gibt es derart strenge Richtlinien bzgl. Programmierstil (dann kann man diese ggf. überdenken) oder es gibt sie nicht (dann ist es sowieso "egal").
 
Finalspace schrieb:
Ich habe mittlerweile auch den ganzen Kram mal privat nachgebaut und anonymisiert und werd dies die Tage mal auf Github hochladen.
Sehr cool, werde ich mir jedenfalls anschauen. Deine Ausführungen klingen so, als wenn ich da noch was lernen kann.

Man sieht hier im Thread ganz gut, dass es nicht unbedingt zielführend ist, wenn man das Thema komplett abstrakt diskutiert :D.
 
KitKat::new() schrieb:
Sicher kann man sich Szenarien ausdenken, in denen der Performancenutzen genau dieser einer Technik gegen 0 geht... und nun? Deswegen nie so nutzen?
Ich gebe es auf.. Ich schrieb nicht etwas von einem absolutem "nie" sondern von "ohne Not"-.-
 
Piktogramm schrieb:
Ich schrieb nicht etwas von einem absolutem "nie" sondern von "ohne Not"-.-
Ack, aber da gings um die Einschränkung der Erweiterbarkeit/Wartbarkeit (setzt du mit den Prinzipien von Clean Code gleich?), aber was wenn es nach #21 der Erweiterbarkeit/Wartbarkeit nicht schadet und sogar Vorteile bringen kann?

Darauf hast du dann eingewendet, dass die Vorteile nicht immer (so stark ausgeprägt) vorhanden sind, und klare Regeln in bestimmten Situationen wichtig sind (was ja imho nicht grundsätzlich einen anderen performancegünstigeren Programmierstil ausschließt)

Und meine Frage ist nun, ob man daher - auch wenn keine Not vorhanden ist - einen solchen performancegünstigeren Programmierstil wählen kann, der zwar in der Wartbarkeit jedoch in konkreten Techniken generell oder in bestimmten Umständen von der klassischen Clean Code Lehre abweicht?
 
Da der Artikel ja C++ behandelt, es gibt ja auch Vergleiche für andere Sprachen.
Der mal für C#, sicherlich nicht 1:1 vergleichbar da der andere Sachen macht.
 
KitKat::new() schrieb:
Und meine Frage ist nun, ob man daher - auch wenn keine Not vorhanden ist - einen solchen performancegünstigeren Programmierstil wählen kann, der zwar in der Wartbarkeit jedoch in konkreten Techniken generell oder in bestimmten Umständen von der klassischen Clean Code Lehre abweicht?
Wie fast immer in der Praxis endet das in einem "kommt drauf an".

Bei Software mit stetiger Weiterentwicklung, wo damit zu rechnen ist, dass man da häufiger (das kann durchaus nur aller Jahre sein) ran muss und wo man abschätzen kann, dass sich die sich zu verarbeitenden Datenstrukturen ändern, würde ich stark von Switchstatements abraten und irgendwelche Optimierungen mit Lookuptables um die Autovektorisierung mitzunehmen noch viel mehr.

Und Performancegünstig.. Davon würde ich Abstand nehmen. Der Overhead von Objektaufrufen nimmt Anteilig ab, je länger im Kontext dieses Objektes verweilt wird. Es kommt also ganz stark drauf an, wie lang man im Kontext eines Objektes verweilt und wie häufig die Objektaufrufe sind. 30Takte Overhead werden halt reichlich egal, wenn >1.000 Takte sinnvolle Arbeit verrichtet wird. Andersherum ist es sinnlos 3..4Takte nützliche Berechnung hinter 30Takte Overhead zu packen. Das mag relativ egal sein, wenn es nur selten passiert, ist aber tödlich wenn es in Masse passiert. Mir wäre aber auch nicht bekannt, dass "Clean Code" irgendwo fordert, dass man sich beim Strukturieren von Daten wie der letzte Depp anstellen soll indem jedes Datum in ein eigenes Objekt gepackt wird. Daten sinnvoll zu clustern ist und bleibt sinnvoll, so einen Cluster als Objekt abzubilden und die gewünschten Berechnungen dann innerhalb der Methoden eines Objekts gescheit vektorisierbar zu verarbeiten ist auch eher erwünscht (wenn sinnvoll, um hunderte bis wenige tausend Takte zu sparen, kann Vektorisierung zum Boomerang werden).

@morcego
Ich muss das Video noch ansehen, aber mit Sprachen, die noch weiter abstrahieren als C++ und gar GarbageCollection haben wird es sowieso spannend.
Mit Performancefanatiker wie Herr Muratori würde ich kein Gespräch über C#, Java, Python, Javascript etc. pp. führen wollen.
 
Zuletzt bearbeitet:
Piktogramm schrieb:
Bei Software mit stetiger Weiterentwicklung, wo damit zu rechnen ist, dass man da häufiger (das kann durchaus nur aller Jahre sein) ran muss [...] würde ich stark von Switchstatements abraten
warum (beachte explizit selektives Zitat - bei den Datenstrukturen sehe ich durchaus ein, mitzugehen)?


Piktogramm schrieb:
Und Performancegünstig.. Davon würde ich Abstand nehmen.
Auch hier - warum?


Piktogramm schrieb:
Daten sinnvoll zu clustern ist und bleibt sinnvoll, so einen Cluster als Objekt abzubilden und die gewünschten Berechnungen dann innerhalb der Methoden eines Objekts gescheit vektorisierbar zu verarbeiten ist auch eher erwünscht
Steht das nicht im Widerspruch dazu von performancegünstigem Code Abstand zu nehmen?
 
Zuletzt bearbeitet:
KitKat::new() schrieb:
Begründung steht da.. Erweitere die optimierten Versionen mal um verschiedene, weitere geometrische Formen inkl. "beliebiger" Polygonenzüge. Die Optimierung mit Lookuptable fällt da komplett auseinander. Bei der Version mit Switch bläht es den Switch-Block auf. Mit etwas Erfahrung werden dir auch Fälle einfallen, wo die Komplexität weit über der simplen Flächenberechnung geht und wie der Spaß dann eskaliert.
Klar die Klassendefinitionen werden dann auch umfangreicher, die grundlegende Struktur bleibt jedoch homogen/übersichtlich.

KitKat::new() schrieb:
Auch hier - warum?
Du fragst das tatsächlich bei einem Zitat vom Anfang eines ganzen Absatzes an Erklärung?

KitKat::new() schrieb:
Steht das nicht im Widerspruch dazu von performancegünstigem Code Abstand zu nehmen?
Ich kenne jetzt keine Forderung im Rahmen des erweiterten "Clean Code" (also nicht nur das Buch, sondern auch anderer entsprechender Leitfäden), wo empfohlen wird von Performance Abstand zu nehmen. Es wird empfohlen besser strukturierten Code zu schreiben und die Performance unterzuordnen. Zumindest so lang, bis die Anforderung an die Performance nicht entsprechend kritisch ist. Was "Clean Code" überhaupt nicht fordert ist, sich beim strukturieren von Daten wie der letzte Depp anzustellen.. Wirklich hart ist sowieso keine der Empfehlungen von CC, die reale Umsetzung kann kaum sinnvoll quantifiziert werden. Entsprechend "locker" ist das Ganze, der Vorteil liegt dennoch in der (versuchten) Konsistenz im Code.
Die Konsistenz ist im Zweifelsfall das, wo es darauf ankommt, solang nichts Anderes mit entsprechender Begründung als wichtiger bewertet wird. Der Linuxkernel kommt auch ohne CC aus, aber die haben ihre eigenen Regeln was Verständlichkeit von Code angeht:
However, if you have a complex function, and you suspect that a less-than-gifted first-year high-school student might not even understand what the function is all about, you should adhere to the maximum limits all the more closely. Use helper functions with descriptive names (you can ask the compiler to in-line them if you think it’s performance-critical, and it will probably do a better job of it than you would have done).
https://www.kernel.org/doc/html/v4.10/process/coding-style.html
Verständlichkeit ist wichtiger als Performance. Wenn nötig kann auf Performance optimiert werden, hauptsache es bleibt verständlich.
Naja und garniert mit Linus Sprachgeflogenheiten aka "less-than-gifted first-year high-school student" um deutlich zu machen, dass sich die Verständlichkeit nicht nach alten Großmeistern richtet, sondern eher am "zu erwartendem Mittelfeld an Einsteigern"..


Beispiel Sensordaten.
Es kommt aller Ewigkeiten (für µController also etwa >= 1/10s) mal ein Datum an. Dieses Datum in einem Objekt zu verpacken wäre vollkommen ok.
Es kommen Bursts von Samples mit >0,1kHz, anstatt jedes Sample in je einem Objekt abzubilden wäre es schon sinnvoll den ganzen Burst in einem Objekt zu halten. Vor allem, wenn die Samples in logischem Zusammenhang stehen/verarbeitet werden sollen. Stehen verschiedene Burts in logischem Zusammenhang bzw. handelt es sich um einen anhaltenden Strom an Signalen, wäre es dann auch sinnvoll diese entsprechend zusammen zu fassen.
 
  • Gefällt mir
Reaktionen: Micke
Bei mir im Unternehmen spielt die Performance der Software zwar eine größere Rolle, wenn da aber jemand mit Loop-Unrolling anfängt wo es nicht unbedingt sein muss, gibt es knallhart ein git-revert.

Performance ja, aber die Verständlichkeit des Codes steht fast immer an erster Stelle. Ob da jemand Switch-Case verwendet (an die beiden Streithähne da oben), ist mir/bei uns vollkommen egal.

Mitarbeiter kommen und gehen, sind krank, im Urlaub oder anderweitig ausgelastet. Niemand hat Zeit ewig an einer Funktion zu sitzen um einen Fehler im Algorithmus zu finden.

Wenn es aufgrund der Performance sein muss dann ja. Das ist dann etwas anderes.
Betrifft aber nur sehr wenige Stellen.
 
Piktogramm schrieb:
Das TLDR wäre dann quasi doch mehr Performance gerne, sofern es nicht auf Kosten der Wartbarkeit geht?

Auch, wenn bei uns wohl beim Switch-Fall die Meinungen auseinander gehen?
Piktogramm schrieb:
Bei der Version mit Switch bläht es den Switch-Block auf. Mit etwas Erfahrung werden dir auch Fälle einfallen, wo die Komplexität weit über der simplen Flächenberechnung geht und wie der Spaß dann eskaliert.
Klar die Klassendefinitionen werden dann auch umfangreicher, die grundlegende Struktur bleibt jedoch homogen/übersichtlich.
Beim häufigen Ändern der Datenstrukturen selbst gehe ich, wie geschrieben, mit, weil die Änderungen sich dann über die Codebase streuen und man ggf. eine Änderung vergisst. Hier (neue/komplexere Flächenberechnungen) fehlt mir wohl einfach die Fantasie.
Die Struktur bleibt in beiden Fällen weitgehend gleich.
 
KitKat::new() schrieb:
Beim häufigen Ändern der Datenstrukturen selbst gehe ich, wie geschrieben, mit, weil die Änderungen sich dann über die Codebase streuen und man ggf. eine Änderung vergisst.
Ja und wenn du mit der Begründung einen entsprechenden Codestil hast, ziehst du ihn am besten über den gesamten Code durch, bevor es jedem Dev. und seiner Stimmung überlasst, welcher Stil in welcher Ecke des Codes nun der Richtige ist. Also einen Stil konsequent und nur mit guter Begründung abweichen. Eine gute Begründung ist nicht, dass man einen Codepfad schneller durchlaufen kann, der sowieso nur 10ns braucht und nur aller Stunden gebraucht wird.
 
  • Gefällt mir
Reaktionen: Micke
Ich fang mal mit einer Story an:

Ich habe auf der Arbeit schon mal mit einem CMS zu tun gehabt habe, dass (angeblich?) den Ansatz "Clean Code" verfolgt hat. Oberflächlich zumindest alles Picobello. Mit Kommentaren, man setzte Design-Patterns um, es war von vorne bis hinten durchdokumentiert, natürlich mit Tests etc., es gab auch Deployment-Prozesse. Alles gut?

Nun.... das CMS war (und ist noch, falls noch in Gebrauch) richtig, richtig, richtig fett und brachte seine eine eigene Script- und Abfragesprache mit. Man dachte in "Blöcken", denen man Typen, Eigenschaften, Abhängigkeiten und Funktionen zuweisen konnte, die dann neben dem CMS-Script dynamisch weitere (Helper-)Klassen aufrufen lassen konnte.

Ich finde, vom Ansatz eigentlich clever, z.B. Block "Downloads" die Abhängigkeit Block "Eingeloggt" zu geben und schwupp, sahen es nur noch eingeloggte Mitglieder.
Als ich nun Block "Upload Mitmachaktion $Sponsor" erstellt habe, war immer dann die Navigation komplett verschwunden, als ich dem Block die Abhängigkeit "Eingeloggt" gegeben habe, was nun? Frust machte sich breit.

Um dann nach ewiger Suche vom "CMS-Profi" gesagt zu bekommen:
Block "Upload Mitmachaktion $Sponsor" ist von Block "Eingeloggt" abhängig, korrekt,
aber auch Block "Navigation Eingeloggt" ist von Block "Eingeloggt" abhängig,
Block "Navigation Eingeloggt" von "Navigation",
und weil Block "DepencyWalker" in allen Richtungen den ganzen Baum abläuft, verschwindet deine Navigation. Darum muss du noch eine Ausnahme in $Tiefverschachelt/.../DepencyWalker/configs/$depencyTree.yaml ein Eintrag $dies, $jenes und $nochwas mit den Werten der GUID des Blocks $bla und $blub eintragen. Achja... Cache löschen nicht vergessen (dauert mindestens eine Minute), viel Spaß noch!

Nicht nur das. Das CMS war voller lauter solche "Späße" und Überraschungen. Ja, das Verhalten des CMS war fein säuberlich dokumentiert, aber die Doku war generisch ("...getBlock(id): liefert Block mit der id 'id'...") und extrem umfangreich - man sah den Wald vor lauter Bäumen nicht.

Wenn mal die "CMS-Meister" krank waren, stockte die Entwicklung schon mal.
Das CMS war eine Insellösung, man konnte nicht Google bemühen, falls was schief läuft. Die Autovervollständigung der IDE half auch nur bedingt.
Das CMS hatte außerdem laufend Performance-Probleme und ein Import von 20.000 Artikeln hat mehrere Stunden gedauert. Die Datenbank direkt anzusprechen war tabu, auch kein DBAL/Doctrine. Durch Block "Encryption" waren manche Daten erst gar nicht auswertbar, da verschlüsselt. Denk dran, immer schön in Blöcken denken!

Was bin ich froh, da raus zu sein.

Ich kann daher nur sagen: Keep It Simple and Stupid. Soll auch ein Prinzip des Clean Codes sein, aber innerhalb ihrer Bubble haben die Entwickler es auf das Äußerste verteidigt (KISS würde heißen, nur so viel Code wie nötig, dieser Helper und CMS-Script sei aber unbedingt nötig, weil ...). Konnte ich nicht wirklich glauben.

Jedenfalls ist es mir in den allermeisten Fällen egal, ob Integer eine Klasse ist oder nicht. Ich möchte nur nicht wieder auf solche Monster stoßen, nur um eine Website mit einem Online-Shop und einer Mitmach-Aktion zu realisieren. Und wenn, dann bitte mit ordentlich Gehalt oder einem CMS, dass Industriestandards folgt.

Privat abstrahiere ich auch, ich nutze für Oberflächen auch gerne HTML/CSS. Ich mag es, einfach auf $user zugreifen zu können ohne dauernd SQLs bauen zu müssen. Nur übertreiben möchte ich es nicht.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: breedmaster
Ich hab nun schon 2x diesen Talk gesehen
und daher auch mal probiert "data oriented design", wie es hier heißt, in C++ zu benchmarken.
Auf meinem GamingPC und aufm Laptop war kein Unterschied messbar. Dh klassisches OOP mit >1MB fetten Objekten vs 'alles relevante in einem seperatem std::vector' war exakt gleich schnell. Egal ob -march-native, -O2, -O3, -Os usw.
Wahrscheinlich hat die https://de.wikipedia.org/wiki/Memory_Management_Unit und prefetching einfach perfekt funktioniert.

Ich halte es daher genau wie auch auf stackoverflow immer steht: Messen, messen, messen.
Nur weil man denkt etwas wäre langsam oder weil man denkt, "anders als sauber programmiert ist bestimmt schneller!!!11" sollte man es nicht ohne Grund tun. Und einen Grund liefert nur eine representative Messung.
 
Zurück
Oben