Ich habe kürzlich den Blogbeitrag von Three Big Lies gelesen und es fällt mir schwer, die zweite Lüge zu rechtfertigen, die hier zitiert wird:
(LIE # 2) CODE SOLLTE UM EIN MODELL DER WELT GESTALTET WERDEN
Es gibt keinen Wert im Code, ein Modell oder eine Karte einer imaginären Welt zu sein. Ich weiß nicht, warum dies für einige Programmierer so überzeugend ist, aber es ist äußerst beliebt. Wenn es eine Rakete im Spiel gibt, können Sie sicher sein, dass es eine "Rocket" -Klasse gibt (vorausgesetzt, der Code ist C ++), die Daten für genau eine Rakete enthält und rockiges Zeug ausführt. Ganz ohne Rücksicht darauf, welche Datenumwandlung tatsächlich durchgeführt wird, oder auf das Layout der Daten. Oder ohne das grundlegende Verständnis, dass es dort, wo es eine Sache gibt, wahrscheinlich mehr als eine gibt.
Obwohl es für diese Art von Design viele Leistungsnachteile gibt, ist das wichtigste, dass es nicht skaliert. Überhaupt. Einhundert Raketen kosten hundertmal so viel wie eine Rakete. Und es ist sehr wahrscheinlich, dass es noch mehr kostet! Selbst für einen Nicht-Programmierer sollte das keinen Sinn ergeben. Wirtschaftlichkeit der Skala. Wenn Sie mehr von etwas haben, sollte es billiger werden, nicht teurer. Und der Weg, dies zu tun, besteht darin, die Daten richtig zu entwerfen und Dinge durch ähnliche Transformationen zu gruppieren.
Hier sind insbesondere meine Probleme mit dieser Lüge.
Code hat den Wert, ein Modell / eine Karte einer imaginären Welt zu sein, da das Modellieren der imaginären Welt (zumindest ich persönlich) dabei hilft, den Code zu visualisieren und zu organisieren.
Eine "Rocket" -Klasse zu haben, ist für mich eine absolut gültige Wahl für eine Klasse. Vielleicht könnten "Raketen" in Raketentypen wie AGM-114 Hellfire usw. unterteilt werden, die Nutzlaststärke, maximale Geschwindigkeit, maximalen Wenderadius, Zieltyp usw. enthalten, aber dennoch müsste jede abgefeuerte Rakete eine Position haben und eine Geschwindigkeit.
Natürlich kostet es mehr als eine Rakete, 100 Raketen zu haben. Wenn sich 100 Raketen auf dem Bildschirm befinden, müssen 100 verschiedene Berechnungen durchgeführt werden, um ihre Position zu aktualisieren. Der zweite Absatz scheint die Behauptung aufzustellen, dass bei 100 Raketen weniger als 100 Berechnungen erforderlich sind, um den Status zu aktualisieren.
Mein Problem hierbei ist, dass der Autor ein "fehlerhaftes" Programmiermodell vorlegt, aber keine Möglichkeit zur "Korrektur" vorlegt. Vielleicht stolpere ich über die Analogie der Rocket-Klasse, aber ich würde wirklich gerne die Gründe für diese Lüge verstehen. Was ist die Alternative?
quelle
Antworten:
Lassen Sie uns zunächst einen Kontext betrachten: Dies ist ein Spieledesigner, der in einem Blog schreibt, dessen Thema den letzten Tropfen der Leistung einer Cell BE-CPU herausholt. Mit anderen Worten: Es geht um die Programmierung von Konsolenspielen, genauer gesagt um die Programmierung von Konsolenspielen für die PlayStation 3.
Jetzt sind Spieleprogrammierer ein merkwürdiger Haufen, Konsolenspielprogrammierer noch mehr, und das Cell BE ist eine ziemlich seltsame CPU. (Es gibt einen Grund, warum Sony ein konventionelleres Design für die PlayStation 4 gewählt hat!)
Wir müssen uns also diese Aussagen in diesem Kontext ansehen.
Es gibt auch einige Vereinfachungen in diesem Blog-Beitrag. Insbesondere wird diese Lüge # 2 schlecht präsentiert.
Ich würde argumentieren, dass alles , was von der realen Welt abstrahiert, in gewissem Sinne ein Modell ist. Und da Software nicht real, sondern virtuell ist, ist sie immer eine Abstraktion und damit immer ein Modell. Aber! Ein Modell muss keine saubere 1: 1-Abbildung auf die reale Welt haben. Schließlich ist es das, was es überhaupt zu einem Modell macht.
In gewisser Hinsicht liegt der Autor also eindeutig falsch: Software ist ein Modell. Zeitraum. In einem anderen Sinne hat er recht: Dieses Modell muss der realen Welt überhaupt nicht ähneln.
Ich werde ein Beispiel geben, das ich bereits in einigen anderen Antworten im Laufe der Jahre gegeben habe, das (in) berühmte Beispiel der Einführung in das OO 101-Bankkonto. So sieht ein Bankkonto in fast jeder OO-Klasse aus:
Also: das
balance
ist Daten undtransfer
ist eine Operation .Aber! So sieht ein Bankkonto in fast jeder Bankensoftware aus:
Jetzt sind
transfer
es also Daten undbalance
eine Operation (eine linke Falte über dem Transaktionslog). (Sie werden auch feststellen, dass diesTransactionSlip
unveränderlichbalance
ist, eine reine Funktion ist, bei der esTransactionLog
sich um eine "fast" unveränderliche Datenstruktur handeln kann, an die nur Anhänge angehängt werden. Ich bin sicher, dass viele von Ihnen die eklatanten Fehler in der ersten Implementierung entdeckt haben, die jetzt auf magische Weise verschwinden .)Beachten Sie, dass beide Modelle sind. Beides gilt gleichermaßen. Beides ist richtig. Beide haben das gleiche Modell. Und doch sind sie genau doppelt zueinander: Alles, was Daten in einem Modell sind, ist eine Operation im anderen Modell, und alles, was eine Operation in einem Modell ist, sind Daten im anderen Modell.
Die Frage ist also nicht, ob Sie die "reale Welt" in Ihrem Code modellieren , sondern wie Sie sie modellieren.
Wie sich herausstellt, ist das zweite Modell tatsächlich auch die Funktionsweise von Bankgeschäften in der realen Welt. Wie ich oben angedeutet habe, ist dieses zweite Modell größtenteils unveränderlich und rein und immun gegen Nebenläufigkeitsfehler, was eigentlich sehr wichtig ist, wenn man bedenkt, dass es eine Zeit vor nicht allzu langer Zeit gab, in der
TransactionSlip
es sich tatsächlich um Zettel handelte, die herumgeschickt wurden mit pferd & wagen.Die Tatsache, dass dieses zweite Modell tatsächlich mit der Funktionsweise von Real-World-Banking und der Funktionsweise von Real-World-Banking-Software übereinstimmt, macht es jedoch nicht automatisch "richtiger". Denn tatsächlich kommt das erste ("falsche") Modell der Sichtweise der Bankkunden ihrer Bank ziemlich nahe . Um sie ,
transfer
ist eine Operation (sie haben ein Formular ausfüllen), undbalance
ist ein Stück Daten am unteren Rande ihres Kontoauszugs.Es kann also durchaus zutreffen, dass es im Kern-Game-Engine-Code eines Hochleistungs-PS3-Shooters keinen
Rocket
Typ geben wird, aber es wird dennoch eine Modellierung der Welt geben, auch wenn das Modell seltsam aussieht an jemanden, der kein Experte auf dem Gebiet der Programmierung von Konsolenspiel-Physik-Engines ist.quelle
balance
als Daten und Transaktionen als mehr Daten und Übertragungen als Vorgänge behandelt, da dies der Benutzer sieht, auch wenn das Back-End dies möglicherweise anders behandelt.Ich bin nicht einverstanden mit jeder "Lüge", die er vorschlägt.
TL; DR Der Autor dieses Artikels versuchte kontrovers zu sein, um seinen Artikel interessanter zu machen, aber die sogenannten "Lügen" werden von Softwareentwicklern aus guten Gründen akzeptiert.
Lüge Nr. 1 - Big O ist wichtig für Skalierungszwecke. Es interessiert niemanden, ob eine winzige Anwendung eine längere Zeit benötigt, was die einzige wichtige Zeitkonstante ist, und es interessiert ihn, dass die Ausführungszeit beim Verdoppeln der Eingabegröße nicht mit dem Faktor 10 multipliziert wird.
Lüge Nr. 2 - Das Modellieren von Programmen nach dem Vorbild der realen Welt ermöglicht es einem Programmierer, 3 Jahre später auf Ihren Code zu schauen, leicht zu verstehen, was er tut. Code muss wartbar sein oder Sie müssen Stunden damit verbringen, zu verstehen, was das Programm versucht. Eine andere Antwort schlug vor, dass Sie allgemeinere Klassen wie
LaunchPad
und haben könnenMassiveDeviceMover
. Das ist nicht unbedingt eine schlechte Klasse, aber du würdest trotzdem dieRocket
Klasse brauchen . Wie soll jemand wissen, was eineMassiveDeviceMover
macht oder was sie bewegt? Bewegt es Berge, Raumschiffe oder Planeten? Dies bedeutet im Grunde, dass das Hinzufügen in Klassen wieMassiveDeviceMover
Ihr Programm weniger effizient (aber möglicherweise viel lesbarer und verständlicher) macht.Darüber hinaus haben die Kosten für Entwicklerzeit schon vor langer Zeit die Kosten für Hardware überschritten. Es ist eine schreckliche Idee, zunächst zu versuchen, mit einer Optimierung zu beginnen, die im Vordergrund Ihrer Überlegungen steht. Sie programmieren es auf einfache und verständliche Weise und optimieren dann Ihr Programm, nachdem Sie herausgefunden haben, welche Teile Ihrer Programme viel Zeit in Anspruch nehmen, um ausgeführt zu werden. Vergessen Sie nicht: 80% der Ausführungszeit werden von 20% des Programms genutzt.
Lüge 3 - Code ist extrem wichtig. Gut geschriebener (und modularer) Code ermöglicht die Wiederverwendbarkeit (spart unzählige Arbeitsstunden). Außerdem können Sie fehlerhafte Daten durchsehen und erkennen, damit sie verarbeitet werden können. Daten sind wunderbar, aber ohne den Code wäre es unmöglich, sie zu analysieren und nützliche Informationen daraus zu erhalten.
quelle
In einem E-Commerce-System handelt es sich nicht um "Raketen" auf Klassenebene, sondern um "Produkte". Es kommt also darauf an, was Sie erreichen wollen und welches Abstraktionsniveau Sie erreichen möchten.
In einem Spiel könnte argumentiert werden, dass Raketen nur eine von vielen Arten von "sich bewegenden Objekten" sind. Für sie gilt die gleiche Physik wie für alle anderen beweglichen Objekte. Zumindest wird "Rakete" also von einer allgemeineren Basisklasse "sich bewegender Objekte" erben.
In jedem Fall scheint der Autor der von Ihnen zitierten Passage seinen Fall ein wenig übertrieben zu haben. Raketen können immer noch einzigartige Eigenschaften haben, wie "verbleibende Treibstoffmenge" und "Schub", und Sie brauchen nicht hundert Klassen, um dies für hundert Raketen darzustellen, Sie brauchen nur eine. Die Objekterstellung ist in den meisten vernünftigen Programmiersprachen recht kostengünstig. Wenn Sie also raketenähnliche Dinge verfolgen müssen, ist die Vorstellung, dass Sie keine Rocket-Objekte erstellen sollten, weil sie möglicherweise zu teuer sind, wenig sinnvoll.
quelle
Das Problem mit der realen Welt ist die verdammte Physik. Wir trennen Dinge in der realen Welt in physische Objekte, weil sie leichter zu bewegen sind als einzelne Atome oder eine riesige geschmolzene Schlacke von etwas, das möglicherweise eine Rakete ist.
Ebenso bietet die reale Welt eine Reihe nützlicher Funktionen, auf die wir uns verlassen können. Es ist wirklich einfach, Pinguin-Ausnahmen zu machen - "alle Vögel fliegen, außer ...". Und es ist wirklich einfach, Dinge als Raketen zu bezeichnen. Ich meine, wenn ich diesen Pinguin eine Rakete nenne und sie anzünde ... funktioniert es einfach nicht.
Wie wir also die Dinge in der realen Welt voneinander trennen, funktioniert unter diesen Bedingungen. Wenn wir Dinge im Code erledigen, sollten wir die Dinge trennen, um unter diesen Einschränkungen, die sich entschieden unterscheiden, gut funktionieren zu können.
Denken Sie an Netzwerke. Wir modellieren keine Ports, Kabel und Router im Code. Stattdessen abstrahieren wir die Netzwerkkommunikation in Verbindungen und Protokolle. Wir machen das, weil es eine nützliche Abstraktion ist, unabhängig von der Implementierung in der realen Welt. Und es enthält nützliche Einschränkungen (z. B. Sie können erst kommunizieren, wenn die Verbindung hergestellt ist), die nur im Code von Bedeutung sind .
Also ja, manchmal funktioniert es, Code nach der realen Welt zu modellieren, aber das ist ein Zufall . Wenn über OOP gesprochen wird, sind die Objekte keine Objekte der realen Welt. Dass Schulen und Tutorials etwas anderes sagen, ist eine jahrzehntelange Tragödie.
quelle
Rocket
Typ im Code dieses Typen gibt, kann ich wetten, dass es dennoch ein Modell von…Die Alternative besteht darin, die Dinge zu modellieren, die Ihre Programme interessieren. Selbst wenn Ihr Programm mit Raketen arbeitet, müssen Sie möglicherweise keine Entität namens a haben
Rocket
. Beispielsweise könnten Sie eineLaunchPad
Entität und eineLaunchSchedule
Entität und eineMassiveDeviceMover
Entität haben. Die Tatsache, dass all dies zum Abschuss von Raketen beiträgt, bedeutet nicht, dass Sie die Raketen selbst handhaben.quelle
Dies ist das eigentliche Problem, aber ich gebe Ihnen meine Meinung als Entwickler, vielleicht hilft das.
Erstens würde ich keine Lüge als häufige Missverständnisse bezeichnen. Es als Lüge zu bezeichnen, ist nur ein Hype.
Ein Recht hat er, in gewisser Weise. Ich werde nicht viel Zeit dafür aufwenden, weil es nicht Teil der Frage ist. Aber im Grunde hat er recht. Ich könnte das so formulieren: "Was in einem Labor funktioniert, funktioniert möglicherweise nicht im wirklichen Leben." Zu oft halten Entwickler an einem Design fest, das in einem "Labor" funktioniert, in realen Anwendungen jedoch nicht funktioniert.
Drei Klingt für mich ein bisschen kantig, aber im Grunde hat er wieder Recht. Dies könnte jedoch so umgeschrieben werden, dass "Code um Ihre Bedürfnisse herum geschrieben wird, versuchen Sie nicht, die Bedürfnisse an Ihren Code anzupassen".
Zwei Auch hier ist er richtig. Ich habe Entwickler gesehen, die Wochen oder länger damit verbracht haben, eine "Raketen" -Klasse zu entwickeln, wenn eine einfache "Fahrzeug" -Klasse funktionieren würde, oder eine noch einfachere "bewegliche" Klasse. Wenn sich Ihre Rakete nur von der linken Seite des Bildschirms nach rechts bewegen und ein Geräusch von sich geben muss, können Sie dieselbe Klasse wie für Autos, Züge, Boote und Fliegen verwenden. Die 100 sollten weniger als 1 * 100 kosten. Das Argument scheint in der Zeit zu liegen, die für die Entwicklung aufgewendet wurde, und weniger in den Berechnungskosten. Obwohl es "billiger" ist, sich an weniger allgemeine Klassen zu halten, die wiederverwendet werden können, als an viele spezifische Klassen, die nicht wiederverwendet werden können. Dies könnte wahrscheinlich umgeschrieben werden als "allgemeine Klassen sind besser als über bestimmte Klassen,
Im Wesentlichen könnte der gesamte Artikel mit weniger Stichwörtern umgeschrieben werden, und es wäre bestenfalls nur ein Absatz lang. Das heißt, es ist ein Blog-Beitrag, der sich auf einen engen Programmbereich konzentriert. Ich habe einige eingebettete Programme erstellt, und ich kann der allgemeinen Idee hinter diesen Aussagen zustimmen, obwohl sie ziemlich viel "Flaum" enthalten, um sie für eine Präsentation auf der GDC geeignet zu machen.
Eine letzte Anmerkung, der Artikel wurde 2008 geschrieben (soweit ich das beurteilen konnte). Dinge ändern sich schnell. Die Aussagen sind heute wahr, aber eingebettete Systeme sind heute viel häufiger als damals und Entwicklungsmuster ändern sich. Vielleicht sogar als Antwort auf diesen Artikel / Vortrag.
quelle
Ich finde es interessant, dass sich diese Lügen um akademische Belange drehen: Plattform, Effizienz der Speichernutzung und Daten. Aber es ignoriert das menschliche Element völlig.
Bei Software geht es darum, die Bedürfnisse der Menschen zu erfüllen. Typischerweise wird dies in geschäftlichen Begriffen quantifiziert - es gibt Kunden, die etwas wollen, und Geldgeber, die bereit sind, dafür zu zahlen. Wenn Software so geschrieben wird, dass sie die Anforderungen beider Seiten der Gleichung erfüllt, ist sie gute Software, wenn nicht, ist sie schlechte Software.
Wenn Plattform für den Kunden nicht wichtig ist, ist Plattform nicht wichtig. Wenn die Speichereffizienz für den Kunden nicht wichtig ist, ist sie auch nicht wichtig. Wenn Daten für den Kunden nicht wichtig sind, sind sie auch nicht wichtig. Wenn der Code funktioniert, aber nicht gelesen oder gewartet werden kann und der Kunde schnelle und zuverlässige Änderungen zu einem angemessenen Preis wünscht, ist schlecht geschriebener Code eine schlechte Sache. Wenn der Code funktioniert, aber nicht gelesen oder gewartet werden kann und es dem Kunden egal ist oder er bereit ist, für teure Refactors zu zahlen, ist schlecht geschriebener Code eine gute Sache.
Die große Lüge ist, dass alles andere als das menschliche Element zählt. Warum sind Daten wichtig? Weil es Kunden oder Stakeholder gibt, die dies benötigen. Das ist die "große Wahrheit".
quelle
IMHO Wenn Code "um ein Modell der Welt herum entworfen" ist, ist es für die Designer und Entwickler sowie für die Betreuer leichter zu verstehen. Aber ich denke, es geht nicht nur um mich und nicht nur um Software. Aus Wikipedia: Wissenschaftliches Modellieren ist eine wissenschaftliche Aktivität, deren Ziel es ist, einen bestimmten Teil oder ein bestimmtes Merkmal der Welt leichter zu verstehen, zu definieren, zu quantifizieren, zu visualisieren oder zu simulieren, indem auf vorhandenes und allgemein anerkanntes Wissen verwiesen wird
quelle