In che modo i globali sono diversi da un database?

247

Ho appena trovato questa vecchia domanda chiedendo cosa c'è di così male sullo stato globale, e la risposta accettata dalla parte più votata afferma che non puoi fidarti di alcun codice che funzioni con variabili globali, perché qualche altro codice da qualche altra parte potrebbe arrivare e modificarne il valore e quindi che non conosci quale sarà il comportamento del tuo codice perché i dati sono diversi! Ma quando lo guardo, non posso fare a meno di pensare che questa è una spiegazione davvero debole, perché in che modo è diverso dal lavorare con i dati memorizzati in un database?

Quando il tuo programma sta lavorando con i dati di un database, non ti interessa se un altro codice nel tuo sistema lo sta cambiando, o anche se un programma completamente diverso lo sta cambiando, del resto. Non ti interessa quali siano i dati; questo è l'intero punto. Tutto ciò che conta è che il tuo codice tratti correttamente con i dati che incontra. (Ovviamente sto sorvogliando il problema spesso spinoso del caching qui, ma ignoriamolo per il momento.)

Ma se i dati con cui stai lavorando provengono da una fonte esterna di cui il tuo codice non ha alcun controllo, come un database (o un input dell'utente, un socket di rete, un file, ecc ...) e non c'è niente di sbagliato in questo, allora come sono i dati globali all'interno del codice stesso - su cui il tuo programma ha un grado di controllo molto maggiore - in qualche modo una cosa cattiva quando è ovviamente molto meno male di cose perfettamente normali che nessuno vede come problema?

    
posta Mason Wheeler 24.05.2016 - 21:42
fonte

22 risposte

117

In primo luogo, direi che la risposta che colleghi per sopravvalutare quel particolare problema e che il male primario dello stato globale è che introduce l'accoppiamento in modi imprevedibili che possono rendere difficile cambiare il comportamento del tuo sistema in futuro.

Ma approfondendo ulteriormente questo problema, ci sono differenze tra lo stato globale in una tipica applicazione orientata agli oggetti e lo stato che è contenuto in un database. In breve, i più importanti di questi sono:

  • I sistemi orientati agli oggetti consentono di sostituire un oggetto con una classe di oggetti diversa, purché si tratti di un sottotipo del tipo originale. Ciò consente di modificare comportamento , non solo dati .

  • Lo stato globale in un'applicazione non fornisce in genere la consistenza strong garantita da un database: non ci sono transazioni durante le quali viene visualizzato uno stato coerente per esso, nessun aggiornamento atomico, ecc.

Inoltre, possiamo vedere lo stato del database come un male necessario; è impossibile eliminarlo dai nostri sistemi. Lo stato globale, tuttavia, non è necessario. Possiamo eliminarlo completamente. Quindi anche se i problemi con un database sono altrettanto brutti, possiamo ancora eliminare alcuni dei potenziali problemi e una soluzione parziale è meglio di nessuna soluzione.

    
risposta data 24.05.2016 - 22:05
fonte
75

Innanzitutto, quali sono i problemi con le variabili globali, in base alla risposta accettata alla domanda che hai collegato?

Very briefly, it makes program state unpredictable.

I database sono, per la maggior parte del tempo, compatibili con ACID. ACID risolve in modo specifico i problemi sottostanti che renderebbero imprevedibile o inaffidabile un archivio dati.

Further, global state hurts the readability of your code.

Questo perché le variabili globali esistono in un ambito molto lontano dal loro utilizzo, forse anche in un file diverso. Quando si utilizza un database, si utilizza un set di record o un oggetto ORM locale per il codice che si sta leggendo (o dovrebbe essere).

I driver di database in genere forniscono un'interfaccia coerente e comprensibile per accedere ai dati che sono gli stessi indipendentemente dal dominio problematico. Quando ottieni dati da un database, il tuo programma ha una copia dei dati. Gli aggiornamenti sono atomici. In contrasto con le variabili globali, in cui più thread o metodi possono operare sullo stesso pezzo di dati senza atomicità, a meno che non si aggiunga la sincronizzazione. Gli aggiornamenti dei dati sono imprevedibili e difficili da rintracciare. Gli aggiornamenti possono essere interlacciati, causando esempi di manuali di bog di corruzione multithread dei dati (ad esempio incrementi interlacciati).

I database di solito modellano dati diversi rispetto alle variabili globali per cominciare, ma lasciandolo da parte per un momento, i database sono progettati da zero per essere un data store compatibile con l'ACID che mitiga molte delle preoccupazioni con le variabili globali. / p>     

risposta data 24.05.2016 - 22:11
fonte
44

Vorrei offrire alcune osservazioni:

Sì, un database è stato globale.

In realtà, è uno stato super globale, come hai sottolineato. È universale! Il suo ambito di applicazione comporta qualsiasi cosa o chiunque che si connette al database. E, sospetto che molte persone con anni di esperienza possano raccontarti storie dell'orrore su come "cose strane" nei dati portino a "comportamenti inaspettati" in una o più delle applicazioni pertinenti ...

Una delle potenziali conseguenze dell'utilizzo di una variabile globale è che due "moduli" distinti utilizzeranno tale variabile per i propri scopi distinti. E in tal senso, una tabella di database non è diversa. Può essere vittima dello stesso problema.

Hmm ... Ecco la cosa:

Se un modulo non funziona in modo estrinseco in qualche modo, non fa nulla.

Un modulo utile può essere dato o può trovarlo . E, può restituire dati o può modificare stato. Ma se non interagisce con il mondo esterno in qualche modo, potrebbe anche non fare nulla.

Ora, la nostra preferenza è ricevere dati e restituire dati. Molti moduli sono semplicemente più facili da scrivere se possono essere scritti con totale disprezzo per ciò che il mondo esterno sta facendo. Ma alla fine, qualcosa deve trovare i dati e modificare quello stato globale esterno.

Inoltre, nelle applicazioni del mondo reale, i dati esistono in modo che possano essere letti e aggiornati da varie operazioni. Alcuni problemi sono impediti da serrature e transazioni. Ma, impedire che queste operazioni siano in conflitto tra di loro in linea di principio , alla fine della giornata, coinvolge semplicemente un attento pensiero. (E facendo errori ...)

Ma in generale non lavoriamo direttamente con lo stato globale.

A meno che l'applicazione risieda nel livello dati (in SQL o qualsiasi altra cosa), gli oggetti con i quali i nostri moduli funzionano sono in realtà copie dello stato globale condiviso. Possiamo fare tutto ciò che vogliamo senza alcun impatto sullo stato attuale e condiviso

E, nei casi in cui abbiamo bisogno di mutare quello stato globale, partendo dal presupposto che i dati che ci sono stati dati non sono cambiati, possiamo generalmente eseguire lo stesso tipo di blocco che faremmo sui nostri globali locali.

E, infine, facciamo di solito cose diverse con i database di quanto potremmo con globali maliziosi.

Un aspetto globale malevolo e interrotto:

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

Semplicemente non usiamo i database per cose in-process / operative come quelle. E potrebbe essere la lentezza del database e la relativa convenienza di una variabile semplice che ci dissuade: la nostra interazione lenta e scomoda con i database li rende semplicemente cattivi candidati per molti degli errori che abbiamo storicamente fatto con variabili

    
risposta data 25.05.2016 - 00:57
fonte
21

Non sono d'accordo con l'affermazione fondamentale che:

When your program is working with data from a database, you don't care if other code in your system is changing it, or even if an entirely different program is changing it, for that matter.

Il mio pensiero iniziale era "Wow, Just Wow". Trascorrere così tanto tempo e sforzi per cercare di evitare esattamente questo - e capire quali compromessi e compromessi funzionano per ciascuna applicazione. Ignorarlo è una ricetta per il disastro.

Ma ho anche diasgree a livello di architettura. Una variabile globale non è solo uno stato globale. È uno stato globale accessibile da qualsiasi luogo in modo trasparente. Al contrario di utilizzare un database, è necessario avere un handle per questo (a meno che non si memorizzi che gestire in una variabile globale ....)

Ad esempio, l'utilizzo di una variabile globale potrebbe essere simile a questo

int looks_ok_but_isnt() {
  return global_int++;
}

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

Ma fare la stessa cosa con un database dovrebbe essere più esplicito su ciò che sta facendo

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

Il database uno è ovviamente muck con un database. Se non si desidera utilizzare un database, è possibile utilizzare lo stato esplicito e sembra quasi lo stesso del caso del database.

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

Quindi direi che usare un database è molto più simile all'utilizzo dello stato esplicito, piuttosto che usare le variabili globali.

    
risposta data 25.05.2016 - 03:10
fonte
18

Il fatto che l'unica ragione per cui le variabili globali non possono essere attendibili poiché lo stato può essere cambiato da qualche altra parte non è, di per sé, una ragione sufficiente per non usarle, d'accordo (è comunque una buona ragione!). È probabile che la risposta stia descrivendo principalmente l'utilizzo in cui limitare l'accesso di una variabile alle sole aree di codice che avrebbe interessato avrebbe avuto più senso.

I database sono una questione diversa, tuttavia, perché sono progettati allo scopo di essere accessibili "globalmente" per così dire.

Ad esempio:

  • I database in genere hanno una convalida di tipo e struttura integrata che va oltre la lingua che li accede
  • Le basi di dati quasi all'unanimità si aggiornano in base alle transazioni, il che impedisce agli stati incoerenti, in cui non vi è alcuna garanzia di come sarà lo stato finale in un oggetto globale (a meno che non sia nascosto dietro un singleton)
  • La struttura del database è almeno implicitamente documentata in base alla tabella o alla struttura di un oggetto, molto più che l'applicazione che lo utilizza

Soprattutto però, i database hanno uno scopo diverso rispetto a una variabile globale. I database servono per archiviare e cercare grandi quantità di dati organizzati, in cui le variabili globali servono nicchie specifiche (quando giustificabili).

    
risposta data 24.05.2016 - 22:03
fonte
10

But when I look at that, I can't help but think that that's a really weak explanation, because how is that any different from working with data stored in a database?

O diverso da un lavoro con un dispositivo interattivo, con un file, con memoria condivisa, ecc. Un programma che fa esattamente la stessa cosa ogni volta che viene eseguito è un programma molto noioso e piuttosto inutile. Quindi sì, è un argomento debole.

Per me, la differenza che fa la differenza rispetto alle variabili globali è che formano linee di comunicazione nascoste e non protette. Leggere da una tastiera è molto ovvio e protetto. Devo effettuare una determinata chiamata di funzione e non riesco ad accedere al driver della tastiera. Lo stesso vale per l'accesso ai file, la memoria condivisa e il tuo esempio, i database. È ovvio per il lettore del codice che questa funzione viene letta dalla tastiera, che la funzione accede a un file, altre funzioni accedono alla memoria condivisa (e sarebbe meglio avere delle protezioni intorno a quella), e tuttavia qualche altra funzione accede a un database.

Con le variabili globali, d'altra parte, non è affatto ovvio. L'API dice di chiamare foo(this_argument, that_argument) . Non c'è nulla nella sequenza chiamante che dice che la variabile globale g_DangerWillRobinson deve essere impostata su un valore ma prima di chiamare foo (o esaminata dopo aver chiamato foo ).

Google ha vietato l'uso di argomenti di riferimento non-const in C ++ principalmente perché non è ovvio al lettore del codice che foo(x) cambierà x perché quel foo prende un riferimento non costante come argomento . (Confronta con C #, che stabilisce che sia la definizione della funzione che il sito di chiamata devono qualificare un parametro di riferimento con la parola chiave ref .) Anche se non sono d'accordo con lo standard di Google su questo, comprendo il loro punto.

Il codice viene scritto una volta e modificato alcune volte, ma se è del tutto buono, viene letto molte, molte volte. Le linee nascoste di comunicazione sono un karma molto cattivo. Il riferimento non const di C ++ rappresenta una piccola linea di comunicazione nascosta. Una buona API o un buon IDE mi mostreranno che "Oh! Questa è una chiamata per riferimento". Le variabili globali sono un'enorme linea di comunicazione nascosta.

    
risposta data 25.05.2016 - 01:24
fonte
8

Penso che la spiegazione citata semplifica eccessivamente la questione fino al punto in cui il ragionamento diventa ridicolo. Naturalmente, lo stato di un database esterno contribuisce allo stato globale. La domanda importante è in che modo il tuo programma dipende dallo stato globale (mutevole). Se una funzione di libreria per dividere stringhe su uno spazio bianco dipenderebbe da risultati intermedi archiviati in un database, farei obiezioni a questo progetto almeno tanto quanto farei a un array di caratteri globale utilizzato per lo stesso scopo. D'altro canto, se si decide che l'applicazione non ha bisogno di un DBMS completo per archiviare dati aziendali a questo punto e una struttura di valori-chiave globale in memoria lo farà, questo non è necessariamente un segno di progettazione scadente. Ciò che è importante è che, indipendentemente dalla soluzione scelta per archiviare i dati, questa scelta è isolata in una porzione molto piccola del sistema, quindi la maggior parte dei componenti può essere indipendente dalla soluzione scelta per la distribuzione e testata in isolamento e implementata la soluzione può essere cambiata in un secondo momento con poco sforzo.

    
risposta data 24.05.2016 - 22:19
fonte
8

Come programmatore di software che lavora prevalentemente con il firmware incorporato, utilizzo quasi sempre variabili globali per qualsiasi cosa passi tra i moduli. In realtà, è la migliore pratica per embedded. Sono assegnati staticamente, quindi non c'è il rischio di far saltare l'heap / stack e non c'è tempo extra per l'allocazione dello stack / ripulitura sull'entrata / uscita della funzione.

Lo svantaggio di questo è che noi do dobbiamo considerare come vengono usate queste variabili, e molte di queste cose si riducono allo stesso tipo di pensiero che va in conflitto con il database. Qualsiasi lettura / scrittura asincrona di variabili DEVE essere atomica. Se più di un posto può scrivere una variabile, è necessario riflettere sul fatto che scrivano sempre dati validi, quindi la scrittura precedente non viene sostituita arbitrariamente (o che la sostituzione arbitraria è una cosa sicura da fare). Se la stessa variabile viene letta più di una volta, qualche pensiero deve prendere in considerazione ciò che accade se la variabile cambia valore tra le letture, o una copia della variabile deve essere presa all'inizio in modo che l'elaborazione avvenga utilizzando un valore coerente, anche se quel valore diventa obsoleto durante l'elaborazione.

(Per l'ultimo, il mio primo giorno di un contratto che lavorava su un sistema di contromisure per velivoli, quindi altamente legato alla sicurezza, il team del software stava esaminando un bug che stavano cercando di capire per una settimana Ho avuto appena il tempo di scaricare gli strumenti di sviluppo e una copia del codice, ho chiesto "non è possibile aggiornare quella variabile tra le letture e provocarla?", ma non ha ottenuto una risposta. che cosa sa il nuovo ragazzo, dopotutto? Così mentre stavano ancora discutendo, ho aggiunto del codice di protezione per leggere la variabile atomicamente, ho fatto un build locale, e in pratica ho detto "hey ragazzi, provate questo". la mia tariffa contrattuale.:)

Quindi le variabili globali non sono una cosa inequivocabilmente negativa, ma ti lasciano aperta a una vasta gamma di problemi se non ci pensi attentamente.

    
risposta data 25.05.2016 - 16:39
fonte
7

A seconda dell'aspetto che stai giudicando, le variabili globali e l'accesso al database possono essere mondi a parte, ma finché li giudichiamo come dipendenze, sono uguali.

Consideriamo che la definizione della funzione di programmazione funzionale di una funzione pura afferma che deve dipendere esclusivamente dai parametri che assume come input, producendo un risultato deterministico. Cioè, dato lo stesso insieme di argomenti due volte, deve produrre lo stesso risultato.

Quando una funzione dipende da una variabile globale, non può più essere considerata pura, poiché, per lo stesso set o argomenti, può produrre output diversi perché il valore della variabile globale potrebbe essere cambiato tra le chiamate.

Tuttavia, la funzione può ancora essere vista come deterministica se consideriamo la variabile globale come una parte dell'interfaccia della funzione come i suoi altri argomenti, quindi non è il problema. Il problema è solo che questo è nascosto fino al momento in cui siamo sorpresi per comportamento inaspettato da funzioni apparentemente ovvie, quindi leggi le loro implementazioni per scoprire le dipendenze nascoste .

Questa parte, il momento in cui una variabile globale diventa una dipendenza nascosta è considerata da noi programmatori malvagia. Rende il codice più difficile da ragionare, difficile da prevedere come si comporterà, difficile da riutilizzare, difficile da testare e, soprattutto, aumenta il tempo di debug e fix quando si verifica un problema.

La stessa cosa accade quando nascondiamo la dipendenza dal database. Possiamo avere funzioni o oggetti che effettuano chiamate dirette a query e comandi di database, nascondendo queste dipendenze e causandoci lo stesso identico problema causato dalle variabili globali; oppure possiamo renderli espliciti, il che, a quanto risulta, è considerato una best practice che va sotto molti nomi, come pattern di repository, data-store, gateway, ecc.

P.S .: Ci sono altri aspetti che sono importanti per questo confronto, ad esempio se è coinvolta la concorrenza, ma quel punto è coperto da altre risposte qui.

    
risposta data 25.05.2016 - 04:20
fonte
6

Ok, iniziamo dal punto storico.

Siamo in una vecchia applicazione, scritta nel tipico mix di assembly e C. Non ci sono funzioni, solo procedure . Quando si desidera passare un argomento o restituire un valore da una procedura, si utilizza una variabile globale. Inutile dire che è abbastanza difficile tenerne traccia e, in generale, ogni procedura può fare tutto ciò che vuole con ogni variabile globale. Non sorprende che le persone si siano rivolte agli argomenti di passaggio e restituiscano i valori in un modo diverso non appena è stato possibile (a meno che non fosse fondamentale per le prestazioni non farlo), ad esempio il codice sorgente di Build Engine (Duke 3D). L'odio delle variabili globali è nato qui - non avevi idea di quale parte dello stato globale ogni procedura avrebbe letto e modificato e non potevi davvero nidificare in modo sicuro le chiamate alle procedure.

Questo significa che l'odio globale variabile è una cosa del passato? Non proprio.

Per prima cosa, devo menzionare che ho visto lo stesso approccio identico a passare argomenti nel progetto su cui sto lavorando in questo momento. Per il passaggio di due istanze di tipi di riferimento in C #, in un progetto che ha circa 10 anni. Non c'è letteralmente nessuna buona ragione per farlo in questo modo, e molto probabilmente è nato da un settaggio del carico o da un completo fraintendimento di come C # funziona.

Il punto più grande è che aggiungendo variabili globali, si sta espandendo l'ambito di ogni singolo pezzo di codice che ha accesso a quella variabile globale. Ricorda tutte quelle raccomandazioni come "mantieni i tuoi metodi brevi"? Se hai 600 variabili globali (di nuovo, esempio del mondo reale: /), tutti gli ambiti dei metodi sono espansi implicitamente da quelle 600 variabili globali e non esiste un modo semplice per tenere traccia di chi ha accesso a cosa.

Se fatto male (nel solito modo :)), le variabili globali possono avere un accoppiamento tra loro. Ma non hai idea di come siano accoppiati, e non c'è alcun meccanismo per garantire che lo stato globale sia sempre coerente. Anche se si introducono sezioni critiche per cercare di mantenere le cose coerenti, si scoprirà che si confronta male con un database ACID corretto:

  • Non è possibile eseguire il rollback di un aggiornamento parziale, a meno che non si conservino i vecchi valori prima della "transazione". Inutile dire che, a questo punto, passare un valore come argomento è già una vittoria:)
  • Tutti gli utenti che accedono allo stesso stato devono aderire allo stesso processo di sincronizzazione. Ma non c'è modo di far rispettare questo - se dimentichi di impostare la sezione critica, sei fregato.
  • Anche se sincronizzi correttamente tutti gli accessi, potrebbero esserci chiamate nidificate che accedono allo stato parzialmente modificato. Ciò significa che sei deadlock (se le tue sezioni critiche non sono reëntrant) o gestisci dati incoerenti (se sono reëntrant).

È possibile risolvere questi problemi? Non proprio. Hai bisogno di incapsulamento per gestire questo, o una disciplina molto severa. È difficile fare le cose per bene, e generalmente non è una buona ricetta per il successo nello sviluppo del software:)

Lo scopo più piccolo tende a rendere il codice più facile da ragionare. Le variabili globali fanno sì che anche i pezzi di codice più semplici includano ampie porzioni di ambito.

Ovviamente, questo non significa che lo scope globale sia malvagio. Non dovrebbe essere la prima soluzione per te - è un tipico esempio di "semplice da implementare, difficile da mantenere".

    
risposta data 25.05.2016 - 10:02
fonte
6

Una variabile globale è uno strumento, può essere utilizzata per il bene e il male.

Un database è uno strumento, può essere utilizzato per il bene e il male.

Come le note del poster originale, la differenza non è poi così grande.

Spesso gli studenti inesperti pensano che i bug siano qualcosa che accade ad altre persone. Gli insegnanti usano "Le variabili globali sono malvagie" come una ragione semplificata per penalizzare la cattiva progettazione. Gli studenti generalmente non capiscono che solo perché il loro programma a 100 righe è privo di bug non significa che gli stessi metodi possano essere usati per i programmi a 10000 linee.

Quando lavori con i database, non puoi semplicemente bannare lo stato globale poiché è di questo che si tratta il programma. Invece ottieni maggiori dettagli sulle linee guida come ACID e Normal Forms e così via.

Se le persone utilizzavano l'approccio ACID alle variabili globali, non sarebbero così male.

D'altra parte, se progetti male i database, possono essere incubi.

    
risposta data 25.05.2016 - 12:33
fonte
5

Per me, il male primario è che i Globali non hanno alcuna protezione contro i problemi di concorrenza. È possibile aggiungere meccanismi per gestire tali problemi con Globals, ma scoprirete che più problemi di concorrenza si risolvono, più i Globali iniziano a imitare un database. Il male secondario non ha contratto sull'uso.

    
risposta data 25.05.2016 - 03:28
fonte
5

Alcune delle altre risposte cercano di spiegare perché l'utilizzo di un database è buono. Si sbagliano! Un database è uno stato globale e in quanto tale è malvagio come un singleton o una variabile globale. È tutto sbagliato utilizzare un database quando puoi facilmente utilizzare semplicemente una mappa locale o una matrice!

Le variabili globali consentono l'accesso globale, che comporta il rischio di abuso. Le variabili globali hanno anche aspetti positivi. Le variabili globali sono generalmente considerate come qualcosa che dovresti evitare, non qualcosa che non dovresti mai usare. Se puoi facilmente evitarli dovresti evitarli. Ma se i benefici superano gli svantaggi, ovviamente dovresti usarli! *

La stessa identica cosa si applica ai database, che sono uno stato globale, proprio come le variabili globali. Se riesci a fare a meno di accedere a un database e la logica risultante fa tutto ciò di cui hai bisogno ed è altrettanto complessa, l'uso di un database aumenta il rischio per il tuo progetto, senza alcun beneficio corrispondente.

Nella vita reale, molte applicazioni richiedono uno stato globale di progettazione, a volte persino uno stato globale persistente: ecco perché abbiamo file, database, ecc.

* L'eccezione qui sono studenti. Ha senso proibire agli studenti di utilizzare variabili globali, quindi devono imparare quali sono le alternative.

** Alcune risposte affermano erroneamente che i database sono in qualche modo meglio protetti rispetto ad altre forme di stato globale (la domanda riguarda esplicitamente lo stato globale , non solo le variabili globali). Questo è bollock. La protezione primaria offerta nello scenario del database è per convenzione, che è esattamente la stessa per qualsiasi altro stato globale. La maggior parte dei linguaggi consente anche molta protezione aggiuntiva per lo stato globale, in forma di const , classi che semplicemente non consentono di cambiare il loro stato dopo che sono state impostate nel costruttore, o getter e setter che possono prendere informazioni sui thread o lo stato del programma in considerazione.

    
risposta data 26.05.2016 - 20:47
fonte
2

In un certo senso, la distinzione tra variabili globali e un database è simile alla distinzione tra membri pubblici e privati di un oggetto (supponendo che qualcuno usi ancora campi pubblici). Se si pensa all'intero programma come a un oggetto, le variabili globali sono le variabili private e il database è i campi pubblici.

La distinzione fondamentale qui è una delle responsabilità assunte.

Quando scrivi un oggetto, si presume che chiunque mantenga i metodi dei membri assicurerà che i campi privati rimangano ben educati. Ma già rinunci a qualsiasi ipotesi sullo stato dei campi pubblici e li tratti con estrema attenzione.

La stessa ipotesi si applica a un livello più ampio al database globale v / s. Inoltre, il linguaggio / ecosistema di programmazione garantisce le restrizioni di accesso sul pubblico v / s privato nello stesso modo in cui le impone sul database v / s globale (memoria non condivisa).

Quando il multithreading entra in gioco, il concetto di v / s database v / s pubblico v / s privato è semplicemente distinzioni lungo uno spettro.

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
        }
    }
}
    
risposta data 30.05.2016 - 02:04
fonte
1

Un database può essere uno stato globale, ma non deve essere tutto il tempo. Non sono d'accordo con l'ipotesi che tu non abbia il controllo. Un modo per gestirlo è il blocco e la sicurezza. Questo può essere fatto al record, alla tabella o all'intero database. Un altro approccio consiste nell'avere una sorta di campo versione che impedirebbe la modifica di un record se i dati sono obsoleti.

Come una variabile globale, i valori in un database possono essere modificati una volta sbloccati, ma ci sono molti modi per controllare l'accesso (Non dare a tutti gli sviluppatori la password per l'account autorizzato a cambiare i dati .). Se hai una variabile con accesso limitato, non è molto globale.

    
risposta data 25.05.2016 - 15:25
fonte
0

Ci sono molte differenze:

  • Un valore del database può essere modificato al volo. Il valore di un globale impostato nel codice, invece, non può essere modificato a meno che non si ridistribuisca l'applicazione e si modifichi il codice. In realtà, questo è intenzionale. Un database è per valori che potrebbero cambiare nel tempo, ma le variabili globali dovrebbero solo essere per cose che non cambieranno mai e quando non contengono dati effettivi.

  • Un valore del database (riga, colonna) ha un contesto e un mapping relazionale nel database. Questa relazione può essere facilmente estratta e analizzata utilizzando strumenti come Jailer (ad esempio). Una variabile globale d'altra parte, è leggermente diversa. Puoi trovare tutti gli usi, ma sarebbe impossibile per te dirmi tutti i modi in cui la variabile interagisce con il resto del tuo mondo.

  • Le variabili globali sono più veloci . Ottenere qualcosa da un database richiede la creazione di una connessione al database, una selezione da eseguire e quindi la connessione al database deve essere chiusa. Tutte le conversioni di tipo che potresti aver bisogno si aggiungono a questo. Confrontalo con un accesso globale nel tuo codice.

Questi sono gli unici a cui riesco a pensare in questo momento, ma sono sicuro che ce ne saranno altri. In poche parole, sono due cose diverse e dovrebbero essere utilizzate per obiettivi diversi .

    
risposta data 25.05.2016 - 14:35
fonte
0

Ovviamente i globali non sono sempre inappropriati. Esistono perché hanno un uso legittimo. Il problema principale con i globali e la fonte primaria dell'ammonizione per evitarli è che il codice che utilizza un globale è associato a quello e solo uno globale.

Ad esempio, considera un server HTTP che memorizza il nome del server.

Se si memorizza il nome del server in un globale, il processo non può eseguire contemporaneamente la logica per due diversi nomi di server. Forse la progettazione originale non prevedeva mai l'esecuzione di più di un'istanza del server alla volta, ma se in seguito decidi di farlo, non puoi farlo se il nome del server è globale.

Al contrario, se il nome del server si trova in un database, non ci sono problemi. È sufficiente creare un'istanza di quel database per ogni istanza del server HTTP. Poiché ogni istanza del server ha una propria istanza del database, può avere il proprio nome del server.

Quindi l'obiezione principale ai globals, ci può essere solo un valore per tutto il codice che accede a quello globale, non si applica alle voci del database. Lo stesso codice può facilmente accedere a istanze di database distinte che hanno valori diversi per una determinata voce.

    
risposta data 26.05.2016 - 12:20
fonte
0

Penso che questa sia una domanda interessante, ma è un po 'difficile rispondere perché ci sono due questioni principali che vengono confuse con il termine "stato globale". Il primo è il concetto di "accoppiamento globale". La prova di ciò è che l'alternativa data per lo stato globale è l'iniezione di dipendenza. Il fatto è che DI non elimina necessariamente lo stato globale. Cioè, è assolutamente possibile e comune iniettare dipendenze dallo stato globale. Ciò che fa DI è rimuovere l'accoppiamento che viene fornito con le variabili globali e il pattern Singleton comunemente usato. A parte un design leggermente meno ovvio, c'è un piccolo svantaggio nell'eliminare questo tipo di accoppiamento ei vantaggi dell'eliminazione dell'accoppiamento aumentano esponenzialmente con il numero di dipendenze su quelle globali.

L'altro aspetto di questo è lo stato condiviso. Non sono sicuro se esista una distinzione molto chiara tra lo stato condiviso globale e lo stato condiviso in generale, ma i costi e i benefici sono molto più sfumati. In poche parole ci sono innumerevoli sistemi software che richiedono uno stato condiviso per essere utili. Bitcoin, ad esempio, è un modo molto intelligente di condividere lo stato globalmente (letteralmente) in modo decentralizzato. Condividere lo stato mutevole correttamente senza creare enormi colli di bottiglia è difficile ma utile. Quindi, se non hai davvero bisogno di farlo, puoi semplificare la tua applicazione riducendo al minimo lo stato mutabile condiviso.

Quindi la domanda su come i database differiscono dai globals è anche biforcata tra questi due aspetti. Introducono l'accoppiamento? Sì, possono ma dipende molto da come è progettata l'applicazione e da come è progettato il database. Ci sono troppi fattori per avere un'unica risposta al fatto che i database introducano l'accoppiamento globale senza dettagli del progetto. Per quanto riguarda l'introduzione della condivisione dello stato, beh, è il punto principale di un database. La domanda è se lo fanno bene. Ancora una volta, penso che sia troppo complicato per rispondere senza molte altre informazioni come le alternative e molti altri compromessi.

    
risposta data 27.05.2016 - 19:24
fonte
0

Ci penserei in modo leggermente diverso: il comportamento di tipo "variabile globale" è un prezzo pagato dagli amministratori di database (DBA) perché è un male necessario fare il loro lavoro.

Il problema con le variabili globali, come molti altri hanno sottolineato, non è arbitrario. Il problema è che il loro uso rende il comportamento del tuo programma sempre meno prevedibile perché diventa più difficile determinare chi sta usando la variabile e in che modo. Questo è un grosso problema per il software moderno, perché in genere il software moderno è chiamato a fare molte cose flessibili. Può fare miliardi o addirittura trilioni di manipolazioni di stato complesse nel corso di una corsa. La capacità di dimostrare le vere affermazioni su ciò che il software farà in quei miliardi o trilioni di operazioni è estremamente preziosa.

Nel caso del software moderno, tutte le nostre lingue forniscono strumenti per aiutare in questo, come l'incapsulamento. La scelta di non usarlo è inutile, il che porta alla mentalità dei "globals are evil". In molte regioni del campo dello sviluppo software, le uniche persone che li utilizzano sono persone che non sanno come codificare meglio. Ciò significa che non solo sono problemi direttamente, ma suggeriscono indirettamente che lo sviluppatore non sapesse cosa stavano facendo. In altre regioni, i globals sono totalmente normali (il software incorporato, in particolare, ama i globals, in parte perché funzionano bene con le ISR). Tuttavia, tra i molti sviluppatori di software là fuori, essi sono la voce minoritaria, quindi l'unica voce che senti è "i globals sono cattivi".

Lo sviluppo del database è una di quelle situazioni vocali minoritarie. Gli strumenti necessari per eseguire il lavoro DBA sono molto potenti e la loro teoria è non radicata nell'incapsulamento. Hanno bisogno di un accesso illimitato a tutto, simile ai globali, per eliminare ogni singola battuta dalle loro banche dati. Utilizza uno dei loro enormi database di 100 milioni di righe (o più!) E apprezzerai il motivo per cui non lasciano che il loro motore DB subisca alcun pugno.

Pagano un prezzo per questo, un caro prezzo. I DBA sono costretti a essere quasi patologici con la loro attenzione ai dettagli, perché i loro strumenti non li proteggono. Il meglio che hanno in termini di protezione è ACID o forse chiavi esterne. Quelli che non sono patologici si trovano con un pasticcio di tabelle completamente inutilizzabile o addirittura corrotto.

Non è raro avere pacchetti software di linea 100k. In teoria, qualsiasi linea nel software può influenzare qualsiasi globale in qualsiasi momento. Nei DBA non si trovano mai 100k query diverse che possono modificare il database. Sarebbe irragionevole mantenere con l'attenzione ai dettagli necessari per proteggerti da te stesso. Se un DBA ha qualcosa di così grande, incapsulerà intenzionalmente il loro database usando gli accessor, aggirando i problemi "globali come" e poi facendo tutto il lavoro possibile attraverso quel meccanismo "più sicuro". Quindi, quando arriva il momento critico, anche le persone del database evitano i globali. Semplicemente arrivano con un sacco di pericoli, e ci sono alternative che sono solo altrettanto forti, ma non altrettanto pericolose.

Preferiresti camminare su vetri rotti, o su marciapiedi ben spazzati, se tutte le altre cose sono uguali? Sì, puoi camminare su vetri rotti. Sì, alcune persone addirittura si guadagnano da vivere facendolo. Ma ancora, lascia che spazzino il marciapiede e prosegua!

    
risposta data 28.05.2016 - 05:14
fonte
0

Penso che la premessa sia falsa. Non c'è ragione per cui un database debba essere "stato globale" piuttosto che un oggetto di contesto (molto grande). Se stai vincolando al particolare database che il tuo codice utilizza tramite variabili globali o parametri fissi di connessione al database globale, non è diverso, e non meno male, di qualsiasi altro stato globale. D'altra parte, se si passa correttamente un oggetto contesto per la connessione al database, è solo uno stato contestualizzato (e ampiamente utilizzato), non uno stato globale.

Misurare la differenza è semplice: potresti eseguire due istanze della logica del tuo programma, ciascuna utilizzando il proprio database, in un singolo programma / processo senza apportare modifiche invasive al codice? Se è così, il tuo database non è realmente "stato globale".

    
risposta data 30.05.2016 - 04:13
fonte
-2

I Globali non sono malvagi; sono semplicemente uno strumento. L'uso scorretto dei globals è problematico, così come lo è l'uso improprio di qualsiasi altra funzione di programmazione.

La mia raccomandazione generale è che i globali dovrebbero essere usati solo in situazioni che sono ben comprese e pensate, dove altre soluzioni sono meno ottimali. Soprattutto, si vuole essere sicuri di avere ben documentato dove quel valore globale potrebbe essere modificato, e se si sta eseguendo il multithreading, si sta garantendo che l'accesso globale e qualsiasi globalità co-dipendente sia transazionale.

    
risposta data 25.05.2016 - 20:19
fonte
-2

Modello di sola lettura e si assume che i dati non siano aggiornati al momento della stampa. Coda scrive o gestisce i conflitti in un altro modo. Benvenuto nel diavolo dell'inferno, stai utilizzando il db globale.

    
risposta data 31.05.2016 - 23:52
fonte

Leggi altre domande sui tag