Wie unterscheiden sich Globals von einer Datenbank?


250

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?


117
Es ist schön zu sehen, wie Veteranen die Dogmen ein wenig herausfordern ...
svidgen

10
In einer Anwendung geben Sie normalerweise einen Mittelwert für den Zugriff auf die Datenbank an. Dieser Mittelwert wird an Funktionen übergeben, die auf die Datenbank zugreifen möchten. Das machen Sie nicht mit globalen Variablen, Sie wissen einfach, dass sie zur Hand sind. Das ist genau dort ein entscheidender Unterschied.
Andy

45
Der globale Status entspricht einer einzelnen Datenbank mit einer einzelnen Tabelle und einer einzelnen Zeile mit unendlich vielen Spalten, auf die eine beliebige Anzahl von Anwendungen gleichzeitig zugreifen kann.
BevynQ

42
Datenbanken sind auch böse.
Stig Hemmer

27
Es ist unterhaltsam, das Argument, das Sie hier vorbringen, umzukehren und in die andere Richtung zu gehen. Eine Struktur, die einen Zeiger auf eine andere Struktur enthält, ist logischerweise nur ein Fremdschlüssel in einer Zeile einer Tabelle, der zu einer anderen Zeile einer anderen Tabelle führt. Wie wird mit Arbeits beliebigen Code, einschließlich Walking verkettete Listen von allen unterschiedlichen Daten in einer Datenbank zu manipulieren? Antwort: ist es nicht. Frage: Warum manipulieren wir dann In-Memory-Datenstrukturen und In-Database-Datenstrukturen mit so unterschiedlichen Werkzeugen? Antwort: Ich weiß es wirklich nicht! Scheint eher ein Unfall der Geschichte als gutes Design.
Eric Lippert

Antworten:


118

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.


44
Ich denke, der Punkt der Konsistenz ist eigentlich der Hauptgrund: Wenn globale Variablen im Code verwendet werden, ist normalerweise nicht abzusehen, wann sie tatsächlich initialisiert werden. Die Abhängigkeiten zwischen den Modulen sind in der Reihenfolge der Aufrufe tief verborgen, und einfache Dinge wie das Vertauschen von zwei Aufrufen können wirklich schlimme Fehler verursachen, da plötzlich eine globale Variable nicht mehr richtig initialisiert wird, wenn sie zum ersten Mal verwendet wird. Zumindest ist dies das Problem, das ich mit dem Legacy-Code habe, mit dem ich arbeiten muss, und das das Refactoring zu einem Albtraum macht.
cmaster

24
@DavidHammen Ich habe tatsächlich an der Weltzustandssimulation für ein Online-Spiel gearbeitet, das eindeutig zu der Kategorie von Anwendungen gehört, über die Sie sprechen, und selbst dort würde ich den globalen Zustand nicht dafür verwenden (und habe es auch nicht verwendet). Auch wenn mit dem globalen Status einige Effizienzgewinne erzielt werden können, besteht das Problem darin, dass der globale Status nicht skalierbar ist . Sobald Sie von einer Architektur mit einem Thread zu einer Architektur mit mehreren Threads wechseln, wird die Verwendung schwierig . Es wird ineffizient, wenn Sie zu einer NUMA-Architektur wechseln. Wenn Sie zu einer verteilten Architektur wechseln, wird dies unmöglich . Die Zeitung, die Sie zitieren, stammt von ...
Jules

24
1993. Diese Probleme waren damals weniger ein Thema. Die Autoren arbeiteten an einem einzelnen Prozessorsystem und simulierten Interaktionen von 1.000 Objekten. In einem modernen System würden Sie wahrscheinlich eine Simulation dieser Art auf mindestens einem Dual-Core-System ausführen, aber es könnten sehr wahrscheinlich mindestens 6 Kerne in einem einzelnen System sein. Bei größeren Problemen würden Sie es auf einem Cluster ausführen. Für diese Art von Änderung müssen Sie den globalen Status vermeiden, da der globale Status nicht effektiv freigegeben werden kann.
Jules

19
Ich denke, dass es ein bisschen schwierig ist, den Datenbankstatus als "notwendiges Übel" zu bezeichnen. Ich meine, seit wann ist der Staat böse geworden? Status ist der gesamte Zweck einer Datenbank. Zustand ist Information. Ohne Bundesland haben Sie nur Operatoren. Was nützen Betreiber ohne etwas zu operieren? Dieser Zustand muss irgendwohin gehen. Am Ende des Tages ist funktionale Programmierung nur ein Mittel zum Zweck und ohne Mutationszustand hätte es keinen Sinn, überhaupt etwas zu tun. Es ist ein bisschen wie ein Bäcker, der den Kuchen als notwendiges Übel bezeichnet - es ist nicht böse. Es ist der ganze Sinn der Sache.
J ...

5
@DavidHammen "Es gibt immer noch ein Objekt, das zumindest ein bisschen über jedes Objekt im Spiel weiß." Nicht unbedingt wahr. Eine Haupttechnik in der modernen verteilten Simulation besteht darin, die Lokalität auszunutzen und Approximationen so vorzunehmen, dass entfernte Objekte nicht über alles in der Ferne Bescheid wissen müssen, sondern nur, welche Daten ihnen von den Eigentümern dieser entfernten Objekte bereitgestellt werden.
JAB

75

Was sind die Probleme mit globalen Variablen, basierend auf der akzeptierten Antwort auf die von Ihnen verknüpfte Frage?

Sehr kurz, es macht den Programmstatus unvorhersehbar.

Datenbanken sind die meiste Zeit ACID-konform. ACID behebt speziell die zugrunde liegenden Probleme, die einen Datenspeicher unvorhersehbar oder unzuverlässig machen würden.

Darüber hinaus beeinträchtigt der globale Status die Lesbarkeit Ihres Codes.

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.


4
+1 Was Sie sagen, ist, dass Datenbanken Transaktionen haben, die es ermöglichen, mehrere Teile eines globalen Zustands atomar zu lesen und zu schreiben . Ein guter Punkt, der nur umgangen werden kann, wenn für jede völlig unabhängige Information globale Variablen verwendet werden .
l0b0

1
@ 10b0-Transaktionen sind der Mechanismus, mit dem die meisten ACID-Ziele erreicht werden. Die DB-Schnittstelle selbst macht den Code jedoch klarer, indem die Daten in einen lokaleren Bereich verschoben werden. Stellen Sie sich vor, Sie verwenden ein JDBC-RecordSet mit einem Try-with-Resources-Block oder eine ORM-Funktion, die ein Datenelement mit einem einzigen Funktionsaufruf abruft. Vergleichen Sie dies mit der Verwaltung von Daten, die weit entfernt von dem Code sind, den Sie in einem globalen Dokument lesen.

1
Es wäre also in Ordnung, globale Variablen zu verwenden, wenn ich den Wert zu Beginn der Funktion in eine lokale Variable (mit einem Mutex) kopiere, die lokale Variable ändere und den Wert dann am Ende von wieder in die globale Variable kopiere die Funktion? (... fragte er rhetorisch.)
RM

1
Er erwähnte zwei Punkte. Was Sie herausgeschmissen haben, betrifft möglicherweise den ersten (Programmstatus unvorhersehbar), nicht jedoch den zweiten (Lesbarkeit Ihres Codes). In der Tat kann es die Lesbarkeit Ihres Programms noch verschlechtern: P.
Riwalk

1
@RM Deine Funktion würde ja durchgehend laufen. Dann hätten Sie aber die Frage, ob die globale Variable in der Zwischenzeit von etwas anderem geändert wurde, und diese Änderung war wichtiger als das, was Sie darauf schreiben. Datenbanken können natürlich auch das gleiche Problem haben.
Graham

45

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:

Int32 counter = 0;

public someMethod() {
  for (counter = 0; counter < whatever; counter++) {
    // do other stuff.
  }
}

public otherMethod() {
  for (counter = 100; counter < whatever; counter--) {
    // do other stuff.
  }
}

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.


3
Die Art und Weise zu garantieren (da wir nicht davon ausgehen können), dass sich die Daten, die wir erhalten haben, nicht geändert haben, in einer Datenbank wäre eine Transaktion.
l0b0

Ja ... das sollte mit "der gleichen Art von Verriegelung" impliziert werden.
Svidgen

Aber am Ende des Tages kann es schwierig sein, sorgfältig zu überlegen.

Ja, Datenbanken sind in der Tat ein globaler Zustand - weshalb es so verlockend ist, Daten mit so etwas wie git oder ipfs zu teilen.
William Payne

21

Ich bin mit der grundsätzlichen Behauptung nicht einverstanden, dass:

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.

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

int looks_ok_but_isnt() {
  return global_int++;
}

int somewhere_else() {
  ...
  int v = looks_ok_but_isnt();
  ...
}

Dasselbe mit einer Datenbank zu tun, müsste jedoch präziser sein

int looks_like_its_using_a_database( MyDB * db ) {
   return db->get_and_increment("v");
}

int somewhere_else( MyBD * db ) { 
   ...
   v = looks_like_its_using_a_database(db);
   ...
}

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.

int looks_like_it_uses_explicit_state( MyState * state ) {
   return state->v++;
}


int somewhere_else( MyState * state ) { 
   ...
   v = looks_like_it_uses_explicit_state(state);
   ...
}

Daher würde ich argumentieren, dass die Verwendung einer Datenbank eher der Verwendung eines expliziten Status gleicht als der Verwendung globaler Variablen.


2
Ja, ich fand es interessant, als das OP sagte: "Es ist dir egal, was die Daten sind, das ist der springende Punkt " - wenn es uns egal ist, warum sie dann speichern? Hier ist ein Gedanke: Lassen Sie uns einfach aufhören, Variablen und Daten zu verwenden . Das sollte die Sache viel einfacher machen. "Halt die Welt an, ich will aussteigen!"

1
+1 Verschiedene Threads oder Apps, die aus derselben Datenbank schreiben und lesen, sind eine potenzielle Ursache für eine Vielzahl bekannter Probleme. Deshalb sollte es immer eine Strategie geben, um damit umzugehen, entweder auf Datenbank- oder App-Ebene oder beide. Es ist also definitiv NICHT wahr, dass es Ihnen (dem App-Entwickler) egal ist, wer noch etwas aus der Datenbank liest oder schreibt.
Andres F.

1
+1 Nebenbei bemerkt erklärt diese Antwort ziemlich genau, was ich am meisten an der Abhängigkeitsinjektion hasse. Diese Art von Abhängigkeiten werden ausgeblendet.
jpmc26

@ jpmc26 Ich markiere vielleicht Wörter, aber ist das obige Beispiel nicht ein gutes Beispiel dafür, wie die Abhängigkeitsinjektion (im Gegensatz zur globalen Suche) dazu beiträgt, Abhängigkeiten explizit zu machen? Mir scheint, Sie haben eher Probleme mit bestimmten APIs, wie z. B. der von JAX-RS und Spring verwendeten Annotation Magic.
Emil Lundberg

2
@EmilLundberg Nein, das Problem ist, wenn Sie eine Hierarchie haben. Durch die Abhängigkeitsinjektion werden die Abhängigkeiten niedrigerer Ebenen vom Code in den höheren Ebenen ausgeblendet, sodass es schwierig ist, zu verfolgen, welche Dinge miteinander interagieren. Wenn es beispielsweise darauf MakeNewThingankommt MakeNewThingInDbund meine Controller-Klasse verwendet MakeNewThing, 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.
jpmc26

18

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:

  • Datenbanken verfügen normalerweise über eine integrierte Typ- und Strukturüberprüfung, die über die Sprache hinausgeht, in der auf sie zugegriffen wird
  • Datenbanken werden basierend auf Transaktionen fast einstimmig aktualisiert, wodurch inkonsistente Zustände verhindert werden, bei denen es keine Garantie dafür gibt, wie der Endzustand in einem globalen Objekt aussehen wird (es sei denn, es ist hinter einem Singleton verborgen).
  • Die Datenbankstruktur wird zumindest implizit anhand der Tabellen- oder Objektstruktur dokumentiert, mehr als die Anwendung, die sie verwendet

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).


1
Huh. Du hast mich geschlagen, als ich auf halbem Weg eine fast identische Antwort geschrieben hatte. :)
Jules

@Jules Ihre Antwort bietet mehr Details von der Anwendungsseite der Dinge; behalte es.
Jeffrey Sweeney

Wenn Sie jedoch nicht ausschließlich auf gespeicherte Prozeduren für den Datenzugriff angewiesen sind, kann die gesamte Struktur nicht erzwingen, dass die Tabellen wie beabsichtigt verwendet werden. Oder dass Vorgänge in der richtigen Reihenfolge ausgeführt werden. Oder dass Sperren (Transaktionen) nach Bedarf erstellt werden.
Svidgen

Hallo, sind die Punkte 1 und 3 noch anwendbar, wenn Sie eine statische Sprache wie Java verwenden?
Jesvin Jose

@aitchnyu Nicht unbedingt. Dabei geht es darum, dass Datenbanken so erstellt werden, dass Daten zuverlässig gemeinsam genutzt werden können, globale Variablen jedoch normalerweise nicht. Ein Objekt, das eine selbstdokumentierende Schnittstelle in einer strengen Sprache implementiert, dient einem anderen Zweck als selbst eine lose typisierte NoSQL-Datenbank.
Jeffrey Sweeney

10

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?

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 Variable g_DangerWillRobinsonvor dem Aufrufen auf einen bestimmten Wert gesetzt werden sollte foo(oder nach dem Aufrufen überprüft werden muss foo).


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, xda dies fooeine nicht konstante Referenz als Argument voraussetzt. (Vergleiche mit C #, das vorschreibt, dass sowohl die Funktionsdefinition als auch die Aufrufsite einen Referenzparameter mit dem refSchlü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.


Ihre Antwort ist sinnvoller.
Billal Begueradj

8

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.


8

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.


7

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.


Ich finde es gut, dass Sie dies unter dem Gesichtspunkt der Abhängigkeiten gesehen haben.
Cbojar

6

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:

  • Es gibt keine Möglichkeit, ein teilweises Update zurückzusetzen, es sei denn, Sie behalten die alten Werte vor der "Transaktion" bei. Zu diesem Zeitpunkt ist es natürlich schon ein Gewinn, einen Wert als Argument zu übergeben :)
  • Jeder Benutzer, der auf denselben Status zugreift, muss denselben Synchronisierungsvorgang ausführen. Aber es gibt keine Möglichkeit, dies durchzusetzen. Wenn Sie vergessen, den kritischen Abschnitt einzurichten, sind Sie fertig.
  • Selbst wenn Sie den gesamten Zugriff korrekt synchronisieren, kann es zu verschachtelten Aufrufen kommen, die auf den Status "teilweise geändert" zugreifen. Dies bedeutet, dass Sie entweder festsitzen (wenn Ihre kritischen Abschnitte nicht neu sind) oder sich mit inkonsistenten Daten befassen (wenn sie neu sind).

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".


Hört sich sehr nach der physischen Welt an: Es ist sehr schwer, die Dinge zurückzurollen.

Dies ist eine gute Antwort, aber es könnte eine These Aussage (TL; DR-Abschnitt) am Anfang stehen.
jpmc26

6

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.


3
Typischer Studentenanspruch auf Stackoverflow: Hilf mir! Mein Code ist perfekt, funktioniert aber nicht richtig!
David Hammen

"ACID-Ansatz für globale Variablen" - siehe Referenzen in Clojure.
Charles Duffy

@ DavidHammen und Sie denken, Profis haben ein Gehirn im Gegensatz zu Studenten?
Billal Begueradj

@BillalBEGUERADJ - Das ist der Unterschied zwischen Fachleuten und Studenten. Wir wissen, dass unser Code trotz jahrelanger Erfahrung und trotz größter Anstrengungen bei Codeüberprüfungen, Tests usw. nicht perfekt ist.
David Hammen


5

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.


3
Zum Beispiel errnoin C.
David Hammen

1
Dies erklärt genau, warum Globale und Datenbanken nicht gleich sind. Es mag andere Unterschiede geben, aber Ihr spezifischer Beitrag zerstört das Konzept vollständig. Wenn Sie ein kurzes Codebeispiel geben würden, würden Sie mit Sicherheit viele positive Stimmen erhalten. zB MyFunc () {x = globalVar * 5; // .... Eine andere Verarbeitung; y = globalVar * 34; // Hoppla, ein anderer Thread könnte globalVar während einer anderen Verarbeitung geändert haben, und x und y verwenden unterschiedliche Werte für globalVar in ihren Berechnungen, die mit ziemlicher Sicherheit keine wünschenswerten Ergebnisse liefern würden.
Dunk

5

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 constKlassen, 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.


2

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.

static int global; // within process memory space
static int dbvar; // mirrors/caches data outside process memory space

class Cls {
    public: static int class_public; // essentially the same as global
    private: static int class_private; // but public to all methods in class

    private: static void method() {
        static int method_private; // but public to all scopes in method
        // ...
        {
            static int scope1_private; // mutex guarded
            int the_only_truly_private_data;
        }
        // ...
        {
            static int scope2_private; // mutex guarded
        }
    }
}

1

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.


0

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 .


0

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.


0

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.


0

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!


0

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".


-2

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.


Würde es einigen Downvotern etwas ausmachen, Ihre Downvotes zu erklären? Es scheint unhöflich, ohne Erklärung abzustimmen.
Byron Jones

-2

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.

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.