Ich bin gerade auf diese alte Frage gestoßen und habe gefragt, was am globalen Zustand so schlimm ist, und die am häufigsten gewählte, akzeptierte Antwort besagt, dass Sie keinem Code vertrauen können, der mit globalen Variablen funktioniert, da ein anderer Code möglicherweise irgendwo anders hinzukommt und dessen Code ändert Wert und dann wissen Sie nicht, wie sich Ihr Code verhält, weil die Daten unterschiedlich sind! Aber wenn ich mir das ansehe, kann ich nicht anders als zu denken, dass das eine wirklich schwache Erklärung ist, denn wie unterscheidet sich das von der Arbeit mit Daten, die in einer Datenbank gespeichert sind?
Wenn Ihr Programm mit Daten aus einer Datenbank arbeitet, ist es Ihnen egal, ob ein anderer Code in Ihrem System dies ändert oder auch, wenn es von einem völlig anderen Programm geändert wird. Es ist dir egal, was die Daten sind; Das ist der springende Punkt. Alles was zählt ist, dass Ihr Code richtig mit den Daten umgeht, auf die er trifft. (Natürlich beschönige ich das oft heikle Thema des Caching hier, aber lassen Sie uns das für den Moment ignorieren.)
Aber wenn die Daten, mit denen Sie arbeiten, von einer externen Quelle stammen, über die Ihr Code keine Kontrolle hat, wie z. B. eine Datenbank (oder Benutzereingaben oder ein Netzwerk-Socket oder eine Datei usw.), und nichts falsch ist Wie sind dann globale Daten im Code selbst - über die Ihr Programm eine weitaus größere Kontrolle hat - irgendwie eine schlechte Sache, wenn sie offensichtlich weitaus weniger schlecht sind als ganz normale Dinge, die niemand als Problem ansieht?
Antworten:
Erstens würde ich sagen, dass die Antwort, die Sie auf dieses spezielle Problem verweisen, darin besteht, dass die Kopplung auf unvorhersehbare Weise eingeführt wird, was es in Zukunft schwierig machen kann, das Verhalten Ihres Systems zu ändern.
Bei näherer Betrachtung dieses Themas gibt es jedoch Unterschiede zwischen dem globalen Status einer typischen objektorientierten Anwendung und dem Status, der in einer Datenbank gespeichert ist. Kurz gesagt, die wichtigsten davon sind:
Objektorientierte Systeme ermöglichen das Ersetzen eines Objekts durch eine andere Objektklasse, sofern es sich um einen Untertyp des ursprünglichen Typs handelt. Dadurch kann das Verhalten geändert werden, nicht nur die Daten .
Der globale Status in einer Anwendung bietet in der Regel nicht die Konsistenzgarantien, die eine Datenbank bietet - es gibt keine Transaktionen, bei denen ein konsistenter Status angezeigt wird, keine atomaren Aktualisierungen usw.
Zusätzlich können wir den Datenbankstatus als notwendiges Übel ansehen. es ist unmöglich, es aus unseren Systemen zu entfernen. Ein globaler Staat ist jedoch nicht notwendig. Wir können es völlig beseitigen. Selbst wenn die Probleme mit einer Datenbank genauso schlimm wären, können wir dennoch einige der potenziellen Probleme beseitigen , und eine Teillösung ist besser als keine Lösung.
quelle
Was sind die Probleme mit globalen Variablen, basierend auf der akzeptierten Antwort auf die von Ihnen verknüpfte Frage?
Datenbanken sind die meiste Zeit ACID-konform. ACID behebt speziell die zugrunde liegenden Probleme, die einen Datenspeicher unvorhersehbar oder unzuverlässig machen würden.
Dies liegt daran, dass globale Variablen in einem Bereich vorhanden sind, der weit von ihrer Verwendung entfernt ist, möglicherweise sogar in einer anderen Datei. Wenn Sie eine Datenbank verwenden, verwenden Sie einen Datensatz oder ein ORM-Objekt, das lokal für den Code ist, den Sie lesen (oder der es sein sollte).
Datenbanktreiber bieten normalerweise eine konsistente, verständliche Schnittstelle für den Zugriff auf Daten, die unabhängig von der Problemdomäne identisch sind. Wenn Sie Daten aus einer Datenbank abrufen, verfügt Ihr Programm über eine Kopie der Daten. Updates sind atomar. Im Gegensatz zu globalen Variablen, bei denen möglicherweise mehrere Threads oder Methoden auf demselben Datenelement ohne Atomizität ausgeführt werden, es sei denn, Sie fügen die Synchronisierung selbst hinzu. Aktualisierungen der Daten sind unvorhersehbar und schwer zu ermitteln. Aktualisierungen können verschachtelt sein, was zu fehlerhaften Lehrbüchern für Multithread-Daten führt (z. B. verschachtelte Inkremente).
Datenbanken modellieren in der Regel zunächst andere Daten als globale Variablen. Abgesehen davon sind Datenbanken von Grund auf als ACID-kompatibler Datenspeicher konzipiert, der viele der Probleme mit globalen Variablen mindert.
quelle
Ich möchte einige Bemerkungen machen:
Ja, eine Datenbank ist ein globaler Status.
Tatsächlich ist es ein superglobaler Staat, wie Sie betont haben. Es ist universell! Der Geltungsbereich umfasst alles oder jeden , der eine Verbindung zur Datenbank herstellt. Und ich vermute, viele Leute mit langjähriger Erfahrung können Ihnen Horrorgeschichten darüber erzählen, wie "seltsame Dinge" in den Daten in einer oder mehreren der relevanten Anwendungen zu "unerwartetem Verhalten" führten ...
Eine der möglichen Konsequenzen der Verwendung einer globalen Variablen besteht darin, dass zwei unterschiedliche "Module" diese Variable für ihre eigenen unterschiedlichen Zwecke verwenden. Insofern ist eine Datenbanktabelle nicht anders. Es kann dem gleichen Problem zum Opfer fallen.
Hmm ... Hier ist das Ding:
Wenn ein Modul nicht in irgendeiner Weise extern arbeitet, tut es nichts.
Einem nützlichen Modul können Daten gegeben werden oder es kann es finden . Und kann es zurückgeben Daten oder es kann ändern Zustand. Aber wenn es nicht in irgendeiner Weise mit der Außenwelt interagiert, kann es auch nichts tun.
Nun, unsere Präferenz ist zu empfangen Daten und Rück Daten. Die meisten Module sind einfach einfacher zu schreiben, wenn sie mit völliger Missachtung dessen, was die Außenwelt tut, geschrieben werden können. Aber letztlich etwas muss finden die Daten und ändern diese externen, globalen Zustand.
Darüber hinaus sind die Daten in realen Anwendungen vorhanden, sodass sie von verschiedenen Vorgängen gelesen und aktualisiert werden können . Einige Probleme werden durch Sperren und Transaktionen verhindert. Um zu verhindern, dass diese Vorgänge letztendlich miteinander in Konflikt geraten , muss man jedoch sorgfältig überlegen. (Und Fehler machen ...)
Aber wir arbeiten im Allgemeinen auch nicht direkt mit dem globalen Staat zusammen.
Sofern sich die Anwendung nicht in der Datenschicht befindet (in SQL oder einem anderen Format), sind die Objekte, mit denen unsere Module arbeiten, tatsächlich Kopien des gemeinsam genutzten globalen Status. Wir können tun, was wir wollen, ohne den tatsächlichen, gemeinsamen Zustand zu beeinflussen.
Und in Fällen, in denen wir diesen globalen Zustand ändern müssen, können wir unter der Annahme, dass sich die uns übermittelten Daten nicht geändert haben, im Allgemeinen die gleiche Art der Sperrung durchführen, die wir für unsere lokalen globalen Zustände durchführen würden.
Und schließlich, was wir tun in der Regel verschiedene Dinge mit Datenbanken , als wir vielleicht mit frechen Globals.
Ein ungezogenes, kaputtes Global sieht so aus:
Wir benutzen einfach keine Datenbanken für solche In-Process / Operational-Sachen. Möglicherweise schreckt uns die Langsamkeit der Datenbank und die relative Bequemlichkeit einer einfachen Variablen ab: Unsere träge und umständliche Interaktion mit Datenbanken macht sie einfach zu schlechten Kandidaten für viele der Fehler, die wir in der Vergangenheit mit Variablen gemacht haben.
quelle
Ich bin mit der grundsätzlichen Behauptung nicht einverstanden, dass:
Mein erster Gedanke war "Wow. Just Wow". Es wird so viel Zeit und Mühe aufgewendet, um genau dies zu vermeiden - und für jede Anwendung herauszufinden, welche Kompromisse und Kompromisse funktionieren. Nur zu ignorieren ist ein Rezept für eine Katastrophe.
Aber ich stimme auch architektonisch zu. Eine globale Variable ist nicht nur ein globaler Zustand. Es ist ein globaler Zustand, auf den von überall transparent zugegriffen werden kann. Im Gegensatz zur Verwendung einer Datenbank müssen Sie ein Handle haben - es sei denn, Sie speichern das Handle in einer globalen Variablen.
Die Verwendung einer globalen Variablen könnte beispielsweise so aussehen
Dasselbe mit einer Datenbank zu tun, müsste jedoch präziser sein
Die Datenbank ist offensichtlich mit einer Datenbank Mist. Wenn Sie keine Datenbank verwenden möchten, können Sie den expliziten Status verwenden, und er sieht fast genauso aus wie der Datenbankfall.
Daher würde ich argumentieren, dass die Verwendung einer Datenbank eher der Verwendung eines expliziten Status gleicht als der Verwendung globaler Variablen.
quelle
MakeNewThing
ankommtMakeNewThingInDb
und meine Controller-Klasse verwendetMakeNewThing
, ist aus dem Code in meinem Controller nicht ersichtlich, dass ich die Datenbank ändere. Was ist dann, wenn ich eine andere Klasse verwende, die meine aktuelle Transaktion tatsächlich in die Datenbank schreibt? DI macht es sehr schwierig, den Umfang eines Objekts zu steuern.Der einzige Grund, warum globalen Variablen nicht vertraut werden kann, da der Status an einer anderen Stelle geändert werden kann, ist, wie vereinbart, nicht der Grund genug, sie nicht zu verwenden (dies ist jedoch ein ziemlich guter Grund!). Es ist wahrscheinlich, dass die Antwort hauptsächlich die Verwendung beschrieb, bei der die Einschränkung des Zugriffs einer Variablen auf nur Codebereiche, mit denen sie sich befasst, sinnvoller wäre.
Anders verhält es sich mit Datenbanken, die sozusagen "global" abgerufen werden sollen.
Zum Beispiel:
Am wichtigsten ist jedoch, dass Datenbanken einen anderen Zweck erfüllen als globale Variablen. Datenbanken dienen zum Speichern und Durchsuchen großer Mengen organisierter Daten, wobei globale Variablen bestimmte Nischen bedienen (sofern dies gerechtfertigt ist).
quelle
Oder anders als bei der Arbeit mit einem interaktiven Gerät, einer Datei, einem gemeinsam genutzten Speicher usw. Ein Programm, das bei jeder Ausführung genau das Gleiche tut, ist ein sehr langweiliges und ziemlich nutzloses Programm. Also ja, es ist ein schwaches Argument.
Für mich macht der Unterschied zu globalen Variablen aus, dass sie verborgene und ungeschützte Kommunikationslinien bilden. Das Lesen von einer Tastatur ist sehr offensichtlich und geschützt. Ich muss eine bestimmte Funktion aufrufen und kann nicht auf den Tastaturtreiber zugreifen. Gleiches gilt für den Dateizugriff, den gemeinsamen Speicher und Ihre Beispieldatenbanken. Für den Leser des Codes ist es offensichtlich, dass diese Funktion von der Tastatur liest, dass die Funktion auf eine Datei zugreift, dass eine andere Funktion auf den gemeinsam genutzten Speicher zugreift (und es sollte besser Schutzmaßnahmen geben) und dass eine andere Funktion auf eine Datenbank zugreift.
Bei globalen Variablen ist dies jedoch überhaupt nicht offensichtlich. Die API fordert zum Aufruf auf
foo(this_argument, that_argument)
. Die aufrufende Sequenz enthält nichts, was besagt, dass die globale Variableg_DangerWillRobinson
vor dem Aufrufen auf einen bestimmten Wert gesetzt werden solltefoo
(oder nach dem Aufrufen überprüft werden mussfoo
).Google hat die Verwendung von nicht konstanten Referenzargumenten in C ++ in erster Linie deshalb verboten, weil es für den Leser des Codes nicht offensichtlich ist, dass
foo(x)
sich der Code ändert,x
da diesfoo
eine nicht konstante Referenz als Argument voraussetzt. (Vergleiche mit C #, das vorschreibt, dass sowohl die Funktionsdefinition als auch die Aufrufsite einen Referenzparameter mit demref
Schlüsselwort qualifizieren müssen .) Obwohl ich dem Google-Standard in dieser Hinsicht nicht zustimme, verstehe ich ihren Punkt.Code wird einmal geschrieben und einige Male modifiziert, aber wenn er überhaupt gut ist, wird er viele Male gelesen. Versteckte Kommunikationswege sind sehr schlechtes Karma. Die Nicht-Konstanten-Referenz von C ++ stellt eine geringfügige versteckte Kommunikationslinie dar. Eine gute API oder eine gute IDE zeigt mir, dass "Oh! Dies ist ein Referenzaufruf." Globale Variablen sind eine riesige versteckte Kommunikationslinie.
quelle
Ich denke, dass die angeführte Erklärung das Thema so stark vereinfacht, dass die Argumentation lächerlich wird. Natürlich trägt der Status einer externen Datenbank zum globalen Status bei. Die wichtige Frage ist, wieIhr Programm hängt vom (veränderlichen) globalen Status ab. Wenn eine Bibliotheksfunktion zum Teilen von Zeichenfolgen in Leerzeichen von in einer Datenbank gespeicherten Zwischenergebnissen abhängen würde, würde ich diesem Entwurf mindestens so viel widersprechen wie einem globalen Zeichenarray, das für denselben Zweck verwendet wird. Wenn Sie jedoch feststellen, dass Ihre Anwendung zu diesem Zeitpunkt kein vollständiges DBMS zum Speichern von Geschäftsdaten benötigt und eine globale speicherinterne Schlüsselwertstruktur dies auch tut, ist dies nicht unbedingt ein Zeichen für ein schlechtes Design. Wichtig ist, dass - unabhängig davon, für welche Lösung Sie sich zum Speichern Ihrer Daten entscheiden - diese Auswahl auf einen sehr kleinen Teil des Systems beschränkt ist, sodass die meisten Komponenten unabhängig von der für die Bereitstellung ausgewählten und einzeln getesteten Lösung und der bereitgestellten Lösung sind Die Lösung kann zu einem späteren Zeitpunkt mit geringem Aufwand geändert werden.
quelle
Als Softwareentwickler, der hauptsächlich mit eingebetteter Firmware arbeitet, verwende ich fast immer globale Variablen für alles zwischen Modulen. In der Tat ist es Best Practice für Embedded. Sie werden statisch zugewiesen, sodass kein Risiko besteht, dass der Heap / Stack aufgeblasen wird, und es wird keine zusätzliche Zeit für die Stapelzuweisung / Bereinigung beim Ein- / Beenden der Funktion benötigt.
Der Nachteil dabei ist, dass wir uns überlegen müssen, wie diese Variablen verwendet werden, und viele davon basieren auf der gleichen Art von Gedanken, die beim Datenbank-Wrangling anfallen. Jedes asynchrone Lesen / Schreiben von Variablen MUSS atomar sein. Wenn mehr als eine Stelle eine Variable schreiben kann, müssen einige Überlegungen angestellt werden, um sicherzustellen, dass sie immer gültige Daten schreiben, damit das vorherige Schreiben nicht willkürlich ersetzt wird (oder dass willkürliches Ersetzen eine sichere Sache ist). Wenn dieselbe Variable mehrmals gelesen wird, müssen einige Überlegungen angestellt werden, was passiert, wenn sich der Wert zwischen den Lesevorgängen ändert, oder es muss zu Beginn eine Kopie der Variablen erstellt werden, damit die Verarbeitung mit einem konsistenten Wert erfolgt, auch wenn Dieser Wert wird während der Verarbeitung veraltet.
(Für das letzte Mal, an meinem allerersten Tag eines Vertrags über die Arbeit an einem Flugzeug-Gegenmaßnahmensystem, sah sich das Software-Team einen Fehlerbericht an, den sie seit ungefähr einer Woche herausfinden wollten. Ich hatte gerade genug Zeit, um die Entwicklertools und eine Kopie des Codes herunterzuladen. Ich fragte: "Konnte diese Variable zwischen den Lesevorgängen nicht aktualisiert werden und es verursachen?", Bekam aber keine wirkliche Antwort. Hey, was macht das? Also, während sie noch darüber diskutierten, fügte ich Schutzcode hinzu, um die Variable atomar zu lesen, erstellte einen lokalen Build und sagte im Grunde: "Hey Leute, probier das mal aus." . :)
Globale Variablen sind also keine eindeutig schlechte Sache, aber sie lassen Sie für eine Vielzahl von Themen offen, wenn Sie nicht sorgfältig darüber nachdenken.
quelle
Je nachdem, welchen Aspekt Sie beurteilen, sind globale Variablen und Datenbankzugriff möglicherweise Welten voneinander entfernt, aber solange wir sie als Abhängigkeiten beurteilen, sind sie gleich.
Angenommen, die Definition einer reinen Funktion in der funktionalen Programmierung besagt, dass sie ausschließlich von den Parametern abhängen muss, die sie als Eingaben verwendet, um eine deterministische Ausgabe zu erzeugen. Dies bedeutet, dass bei zweimaliger Angabe derselben Argumente dasselbe Ergebnis erzielt werden muss.
Wenn eine Funktion von einer globalen Variablen abhängt, kann sie nicht mehr als rein betrachtet werden, da sie bei derselben Menge oder denselben Argumenten möglicherweise unterschiedliche Ausgaben liefert, weil sich der Wert der globalen Variablen zwischen den Aufrufen geändert hat.
Die Funktion kann jedoch immer noch als deterministisch angesehen werden, wenn wir die globale Variable als Teil der Schnittstelle der Funktion und ihrer anderen Argumente betrachten, sodass dies nicht das Problem ist. Das Problem ist nur, dass dies verborgen ist, bis wir von unerwartetem Verhalten scheinbar offensichtlicher Funktionen überrascht werden. Lesen Sie dann deren Implementierungen, um die verborgenen Abhängigkeiten zu entdecken .
Dieser Teil, der Moment, in dem eine globale Variable zu einer verborgenen Abhängigkeit wird, wird von uns Programmierern als böse angesehen. Es erschwert das Nachdenken über den Code, das Vorhersagen des Verhaltens, die Wiederverwendung und das Testen des Codes und erhöht insbesondere die Fehlerbehebungs- und Behebungszeit, wenn ein Problem auftritt.
Dasselbe passiert, wenn wir die Abhängigkeit von der Datenbank verbergen. Wir können Funktionen oder Objekte haben, die Datenbankabfragen und -befehle direkt aufrufen, diese Abhängigkeiten verbergen und uns genau die Probleme bereiten, die globale Variablen verursachen. oder wir können sie explizit machen, was, wie sich herausstellt, eine bewährte Methode ist, die viele Namen hat, wie z. B. Repository-Muster, Datenspeicher, Gateway usw.
PS: Es gibt andere Aspekte, die für diesen Vergleich wichtig sind, z. B. die Frage, ob es sich um Parallelität handelt, aber dieser Punkt wird hier durch andere Antworten abgedeckt.
quelle
Okay, lassen Sie uns vom historischen Punkt aus beginnen.
Wir befinden uns in einer alten Anwendung, die in einem typischen Mix aus Assembly und C geschrieben ist. Es gibt keine Funktionen, nur Prozeduren . Wenn Sie ein Argument übergeben oder einen Wert von einer Prozedur zurückgeben möchten, verwenden Sie eine globale Variable. Natürlich ist es ziemlich schwierig, dies im Auge zu behalten, und im Allgemeinen kann jede Prozedur mit jeder globalen Variablen tun, was sie will. Es ist nicht verwunderlich, dass die Benutzer Argumente übergeben und Werte auf eine andere Weise zurückgeben, sobald dies machbar war (es sei denn, es war leistungskritisch, dies nicht zu tun - z. B. den Quellcode der Build Engine (Duke 3D) ansehen). Hier wurde der Hass auf globale Variablen geboren - Sie hatten keine Ahnung, welchen globalen Status die einzelnen Prozeduren lesen und ändern würden, und Sie konnten Prozeduraufrufe nicht wirklich sicher verschachteln.
Bedeutet dies, dass der Hass auf globale Variablen der Vergangenheit angehört? Nicht ganz.
Zunächst muss ich erwähnen, dass ich in dem Projekt, an dem ich gerade arbeite, genau den gleichen Ansatz zur Übergabe von Argumenten gesehen habe . Zum Übergeben von zwei Referenztypinstanzen in C # in einem Projekt, das ungefähr 10 Jahre alt ist. Es gibt buchstäblich keinen guten Grund, es so zu machen, und es ist höchstwahrscheinlich darauf zurückzuführen, dass man Fracht kultiviert oder die Funktionsweise von C # völlig missverstanden hat.
Der größere Punkt ist, dass Sie durch Hinzufügen globaler Variablen den Gültigkeitsbereich jedes einzelnen Codeteils erweitern, der Zugriff auf diese globale Variable hat. Erinnern Sie sich an all diese Empfehlungen wie "Halten Sie Ihre Methoden kurz"? Wenn Sie 600 globale Variablen haben (wieder ein Beispiel aus der Praxis: /), werden alle Ihre Methodenbereiche implizit um diese 600 globalen Variablen erweitert, und es gibt keine einfache Möglichkeit, festzustellen, wer Zugriff auf was hat.
Bei falscher Vorgehensweise (wie üblich :) können globale Variablen miteinander gekoppelt sein. Sie haben jedoch keine Ahnung, wie sie gekoppelt sind, und es gibt keinen Mechanismus, um sicherzustellen, dass der globale Zustand immer konsistent ist. Selbst wenn Sie kritische Abschnitte einführen, um die Konsistenz zu gewährleisten, werden Sie feststellen, dass der Vergleich mit einer ordnungsgemäßen ACID-Datenbank schlecht ist:
Ist es möglich, diese Probleme zu beheben? Nicht wirklich. Sie brauchen eine Kapselung, um damit umzugehen, oder wirklich strenge Disziplin. Es ist schwer, die Dinge richtig zu machen, und das ist im Allgemeinen kein sehr gutes Erfolgsrezept für die Softwareentwicklung :)
Ein kleinerer Bereich erleichtert das Nachdenken über Code. Globale Variablen sorgen dafür, dass selbst die einfachsten Codeteile große Bereiche umfassen.
Dies bedeutet natürlich nicht, dass globales Scoping böse ist. Es sollte einfach nicht die erste Lösung sein, für die Sie sich entscheiden - es ist ein typisches Beispiel für "einfach zu implementieren, schwer zu warten".
quelle
Eine globale Variable ist ein Werkzeug, das zum Guten und zum Bösen eingesetzt werden kann.
Eine Datenbank ist ein Werkzeug, das zum Guten und zum Bösen eingesetzt werden kann.
Wie das Originalplakat festhält, ist der Unterschied nicht allzu groß.
Unerfahrene Schüler denken oft, dass Fehler anderen Menschen passieren. Lehrer verwenden "Globale Variablen sind böse" als vereinfachten Grund, um schlechtes Design zu bestrafen. Die Schüler verstehen im Allgemeinen nicht, dass ein fehlerfreies Programm mit 100 Zeilen nicht bedeutet, dass die gleichen Methoden für Programme mit 100 Zeilen verwendet werden können.
Wenn Sie mit Datenbanken arbeiten, können Sie den globalen Status nicht einfach sperren, denn darum geht es beim Programm. Stattdessen erhalten Sie detailliertere Richtlinien wie ACID und Normal Forms und so weiter.
Wenn die Leute den ACID-Ansatz für globale Variablen verwenden würden, wären sie nicht so schlecht.
Wenn Sie Datenbanken dagegen schlecht gestalten, können sie Albträume sein.
quelle
Für mich ist das primäre Übel, dass Globals keinen Schutz vor Nebenläufigkeitsproblemen haben. Sie können Mechanismen zur Behandlung solcher Probleme mit Globals hinzufügen. Je mehr Probleme Sie jedoch gleichzeitig lösen, desto mehr ahmen Ihre Globals eine Datenbank nach. Das sekundäre Übel ist kein Nutzungsvertrag.
quelle
errno
in C.In einigen anderen Antworten wird versucht zu erklären, warum die Verwendung einer Datenbank sinnvoll ist. Sie liegen falsch! Eine Datenbank ist ein globaler Zustand und daher genauso böse wie ein Singleton oder eine globale Variable. Es ist völlig falsch, eine Datenbank zu verwenden, wenn Sie stattdessen einfach eine lokale Karte oder ein Array verwenden können!
Globale Variablen ermöglichen den globalen Zugriff, der ein Missbrauchsrisiko birgt. Globale Variablen haben auch Vorteile. Globale Variablen werden allgemein gesagt , etwas zu sein , die Sie vermeiden sollten, nicht etwas , das Sie nie verwenden sollten. Wenn Sie sie leicht vermeiden können, sollten Sie sie vermeiden. Aber wenn die Vorteile die Nachteile überwiegen, sollten Sie sie natürlich nutzen! *
Genau das Gleiche gilt für Datenbanken, die einen globalen Status haben - genau wie globale Variablen. Wenn Sie auf den Zugriff auf eine Datenbank verzichten können und die daraus resultierende Logik alles Notwendige und auch Komplexe leistet, erhöht die Verwendung einer Datenbank das Risiko für Ihr Projekt, ohne dass ein entsprechender Nutzen entsteht.
Im wirklichen Leben erfordern viele Anwendungen einen globalen Status, manchmal sogar einen dauerhaften globalen Status. Aus diesem Grund verfügen wir über Dateien, Datenbanken usw.
* Die Ausnahme bilden hier Studenten. Es ist sinnvoll, Schülern die Verwendung globaler Variablen zu verbieten, damit sie lernen können, welche Alternativen es gibt.
** Einige Antworten behaupten fälschlicherweise, dass Datenbanken irgendwie besser geschützt sind als andere Formen des globalen Zustands (die Frage bezieht sich ausdrücklich auf den globalen Zustand , nicht nur auf globale Variablen). Das ist Blödsinn. Der im Datenbankszenario angebotene Primärschutz ist konventionell und für jeden anderen globalen Status identisch. Die meisten Sprachen bieten außerdem eine Menge zusätzlichen Schutz für den globalen Status in Form von
const
Klassen, die es einfach nicht zulassen, ihren Status zu ändern, nachdem er im Konstruktor festgelegt wurde, oder Gettern und Setzern, die Threadinformationen oder den Programmstatus berücksichtigen können.quelle
In gewissem Sinne ähnelt die Unterscheidung zwischen globalen Variablen und einer Datenbank der Unterscheidung zwischen privaten und öffentlichen Mitgliedern eines Objekts (vorausgesetzt, dass noch öffentliche Felder verwendet werden). Wenn Sie sich das gesamte Programm als Objekt vorstellen, sind die globalen Variablen die privaten Variablen und die Datenbank die öffentlichen Felder.
Die Hauptunterscheidung liegt hier in der Übernahme von Verantwortung.
Wenn Sie ein Objekt schreiben, wird davon ausgegangen, dass jeder, der die Member-Methoden verwaltet, dafür sorgt, dass sich private Felder gut verhalten. Aber Sie geben bereits alle Annahmen über den Zustand der öffentlichen Felder auf und behandeln sie mit besonderer Sorgfalt.
Die gleiche Annahme gilt auf einer breiteren Ebene für die globale v / s-Datenbank. Außerdem garantiert die Programmiersprache / das Programmiersystem Zugriffsbeschränkungen für private v / s public, so wie sie für die globale v / s-Datenbank (nicht gemeinsam genutzter Speicher) gelten.
Wenn Multithreading ins Spiel kommt, ist das Konzept der privaten, öffentlichen und globalen V / S-Datenbank lediglich eine Unterscheidung entlang eines Spektrums.
quelle
Eine Datenbank kann ein globaler Status sein, muss jedoch nicht immer vorhanden sein. Ich bin nicht einverstanden mit der Annahme, dass Sie keine Kontrolle haben. Eine Möglichkeit, dies zu verwalten, sind Sperren und Sicherheit. Dies kann im Datensatz, in der Tabelle oder in der gesamten Datenbank erfolgen. Ein anderer Ansatz besteht darin, eine Art Versionsfeld zu haben, das das Ändern eines Datensatzes verhindert, wenn die Daten veraltet sind.
Wie eine globale Variable können die Werte in einer Datenbank geändert werden, sobald sie entsperrt sind. Es gibt jedoch viele Möglichkeiten, den Zugriff zu steuern (Geben Sie nicht allen Entwicklern das Kennwort für das Konto, das Daten ändern darf.). Wenn Sie eine Variable mit eingeschränktem Zugriff haben, ist diese nicht sehr global.
quelle
Es gibt verschiedene Unterschiede:
Ein Datenbankwert kann im laufenden Betrieb geändert werden. Der Wert eines globalen Elements, das im Code festgelegt ist, kann jedoch nur geändert werden, wenn Sie Ihre Anwendung erneut bereitstellen und Ihren Code ändern. In der Tat ist dies beabsichtigt. Eine Datenbank ist für Werte gedacht, die sich im Laufe der Zeit ändern können. Globale Variablen sollten jedoch nur für Dinge gelten, die sich niemals ändern, und wenn sie keine tatsächlichen Daten enthalten.
Ein Datenbankwert (Zeile, Spalte) hat einen Kontext und eine relationale Zuordnung in der Datenbank. Diese Beziehung kann einfach mit Tools wie Jailer (zum Beispiel) extrahiert und analysiert werden. Eine globale Variable ist dagegen etwas anders. Sie können alle Verwendungen finden, aber es wäre unmöglich, mir alle Arten der Interaktion der Variablen mit dem Rest Ihrer Welt mitzuteilen .
Globale Variablen sind schneller . Um etwas aus einer Datenbank abzurufen, muss eine Datenbankverbindung hergestellt, eine Auswahl ausgeführt und anschließend die Datenbankverbindung geschlossen werden. Darüber hinaus können alle erforderlichen Typkonvertierungen vorgenommen werden. Vergleichen Sie dies mit einem globalen Code, auf den zugegriffen wird.
Dies sind die einzigen, an die ich im Moment denken kann, aber ich bin mir sicher, dass es noch mehr gibt. Einfach ausgedrückt handelt es sich um zwei verschiedene Dinge, die für unterschiedliche Ziele verwendet werden sollten .
quelle
Natürlich sind Globals nicht immer unangemessen. Sie existieren, weil sie eine legitime Verwendung haben. Das Hauptproblem bei Globals und die Hauptquelle der Mahnung, sie zu vermeiden, ist, dass Code, der ein Global verwendet, mit diesem einen und nur einem Global verknüpft ist.
Angenommen, ein HTTP-Server speichert den Servernamen.
Wenn Sie den Servernamen global speichern, kann der Prozess keine Logik für zwei verschiedene Servernamen gleichzeitig ausführen. Das ursprüngliche Design sah möglicherweise nie vor, mehr als eine Serverinstanz gleichzeitig auszuführen. Wenn Sie sich jedoch später dazu entschließen, können Sie dies einfach nicht tun, wenn der Servername global ist.
Befindet sich der Servername hingegen in einer Datenbank, ist dies kein Problem. Sie können einfach eine Instanz dieser Datenbank für jede Instanz des HTTP-Servers erstellen. Da jede Instanz des Servers eine eigene Instanz der Datenbank hat, kann sie einen eigenen Servernamen haben.
Der primäre Einwand gegen Globals, es kann nur einen Wert für den gesamten Code geben, der auf diesen globalen Code zugreift, gilt nicht für Datenbankeinträge. Mit demselben Code kann problemlos auf verschiedene Datenbankinstanzen zugegriffen werden, die für einen bestimmten Eintrag unterschiedliche Werte aufweisen.
quelle
Ich halte dies für eine interessante Frage, aber es ist etwas schwierig zu beantworten, da unter dem Begriff "globaler Staat" zwei Hauptprobleme zusammengefasst werden. Das erste ist das Konzept der "globalen Kopplung". Der Beweis dafür ist, dass die Alternative für den globalen Zustand die Abhängigkeitsinjektion ist. Die Sache ist, dass DI den globalen Zustand nicht unbedingt eliminiert. Das heißt, es ist absolut möglich und üblich, Abhängigkeiten vom globalen Zustand zu erzeugen. DI entfernt die Kopplung, die mit globalen Variablen und dem häufig verwendeten Singleton-Muster geliefert wird. Abgesehen von einem etwas weniger offensichtlichen Design hat die Eliminierung dieser Art von Kopplung nur einen sehr geringen Nachteil, und die Vorteile der Eliminierung der Kopplung steigen exponentiell mit der Anzahl der Abhängigkeiten von diesen Globalen.
Der andere Aspekt ist der geteilte Zustand. Ich bin mir nicht sicher, ob es wirklich eine klare Unterscheidung zwischen global geteiltem Staat und geteiltem Staat im Allgemeinen gibt, aber die Kosten und der Nutzen sind viel differenzierter. Einfach ausgedrückt gibt es unzählige Softwaresysteme, die den gemeinsamen Status benötigen, um nützlich zu sein. Bitcoin zum Beispiel ist eine sehr clevere Methode, um den Staat global (im wahrsten Sinne des Wortes) dezentral zu teilen. Es ist schwierig, aber nützlich, den veränderlichen Zustand richtig zu teilen, ohne große Engpässe zu verursachen. Wenn Sie dies nicht wirklich tun müssen, können Sie Ihre Anwendung vereinfachen, indem Sie den gemeinsam genutzten veränderlichen Status minimieren.
Die Frage, inwiefern sich Datenbanken von globalen Datenbanken unterscheiden, ist also auch auf diese beiden Aspekte verteilt. Führen sie eine Kopplung ein? Ja, das können sie, aber es hängt sehr davon ab, wie die Anwendung und die Datenbank gestaltet sind. Es gibt zu viele Faktoren, um eine einzige Antwort darauf zu haben, ob Datenbanken eine globale Kopplung einführen, ohne dass Details zum Entwurf vorliegen. Die Frage, ob sie die gemeinsame Nutzung des Staates einführen, ist der Hauptpunkt einer Datenbank. Die Frage ist, ob sie es gut machen. Auch hier denke ich, dass dies zu kompliziert ist, um ohne viele andere Informationen wie die Alternativen und viele andere Kompromisse zu antworten.
quelle
Ich würde es etwas anders sehen: "Global Variable" ähnliches Verhalten ist ein Preis, den Datenbankadministratoren (DBAs) zahlen, weil es ein notwendiges Übel ist, um ihre Arbeit zu erledigen.
Das Problem mit globalen Variablen ist, wie mehrere andere betont haben, nicht willkürlich. Das Problem ist, dass ihre Verwendung das Verhalten Ihres Programms immer weniger vorhersehbar macht, da es schwieriger wird, festzustellen, wer die Variable auf welche Weise verwendet. Dies ist ein großes Problem für moderne Software, da moderne Software in der Regel viele, viele flexible Aufgaben ausführen muss. Es kann im Laufe eines Laufs Milliarden oder sogar Billionen komplexer Manipulationen des Zustands ausführen. Die Fähigkeit, wahre Aussagen darüber zu beweisen, was diese Software in diesen Milliarden oder Billionen von Operationen bewirken wird, ist äußerst wertvoll.
Bei moderner Software stellen alle unsere Sprachen Tools zur Verfügung, die dies unterstützen, z. B. die Kapselung. Die Entscheidung, es nicht zu benutzen, ist unnötig, was zu der Mentalität "Globals are evil" führt. In vielen Bereichen der Softwareentwicklung sind die einzigen Personen, die sie verwenden, Personen, die nicht wissen, wie man besser codiert. Dies bedeutet, dass sie nicht nur direkt Probleme bereiten, sondern auch indirekt darauf hinweisen, dass der Entwickler nicht wusste, was sie taten. In anderen Regionen sind Globals völlig normal (eingebettete Software liebt insbesondere Globals, zum Teil, weil sie gut mit ISRs zusammenarbeiten). Unter den vielen Software-Entwicklern sind sie jedoch die Minderheitsstimme, sodass die einzige Stimme, die Sie hören, "Globale sind böse" ist.
Die Datenbankentwicklung ist eine dieser Sprachprobleme. Die Tools, die für die Ausführung der DBA-Arbeit benötigt werden, sind sehr leistungsfähig, und ihre Theorie basiert nicht auf der Kapselung. Um jeden Augenblick der Performance aus ihren Datenbanken herauszuholen, benötigen sie uneingeschränkten Zugriff auf alles, ähnlich wie bei Globals. Nutzen Sie eine ihrer riesigen Datenbanken mit 100 Millionen Zeilen (oder mehr!), Und Sie werden verstehen, warum sie nicht zulassen, dass ihre DB-Engine Schläge aushält.
Sie zahlen dafür einen Preis, einen lieben Preis. DBAs müssen mit ihrer Liebe zum Detail fast pathologisch sein, weil ihre Tools sie nicht schützen. Das Beste, was sie im Hinblick auf den Schutz haben, ist ACID oder möglicherweise Fremdschlüssel. Diejenigen, die nicht pathologisch sind, befinden sich in einem völligen Durcheinander von Tabellen, das völlig unbrauchbar oder sogar korrupt ist.
Es ist nicht ungewöhnlich, Softwarepakete mit 100.000 Zeilen zu haben. Theoretisch kann sich jede Zeile in der Software zu jedem Zeitpunkt auf jedes globale Element auswirken. In DBAs finden Sie nie 100.000 verschiedene Abfragen, die die Datenbank ändern können. Es wäre unvernünftig, mit der Liebe zum Detail vorzugehen, um Sie vor sich selbst zu schützen. Wenn ein DBA über so etwas Großes verfügt, kapselt er seine Datenbank absichtlich mit Accessoren, umgeht die "globalen" Probleme und erledigt dann so viel Arbeit wie möglich über diesen "sichereren" Mechanismus. Wenn es darum geht, Druck auszuüben, meiden sogar die Datenbankmitarbeiter globale Zusammenhänge. Sie sind einfach mit einer großen Gefahr verbunden, und es gibt Alternativen, die genauso stark, aber nicht so gefährlich sind.
Möchten Sie lieber auf Glasscherben herumlaufen oder auf gepflegten Gehsteigen, wenn alle anderen Dinge gleich sind? Ja, Sie können auf Glasscherben gehen. Ja, manche Leute verdienen sogar ihren Lebensunterhalt damit. Aber lass sie doch einfach den Bürgersteig fegen und weiterziehen!
quelle
Ich denke, die Prämisse ist falsch. Es gibt keinen Grund, warum eine Datenbank "global state" sein muss, anstatt ein (sehr großes) Kontextobjekt. Wenn Sie über globale Variablen oder feste globale Datenbankverbindungsparameter an die bestimmte Datenbank binden, die Ihr Code verwendet, ist dies nicht anders und auch nicht weniger schlimm als jeder andere globale Status. Wenn Sie andererseits ein Kontextobjekt für die Datenbankverbindung ordnungsgemäß weitergeben, handelt es sich nur um einen großen (und häufig verwendeten) Kontextstatus, nicht um einen globalen Status.
Das Messen des Unterschieds ist einfach: Können Sie zwei Instanzen Ihrer Programmlogik mit jeweils einer eigenen Datenbank in einem einzigen Programm / Prozess ausführen, ohne den Code invasiv zu ändern? Wenn ja, ist Ihre Datenbank nicht wirklich "global state".
quelle
Globale sind nicht böse; Sie sind einfach ein Werkzeug. MISSBRAUCH von Globals ist ebenso problematisch wie der Missbrauch anderer Programmierfunktionen.
Meine allgemeine Empfehlung ist, dass Globale nur in Situationen verwendet werden sollten, die gut verstanden und durchdacht sind, in denen andere Lösungen weniger optimal sind. Vor allem möchten Sie sicherstellen, dass Sie gut dokumentiert haben, wo dieser globale Wert geändert werden kann, und wenn Sie Multithreading ausführen, sicherstellen, dass der Zugriff auf globale und alle co-abhängigen globalen Werte transaktionell erfolgt.
quelle
Schreibgeschütztes Muster, und nehmen Sie an, dass Ihre Daten beim Drucken nicht auf dem neuesten Stand sind. Die Warteschlange schreibt oder verarbeitet Konflikte auf andere Weise. Willkommen in der Hölle Teufel, verwenden Sie globale DB.
quelle