web-dev-qa-db-fra.com

En quoi les globaux sont-ils différents d'une base de données?

Je viens de traverser cette vieille question demandant ce qui est si mal à propos de l'état global, et la réponse acceptée la mieux votée affirme que vous ne pouvez pas faire confiance à un code qui fonctionne avec des variables globales, car un autre code quelque part d'autre pourrait venir et modifier sa valeur, puis vous ne savez pas quel sera le comportement de votre code car les données sont différentes! Mais quand je regardez ça, je ne peux pas m'empêcher de penser que c'est une explication vraiment faible, car en quoi est-ce différent de travailler avec des données stockées dans une base de données?

Lorsque votre programme travaille avec des données à partir d'une base de données, vous ne vous souciez pas si un autre code de votre système le change, ou même si un programme entièrement différent le change, d'ailleurs. Peu vous importe ce que sont les données; c'est tout le problème. Tout ce qui compte, c'est que votre code traite correctement les données qu'il rencontre. (Évidemment, je passe sous silence le problème souvent épineux de la mise en cache ici, mais ignorons cela pour le moment.)

Mais si les données avec lesquelles vous travaillez proviennent d'une source externe sur laquelle votre code n'a aucun contrôle, comme une base de données (ou une entrée utilisateur, ou une prise réseau, ou un fichier, etc.) et qu'il n'y a rien de mal avec cela, alors comment les données globales dans le code lui-même - sur lesquelles votre programme a un degré de contrôle beaucoup plus important - sont-elles en quelque sorte une mauvaise chose quand elles sont évidemment beaucoup moins mauvaises que des choses parfaitement normales que personne ne considère comme un problème?

253
Mason Wheeler

Tout d'abord, je dirais que la réponse que vous liez à exagère ce problème particulier et que le principal mal de l'État mondial est qu'il introduit le couplage de manière imprévisible qui peut rendre difficile le changement de comportement de votre système à l'avenir.

Mais en approfondissant ce problème, il existe des différences entre l'état global dans une application orientée objet typique et l'état contenu dans une base de données. En bref, les plus importants d'entre eux sont:

  • Les systèmes orientés objet permettent de remplacer un objet par une classe d'objet différente, tant qu'il s'agit d'un sous-type du type d'origine. Cela permet de modifier comportement, pas seulement données.

  • L'état global dans une application ne fournit généralement pas les garanties de cohérence solides qu'une base de données fait - il n'y a aucune transaction pendant laquelle vous voyez un état cohérent pour elle, pas de mises à jour atomiques, etc.

De plus, nous pouvons voir l'état de la base de données comme un mal nécessaire; il est impossible de l'éliminer de nos systèmes. Cependant, l'état mondial n'est pas nécessaire. Nous pouvons entièrement l'éliminer. Donc, même si les problèmes avec une base de données étaient tout aussi mauvais, nous pouvons toujours éliminer certains des problèmes potentiels et une solution partielle vaut mieux que pas de solution.

118
Jules

Premièrement, quels sont les problèmes avec les variables globales, sur la base de la réponse acceptée à la question que vous avez liée?

Très brièvement, cela rend l'état du programme imprévisible.

Les bases de données sont, la grande majorité du temps, conformes à ACID. ACID traite spécifiquement les problèmes sous-jacents qui rendraient un magasin de données imprévisible ou peu fiable.

De plus, l'état global nuit à la lisibilité de votre code.

En effet, les variables globales existent dans une portée très éloignée de leur utilisation, peut-être même dans un fichier différent. Lorsque vous utilisez une base de données, vous utilisez un jeu d'enregistrements ou un objet ORM qui est local au code que vous lisez (ou devriez être).

Les pilotes de base de données fournissent généralement une interface cohérente et compréhensible pour accéder à des données identiques, quel que soit le domaine problématique. Lorsque vous obtenez des données d'une base de données, votre programme a copie des données. Les mises à jour sont atomiques. Contrairement aux variables globales, où plusieurs threads ou méthodes peuvent fonctionner sur le même morceau de données sans atomicité, sauf si vous ajoutez la synchronisation vous-même. Les mises à jour des données sont imprévisibles et difficiles à retrouver. Les mises à jour peuvent être entrelacées, provoquant des exemples de manuels standards de corruption de données multithread (par exemple, des incréments entrelacés).

Les bases de données modélisent généralement des données différentes des variables globales pour commencer, mais en laissant cela de côté pendant un moment, les bases de données sont conçues dès le départ pour être un magasin de données conforme à ACID qui atténue bon nombre des problèmes liés aux variables globales.

75
user22815

Je voudrais faire quelques observations:

Oui, une base de données est à l'état global.

En fait, c'est un état super-mondial, comme vous l'avez souligné. C'est universel ! Sa portée implique n'importe quoi ou n'importe qui qui se connecte à la base de données. Et, je soupçonne que beaucoup de gens avec des années d'expérience peuvent vous raconter des histoires d'horreur sur la façon dont "des choses étranges" dans les données ont conduit à un "comportement inattendu" dans une ou plusieurs des applications pertinentes ...

L'une des conséquences potentielles de l'utilisation d'une variable globale est que deux "modules" distincts utiliseront cette variable à leurs propres fins distinctes. Et dans cette mesure, une table de base de données n'est pas différente. Il peut être victime du même problème.

Hmm ... Voici le truc:

Si un module ne fonctionne pas d'une manière extrinsèque, il ne fait rien.

Un module utile peut être donné données ou il peut trouver il. Et, il peut retourner données ou il peut modifier état. Mais, s'il n'interagit pas avec le monde extérieur d'une manière ou d'une autre, il peut tout aussi bien ne rien faire.

Maintenant, notre préférence est de recevoir données et retourner données. La plupart des modules sont tout simplement plus faciles à écrire s’ils peuvent être écrits sans tenir compte de ce que fait le monde extérieur. Mais finalement, quelque chose doit trouver les données et modifier cet état global externe.

De plus, dans les applications du monde réel, les données existent pour pouvoir être lues et mises à jour par des opérations divers. Certains problèmes sont évités par les verrous et les transactions. Mais, pour éviter que ces opérations n'entrent en conflit les unes avec les autres en principe, à la fin de la journée, implique simplement une réflexion approfondie. (Et faire des erreurs ... )

Mais aussi, nous ne travaillons généralement pas directement avec l'état global.

À moins que l'application ne réside dans la couche de données (en SQL ou autre), les objets avec lesquels nos modules travaillent sont en fait un copies de l'état global partagé. Nous pouvons faire tout ce que nous voulons sans impact sur l'état réel, partagé.

Et, dans les cas où nous devons muter cet état global, en supposant que les données qui nous ont été données n'ont pas changé, nous pouvons généralement effectuer le même type de verrouillage que nous le ferions sur nos globaux locaux.

Et enfin, nous faisons généralement des choses différentes avec les bases de données que nous pourrait avec des méchants globaux.

Un monde méchant et brisé ressemble à ceci:

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

Nous n'utilisons tout simplement pas de bases de données pour des trucs en cours/opérationnels comme ça. Et cela pourrait être la nature lente de la base de données et la commodité relative d'une simple variable qui nous dissuade: Notre interaction lente et maladroite avec les bases de données en fait simplement de mauvais candidats pour bon nombre des erreurs que nous ' ve historiquement fait avec variables.

45
svidgen

Je ne suis pas d'accord avec l'affirmation fondamentale selon laquelle:

Lorsque votre programme travaille avec des données à partir d'une base de données, vous ne vous souciez pas si un autre code de votre système le change, ou même si un programme entièrement différent le change, d'ailleurs.

Ma pensée initiale était "Wow. Just Wow". Tant de temps et d'efforts sont consacrés à éviter exactement cela - et à déterminer quels compromis et compromis fonctionnent pour chaque application. L'ignorer est une recette de catastrophe.

Mais je diasgree aussi au niveau architectural. Une variable globale n'est pas seulement un état global. C'est un état global qui est accessible de n'importe où de manière transparente. En revanche, pour utiliser une base de données, vous devez avoir une poignée - (sauf si vous stockez que gérer dans une variable globale ....)

Par exemple, l'utilisation d'une variable globale pourrait ressembler à ceci

int looks_ok_but_isnt() {
  return global_int++;
}

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

Mais faire la même chose avec une base de données devrait être plus explicite sur ce qu'elle fait

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

La base de données est évidemment en train de déblayer une base de données. Si vous ne souhaitez pas utiliser une base de données, vous pouvez utiliser un état explicite et il ressemble presque au cas de la base de données.

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

Je dirais donc que l'utilisation d'une base de données ressemble beaucoup plus à l'utilisation d'un état explicite qu'à l'utilisation de variables globales.

21
Michael Anderson

Le fait que la seule raison pour laquelle les variables globales ne peuvent pas être fiables car l'état peut être changé ailleurs n'est pas en soi une raison suffisante pour ne pas les utiliser, d'accord (c'est une très bonne raison cependant!). Il est probable que la réponse décrivait principalement l'utilisation où restreindre l'accès d'une variable aux seules zones de code qui la concernaient aurait plus de sens.

Cependant, les bases de données sont différentes, car elles sont conçues pour être accessibles "globalement" pour ainsi dire.

Par exemple:

  • Les bases de données ont généralement une validation de type et de structure intégrée qui va plus loin que la langue qui y accède
  • Les bases de données sont mises à jour presque à l'unanimité en fonction des transactions, ce qui empêche les états incohérents, où il n'y a aucune garantie à quoi ressemblera l'état final dans un objet global (sauf s'il est caché derrière un singleton)
  • La structure de la base de données est au moins implicitement documentée sur la base de la structure de table ou d'objet, plus que l'application qui l'utilise

Mais surtout, les bases de données ont un objectif différent de celui d'une variable globale. Les bases de données sont destinées au stockage et à la recherche de grandes quantités de données organisées, où les variables globales servent des niches spécifiques (lorsque cela est justifiable).

18
Jeffrey Sweeney

Mais quand je regarde cela, je ne peux pas m'empêcher de penser que c'est une explication vraiment faible, car en quoi est-ce différent de travailler avec des données stockées dans une base de données?

Ou tout autre que de travailler avec un appareil interactif, avec un fichier, avec de la mémoire partagée, etc. Un programme qui fait exactement la même chose à chaque exécution est un programme très ennuyeux et plutôt inutile. Alors oui, c'est un argument faible.

Pour moi, la différence qui fait la différence en ce qui concerne les variables globales est qu'elles forment des lignes de communication cachées et non protégées. La lecture à partir d'un clavier est très évidente et protégée. Je dois effectuer un certain appel de fonction et je ne peux pas accéder au pilote de clavier. Il en va de même pour l'accès aux fichiers, la mémoire partagée et votre exemple, les bases de données. Il est évident pour le lecteur du code que cette fonction lit à partir du clavier, cette fonction accède à un fichier, une autre fonction accède à la mémoire partagée (et il vaut mieux qu'il y ait des protections autour de cela), et pourtant une autre fonction accède à une base de données.

Avec les variables globales, en revanche, ce n'est pas évident du tout. L'API dit d'appeler foo(this_argument, that_argument). Il n'y a rien dans la séquence d'appel qui dit que la variable globale g_DangerWillRobinson Doit être définie sur une certaine valeur mais avant d'appeler foo (ou examinée après avoir appelé foo).


Google a interdit l'utilisation d'arguments de référence non const en C++ principalement parce qu'il n'est pas évident pour le lecteur du code que foo(x) va changer x parce que foo prend un référence non constante comme argument. (Comparez avec C #, qui dicte que la définition de la fonction et le site d'appel doivent tous deux qualifier un paramètre de référence avec le mot clé ref.) Bien que je ne sois pas d'accord avec la norme Google à ce sujet, je comprends leur point.

Le code est écrit une fois et modifié plusieurs fois, mais s'il est bon, il est lu plusieurs fois. Les lignes de communication cachées sont un très mauvais karma. La référence non const de C++ représente une ligne de communication cachée mineure. Une bonne API ou une bonne IDE me montrera que "Oh! C'est un appel par référence." Les variables globales sont une énorme ligne de communication cachée.

10
David Hammen

Je pense que l'explication citée simplifie à l'excès la question au point que le raisonnement devient ridicule. Bien sûr, l'état d'une base de données externe contribue à l'état global. La question importante est comment votre programme dépend de l'état global (modifiable). Si une fonction de bibliothèque pour diviser des chaînes sur un espace blanc dépendait des résultats intermédiaires stockés dans une base de données, je m'opposerais à cette conception au moins autant que je m'opposerais à un tableau de caractères global utilisé dans le même but. D'un autre côté, si vous décidez que votre application n'a pas besoin d'un SGBD complet pour stocker les données commerciales à ce stade et qu'une structure de valeur-clé en mémoire globale suffira, ce n'est pas nécessairement un signe de mauvaise conception. Ce qui est important, c'est que - quelle que soit la solution que vous choisissez pour stocker vos données - ce choix est isolé sur une très petite partie du système afin que la plupart des composants puissent être agnostiques à la solution choisie pour le déploiement et testés en unité de manière isolée et déployée la solution peut être modifiée ultérieurement sans effort.

8
5gon12eder

En tant qu'ingénieur logiciel travaillant principalement avec des microprogrammes intégrés, j'utilise presque toujours des variables globales pour tout ce qui se passe entre les modules. En fait, c'est la meilleure pratique pour l'embarqué. Ils sont assignés statiquement, donc il n'y a aucun risque de faire sauter le tas/la pile et il n'y a pas de temps supplémentaire pour l'allocation/le nettoyage de la pile à l'entrée/la sortie de la fonction.

L'inconvénient est que nous devons considérer comment ces variables sont utilisées, et cela revient en grande partie au même genre de pensée qui va dans la dispute de base de données. Toute lecture/écriture asynchrone de variables DOIT être atomique. Si plus d'un endroit peut écrire une variable, il faut penser à toujours écrire des données valides, afin que l'écriture précédente ne soit pas remplacée arbitrairement (ou que le remplacement arbitraire soit une chose sûre à faire). Si la même variable est lue plus d'une fois, il faut réfléchir à ce qui se passe si la variable change de valeur entre les lectures, ou si une copie de la variable doit être prise au début pour que le traitement se fasse à l'aide d'une valeur cohérente, même si cette valeur devient périmée pendant le traitement.

(Pour cette dernière, lors de mon tout premier jour de contrat de travail sur un système de contre-mesures pour avions, si hautement lié à la sécurité, l'équipe du logiciel examinait un rapport de bug qu'elle essayait de comprendre depuis une semaine environ. J'avais eu juste assez de temps pour télécharger les outils de développement et une copie du code. J'ai demandé "cette variable ne pouvait-elle pas être mise à jour entre les lectures et la provoquer?", Mais je n'ai pas vraiment obtenu de réponse. Hé, qu'est-ce que le nouveau mec savez, après tout? Alors alors qu'ils en discutaient encore, j'ai ajouté un code de protection pour lire la variable atomiquement, j'ai fait une construction locale, et j'ai dit en gros "hé les gars, essayez ceci". . :)

Les variables globales ne sont donc pas une mauvaise chose sans équivoque, mais elles vous laissent ouvert à un large éventail de problèmes si vous n'y réfléchissez pas attentivement.

8
Graham

Selon l'aspect que vous jugez, les variables globales et l'accès à la base de données peuvent être différents, mais tant que nous les jugeons comme des dépendances, ce sont les mêmes.

Considérons la définition par la programmation fonctionnelle d'une fonction pure qui doit dépendre uniquement des paramètres qu'elle prend en entrée, produisant une sortie déterministe. Autrement dit, étant donné le même ensemble d'arguments deux fois, il doit produire le même résultat.

Lorsqu'une fonction dépend d'une variable globale, elle ne peut plus être considérée comme pure, car, pour le même ensemble ou les mêmes arguments, elle peut produire des sorties différentes car la valeur de la variable globale peut avoir changé entre les appels.

Cependant, la fonction peut toujours être considérée comme déterministe si nous considérons la variable globale autant comme faisant partie de l'interface de la fonction que ses autres arguments, donc ce n'est pas le problème. Le problème est seulement que cela est caché jusqu'au moment où nous sommes surpris par un comportement inattendu de fonctions apparemment évidentes, puis allez lire leurs implémentations pour découvrir les dépendances cachées .

Cette partie, le moment où une variable globale devient une dépendance cachée est ce qui est considéré comme mauvais par nous, programmeurs. Cela rend le code plus difficile à raisonner, difficile à prévoir comment il se comportera, difficile à réutiliser, difficile à tester et surtout, il augmente le débogage et le temps de correction en cas de problème.

La même chose se produit lorsque nous masquons la dépendance à la base de données. Nous pouvons avoir des fonctions ou des objets faisant des appels directs aux requêtes et commandes de base de données, cachant ces dépendances et nous causant exactement le même problème que les variables globales causent; ou nous pouvons les rendre explicites, ce qui, en fin de compte, est considéré comme une meilleure pratique qui porte de nombreux noms, comme le modèle de référentiel, le magasin de données, la passerelle, etc.

P.S .: Il y a d'autres aspects qui sont importants pour cette comparaison, comme si la concurrence est impliquée, mais ce point est couvert par d'autres réponses ici.

7
MichelHenrich

D'accord, commençons par le point historique.

Nous sommes dans une ancienne application, écrite dans votre mélange typique de Assembly et C. Il n'y a pas de fonctions, juste procédures. Lorsque vous souhaitez passer un argument ou renvoyer une valeur à partir d'une procédure, vous utilisez une variable globale. Inutile de dire que cela est assez difficile à suivre et, en général, chaque procédure peut faire ce qu'elle veut avec chaque variable globale. Sans surprise, les gens se sont tournés vers la transmission d'arguments et retournent des valeurs d'une manière différente dès que cela était possible (sauf s'il était essentiel de ne pas le faire - par exemple, regardez le code source de Build Engine (Duke 3D)). La haine des variables globales est née ici - vous aviez très peu d'idée de quel état global chaque procédure lirait et changerait, et vous ne pouviez pas vraiment imbriquer les appels de procédure en toute sécurité.

Est-ce à dire que la haine des variables globales appartient au passé? Pas assez.

Tout d'abord, je dois mentionner que j'ai vu le exactement la même approche pour passer des arguments dans le projet sur lequel je travaille en ce moment. Pour passer deux instances de type référence en C #, dans un projet qui a environ 10 ans. Il n'y a littéralement aucune bonne raison de le faire comme ça, et est probablement né de la culture du fret ou d'une incompréhension complète du fonctionnement de C #.

Le plus gros point est qu'en ajoutant des variables globales, vous étendez la portée de chaque morceau de code qui a accès à cette variable globale. Vous vous souvenez de toutes ces recommandations comme "gardez vos méthodes courtes"? Si vous avez 600 variables globales (encore une fois, exemple réel: /), toutes vos étendues de méthode sont implicitement étendues par ces 600 variables globales, et il n'y a pas de moyen simple de savoir qui a accès à quoi.

Si mal fait (de la manière habituelle :)), les variables globales peuvent avoir un couplage entre elles. Mais vous ne savez pas comment ils sont couplés, et il n'y a aucun mécanisme pour garantir que l'état global est toujours cohérent. Même si vous introduisez des sections critiques pour essayer de garder les choses cohérentes, vous constaterez qu'elle se compare mal à une base de données ACID appropriée:

  • Il n'y a aucun moyen d'annuler une mise à jour partielle, sauf si vous conservez les anciennes valeurs avant la "transaction". Inutile de dire qu'à ce stade, passer une valeur en argument est déjà une victoire :)
  • Tout le monde accédant au même état doit adhérer au même processus de synchronisation. Mais il n'y a aucun moyen de faire respecter cela - si vous oubliez de configurer la section critique, vous êtes foutu.
  • Même si vous synchronisez correctement tous les accès, il peut y avoir des appels imbriqués qui accèdent à l'état partiellement modifié. Cela signifie que vous pouvez soit bloquer (si vos sections critiques ne sont pas réactivées), soit traiter des données incohérentes (si elles sont réactivées).

Est-il possible de résoudre ces problèmes? Pas vraiment. Vous avez besoin d'encapsulation pour gérer cela, ou d'une discipline vraiment stricte. Il est difficile de bien faire les choses, et ce n'est généralement pas une très bonne recette pour réussir dans le développement de logiciels :)

Une portée plus petite a tendance à faciliter le raisonnement du code. Les variables globales font que même les morceaux de code les plus simples incluent de vastes étendues de portée.

Bien sûr, cela ne signifie pas que la portée mondiale est mauvaise. Ce ne devrait pas être la première solution que vous recherchez - c'est un exemple typique de "simple à mettre en œuvre, difficile à maintenir".

6
Luaan

Une variable globale est un outil, elle peut être utilisée pour le bien et pour le mal.

Une base de données est un outil, elle peut être utilisée pour le bien et pour le mal.

Comme le note l'affiche originale, la différence n'est pas si grande.

Les étudiants inexpérimentés pensent souvent que les bogues sont quelque chose qui arrive à d'autres personnes. Les enseignants utilisent "les variables globales sont mauvaises" comme raison simplifiée pour pénaliser une mauvaise conception. Les étudiants ne comprennent généralement pas que le fait que leur programme de 100 lignes soit exempt de bogues ne signifie pas que les mêmes méthodes peuvent être utilisées pour les programmes de 10000 lignes.

Lorsque vous travaillez avec des bases de données, vous ne pouvez pas simplement interdire l'état global car c'est de cela qu'il s'agit. Au lieu de cela, vous obtenez des directives plus détaillées comme ACID et les formulaires normaux, etc.

Si les gens utilisaient l'approche ACID pour les variables globales, ils ne seraient pas si mauvais.

En revanche, si vous concevez mal les bases de données, elles peuvent être des cauchemars.

6
Stig Hemmer

Certaines des autres réponses tentent d'expliquer pourquoi l'utilisation d'une base de données est bonne. Ils ont tort! Une base de données est un état global et en tant que tel est tout aussi mauvais qu'un singleton ou une variable globale. Il est tout à fait erroné d'utiliser une base de données alors que vous pouvez facilement utiliser une carte locale ou un tableau à la place!

Les variables globales permettent un accès global, qui comporte un risque d'abus. Les variables globales ont également des avantages. Les variables globales sont généralement considérées comme quelque chose que vous devriez éviter, pas quelque chose que vous ne devriez jamais utiliser. Si vous pouvez facilement les éviter, vous devez les éviter. Mais si les avantages l'emportent sur les inconvénients, vous devez bien sûr les utiliser! *

La même chose ** s'applique aux bases de données, qui sont un état global - tout comme les variables globales. Si vous pouvez vous débrouiller sans accéder à une base de données et que la logique résultante fait tout ce dont vous avez besoin et est tout aussi complexe, l'utilisation d'une base de données augmente le risque pour votre projet, sans aucun avantage correspondant.

Dans la vie réelle, de nombreuses applications nécessitent un état global par conception, parfois même un état global persistant - c'est pourquoi nous avons des fichiers, des bases de données, etc.


* L'exception ici concerne les étudiants. Il est logique d'interdire aux élèves d'utiliser des variables globales pour qu'ils apprennent quelles sont les alternatives.

** Certaines réponses affirment à tort que les bases de données sont en quelque sorte mieux protégées que les autres formes d'état global (la question concerne explicitement état global, pas seulement les variables globales). Ce sont des conneries. La protection principale offerte dans le scénario de base de données est par convention, ce qui est exactement le même pour tout autre état global. La plupart des langages permettent également une grande protection supplémentaire pour l'état global, sous la forme de const, des classes qui ne permettent tout simplement pas de changer leur état après qu'il a été défini dans le constructeur, ou des getters et setters qui peuvent prendre des informations sur les threads ou l'état du programme.

5
Peter

Pour moi, le principal mal est que les globaux n'ont aucune protection contre les problèmes de concurrence. Vous pouvez ajouter des mécanismes pour gérer ces problèmes avec Globals, mais vous constaterez que plus vous résolvez de problèmes de concurrence, plus vos Globals commencent à imiter une base de données. Le mal secondaire n'est pas un contrat d'utilisation.

5
G DeMasters

Dans un sens, la distinction entre les variables globales et une base de données est similaire à la distinction entre les membres privés et publics d'un objet (en supposant que quiconque utilise encore des champs publics). Si vous considérez l'ensemble du programme comme un objet, les globaux sont les variables privées et la base de données est les champs publics.

Leur distinction clé ici est celle de la responsabilité assumée.

Lorsque vous écrivez un objet, il est supposé que toute personne qui gère les méthodes membres veillera à ce que les champs privés se comportent correctement. Mais vous renoncez déjà à toute hypothèse sur l'état des domaines publics et les traitez avec plus de soin.

La même hypothèse s'applique à un niveau plus large à la base de données v/s globale. De plus, le langage de programmation/l'écosystème garantit les restrictions d'accès sur le public privé v/s de la même manière qu'il les applique sur la base de données v/s globales (mémoire non partagée).

Lorsque le multithreading entre en jeu, le concept de base de données privée v/s publique v/s globale v/s n'est que des distinctions le long d'un spectre.

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
        }
    }
}
2
Benito Ciaro

Une base de données peut être un état global, mais cela ne doit pas être tout le temps. Je ne suis pas d'accord avec l'hypothèse que vous n'avez pas le contrôle. Une façon de gérer cela est le verrouillage et la sécurité. Cela peut être fait sur l'enregistrement, la table ou la base de données entière. Une autre approche consiste à avoir une sorte de champ de version qui empêcherait la modification d'un enregistrement si les données sont périmées.

Comme une variable globale, la ou les valeurs d'une base de données peuvent être modifiées une fois qu'elles sont déverrouillées, mais il existe de nombreuses façons de contrôler l'accès (ne donnez pas à tous les développeurs le mot de passe du compte autorisé à modifier les données.). Si vous avez une variable dont l'accès est limité, ce n'est pas très global.

1
JeffO

Bien sûr, les globaux ne sont pas toujours inappropriés. Ils existent parce qu'ils ont une utilisation légitime. Le principal problème avec les globaux, et la principale source de l'avertissement pour les éviter, est que le code qui utilise un global est attaché à celui-ci et à un seul global.

Par exemple, considérons un serveur HTTP stockant le nom du serveur.

Si vous stockez le nom du serveur dans un global, le processus ne peut pas exécuter simultanément la logique pour deux noms de serveur différents. Peut-être que la conception d'origine n'a jamais envisagé d'exécuter plus d'une instance de serveur à la fois, mais si vous décidez plus tard de le faire, vous ne pouvez tout simplement pas si le nom du serveur est dans un global.

En revanche, si le nom du serveur est dans une base de données, il n'y a pas de problème. Vous pouvez simplement créer une instance de cette base de données pour chaque instance du serveur HTTP. Étant donné que chaque instance du serveur a sa propre instance de la base de données, elle peut avoir son propre nom de serveur.

Ainsi, l'objection principale aux globaux, il ne peut y avoir qu'une seule valeur pour tout le code qui accède à ce global, ne s'applique pas aux entrées de la base de données. Le même code peut facilement accéder à des instances de base de données distinctes qui ont des valeurs différentes pour une entrée particulière.

0
David Schwartz

Je pense que la prémisse est fausse. Il n'y a aucune raison qu'une base de données doive être un "état global" plutôt qu'un (très grand) objet de contexte. Si vous vous liez à la base de données particulière que votre code utilise via des variables globales ou des paramètres de connexion de base de données globaux fixes, ce n'est pas différent, et pas moins maléfique, que tout autre état global. D'un autre côté, si vous passez correctement un objet contextuel pour la connexion à la base de données, c'est juste un état contextuel grand (et largement utilisé), pas un état global.

Mesurer la différence est facile: pourriez-vous exécuter deux instances de la logique de votre programme, chacune utilisant sa propre base de données, dans un seul programme/processus sans apporter de modifications invasives au code? Si c'est le cas, votre base de données n'est pas vraiment un "état global".

Je pense que c'est une question intéressante, mais il est un peu difficile de répondre, car il y a deux problèmes principaux qui sont confondus sous le terme "État mondial". Le premier est le concept de "couplage global". La preuve en est que l'alternative donnée à l'état global est l'injection de dépendances. Le fait est que DI n'élimine pas nécessairement l'état global. Autrement dit, il est absolument possible et courant d'injecter des dépendances sur l'état global. Ce que DI fait est de supprimer le couplage fourni avec les variables globales et le modèle Singleton couramment utilisé. Mis à part une conception un peu moins évidente, il y a très peu d'inconvénients à éliminer ce type de couplage et les avantages de l'élimination du couplage augmentent de façon exponentielle avec le nombre de dépendances de ces globaux.

L'autre aspect de cela est l'état partagé. Je ne sais pas s'il y a une distinction vraiment claire entre un État partagé à l'échelle mondiale et un État partagé en général, mais les coûts et avantages sont beaucoup plus nuancés. Autrement dit, il existe d'innombrables systèmes logiciels qui nécessitent un état partagé pour être utiles. Le Bitcoin, par exemple, est un moyen très intelligent de partager l'état global (littéralement) de manière décentralisée. Partager correctement un état mutable sans créer d'énormes goulots d'étranglement est difficile mais utile. Donc, si vous n'avez pas vraiment besoin de le faire, vous pouvez simplifier votre application en minimisant l'état mutable partagé.

Ainsi, la question de savoir comment les bases de données diffèrent des globales est également bifurquée entre ces deux aspects. Introduisent-ils le couplage? Oui, ils le peuvent, mais cela dépend beaucoup de la façon dont l'application est conçue et de la conception de la base de données. Il y a trop de facteurs pour avoir une réponse unique à savoir si les bases de données introduisent un couplage global sans détails sur la conception. Quant à savoir s'ils introduisent le partage de l'État, eh bien, c'est en quelque sorte le point principal d'une base de données. La question est de savoir s'ils le font bien. Encore une fois, je pense que c'est trop compliqué pour répondre sans beaucoup d'autres éléments d'information tels que les alternatives et de nombreux autres compromis.

0
JimmyJames

J'y penserais un peu différemment: le comportement de "variable globale" est un prix payé par les administrateurs de base de données (DBA) parce que c'est un mal nécessaire pour faire leur travail.

Le problème des variables globales, comme plusieurs autres l'ont souligné, n'est pas arbitraire. Le problème est que leur utilisation rend le comportement de votre programme de moins en moins prévisible car il devient plus difficile de déterminer qui utilise la variable et de quelle manière. C'est un gros problème pour les logiciels modernes, car il est généralement demandé aux logiciels modernes de faire beaucoup de choses flexibles. Il peut effectuer des milliards voire des milliers de milliards de manipulations d'état complexes au cours d'une analyse. La capacité de prouver de véritables déclarations sur ce que ce logiciel fera dans ces milliards ou billions d'opérations est extrêmement précieuse.

Dans le cas des logiciels modernes, toutes nos langues fournissent des outils pour aider à cela, comme l'encapsulation. Le choix de ne pas l'utiliser est inutile, ce qui conduit à la mentalité "les globaux sont mauvais". Dans de nombreuses régions du développement de logiciels, les seules personnes qui les utilisent sont des personnes qui ne savent pas mieux coder. Cela signifie non seulement qu'ils posent directement des problèmes, mais ils suggèrent indirectement que le développeur ne savait pas ce qu'ils faisaient. Dans d'autres régions, vous constaterez que les globaux sont totalement normaux (les logiciels embarqués, en particulier, adorent les globaux, en partie parce qu'ils fonctionnent bien avec les ISR). Cependant, parmi les nombreux développeurs de logiciels là-bas, ils sont la voix minoritaire, donc la seule voix que vous entendez est "les globaux sont mauvais".

Le développement de bases de données est l'une de ces situations de voix minoritaires. Les outils nécessaires pour effectuer le travail DBA sont très puissants, et leur théorie est pas enracinée dans l'encapsulation. Pour tirer le meilleur de chaque performance Jiffy de leurs bases de données, ils ont besoin d'un accès complet et sans restriction à tout, comme dans le monde. Manipulez l'une de leurs gigantesques bases de données de 100 millions de lignes (ou plus!), Et vous comprendrez pourquoi ils ne laissent pas leur moteur DB tenir le coup.

Ils paient un prix pour cela, un prix cher. Les DBA sont forcés d'être presque pathologiques avec leur souci du détail, car leurs outils ne les protègent pas. Le meilleur qu'ils ont en termes de protection est ACID ou peut-être des clés étrangères. Ceux qui ne sont pas pathologiques se retrouvent avec un mess de tables complètement inutilisable, voire corrompu.

Il n'est pas rare d'avoir des progiciels de ligne 100k. En théorie, n'importe quelle ligne du logiciel peut affecter n'importe quel global à tout moment. Dans les administrateurs de base de données, vous ne trouvez jamais 100 000 requêtes différentes qui peuvent modifier la base de données. Ce serait déraisonnable à maintenir avec l'attention aux détails nécessaires pour vous protéger de vous-même. Si un administrateur de base de données a quelque chose de grand comme ça, il encapsulera intentionnellement sa base de données à l'aide d'accesseurs, en évitant les problèmes "globaux", puis fera autant de travail que possible grâce à ce mécanisme "plus sûr". Ainsi, lorsque Push arrive à pousser, même les gens de la base de données évitent les globaux. Ils viennent tout simplement avec beaucoup de danger, et il existe des alternatives qui sont juste aussi fortes, mais pas aussi dangereuses.

Préférez-vous vous promener sur du verre brisé ou sur des trottoirs bien balayés, si toutes les autres choses sont égales? Oui, vous pouvez marcher sur du verre brisé. Oui, certaines personnes gagnent même leur vie en le faisant. Mais encore, laissez-les simplement balayer le trottoir et continuer!

0
Cort Ammon

Il existe plusieurs différences:

  • Une valeur de base de données peut être modifiée à la volée. La valeur d'un global qui est définie dans le code, d'autre part, ne peut pas être modifiée sauf si vous redéployez votre application et modifiez votre code. En fait, c'est intentionnel. Une base de données est pour les valeurs qui pourraient changer avec le temps, mais les variables globales devraient seulement être pour des choses qui ne changeront jamais et quand ils ne contiennent pas de données réelles.

  • Une valeur de base de données (ligne, colonne) a un contexte et un mappage relationnel dans la base de données. Cette relation peut être facilement extraite et analysée à l'aide d'outils comme Jailer (par exemple). En revanche, une variable globale est légèrement différente. Vous pouvez trouver tous les usages, mais il vous serait impossible de me dire tous les façons dont la variable interagit avec le reste de votre monde.

  • Les variables globales sont plus rapide. Pour obtenir quelque chose d'une base de données, une connexion à la base de données doit être établie, une sélection doit être exécutée, puis la connexion à la base de données doit être fermée. Toutes les conversions de types dont vous pourriez avoir besoin s'ajoutent à cela. Comparez cela à un accès global dans votre code.

Ce sont les seules auxquelles je peux penser en ce moment, mais je suis sûr qu'il y en a plus. Autrement dit, ils sont deux choses différentes et doivent être utilisées pour des objectifs différents.

0
Arnab Datta