Czym globały różnią się od bazy danych?


250

Właśnie natknąłem się na to stare pytanie, zadając sobie pytanie, co jest tak złego w stanie globalnym, a najczęściej głosowana, akceptowana odpowiedź zapewnia, że ​​nie można ufać żadnemu kodowi, który działa ze zmiennymi globalnymi, ponieważ jakiś inny kod gdzieś indziej może się pojawić i zmodyfikować jego wartość, a następnie nie wiesz, jakie będzie zachowanie twojego kodu, ponieważ dane są inne! Ale kiedy na to patrzę, nie mogę przestać myśleć, że to naprawdę słabe wytłumaczenie, ponieważ czym to się różni od pracy z danymi przechowywanymi w bazie danych?

Kiedy twój program pracuje z danymi z bazy danych, nie obchodzi cię, czy inny kod w twoim systemie go zmienia, a nawet jeśli zmienia go zupełnie inny program. Nie obchodzi Cię, jakie są dane; o to chodzi. Liczy się tylko to, że kod poprawnie radzi sobie z napotkanymi danymi. (Oczywiście zastanawiam się nad często drażliwym problemem buforowania tutaj, ale na razie zignorujmy to.)

Ale jeśli dane, z którymi pracujesz, pochodzą z zewnętrznego źródła, nad którym twój kod nie ma kontroli, takiego jak baza danych (dane wejściowe użytkownika, gniazdo sieciowe, plik itp.) I nie ma nic złego w związku z tym, w jaki sposób globalne dane w samym kodzie - nad którymi program ma znacznie większy stopień kontroli - są czymś złym, gdy są znacznie mniej złe niż całkowicie normalne rzeczy, których nikt nie widzi jako problemu?


117
Miło jest widzieć weteranów, którzy rzucają wyzwanie dogmatom ...
svidgen

10
W aplikacji zazwyczaj podajesz sposób dostępu do bazy danych, ten środek jest przekazywany do funkcji, które chcą uzyskać dostęp do bazy danych. Nie robisz tego ze zmiennymi globalnymi, po prostu wiesz, że są one pod ręką. To kluczowa różnica.
Andy

45
Stan globalny jest jak posiadanie pojedynczej bazy danych z pojedynczą tabelą z jednym wierszem z nieskończenie wieloma kolumnami, do których dostęp uzyskuje jednocześnie dowolna liczba aplikacji.
BevynQ

42
Bazy danych są również złe.
Stig Hemmer,

27
Zabawne jest „odwrócenie” argumentu, który tu wysyłasz, i pójście w innym kierunku. Struktura, która ma wskaźnik do innej struktury, jest logicznie po prostu kluczem obcym w jednym rzędzie jednej tabeli, który prowadzi do innego wiersza innej tabeli. W jaki sposób praca z dowolnym kodem, w tym chodzenie połączonych list, różni się od manipulowania danymi w bazie danych? Odpowiedź: nie jest. Pytanie: dlaczego zatem manipulujemy strukturami danych w pamięci i strukturami danych w bazie danych za pomocą tak różnych narzędzi? Odpowiedź: Naprawdę nie wiem! Wydaje się raczej wypadkiem historycznym niż dobrym projektem.
Eric Lippert,

Odpowiedzi:


118

Po pierwsze, powiedziałbym, że odpowiedź, którą podajesz, przesadza z tym konkretnym problemem i że podstawowym złem stanu globalnego jest to, że wprowadza sprzężenie w nieprzewidywalny sposób, który może utrudnić zmianę zachowania twojego systemu w przyszłości.

Ale zagłębiając się w tę kwestię, istnieją różnice między stanem globalnym w typowej aplikacji obiektowej a stanem przechowywanym w bazie danych. W skrócie najważniejsze z nich to:

  • Systemy zorientowane obiektowo pozwalają na zastąpienie obiektu inną klasą obiektu, o ile jest on podtypem typu oryginalnego. Umożliwia to zmianę zachowania , a nie tylko danych .

  • Stan globalny w aplikacji zazwyczaj nie zapewnia silnych gwarancji spójności, jakie zapewnia baza danych - nie ma transakcji, w których można zaobserwować spójny stan, brak aktualizacji atomowych itp.

Dodatkowo widzimy stan bazy danych jako zło konieczne; nie da się go wyeliminować z naszych systemów. Stan globalny jest jednak niepotrzebny. Możemy to całkowicie wyeliminować. Więc nawet jeśli problemy z bazą danych były równie złe, nadal możemy wyeliminować niektóre potencjalne problemy, a częściowe rozwiązanie jest lepsze niż brak rozwiązania.


44
Myślę, że główną konsekwencją jest spójność: kiedy w kodzie używane są zmienne globalne, zwykle nie wiadomo, kiedy są one faktycznie inicjowane. Zależności między modułami są głęboko ukryte w sekwencji wywołań, a proste rzeczy, takie jak zamiana dwóch wywołań, mogą powodować naprawdę paskudne błędy, ponieważ nagle jakaś zmienna globalna nie jest już poprawnie inicjowana przy pierwszym użyciu. Przynajmniej taki mam problem ze starszym kodem, z którym muszę pracować, co sprawia, że ​​refaktoryzacja jest koszmarem.
cmaster

24
@DavidHammen Właściwie pracowałem nad symulacją stanu świata dla gry online, która wyraźnie należy do kategorii aplikacji, o której mówisz, i nawet tam nie użyłbym (i nie użyłbym) globalnego stanu do tego. Nawet jeśli można uzyskać pewien wzrost wydajności przy użyciu stanu globalnego, problem polega na tym, że stanu globalnego nie można skalować . Korzystanie z architektury jednowątkowej na wielowątkową staje się trudne . Staje się nieefektywny po przejściu do architektury NUMA. Staje się to niemożliwe po przejściu do architektury rozproszonej. Artykuł, który cytujesz, pochodzi z ...
Jules

24
1993. Wówczas problemy te stanowiły mniejszy problem. Autorzy pracowali nad systemem jednoprocesorowym, symulując interakcje 1000 obiektów. W nowoczesnym systemie prawdopodobnie przeprowadziłbyś tego rodzaju symulację przynajmniej w systemie dwurdzeniowym, ale całkiem prawdopodobne, że może to być co najmniej 6 rdzeni w jednym systemie. W przypadku większych problemów uruchomiłbyś go w klastrze. W przypadku tego rodzaju zmian należy unikać stanu globalnego, ponieważ nie można skutecznie współdzielić stanu globalnego.
Jules

19
Uważam, że nazwanie bazy danych „złem koniecznym” jest trochę trudne. Mam na myśli, odkąd państwo stało się złe? Stan jest całym celem bazy danych. Stan to informacja. Bez stanu wszystko, co masz, to operatorzy. Na czym polegają operatorzy, bez których można operować? Ten stan musi gdzieś iść. Ostatecznie programowanie funkcjonalne jest tylko środkiem do celu i bez stanu mutacji nie ma sensu nic robić. To trochę jak piekarz, który nazywa ciasto koniecznym złem - to nie jest złe. To jest sedno sprawy.
J ...

5
@DavidHammen „wciąż jest jakiś obiekt, który wie przynajmniej trochę o każdym obiekcie w grze” Niekoniecznie prawda. Główną techniką w nowoczesnej symulacji rozproszonej jest wykorzystywanie lokalizacji i dokonywanie przybliżeń, tak aby odległe obiekty nie musiały wiedzieć o wszystkim z daleka, a jedynie dane dostarczane im przez właścicieli tych odległych obiektów.
JAB,

75

Po pierwsze, jakie są problemy ze zmiennymi globalnymi, w oparciu o zaakceptowaną odpowiedź na pytanie, które połączyłeś?

Krótko mówiąc, sprawia, że ​​stan programu jest nieprzewidywalny.

Bazy danych są w przeważającej części zgodne z ACID. ACID w szczególności rozwiązuje podstawowe problemy, które powodują, że magazyn danych jest nieprzewidywalny lub zawodny.

Ponadto stan globalny szkodzi czytelności twojego kodu.

Wynika to z faktu, że zmienne globalne istnieją w zakresie dalekim od ich użycia, może nawet w innym pliku. Korzystając z bazy danych, używasz zestawu rekordów lub obiektu ORM, który jest lokalny dla czytanego kodu (lub powinien być).

Sterowniki baz danych zazwyczaj zapewniają spójny, zrozumiały interfejs umożliwiający dostęp do danych, które są takie same, niezależnie od domeny problemu. Kiedy pobierasz dane z bazy danych, twój program ma kopię danych. Aktualizacje są atomowe. Porównaj ze zmiennymi globalnymi, w których wiele wątków lub metod może działać na tym samym kawałku danych bez atomowości, chyba że sam dodasz synchronizację. Aktualizacje danych są nieprzewidywalne i trudne do wyśledzenia. Aktualizacje mogą być przeplatane, co powoduje, że podręczne przykłady korupcji danych wielowątkowych (np. Przyrosty przeplotu).

Bazy danych zazwyczaj na początku modelują inne dane niż zmienne globalne, ale pomijając je na chwilę, bazy danych są projektowane od podstaw jako magazyn danych zgodny z ACID, który łagodzi wiele obaw związanych ze zmiennymi globalnymi.


4
+1 Mówisz, że bazy danych zawierają transakcje, co umożliwia atomowy odczyt i zapis wielu elementów stanu globalnego. Dobra uwaga, którą można obejść tylko przy użyciu zmiennych globalnych dla każdej całkowicie niezależnej informacji.
l0b0

1
Transakcje @ 10b0 są mechanizmem, który osiąga większość celów ACID, prawda. Ale sam interfejs DB sprawia, że ​​kod jest bardziej przejrzysty, ponieważ dane są przenoszone w bardziej lokalny zakres. Pomyśl o użyciu JDBC RecordSet z blokiem try-with-resources lub funkcji ORM, która pobiera kawałek danych za pomocą pojedynczego wywołania funkcji. Porównaj to z zarządzaniem danymi daleko od kodu, który czytasz gdzieś w świecie.

1
Byłoby więc w porządku użycie zmiennych globalnych, jeśli skopiuję wartość do zmiennej lokalnej (z muteksem) na początku funkcji, zmodyfikuję zmienną lokalną, a następnie skopiuję wartość z powrotem do zmiennej globalnej na końcu funkcja? (... zapytał retorycznie.)
RM

1
@RM Wspomniał o dwóch punktach. To, co wyrzuciłeś, może dotyczyć pierwszego (nieprzewidywalny stan programu), ale nie dotyczy drugiego (czytelności twojego kodu). W rzeczywistości może to pogorszyć czytelność twojego programu: P.
riwalk

1
@RM Twoja funkcja działałaby konsekwentnie, tak. Ale wtedy miałbyś pytanie, czy w międzyczasie coś globalnego zmodyfikowało zmienną globalną, a ta modyfikacja była ważniejsza niż to, co do niej piszesz. Oczywiście bazy danych mogą mieć ten sam problem.
Graham

45

Chciałbym przedstawić kilka uwag:

Tak, baza danych jest stanem globalnym.

W rzeczywistości jest to stan superglobalny, jak zauważyłeś. To jest uniwersalne! Jego zakres obejmuje wszystko lub każdego , kto łączy się z bazą danych. Podejrzewam, że wielu ludzi z wieloletnim doświadczeniem może opowiedzieć horrory o tym, jak „dziwne rzeczy” w danych doprowadziły do ​​„nieoczekiwanego zachowania” w jednej lub kilku odpowiednich aplikacjach ...

Jedną z potencjalnych konsekwencji używania zmiennej globalnej jest to, że dwa odrębne „moduły” wykorzystają tę zmienną do własnych, odrębnych celów. I w tym zakresie tabela bazy danych nie różni się. Może paść ofiarą tego samego problemu.

Hmm ... Oto rzecz:

Jeśli moduł nie działa w jakiś sposób na zewnątrz, nic nie robi.

Przydatny moduł może otrzymać dane lub może je znaleźć . I może zwrócić dane lub zmienić stan. Ale jeśli w jakiś sposób nie wchodzi w interakcje ze światem zewnętrznym, równie dobrze może nic nie robić.

Teraz preferujemy odbieranie danych i zwracanie danych. Większość modułów jest po prostu łatwiej napisać, jeśli można je napisać z całkowitym lekceważeniem tego, co robi świat zewnętrzny. Ale ostatecznie coś musi znaleźć dane i zmodyfikować ten zewnętrzny, globalny stan.

Ponadto w rzeczywistych aplikacjach dane istnieją, dzięki czemu można je odczytać i zaktualizować za pomocą różnych operacji. Niektórym problemom zapobiegają blokady i transakcje. Ale zapobieganie konfliktom między tymi operacjami w zasadzie na koniec dnia wymaga po prostu uważnego myślenia. (I popełnianie błędów ...)

Ale generalnie nie współpracujemy bezpośrednio ze stanem globalnym.

O ile aplikacja nie znajduje się w warstwie danych (SQL lub cokolwiek), obiekty, z którymi współpracują nasze moduły, są w rzeczywistości kopiami wspólnego stanu globalnego. Możemy robić, co chcemy, bez wpływu na rzeczywisty, wspólny stan.

I w przypadkach, w których musimy zmutować ten stan globalny, zakładając, że dane, które nam przekazano, nie uległy zmianie, możemy zasadniczo wykonać taki sam rodzaj blokowania, jak w przypadku naszych lokalnych globali.

I wreszcie, zwykle robimy różne rzeczy z bazami danych, niż może się niegrzeczne globalnych.

Niegrzeczny, zepsuty glob wygląda tak:

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

Po prostu nie używamy baz danych do takich procesów wewnętrznych / operacyjnych. I może to być powolny charakter bazy danych i względna wygoda prostej zmiennej, która nas odstrasza: nasza powolna, niezręczna interakcja z bazami danych po prostu czyni z nich złych kandydatów na wiele błędów, które popełniliśmy w przeszłości ze zmiennymi.


3
Sposobem na zagwarantowanie (ponieważ nie możemy założyć) „że dane, które otrzymaliśmy nie uległy zmianie” w bazie danych, byłaby transakcja.
l0b0

Tak ... miało to wynikać z „tego samego rodzaju zamka”.
svidgen

Ale trudno jest dokładnie przemyśleć pod koniec dnia.

Tak, bazy danych są rzeczywiście stanem globalnym - dlatego tak kuszące jest udostępnianie danych przy użyciu czegoś takiego jak git lub ipfs.
William Payne

21

Nie zgadzam się z podstawowym twierdzeniem, że:

Kiedy twój program pracuje z danymi z bazy danych, nie obchodzi cię, czy inny kod w twoim systemie go zmienia, a nawet jeśli zmienia go zupełnie inny program.

Moją pierwszą myślą było „Wow. Just Wow”. Tyle czasu i wysiłku poświęca się na uniknięcie tego - i na ustalenie, jakie kompromisy i kompromisy działają dla każdej aplikacji. Zignorować to przepis na katastrofę.

Ale ja również diasgree na poziomie architektonicznym. Zmienna globalna to nie tylko stan globalny. Jest to stan globalny, który jest dostępny z dowolnego miejsca w sposób transparentny. W przeciwieństwie do korzystania z bazy danych, musisz mieć do niej uchwyt - (chyba że przechowujesz niż obsługujesz zmienną globalną ....)

Na przykład użycie zmiennej globalnej może wyglądać tak

int looks_ok_but_isnt() {
  return global_int++;
}

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

Ale robienie tego samego z bazą danych musiałoby być bardziej wyraźne na temat tego, co robi

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

Baza danych oczywiście ewakuuje się z bazą danych. Jeśli nie chcesz korzystać z bazy danych, możesz użyć jawnego stanu i wygląda ona prawie tak samo jak przypadek bazy danych.

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

Argumentowałbym więc, że korzystanie z bazy danych jest bardziej podobne do używania stanu jawnego niż używania zmiennych globalnych.


2
Tak, pomyślałem, że to ciekawe, gdy OP powiedział: „ Nie obchodzi cię, jakie są dane; o to właśnie chodzi ” - jeśli nas to nie obchodzi, to po co je przechowywać? Oto myśl: przestańmy w ogóle używać zmiennych i danych . To powinno uprościć sprawę. „Zatrzymaj świat, chcę uciec!”

1
+1 Różne wątki lub aplikacje zapisujące i odczytujące z tej samej bazy danych są potencjalnym źródłem wielu znanych problemów, dlatego zawsze powinna istnieć strategia radzenia sobie z tym, na poziomie bazy danych lub aplikacji, lub obie. Więc zdecydowanie NIE jest prawdą, że Ty (twórca aplikacji) nie obchodzi Cię, kto jeszcze czyta lub pisze z bazy danych.
Andres F.

1
+1 Na marginesie, ta odpowiedź wyjaśnia, czego najbardziej nienawidzę w iniekcji zależności. Ukrywa tego rodzaju zależności.
jpmc26

@ jpmc26 Być może zaznaczam słowa, ale czy powyższy przykład nie jest dobrym przykładem tego, w jaki sposób wstrzykiwanie zależności (w przeciwieństwie do globalnego wyszukiwania) pomaga jawnie określić zależności? Wydaje mi się, że wolisz mieć problemy z niektórymi interfejsami API, na przykład magią adnotacji używaną przez JAX-RS i Springa.
Emil Lundberg

2
@EmilLundberg Nie, problem polega na tym, że masz hierarchię. Wstrzykiwanie zależności ukrywa zależności kodu niższych warstw od kodu na wyższych poziomach, co utrudnia śledzenie interakcji między nimi. Na przykład, jeśli MakeNewThingzależy od MakeNewThingInDbi moja klasa kontrolera używa MakeNewThing, to z kodu w moim kontrolerze nie wynika jasno, że modyfikuję bazę danych. Co więc, jeśli użyję innej klasy, która faktycznie zatwierdza moją bieżącą transakcję do DB? DI bardzo utrudnia kontrolowanie zakresu obiektu.
jpmc26

18

Zgadza się, że jedynym powodem, dla którego nie można ufać zmiennym globalnym, ponieważ stan można zmienić gdzie indziej, nie jest sam w sobie wystarczającym powodem, aby z nich nie korzystać, jest to całkiem dobry powód! Prawdopodobnie odpowiedzią było głównie opisanie użycia, w którym ograniczenie dostępu zmiennej do tylko tych obszarów kodu, które są zainteresowane, miałoby większy sens.

Bazy danych to jednak inna sprawa, ponieważ zostały zaprojektowane w celu uzyskania dostępu „globalnie”, że tak powiem.

Na przykład:

  • Bazy danych zazwyczaj mają wbudowane sprawdzanie poprawności typu i struktury, które wykracza poza język, do którego się one uzyskują
  • Bazy danych niemal jednogłośnie aktualizują transakcje oparte na transakcjach, co zapobiega niespójnym stanom, w których nie ma gwarancji, jak stan końcowy będzie wyglądał w obiekcie globalnym (chyba że jest ukryty za singletonem)
  • Struktura bazy danych jest co najmniej niejawnie udokumentowana na podstawie struktury tabeli lub obiektu, bardziej niż aplikacja, która z niej korzysta

Najważniejsze jednak, że bazy danych służą innym celom niż zmienna globalna. Bazy danych służą do przechowywania i wyszukiwania dużych ilości zorganizowanych danych, w których zmienne globalne służą określonym niszom (o ile jest to uzasadnione).


1
Huh Pobiłaś mnie, gdy byłem w połowie pisania prawie identycznej odpowiedzi. :)
Jules

@Jules Twoja odpowiedź zawiera szczegółowe informacje ze strony aplikacji; Zatrzymaj to.
Jeffrey Sweeney

Ale jeśli nie będziesz całkowicie polegać na procedurach przechowywanych dostępu do danych, cała ta struktura nadal nie będzie wymuszać stosowania tabel zgodnie z przeznaczeniem. Lub że operacje są wykonywane w odpowiedniej kolejności. Lub że blokady (transakcje) są tworzone w razie potrzeby.
svidgen

Cześć, czy punkty 1 i 3 nadal obowiązują, jeśli używasz języka typu statycznego, takiego jak Java?
Jesvin Jose

@ aitchnyu Niekoniecznie. Chodzi o to, że bazy danych są budowane w celu niezawodnego udostępniania danych, w przypadku których zmienne globalne zwykle nie są. Obiekt implementujący interfejs samo-dokumentowania w ścisłym języku służy innym celom niż nawet luźna baza danych NoSQL.
Jeffrey Sweeney

10

Ale kiedy na to patrzę, nie mogę przestać myśleć, że to naprawdę słabe wytłumaczenie, ponieważ czym to się różni od pracy z danymi przechowywanymi w bazie danych?

Lub coś innego niż praca z urządzeniem interaktywnym, z plikiem, ze wspólną pamięcią itp. Program, który robi dokładnie to samo za każdym razem, gdy jest uruchamiany, jest bardzo nudnym i raczej bezużytecznym programem. Tak, to słaby argument.

Dla mnie różnica, która robi różnicę w odniesieniu do zmiennych globalnych, polega na tym, że tworzą one ukryte i niechronione linie komunikacyjne. Czytanie z klawiatury jest bardzo oczywiste i chronione. Muszę wykonać określone wywołanie funkcji i nie mogę uzyskać dostępu do sterownika klawiatury. To samo dotyczy dostępu do plików, pamięci współużytkowanej i przykładowych baz danych. Dla czytelnika kodu oczywiste jest, że ta funkcja odczytuje z klawiatury, że funkcja uzyskuje dostęp do pliku, niektóre inne funkcje uzyskują dostęp do pamięci współużytkowanej (i lepiej, żeby były wokół tego zabezpieczenia), a jednak niektóre inne funkcje uzyskują dostęp do bazy danych.

Z drugiej strony w przypadku zmiennych globalnych wcale nie jest to oczywiste. Interfejs API mówi, aby zadzwonić foo(this_argument, that_argument). W sekwencji wywołującej nic nie mówi, że zmienna globalna g_DangerWillRobinsonpowinna być ustawiona na pewną wartość, ale przed wywołaniem foo(lub zbadana po wywołaniu foo).


Google zakazał używania nie stałych argumentów referencyjnych w C ++ przede wszystkim dlatego, że nie jest oczywiste dla czytelnika kodu, który foo(x)się zmieni, xponieważ fooprzyjmuje on jako argument nietrwałe odwołanie. (Porównaj z C #, który dyktuje, że zarówno definicja funkcji, jak i strona wywołująca muszą kwalifikować parametr referencyjny ze refsłowem kluczowym.) Chociaż nie zgadzam się ze standardem Google w tym zakresie, rozumiem ich punkt widzenia.

Kod jest zapisywany raz i modyfikowany kilka razy, ale jeśli w ogóle jest dobry, jest czytany wiele, wiele razy. Ukryte linie komunikacyjne są bardzo złą karmą. Niestałe odniesienie do C ++ reprezentuje niewielką ukrytą linię komunikacji. Dobre API lub dobre IDE pokaże mi, że „Och! To jest wywołanie przez referencję”. Zmienne globalne to ogromna ukryta linia komunikacji.


Twoja odpowiedź ma większy sens.
Billal Begueradj

8

Myślę, że przytoczone wyjaśnienie upraszcza tę kwestię do tego stopnia, że ​​rozumowanie staje się śmieszne. Oczywiście stan zewnętrznej bazy danych przyczynia się do stanu globalnego. Ważnym pytaniem jest jaktwój program zależy od (zmiennego) globalnego stanu. Jeśli funkcja biblioteczna do dzielenia ciągów znaków na białych znakach byłaby zależna od wyników pośrednich przechowywanych w bazie danych, sprzeciwiłbym się temu projektowi co najmniej tak samo, jak sprzeciwiłbym się globalnej tablicy znaków używanej w tym samym celu. Z drugiej strony, jeśli zdecydujesz, że twoja aplikacja nie potrzebuje w pełni rozbudowanego DBMS do przechowywania danych biznesowych w tym momencie, a wystarczy globalna struktura klucz-wartość w pamięci, niekoniecznie jest to oznaką złego projektu. Ważne jest to, że - bez względu na to, jakie rozwiązanie wybierzesz do przechowywania danych - ten wybór jest odizolowany od bardzo małej części systemu, dzięki czemu większość komponentów może być niezależna od rozwiązania wybranego do wdrożenia i przetestowanego w izolacji i wdrożonego rozwiązanie można później zmienić przy niewielkim wysiłku.


8

Jako inżynier oprogramowania pracujący głównie z wbudowanym oprogramowaniem układowym, prawie zawsze używam zmiennych globalnych do wszystkiego pomiędzy modułami. W rzeczywistości jest to najlepsza praktyka dotycząca osadzania. Są one przypisywane statycznie, więc nie ma ryzyka wysadzenia stosu / stosu i nie ma dodatkowego czasu przeznaczanego na przydzielanie / czyszczenie stosu przy wejściu / wyjściu funkcji.

Wadą jest to, że nie trzeba zastanowić się, jak wykorzystywane są te zmienne, i dużo, że wszystko sprowadza się do tego samego rodzaju myśli, że idzie do bazy spory. Wszelkie asynchroniczne operacje odczytu / zapisu zmiennych MUSZĄ mieć charakter atomowy. Jeśli więcej niż jedno miejsce może zapisać zmienną, należy się zastanowić, aby zawsze zapisywać prawidłowe dane, aby poprzednie zapisanie nie zostało arbitralnie zastąpione (lub że dowolna zamiana jest bezpieczna). Jeśli ta sama zmienna zostanie odczytana więcej niż raz, należy zastanowić się, co się stanie, jeśli zmienna zmieni wartość między odczytami, lub kopia zmiennej musi zostać pobrana na początku, aby przetwarzanie odbywało się przy użyciu spójnej wartości, nawet jeśli ta wartość staje się nieaktualna podczas przetwarzania.

(W tym ostatnim, pierwszego dnia kontraktu dotyczącego systemu przeciwdziałania samolotom, tak bardzo związanego z bezpieczeństwem, zespół oprogramowania patrzył na raport o błędzie, który starali się znaleźć przez około tydzień. Miałem wystarczająco dużo czasu, aby pobrać narzędzia programistyczne i kopię kodu. Zapytałem „czy ta zmienna nie może być aktualizowana między odczytami i powodować ją?”, Ale tak naprawdę nie otrzymałem odpowiedzi. Hej, co robi nowy facet wie przecież? Więc kiedy jeszcze o tym dyskutowali, dodałem kod ochronny, aby odczytać zmienną atomowo, zrobiłem lokalną kompilację i po prostu powiedziałem „hej, spróbujcie tego”. . :)

Tak więc zmienne globalne nie są jednoznacznie złe, ale pozostawiają cię otwartą na szeroki zakres problemów, jeśli nie zastanowisz się nad nimi ostrożnie.


7

W zależności od tego, jaki aspekt oceniasz, zmienne globalne i dostęp do bazy danych mogą być odrębnymi światami, ale dopóki oceniamy je jako zależności, są one takie same.

Rozważmy definicję programowania funkcjonalnego funkcji czystej, która musi zależeć wyłącznie od parametrów, które przyjmuje jako dane wejściowe, tworząc deterministyczny wynik. Oznacza to, że biorąc pod uwagę ten sam zestaw argumentów dwa razy, musi on dawać ten sam wynik.

Gdy funkcja zależy od zmiennej globalnej, nie może być dłużej uważana za czystą, ponieważ dla tego samego zestawu lub argumentów może dawać różne wyniki, ponieważ wartość zmiennej globalnej mogła się zmieniać między wywołaniami.

Jednak funkcja może być nadal postrzegana jako deterministyczna, jeśli weźmiemy pod uwagę zmienną globalną jako część interfejsu funkcji, podobnie jak inne argumenty, więc nie stanowi to problemu. Problem polega tylko na tym, że jest to ukryte, dopóki nie zaskoczy nas nieoczekiwane zachowanie z pozornie oczywistych funkcji, a następnie przeczytaj ich implementacje, aby odkryć ukryte zależności .

Ta część, moment, w którym zmienna globalna staje się ukrytą zależnością, jest przez programistów uważana za zło. Utrudnia to rozumowanie kodu, trudność z przewidywaniem jego zachowania, trudność do ponownego użycia, trudność do przetestowania, a zwłaszcza zwiększa czas debugowania i naprawy w przypadku wystąpienia problemu.

To samo dzieje się, gdy ukrywamy zależność od bazy danych. Możemy mieć funkcje lub obiekty, które wywołują bezpośrednie wywołania zapytań do bazy danych i poleceń, ukrywając te zależności i powodując taki sam problem, jaki powodują zmienne globalne; lub możemy je wyrazić, co, jak się okazuje, jest uważane za najlepszą praktykę, która ma wiele nazw, takich jak wzorzec repozytorium, magazyn danych, brama itp.

PS: Istnieją inne aspekty, które są ważne dla tego porównania, takie jak to, czy występuje współbieżność, ale ten punkt jest objęty innymi odpowiedziami tutaj.


Podoba mi się, że wziąłeś to pod kątem zależności.
cbojar

6

OK, zacznijmy od historycznego punktu.

Jesteśmy w starej aplikacji, napisanej w typowej mieszance zestawu i C. Nie ma żadnych funkcji, tylko procedury . Gdy chcesz przekazać argument lub zwrócić wartość z procedury, użyj zmiennej globalnej. Nie trzeba dodawać, że jest to dość trudne do śledzenia i ogólnie każda procedura może zrobić, co chce z każdą zmienną globalną. Nic dziwnego, że ludzie zwracali się do przekazywania argumentów i zwracania wartości w inny sposób, gdy tylko było to wykonalne (chyba że nie było to krytyczne pod względem wydajności, aby tego nie robić - np. Spójrz na kod źródłowy Build Engine (Duke 3D)). Narodziła się nienawiść do zmiennych globalnych - nie miałeś pojęcia, jaki kawałek stanu globalnego każda procedura będzie czytać i zmieniać, a tak naprawdę nie możesz bezpiecznie zagnieżdżać wywołań procedur.

Czy to oznacza, że ​​nienawiść do zmiennych globalnych należy już do przeszłości? Nie do końca.

Po pierwsze muszę wspomnieć, że widziałem dokładnie to samo podejście do przekazywania argumentów w projekcie, nad którym teraz pracuję. Za przekazanie dwóch wystąpień typu referencyjnego w języku C # w projekcie, który ma około 10 lat. Nie ma dosłownie żadnego powodu, aby robić to w ten sposób, i najprawdopodobniej zrodził się albo z hodowli ładunków, albo z całkowitego nieporozumienia, jak działa C #.

Najważniejsze jest to, że dodając zmienne globalne, rozszerzasz zakres każdego kawałka kodu, który ma dostęp do tej zmiennej globalnej. Pamiętasz wszystkie te zalecenia, takie jak „trzymaj swoje metody krótkie”? Jeśli masz 600 zmiennych globalnych (ponownie, przykład ze świata rzeczywistego: /), wszystkie zakresy metod są domyślnie rozszerzane o te 600 zmiennych globalnych i nie ma prostego sposobu, aby śledzić, kto ma do czego dostęp.

Jeśli zrobione źle (zwykły sposób :)), zmienne globalne mogą mieć między sobą sprzężenie. Ale nie masz pojęcia, jak są ze sobą sprzężone i nie ma mechanizmu zapewniającego, że stan globalny jest zawsze spójny. Nawet jeśli wprowadzisz sekcje krytyczne, aby zachować spójność, okaże się, że słabo porównuje się z odpowiednią bazą danych ACID:

  • Nie ma możliwości wycofania częściowej aktualizacji, chyba że zachujesz stare wartości przed „transakcją”. Nie trzeba dodawać, że w tym momencie przekazywanie wartości jako argumentu już wygrywa :)
  • Każdy uzyskujący dostęp do tego samego stanu musi przestrzegać tego samego procesu synchronizacji. Ale nie ma sposobu, aby to wymusić - jeśli zapomnisz skonfigurować sekcję krytyczną, to jesteś zepsuty.
  • Nawet jeśli poprawnie zsynchronizujesz cały dostęp, mogą być zagnieżdżone połączenia, które uzyskują dostęp do częściowo zmodyfikowanego stanu. Oznacza to, że albo jesteś w impasie (jeśli twoje krytyczne sekcje nie są ponownie wysyłane), albo masz do czynienia z niespójnymi danymi (jeśli są ponownie wysyłane).

Czy można rozwiązać te problemy? Nie całkiem. Potrzebujesz kapsułkowania, aby poradzić sobie z tą, lub naprawdę ścisłą dyscypliną. Trudno jest postępować właściwie i ogólnie nie jest to zbyt dobry przepis na sukces w tworzeniu oprogramowania :)

Mniejszy zakres ułatwia kodowanie. Zmienne globalne sprawiają, że nawet najprostsze fragmenty kodu obejmują ogromne zakresy zasięgu.

Oczywiście nie oznacza to, że globalny zasięg jest zły. To nie powinno być pierwsze rozwiązanie, na które się wybierasz - to typowy przykład „prosty w implementacji, trudny w utrzymaniu”.


Brzmi bardzo podobnie do świata fizycznego: bardzo trudno jest wycofać rzeczy.

To dobra odpowiedź, ale na początku może znieść tezę (sekcja TL; DR).
jpmc26

6

Zmienna globalna jest narzędziem, może być używana dla dobra i zła.

Baza danych jest narzędziem, może być używana dla dobra i zła.

Jak zauważa oryginalny plakat, różnica nie jest aż tak duża.

Niedoświadczeni studenci często myślą, że robaki zdarzają się innym ludziom. Nauczyciele wykorzystują „Zmienne globalne są złe” jako uproszczony powód do karania złego projektu. Studenci na ogół nie rozumieją tego tylko dlatego, że ich program 100-liniowy jest wolny od błędów, nie oznacza, że ​​te same metody można zastosować w programach 10000-liniowych.

Podczas pracy z bazami danych nie można po prostu zablokować stanu globalnego, ponieważ o to właśnie chodzi w programie. Zamiast tego otrzymasz więcej szczegółowych wskazówek, takich jak ACID i formularze normalne itd.

Gdyby ludzie stosowali podejście ACID do zmiennych globalnych, nie byliby tacy źli.

Z drugiej strony, jeśli źle zaprojektujesz bazy danych, mogą to być koszmary.


3
Typowe roszczenie studenta dotyczące przepełnienia stosu: Pomóż mi! Mój kod jest idealny, ale nie działa poprawnie!
David Hammen

„Podejście ACID do zmiennych globalnych” - patrz referencje w Clojure.
Charles Duffy,

@DavidHammen i myślisz, że profesjonaliści mają mózg w przeciwieństwie do studentów?
Billal Begueradj

@BillalBEGUERADJ - To różnica między profesjonalistami a studentami. Wiemy, że pomimo wieloletniego doświadczenia i najlepszych starań związanych z przeglądaniem kodu, testowaniem itp., Nasz kod nie jest doskonały.
David Hammen


5

Dla mnie głównym złem jest to, że Globals nie mają ochrony przed problemami współbieżności. Możesz dodać mechanizmy do obsługi takich problemów z Globals, ale przekonasz się, że im więcej rozwiążesz problemów z współbieżnością, tym bardziej Twoje Globale zaczną naśladować bazę danych. Drugim złem nie jest umowa użytkowania.


3
Na przykład errnow C.
David Hammen

1
To dokładnie wyjaśnia, dlaczego globały i bazy danych nie są takie same. Mogą występować inne różnice, ale Twój konkretny post całkowicie niszczy koncepcję. Jeśli podałeś szybki przykład kodu, jestem pewien, że dostaniesz wiele pozytywnych opinii. np. MyFunc () {x = globalVar * 5; // .... Inne przetwarzanie; y = globalVar * 34; // Ups, jakiś inny wątek mógł zmienić globalVar podczas innych procesów, a xiy używają różnych wartości dla globalVar w swoich obliczeniach, co prawie na pewno nie dałoby pożądanych rezultatów.
Dunk

5

Niektóre inne odpowiedzi próbują wyjaśnić, dlaczego korzystanie z bazy danych jest dobre. Oni są źli! Baza danych jest stanem globalnym i jako taka jest tak samo zła jak singleton lub zmienna globalna. Korzystanie z bazy danych jest niewłaściwe, gdy zamiast tego można po prostu użyć lokalnej mapy lub tablicy!

Zmienne globalne umożliwiają globalny dostęp, który niesie ryzyko nadużyć. Zmienne globalne mają również zalety. Mówi się, że zmienne globalne są czymś, czego należy unikać, a nie czymś, czego nigdy nie powinieneś używać. Jeśli możesz ich łatwo uniknąć, powinieneś ich unikać. Ale jeśli korzyści przeważają nad wadami, oczywiście powinieneś ich użyć! *

Dokładnie to samo ** dotyczy baz danych, które są stanem globalnym - podobnie jak zmienne globalne. Jeśli możesz zrobić to bez dostępu do bazy danych, a wynikowa logika robi wszystko, czego potrzebujesz i jest równie złożona, korzystanie z bazy danych zwiększa ryzyko dla twojego projektu, bez żadnych odpowiednich korzyści.

W rzeczywistości wiele aplikacji wymaga stanu globalnego od samego początku, czasem nawet trwałego stanu globalnego - dlatego mamy pliki, bazy danych itp.


* Wyjątkiem są tutaj studenci. Sensowne jest zakazanie uczniom używania zmiennych globalnych, aby musieli dowiedzieć się, jakie są alternatywy.

** Niektóre odpowiedzi błędnie twierdzą, że bazy danych są w jakiś sposób lepiej chronione niż inne formy stanu globalnego (pytanie dotyczy wyraźnie stanu globalnego , a nie tylko zmiennych globalnych). To pierdoły. Podstawową ochroną oferowaną w scenariuszu bazy danych jest konwencja, która jest dokładnie taka sama dla każdego innego stanu globalnego. Większość języków pozwala również na wiele dodatkowych zabezpieczeń dla stanu globalnego, w postaci constklas, które po prostu nie pozwalają na zmianę ich stanu po ustawieniu w konstruktorze, lub pobierających i ustawiających, które mogą brać pod uwagę informacje o wątku lub stan programu.


2

W pewnym sensie rozróżnienie między zmiennymi globalnymi a bazą danych jest podobne do rozróżnienia między prywatnymi i publicznymi elementami obiektu (zakładając, że ktoś nadal korzysta z pól publicznych). Jeśli myślisz o całym programie jako obiekcie, to globale są zmiennymi prywatnymi, a baza danych to pola publiczne.

Kluczowym rozróżnieniem jest tutaj przyjęta odpowiedzialność.

Kiedy piszesz obiekt, zakłada się, że każdy, kto utrzymuje metody składowe, zapewni, że pola prywatne pozostaną prawidłowe. Ale już rezygnujesz z jakichkolwiek założeń dotyczących stanu terenów publicznych i traktujesz je z większą ostrożnością.

To samo założenie dotyczy na szerszym poziomie bazy danych globals v / s. Ponadto język programowania / ekosystem gwarantuje ograniczenia dostępu dla prywatnych v / s publicznych w taki sam sposób, w jaki wymusza je na (globalnej pamięci) globalnej bazie danych v / s.

Kiedy pojawia się wielowątkowość, koncepcja prywatnej globalnej bazy danych v / s v / s stanowi jedynie rozróżnienie w całym spektrum.

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

Baza danych może być stanem globalnym, ale nie musi tak być przez cały czas. Nie zgadzam się z założeniem, że nie masz kontroli. Jednym ze sposobów zarządzania tym jest blokowanie i bezpieczeństwo. Można to zrobić przy rekordzie, tabeli lub całej bazie danych. Innym podejściem jest posiadanie pewnego rodzaju pola wersji, które zapobiegałoby zmianie rekordu, jeśli dane są nieaktualne.

Podobnie jak zmienna globalna, wartości w bazie danych można zmienić po ich odblokowaniu, ale istnieje wiele sposobów kontrolowania dostępu (nie podawaj wszystkim programistom hasła do konta, które może zmieniać dane). Jeśli masz zmienną, która ma ograniczony dostęp, nie jest bardzo globalna.


0

Istnieje kilka różnic:

  • Wartość bazy danych można modyfikować na bieżąco. Z drugiej strony wartości globalnej, która jest ustawiona w kodzie, nie można zmienić, chyba że ponownie wdrożysz aplikację i zmodyfikujesz kod. W rzeczywistości jest to celowe. Baza danych jest przeznaczona dla wartości, które mogą się zmieniać w czasie, ale zmienne globalne powinny być przeznaczone tylko dla rzeczy, które nigdy się nie zmienią i gdy nie zawierają rzeczywistych danych.

  • Wartość bazy danych (wiersz, kolumna) ma kontekst i odwzorowanie relacyjne w bazie danych. Relację tę można łatwo wyodrębnić i przeanalizować za pomocą narzędzi takich jak Jailer (na przykład). Z drugiej strony zmienna globalna jest nieco inna. Możesz znaleźć wszystkie zastosowania, ale nie byłbyś w stanie powiedzieć mi wszystkich sposobów, w jakie zmienna wchodzi w interakcje z resztą twojego świata.

  • Zmienne globalne są szybsze . Pobieranie czegoś z bazy danych wymaga nawiązania połączenia z bazą danych, wybierz opcję Uruchom, a następnie połączenie z bazą danych musi zostać zamknięte. Do tego dochodzą wszelkie potrzebne konwersje typu. Porównaj to z globalną dostępną w twoim kodzie.

To jedyne, o czym mogę teraz myśleć, ale jestem pewien, że jest ich więcej. Krótko mówiąc, są to dwie różne rzeczy i powinny być wykorzystywane do różnych celów .


0

Oczywiście globały nie zawsze są nieodpowiednie. Istnieją, ponieważ mają uzasadnione zastosowanie. Głównym problemem związanym z globalsami i głównym źródłem ostrzeżenia, aby ich unikać, jest to, że kod, który używa globalnego, jest dołączony do tego jednego i tylko jednego globalnego.

Rozważmy na przykład serwer HTTP przechowujący nazwę serwera.

Jeśli nazwa serwera jest przechowywana w globalnej, proces nie może jednocześnie uruchamiać logiki dla dwóch różnych nazw serwerów. Być może oryginalny projekt nigdy nie rozważał uruchomienia więcej niż jednej instancji serwera na raz, ale jeśli później zdecydujesz, że chcesz to zrobić, po prostu nie możesz, jeśli nazwa serwera jest globalna.

Natomiast jeśli nazwa serwera znajduje się w bazie danych, nie ma problemu. Możesz po prostu utworzyć jedną instancję tej bazy danych dla każdej instancji serwera HTTP. Ponieważ każda instancja serwera ma własną instancję bazy danych, może mieć własną nazwę serwera.

Tak więc główny sprzeciw wobec globałów, może istnieć tylko jedna wartość dla całego kodu, który uzyskuje dostęp do tego globalnego, nie dotyczy wpisów w bazie danych. Ten sam kod może łatwo uzyskać dostęp do różnych instancji bazy danych, które mają różne wartości dla konkretnego wpisu.


0

Myślę, że jest to interesujące pytanie, ale trudno jest na nie odpowiedzieć, ponieważ istnieją dwa główne problemy, które są łączone pod pojęciem „państwo globalne”. Pierwszym z nich jest koncepcja „globalnego połączenia”. Dowodem na to jest to, że alternatywą dla stanu globalnego jest wstrzykiwanie zależności. Chodzi o to, że DI niekoniecznie eliminuje stan globalny. Oznacza to, że absolutnie możliwe i powszechne jest wstrzykiwanie zależności od stanu globalnego. To, co robi DI, to usunięcie sprzężenia, które pochodzi ze zmiennych globalnych i powszechnie stosowanego wzorca Singleton. Oprócz nieco mniej oczywistej konstrukcji wyeliminowanie tego rodzaju sprzężenia ma bardzo niewielką wadę, a korzyści wynikające z wyeliminowania sprzężenia rosną wykładniczo wraz z liczbą zależności od tych globałów.

Innym aspektem tego jest stan współdzielony. Nie jestem pewien, czy istnieje naprawdę wyraźne rozróżnienie między stanem współdzielonym globalnie a stanem współdzielonym ogólnie, ale koszty i korzyści są znacznie bardziej zróżnicowane. Mówiąc wprost, istnieją niezliczone systemy oprogramowania, które wymagają współdzielenia, aby były użyteczne. Na przykład Bitcoin jest bardzo sprytnym sposobem dzielenia się stanem na całym świecie (dosłownie) w sposób zdecentralizowany. Prawidłowe udostępnianie stanu zmiennego bez tworzenia ogromnych wąskich gardeł jest trudne, ale przydatne. Więc jeśli tak naprawdę nie musisz tego robić, możesz uprościć aplikację, minimalizując współdzielony stan mutable.

Pytanie o to, w jaki sposób bazy danych różnią się od globali, jest również rozwidlone w tych dwóch aspektach. Czy wprowadzają sprzężenie? Tak, mogą, ale zależy to w dużej mierze od sposobu zaprojektowania aplikacji i projektu bazy danych. Jest zbyt wiele czynników, aby udzielić jednej odpowiedzi na pytanie, czy bazy danych wprowadzają globalne łączenie bez szczegółów projektu. Jeśli chodzi o to, czy wprowadzają współdzielenie stanu, to jest główny punkt bazy danych. Pytanie brzmi, czy robią to dobrze. Ponownie uważam, że jest to zbyt skomplikowane, aby odpowiedzieć bez wielu innych informacji, takich jak alternatywy i wiele innych kompromisów.


0

Pomyślałbym o tym nieco inaczej: zachowanie podobne do „zmiennej globalnej” jest ceną płaconą przez administratorów baz danych (DBA), ponieważ wykonywanie ich pracy jest złem koniecznym.

Problem ze zmiennymi globalnymi, jak wskazało kilka innych, nie jest arbitralny. Problem polega na tym, że ich użycie sprawia, że ​​zachowanie twojego programu jest coraz mniej przewidywalne, ponieważ trudniej jest ustalić, kto i w jaki sposób używa zmiennej. Jest to duży problem dla nowoczesnego oprogramowania, ponieważ nowoczesne oprogramowanie jest zwykle proszone o wiele elastycznych rzeczy. Może wykonywać miliardy, a nawet biliony skomplikowanych manipulacji stanem podczas przebiegu. Możliwość udowodnienia prawdziwych stwierdzeń dotyczących tego, co oprogramowanie zrobi w tych miliardach lub trylionach operacji, jest niezwykle cenna.

W przypadku nowoczesnego oprogramowania wszystkie nasze języki zapewniają narzędzia, które mogą w tym pomóc, takie jak enkapsulacja. Wybór, aby go nie używać, jest niepotrzebny, co prowadzi do mentalności „globals są złe”. W wielu regionach związanych z tworzeniem oprogramowania jedynymi osobami, które ich używają, są ludzie, którzy nie wiedzą, jak lepiej kodować. Oznacza to, że nie tylko bezpośrednio kłopoty, ale pośrednio sugerują, że programista nie wiedział, co robią. W innych regionach globale są całkowicie normalne (w szczególności oprogramowanie wbudowane uwielbia globały, częściowo dlatego, że dobrze współpracują z ISR). Jednak wśród wielu twórców oprogramowania są oni głosem mniejszości, więc jedynym głosem, który słyszysz, jest „globale są złe”.

Tworzenie baz danych jest jedną z takich sytuacji głosowych mniejszości. Narzędzia potrzebne do pracy z DBA są bardzo potężne, a ich teoria nie jest zakorzeniona w enkapsulacji. Aby wyciągnąć każdą odrobinę wydajności ze swoich baz danych, potrzebują pełnego, nieograniczonego dostępu do wszystkiego, podobnie jak globals. Posługuj się jedną z ich potężnych 100 milionów wierszy (lub więcej!) Baz danych, a docenisz, dlaczego ich silnik DB nie przechowuje żadnych ciosów.

Płacą za to cenę, droga cenę. DBA są zmuszone do patologii z dbałością o szczegóły, ponieważ ich narzędzia ich nie chronią. Najlepsze, jakie mają pod względem ochrony, to ACID lub klucze obce. Ci, którzy nie są patologiczni, znajdują się w kompletnym bałaganie tabel, który jest całkowicie bezużyteczny, a nawet uszkodzony.

Często zdarza się, że mamy pakiety oprogramowania na 100 000 linii. Teoretycznie każda linia w oprogramowaniu może wpływać na dowolną globalną w dowolnym momencie. W bazach danych nigdy nie można znaleźć 100 000 różnych zapytań, które mogą modyfikować bazę danych. Byłoby to nierozsądne, aby zachować dbałość o szczegóły potrzebne do ochrony przed sobą. Jeśli DBA ma coś takiego dużego, celowo obuduje swoją bazę danych za pomocą akcesorów, omijając problemy „globalne jak”, a następnie wykona tyle pracy, ile tylko możliwe, dzięki temu „bezpieczniejszemu” mechanizmowi. Tak więc, gdy przychodzi push, nawet ludzie bazy danych unikają globalizacji. Po prostu przychodzą z dużym niebezpieczeństwem i istnieją alternatywy, które są tak samo silne, ale nie tak niebezpieczne.

Czy wolisz chodzić po potłuczonym szkle, czy po ładnych chodnikach, jeśli wszystkie inne rzeczy są równe? Tak, możesz chodzić po stłuczonym szkle. Tak, niektórzy ludzie utrzymują się z tego. Ale nadal pozwól im zamiatać chodnik i iść dalej!


0

Myślę, że przesłanka jest fałszywa. Nie ma powodu, dla którego baza danych musi być „stanem globalnym”, a nie (bardzo dużym) obiektem kontekstowym. Jeśli wiążesz się z konkretną bazą danych, której używa Twój kod za pomocą zmiennych globalnych lub stałych parametrów połączenia z globalną bazą danych, nie różni się to ani nie jest mniej złe niż jakikolwiek inny stan globalny. Z drugiej strony, jeśli poprawnie przekażesz obiekt kontekstowy dla połączenia z bazą danych, jest to po prostu duży (i powszechnie używany) stan kontekstowy, a nie globalny.

Mierzenie różnicy jest łatwe: czy możesz uruchomić dwie instancje logiki programu, z których każda korzysta z własnej bazy danych, w jednym programie / procesie bez wprowadzania inwazyjnych zmian w kodzie? Jeśli tak, baza danych nie jest tak naprawdę „stanem globalnym”.


-2

Globale nie są złe; są po prostu narzędziem. NIEPRAWIDŁOWOŚĆ globali jest problematyczna, podobnie jak niewłaściwe użycie jakiejkolwiek innej funkcji programowania.

Moje ogólne zalecenie jest takie, aby globals stosować tylko w sytuacjach, które są dobrze zrozumiane i przemyślane, w których inne rozwiązania są mniej optymalne. Co najważniejsze, chcesz mieć pewność, że dobrze udokumentowałeś, gdzie ta globalna wartość może zostać zmodyfikowana, a jeśli korzystasz z wielowątkowości, masz pewność, że globalne i globale współzależne mają dostęp w sposób transakcyjny.


Czy niektórzy z downvoters mogliby wyjaśnić twoje opinie? Głosowanie bez uzasadnienia wydaje się niegrzeczne.
Byron Jones,

-2

Wzorzec tylko do odczytu i załóż, że dane nie są aktualne podczas drukowania. Kolejka zapisuje konflikty lub obsługuje je w inny sposób. Witaj w diabła diabła, używasz globalnej bazy danych.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.