Einfache vs. komplexe (aber leistungseffiziente) Lösung - welche wählen Sie wann?


28

Ich programmiere seit ein paar Jahren und bin oft in ein Dilemma geraten.

Es gibt zwei Lösungen -

  • Einer ist einfach, dh einfacher Ansatz, einfacher zu verstehen und zu pflegen. Dies erfordert Redundanz und zusätzlichen Arbeitsaufwand (zusätzliche E / A, zusätzliche Verarbeitung) und ist daher nicht die optimalste Lösung.
  • Andere verwenden jedoch einen komplexen Ansatz, der schwierig zu implementieren ist, häufig die Interaktion mehrerer Module umfasst und eine leistungsfähige Lösung darstellt.

Welche Lösung sollte ich anstreben, wenn ich keine SLA mit hoher Leistung zu erfüllen habe und selbst die einfache Lösung die SLA mit Leistung erfüllen kann? Ich habe mich unter meinen Mitentwicklern für eine einfache Lösung verachtet gefühlt.

Ist es empfehlenswert, eine optimale komplexe Lösung zu finden, wenn Ihre Leistungs-SLA durch eine einfache Lösung erfüllt werden kann?


10
siehe: Wie vermeide ich die „Intuition zur schlechten Optimierung von Entwicklern“? „Leider haben die Entwickler im Allgemeinen schrecklich Intuition darüber , wo die Performance - Probleme in einer Anwendung werden tatsächlich ....“
gnat

1
Wird "nicht das Optimalste" noch "gut genug" sein? Dann bleib dabei.

8
Ja. " Le mieux est l'ennemi du bien. " Voltaire. ("Perfekt ist der Feind des Guten.") Gut genug ist gut genug - bis Leistungstests etwas anderes aussagen.
David Hammen

Ich finde, dass (im Allgemeinen) einfach effizient bedeutet. Kompromisse sind daher häufig nicht erforderlich.
Dan

2
"Es scheint, dass Perfektion nicht erreicht wird, wenn es nichts mehr hinzuzufügen gibt, sondern wenn es nichts mehr zu entfernen gibt." - Antoine de Saint-Exupery
keuleJ

Antworten:


58

Welche Lösung sollte ich anstreben, wenn ich keine SLA mit hoher Leistung zu erfüllen habe und selbst die einfache Lösung die SLA mit Leistung erfüllen kann?

Die einfache. Es entspricht den Spezifikationen, ist einfacher zu verstehen, einfacher zu warten und wahrscheinlich viel weniger fehleranfällig.

Sie setzen sich für eine leistungsfähige Lösung ein, indem Sie spekulative Allgemeingültigkeit und vorzeitige Optimierung in Ihren Code integrieren. Tu es nicht! Die Leistung widerspricht nahezu jeder anderen Softwareentwicklungsfunktionalität (Zuverlässigkeit, Wartbarkeit, Lesbarkeit, Testbarkeit, Verständlichkeit usw.). Verfolgungsjagd beim Testen zeigt, dass es wirklich notwendig ist, nach der Leistung zu jagen.

Jagen Sie nicht nach Leistung, wenn die Leistung keine Rolle spielt. Auch wenn es wichtig ist, sollten Sie die Leistung nur in den Bereichen verfolgen, in denen der Test auf einen Leistungsengpass hinweist. Lassen Sie sich nicht von Leistungsproblemen entschuldigen, die simple_but_slow_method_to_do_X()durch eine schnellere Version ersetzt werden könnten, wenn diese einfache Version nicht als Engpass erscheint.

Eine verbesserte Leistung ist fast zwangsläufig mit einer Vielzahl von Code-Geruchsproblemen behaftet. Sie haben mehrere in der Frage erwähnt: Ein komplexer Ansatz, schwer umzusetzen, höhere Kopplung. Sind diese wirklich einen Besuch wert?


Ihre Antwort ist sehr hilfreich
MoveFast

1
So einfach wie möglich, aber nicht einfacher. So schnell wie möglich, aber nicht schneller. etc
user606723

2
"Wenn Sie Zweifel haben,
wenden Sie

Kommentare im Code können hier sowohl kathartisch als auch hilfreich sein. Ein kleiner Kommentar, der auf die komplexe und schnelle Lösung hinweist und warum Sie sie nicht verwendet haben, kann dazu führen, dass Sie weniger das Gefühl haben, den optimalen Algorithmus ignoriert zu haben. Und es kann den Betreuern helfen, Ihre Wahl zu verstehen und sie in die richtige Richtung zu lenken, wenn eine spätere Optimierung tatsächlich erforderlich ist.
TheAtomicOption

12

Kurze Antwort: Ziehen Sie die einfachen Lösungen komplexen vor und erinnern Sie sich an die Prinzipien von KISS und YAGNI

Da anfängliche Projektanforderungen und Software niemals perfekt sind, sind Änderungen erforderlich, wenn eine Anwendung entwickelt / verwendet wird. Ein iterativer Ansatz in den Entwicklungsphasen passt sehr gut dazu, Dinge einfach anzufangen und bei Bedarf zu erweitern. Die einfachsten Lösungen bieten Raum für Flexibilität und sind wartungsfreundlicher.

Darüber hinaus ist es keine gute Praxis, klug zu sein und eine Add-Hoc-Optimierung vorzunehmen, während Ihre Anwendung noch erstellt wird. Dies kann Ihre Lösung überkomplizieren. Wie es bekannt ist, "premature optimization is the root of all evil"- von Knuths Buch


1
@ManojGumber, kein Problem und es ist wirklich das Wesentliche, worauf wir als Programmierer an erster Stelle achten sollten.
EL Yusubov

8

Nehmen Sie hier eine Lehre von Knuth: "Wir sollten kleine Wirkungsgrade vergessen, sagen wir in 97% der Fälle: Vorzeitige Optimierung ist die Wurzel allen Übels."

Denken Sie über Ihre Lösungen in dieser Reihenfolge nach: Zuerst immer die Richtigkeit. Zweitens verbessern Sie Klarheit und Einfachheit. Drittens und nur, wenn Sie die Notwendigkeit, Effizienz demonstrieren können.

Das Hinzufügen von Effizienz kostet Sie fast immer etwas Wichtiges und sollte daher nur dann fortgesetzt werden, wenn Sie wissen, dass dies erforderlich ist.


4
Beachten Sie, dass dies nicht bedeutet, dass Sie überhaupt keine gute Implementierung schreiben sollten.

@ ThorbjørnRavnAndersen: Natürlich geht es darum, worum es in den ersten beiden Punkten geht.
Simon

1
@ Simon das Zitat wird häufig als Ausrede verwendet, um schlampig zu wählen,

Zu Ihrem zweiten Punkt: Ich hatte einen Kollegen, der ziemlich oft sagte, er bevorzuge fehlerhaften, gut strukturierten und sauberen Code vor korrekten Spaghetti.
Buhb

@ ThorbjørnRavnAndersen Inkompetente werden alles als Entschuldigung benutzen. Hat keinen Einfluss auf den Wert des ursprünglichen Gedankens.
Simon

7

Einfachheit ist die Voraussetzung für Zuverlässigkeit . Wenn Sie eine einfache Lösung haben, die funktioniert, machen Sie es auf jeden Fall! Es ist viel einfacher, ein Arbeitsprogramm zu optimieren, als ein optimiertes Programm zum Laufen zu bringen. Vergessen Sie auch nicht über Moores Gesetz : Wenn Ihre einfache Lösung erfüllen die Leistungsziele heute, wird es wahrscheinlich zerdrücken 1 in einem Jahr oder zwei.


1 Da gibt es keine Garantie, denn wie Jimmy Hoffa in seinem Kommentar unten feststellte, hat Moores Gesetz seine Grenzen.


Sie haben Moores anderes Gesetz vergessen, das besagt: "Ups, über mein erstes Gesetz ..." Sorry Boss, Moores Gesetz ist nicht mehr (pun pun). Ich bin mit dem Rest deines Standpunkts nicht einverstanden, ich würde den letzten Teil hier zumindest einschränken.
Jimmy Hoffa

2
Sorry, aber nach all meinen Erfahrungen in dieser Branche. "Arbeitssets" nehmen um ein Vielfaches schneller zu als die Geschwindigkeit unserer Hardware, die ständig aktualisiert wird. Wirklich, ich würde nur den Moore'schen Gesetzespunkt entfernen.
user606723

@ user606723 Das Wachstum des Arbeitssollwerts ist orthogonal zur Frage "optimiert oder einfach": Die Arbeitsbelastung wird sie einholen, unabhängig davon, welche Lösung sie implementieren. Um das Moore-Gesetz in den Mix aufzunehmen, musste darauf hingewiesen werden, dass der Druck abnehmen wird, wenn schnellere Hardware verfügbar wird, auch wenn die einfache Lösung zum Zeitpunkt des Schreibens unter einem gewissen Leistungsdruck steht.
dasblinkenlight

@dasblinkenlight, das Wachstum des Workset ist nicht orthogonaler zur Frage als Moores Gesetz. Der Punkt, der das Workset in das Problem einbezieht, ist, dass, wenn eine einfache Lösung zum Zeitpunkt der Veröffentlichung unter einem gewissen Leistungsdruck steht, die Leistung in naher Zukunft unzureichend sein wird, da das zunehmende Workset jegliche Leistungsverbesserungen zunichte macht, die durch verbesserte Hardware erzielt werden. Während ich alles für einfache, zuverlässige und wartbare Software bin, ist es eine schreckliche Philosophie, Software zu veröffentlichen, die bereits bei der Veröffentlichung unter Leistungsdruck steht, und zu erwarten, dass Moores Gesetz dies ausgleicht.
user606723

3

Ist es empfehlenswert, eine optimale komplexe Lösung zu finden, wenn Ihre Leistungs-SLA durch eine einfache Lösung erfüllt werden kann?

Optimal ist ein mehrdeutiges Wort!

Letztendlich würde ich mich immer auf die Seite des Einfachen irren, wenn das Risiko groß ist, den Komplexen warten zu müssen, und wenn der Einfache "gut genug" ist.

Fügen Sie das Risiko hinzu, dass der Komplex nicht gut genug ist, dann ist KISS wahrscheinlich die richtige Antwort.


2

Ich würde die einfache vorziehen. Meiner Meinung nach verursachen die vorzeitigen Optimierungen so viele Probleme, wie sie lösen. In vielen Fällen können Sie durch gutes Design bestimmte Implementierungen in Zukunft ändern, wenn sie zu Engpässen werden.

Unterm Strich also - ich werde es so flexibel wie möglich gestalten, aber nicht zu sehr auf Einfachheit und Flexibilität verzichten.


2

Welches kostet weniger?

In den meisten Fällen ist eine einfache Lösung, die etwas langsamer ist, in Bezug auf die Leistung vollkommen akzeptabel, und durch die Einfachheit wird die Entwicklung, Wartung und eventuelles Ersetzen billiger.

Auf der anderen Seite ist die Geschwindigkeit manchmal sehr wichtig, und der finanzielle Gewinn, der durch kleine Geschwindigkeitsverbesserungen erzielt wird, kann weitaus größer sein als die höheren Kosten einer komplizierteren Lösung. Wenn Sie beispielsweise 0,01 Sekunden vor dem Abschluss einer Transaktion sparen, kann ein Wertpapierhandelssystem erheblich rentabler werden. Eine 10% ige Verbesserung der Effizienz eines Systems, das mehrere Millionen Benutzer unterstützt, könnte zu einer erheblichen Reduzierung der Serverkosten führen.

Die Frage, die Sie sich stellen müssen, lautet also: Hat die Verwendung der komplexen Lösung eine ausreichende Auswirkung auf das Endergebnis, um die zusätzlichen Kosten zu tragen? Eigentlich sollten Sie Ihren Kunden wahrscheinlich bitten, sich zu entscheiden, da er die Rechnungen bezahlt und den potenziellen Nutzen daraus zieht. Eine gute Option ist, zuerst die einfache Lösung zu wählen und die komplexere Lösung als mögliche Verbesserung anzubieten. Auf diese Weise können Sie Ihr System in Betrieb nehmen und Ihren Kunden die Möglichkeit geben, mit dem Testen zu beginnen. Diese Erfahrung kann die Entscheidung für die Implementierung (oder Nichtimplementierung) der komplizierteren Lösung beeinflussen.


2

Bei der Bewertung von zwei Ansätzen, von denen einer einfacher, aber weniger effizient ist, während der andere komplexer und effizienter ist, müssen das Problem und der Projektbereich berücksichtigt werden.

Betrachten Sie ein milliardenschweres Softwareprojekt für das Gesundheitswesen, dessen Lebensdauer auf über 15 Jahre Wartung und über 20 Jahre Nutzung ausgelegt ist. In einem solchen Projekt wird die Leistung definitiv kein Problem sein, aber die Komplexität und Struktur des Projekts kann zu großen Problemen bei der Aufrechterhaltung des Projekts führen, die mindestens 15 Jahre dauert. Wartbarkeit und Einfachheit stehen an erster Stelle.

Betrachten Sie dann ein anderes Beispiel. Eine Konsolenspiel-Engine, die die kommenden Spiele des Unternehmens für die nächsten 5+ Jahre antreiben soll. Da Spiele äußerst ressourcenbeschränkte Programme sind, geht die Effizienz in vielen Fällen vor der Wartbarkeit. Das Schreiben eigener, sehr spezifischer Datenstrukturen und Algorithmen für eine bestimmte Aufgabe kann sehr wichtig sein, auch wenn dies gegen jegliche Art von "Best Practices" der Softwareentwicklung verstößt. Ein gutes Beispiel hierfür ist Data Oriented Design, bei dem Sie Ihre Daten in ähnlichen Datenfeldern statt in tatsächlichen Objekten speichern. Dies dient dazu, die Lokalitätsreferenz zu erhöhen und somit die CPU-Cache-Effizienz zu erhöhen. Nicht praktisch, aber in der gegebenen Domäne sehr wichtig.


1

Dies ist immer eine schwierige Frage, und ich sehe, dass die Antworten in die eine oder andere Richtung schwanken. Daher spiele ich das Spiel für die andere Seite, auch wenn ich nicht behaupte, dass beide Antworten richtig sind.

Bei einer komplexen, aber leistungsstarken Lösung können Sie immer nur das allgegenwärtige Problem dokumentieren. Ich bin im Allgemeinen ein Fan von selbstdokumentierendem Code, aber ich bin auch ein Fan von Software, die in einer Zeitspanne reagiert, in der ich das Gefühl habe, dass sie mich nicht verlangsamt. Wenn Sie sich für die komplexe, aber leistungsstarke Lösung entscheiden, überlegen Sie, was Sie tun können, um sie nicht so schlecht zu machen:

Binden Sie es in eine Schnittstelle ein, fügen Sie es in eine eigene Assembly ein, möglicherweise sogar in einen eigenen Prozess. Machen Sie es so locker wie möglich mit einer möglichst dicken Abstraktionswand, um Undichtigkeiten zu vermeiden . Schreiben Sie viele Komponententests, um zukünftige Regressionen zu vermeiden.

Dokumentieren Sie es im Code, und erwägen Sie sogar, eine echte Dokumentation zu verfassen. Denken Sie an komplexe Datenstrukturen und wie sie dokumentiert sind. Stellen Sie sich vor, Sie würden versuchen, die Implementierung von Code ohne einen Datenstruktur-Buch- / Wikipedia-Artikel zu verstehen, um dies zu erklären. Und doch sind wir uns alle einig, dass diese komplexen Datenstrukturen in der Tat gute Dinge sind und es von Vorteil ist, dass jemand sie in unseren Sprachen implementiert hat.

Denken Sie daran, dass wir alle Nachrichten auf einem TCP / IP-Stack senden, der wahrscheinlich so umfangreich ist, wie es der Code nur kann, wenn einer von uns ihn sich ansieht. Vielleicht erfordert Ihr Problem nicht diese Optimierungsstufe, vielleicht auch nicht, aber seien Sie vorsichtig, wenn Sie diese Frage angehen, da wir alle von Zeit zu Zeit müssen: Es gibt dort Drachen.


0

Ich arbeite in Bereichen, in denen es keine Leistungs-SLA gibt. Wenn es um Offline-Renderer in der Computergrafik geht, gibt es für Benutzer keine "zufriedenstellende Leistung", da sie bereits enorme Summen für die Verteilung von Computing auf Clouds und das Rendern von Farmen ausgeben, selbst mit den modernsten Renderern um Bilder und Rahmen in Produktionsqualität für Filme auszugeben, z

Aber ich muss sagen, dass jede Lösung, die die Wartbarkeit zugunsten der Effizienz erheblich beeinträchtigt, tatsächlich gegen die sich ständig ändernden Leistungsanforderungen arbeitet. Denn wenn Sie Ihre Lösung jahrelang nicht effektiv warten können, da sich die Dinge unter Ihren Füßen verschieben (sowohl in Bezug auf den Umgebungscode als auch auf das, was die Benutzer von Konkurrenten erwarten, die sich gegenseitig übertreffen), dann arbeitet Ihre Lösung bereits in Richtung Veralterung und In Notwendigkeit des Großhandelsersatzes.

Ich sehe den ultimativen Zweck von Profilern wie VTune nicht darin, meinen Code schneller laufen zu lassen. Ihr größter Wert ist es, sicherzustellen, dass ich meine Produktivität nicht einschränke, um den ständig steigenden Leistungsanforderungen gerecht zu werden. Wenn ich absolut etwas grob aussehende Mikro-Optimierung anwenden müssen, dann den Profiler, kombiniert mit ihm gegen reale Benutzer Fällen läuft (und nicht einige Testfall stelle ich mir vielleicht wichtig sein), stellt sicher , bewerbe ich mich so zwangsläufig grob aussehenden Optimierungen werden sehr, sehr vernünftig nur für die Top-Hotspots durchgeführt, die angezeigt werden, und sie werden sehr sorgfältig dokumentiert, da ich sie in den kommenden Jahren unweigerlich überarbeiten und warten sowie optimieren und ändern muss, wenn diese Lösung funktionsfähig bleibt.

Und vor allem, wenn Ihre optimierte Lösung mehr Kopplung beinhaltet, würde ich sie nur ungern verwenden. Zu den wertvollsten Messwerten, die ich in den leistungskritischsten Bereichen der Codebasis zu schätzen gelernt habe, gehört das Entkoppeln (wie bei der Minimierung der Informationsmenge, die benötigt wird, um zu funktionieren, was ebenfalls die Wahrscheinlichkeit minimiert, dass Änderungen erforderlich sind, sofern keine direkten Änderungen erforderlich sind) ), weil diese kritischen Bereiche die Gründe für Änderungen erheblich vervielfachen. Das heißt, je weniger Informationen für die Arbeit benötigt werden, desto weniger Gründe für Änderungen und die Minimierung der Änderungsgründe tragen wesentlich zur Verbesserung der Produktivität in meinen speziellen Schwerpunktbereichen bei, da sich die Dinge sowieso ständig ändern müssen (wir) veraltet sonst in einem Jahr),

Für mich sind die besten und effektivsten Lösungen, die ich gefunden habe, diejenigen, bei denen sich Effizienz, Wartbarkeit und Produktivität nicht diametral gegenüberstehen. Mir geht es darum, diese Konzepte so harmonisch wie möglich zu gestalten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.