私はちょうど この古い質問 に遭遇しただけで、グローバル状態について何が悪いのかを尋ね、トップ投票で受け入れられた回答は、他のコードがどこかにあるため、グローバル変数で動作するコードを信頼できないと主張しています他の人がやって来てその値を変更してから、データが異なるため、コードの動作がわかりません!しかし、私がそれを見て、私は仕方がありませんが、データベースに格納されているデータを操作することと何が違うので、それは本当に弱い説明だと思います。
プログラムがデータベースからのデータを処理しているとき、システムの他のコードがそれを変更しているかどうか、またはまったく別のプログラムがそれを変更しているかどうかは関係ありません。データが何であるかは気にしません。それがポイントです。重要なのは、コードが遭遇するデータを正しく処理することです。 (明らかに、私はここでキャッシュの厄介な問題についてつぶやいていますが、今のところそれは無視しましょう。)
ただし、作業しているデータが、データベース(またはユーザー入力、ネットワークソケット、ファイルなど)など、コードで制御できない外部ソースからのものであり、何も問題がない場合それで、コード内のグローバルデータはどのようになっていますか(プログラムはより高度な制御が可能です)。それは、誰も問題と見なさない完全に通常のものより明らかにはるかに悪い場合、どういうわけか悪いことですか?
最初に、あなたがリンクする答えはその特定の問題を誇張していること、そしてグローバルな状態の主な悪はそれが将来のシステムの動作を変更することを困難にする予測できない方法でカップリングを導入することであると私は言います。
しかし、この問題をさらに掘り下げてみると、一般的なオブジェクト指向アプリケーションのグローバルな状態とデータベースに保持されている状態には違いがあります。簡単に言うと、これらのうち最も重要なものは次のとおりです。
オブジェクト指向システムでは、オブジェクトが元のタイプのサブタイプである限り、オブジェクトを別のクラスのオブジェクトに置き換えることができます。これにより、dataだけでなくbehaviourを変更できます。
アプリケーションのグローバル状態は、通常、データベースが提供する強力な一貫性保証を提供しません。一貫性のある状態が表示されるトランザクションや、アトミックな更新などはありません。
さらに、データベースの状態を必要悪と見なすことができます。私たちのシステムからそれを排除することは不可能です。ただし、グローバルな状態は不要です。完全に排除できます。したがって、データベースの問題と同じくらい悪い場合でも、潜在的な問題のsomeを排除することができ、部分的な解決策は、解決策がないよりも優れています。
最初に、リンクした質問に対する受け入れられた回答に基づいて、グローバル変数の問題は何ですか?
非常に簡単に言うと、プログラムの状態を予測できなくなります。
ほとんどの場合、データベースはACIDに準拠しています。 ACIDは特に、データストアを予測不能または信頼できないものにする根本的な問題に対処します。
さらに、グローバルな状態はコードの読みやすさを損ないます。
これは、グローバル変数がその使用法から遠く離れたスコープに存在するためです。データベースを使用するときは、読み取るコード(またはそうする必要がある)に対してローカルなレコードセットまたはORMオブジェクトを使用しています。
データベースドライバーは通常、問題のドメインに関係なく同じデータにアクセスするための一貫性のある理解可能なインターフェイスを提供します。データベースからデータを取得すると、プログラムにはcopyのデータが含まれます。更新はアトミックです。自分で同期を追加しない限り、複数のスレッドまたはメソッドが原子性のない同じデータの一部を操作する可能性があるグローバル変数とは対照的です。データの更新は予測不可能であり、追跡するのが困難です。更新はインターリーブされる可能性があり、マルチスレッドデータの破損の沼地標準の教科書の例(インターリーブされた増分など)を引き起こします。
データベースは通常、最初はグローバル変数とは異なるデータをモデル化しますが、少しの間、データベースは最初からグローバル変数に関する多くの懸念を軽減するACID準拠のデータストアになるように設計されています。
私はいくつかの観察を提供します:
はい、データベースはグローバル状態です。
実際、あなたが指摘したように、それはスーパーグローバルな状態です。 universal!スコープは、データベースに接続するanythingまたはanyoneを伴います。そして、長年の経験を持つ多くの人々が、データの「奇妙なこと」が1つ以上の関連するアプリケーションで「予期しない動作」につながった方法についてのホラーストーリーを伝えることができると思います...
グローバル変数を使用した場合の潜在的な結果の1つは、2つの異なる「モジュール」が独自の異なる目的でその変数を使用することです。その点で、データベーステーブルも同じです。同じ問題の犠牲になる可能性があります。
うーん...ここにあるものです:
モジュールが外因的に何らかの方法で動作しない場合、何もしません。
有用なモジュールは、与えられたデータにすることも、見つけるデータにすることもできます。また、データを返すか、状態を変更できます。しかし、それが外界と何らかの形で相互作用しない場合は、何もしないこともあります。
今、私たちの好みはreceiveデータとreturnデータです。ほとんどのモジュールは、外部の世界が何をしているかをまったく無視して書くことができれば、簡単に書くことができます。しかし最終的には、何かはデータを見つけ、そしてその外部を変更する必要があります、グローバルな状態。
さらに、実際のアプリケーションでは、データが存在するため、various操作でデータを読み取り、更新できます。一部の問題は、ロックとトランザクションによって防止されます。ただし、これらの操作が互いに競合しないようにする原則、結局のところ、注意深い思考(そしてミスをする...)
ただし、通常、グローバル状態を直接処理していません。
アプリケーションが(SQLまたはその他の)データ層に存在しない限り、モジュールで動作するオブジェクトは、実際には共有グローバル状態のコピーです。 実際の共有状態に影響を与えることなく、必要なことを何でも実行できます。
そして、与えられたデータが変更されていないという前提の下で、そのグローバルな状態を変更する必要がある場合、通常、ローカルのグローバルと同じようなロックを実行できます。
そして最後に、データベースでは通常、私たちはmightいたずらなグローバルとは異なることをします。
いたずらで壊れたグローバルは次のようになります。
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.
}
}
そのようなインプロセス/運用にデータベースを使用することはありません。そして、それはデータベースの遅い性質と単純な変数の相対的な利便性が私たちを妨げているかもしれません:データベースとの私たちの遅くてぎこちない相互作用は、単にそれらの多くのためにそれらを悪い候補にします変数でこれまでに発生した間違い。
私は、次の基本的な主張に同意しません。
プログラムがデータベースからのデータを処理しているとき、システムの他のコードがそれを変更しているかどうか、またはまったく別のプログラムがそれを変更しているかどうかは関係ありません。
私の最初の考えは「すごい、ただすごい」だった。これを正確に回避するために多くの時間と労力が費やされ、各アプリケーションでどのようなトレードオフと妥協が機能するかが明らかにされます。それを無視することは災害のレシピです。
しかし、私は建築レベルでも同意します。グローバル変数は単にグローバルな状態ではありません。どこからでも透過的にアクセスできるグローバルな状態です。データベースを使用するのとは対照的に、データベースへのハンドルが必要です(グローバル変数にハンドルよりも格納する場合を除きます...)。
たとえば、グローバル変数を使用すると、次のようになります
int looks_ok_but_isnt() {
return global_int++;
}
int somewhere_else() {
...
int v = looks_ok_but_isnt();
...
}
しかし、データベースで同じことを行うには、そのことについてより明確にする必要があります
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);
...
}
データベースの1つは、明らかにデータベースを酷使しています。データベースを使用しない場合は、明示的な状態を使用でき、データベースの場合とほとんど同じように見えます。
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);
...
}
したがって、データベースを使用することは、グローバル変数を使用することよりも、明示的な状態を使用することに似ています。
状態がどこかで変更される可能性があるためにグローバル変数を信頼できない唯一の理由は、それ自体、それらを使用しない十分な理由ではないことには同意されます(ただし、それはかなり良い理由です!)。おそらく、答えは主に、変数のアクセスを、関係するコードの領域のみに制限するほうが理にかなっている使用法を説明していたと考えられます。
ただし、データベースは、いわば「グローバル」にアクセスすることを目的として設計されているため、別の問題です。
例えば:
最も重要なことですが、データベースはグローバル変数とは異なる目的を果たします。データベースは、大量の整理されたデータを格納および検索するためのもので、グローバル変数は特定のニッチ(正当な場合)に役立ちます。
しかし、それを見ると、データベースに格納されているデータを操作するのとどのように違うのか、それは本当に弱い説明だと思わざるを得ません。
または、対話型デバイス、ファイル、共有メモリなどでの作業とは異なります。実行するたびにまったく同じことを行うプログラムは、非常に退屈であり、役に立たないプログラムです。そう、それは弱い議論です。
私にとって、グローバル変数に関して違いをもたらす違いは、それらが隠された、保護されていないコミュニケーションのラインを形成することです。キーボードからの読み取りは非常に明白で保護されています。特定の関数を呼び出さなければならず、キーボードドライバーにアクセスできません。同じことは、ファイルアクセス、共有メモリ、および例のデータベースにも当てはまります。この関数がキーボードから読み取ること、その関数がファイルにアクセスすること、他のいくつかの関数が共有メモリにアクセスすること(そしてそれを保護する方がよい)、さらに他のいくつかの関数がデータベースにアクセスすることは、コードの読者には明らかです。
一方、グローバル変数では、まったく明らかではありません。 APIはfoo(this_argument, that_argument)
を呼び出すよう指示しています。グローバル変数_g_DangerWillRobinson
_をある値に設定する必要があるが、foo
を呼び出す前に(またはfoo
を呼び出した後に調べて)、呼び出しシーケンスには何もありません。
Googleでは、主にfoo(x)
がx
を変更することがコードの読者に明らかでないため、C++での非const参照引数の使用を禁止しました。これは、foo
が引数としての非定数参照。 (C#と比較してください。これは、関数定義と呼び出しサイトの両方がref
キーワードを使用して参照パラメーターを修飾する必要があることを示しています。)私はこれに関するGoogleの基準に同意しませんが、その点は理解しています。
コードは1回記述され、数回変更されますが、それが良ければ、何度も読み込まれます。隠された通信ラインは非常に悪いカルマです。 C++の非const参照は、コミュニケーションの小さな隠線を表しています。優れたAPIまたは優れたIDEは、「ああ!これは参照によって呼び出されます。
引用された説明は、推論が馬鹿げたものになるまで問題を単純化しすぎていると思います。もちろん、外部データベースの状態は、グローバルな状態に影響します。重要な質問は方法プログラムは(可変)グローバル状態に依存します。空白で文字列を分割するライブラリ関数がデータベースに格納されている中間結果に依存する場合、少なくとも同じ目的で使用されるグローバル文字配列に反対するのと同じくらい、この設計に反対します。一方、アプリケーションがこの時点でビジネスデータを格納するための本格的なDBMSを必要とせず、グローバルなメモリ内のキーと値の構造が必要であると判断した場合、これは必ずしも設計が悪い兆候ではありません。重要なのは、データを保存するためにどのソリューションを選択する場合でも、この選択はシステムのごく一部に分離されているため、ほとんどのコンポーネントは、展開用に選択されたソリューションにとらわれず、単体でテストされ、展開されます。ソリューションは、後で簡単に変更できます。
組み込みファームウェアで主に作業するソフトウェアエンジニアとして、私はほとんどの場合、モジュール間を移動するためにグローバル変数を使用しています。実際には、組み込みのベストプラクティスです。それらは静的に割り当てられるので、ヒープ/スタックを爆破するリスクはなく、関数の入り口/出口でのスタックの割り当て/クリーンアップにかかる余分な時間もありません。
これの欠点は、doがこれらの変数がどのように使用されるかを考慮する必要があることであり、その多くは、データベースラングリングに。変数の非同期の読み取り/書き込み[〜#〜] must [〜#〜]はアトミックである必要があります。複数の場所で変数を書き込むことができる場合は、常に有効なデータを書き込むようにする必要があります。そのため、前の書き込みが勝手に置き換えられることはありません(または任意の置き換えが安全です)。同じ変数が複数回読み取られる場合、変数が読み取り間で値を変更するとどうなるかを検討する必要があります。または、変数のコピーを最初に取得して、一貫した値を使用して処理が行われるようにする必要があります。その値は、処理中に古くなります。
(その最後の1つについては、航空機対策システムに取り組んでいる契約の最初の日に、非常に安全性に関連して、ソフトウェアチームは1週間ほど把握しようとしていたバグレポートを見ていました。開発ツールとコードのコピーをダウンロードするのに十分な時間があったので、「その変数を読み取りと更新の間に更新しないでください」と尋ねましたが、実際には答えがありませんでした。結局のところ、新しい人は知っていますか?それで、彼らがまだそれを話し合っている間に、私は変数をアトミックに読み取る保護コードを追加し、ローカルビルドを行い、基本的には「やあ、これを試してください」と言いました。 。:)
したがって、グローバル変数は明白に悪いことではありませんが、慎重に検討しなければ、さまざまな問題に直面する可能性があります。
判断する側面によっては、グローバル変数とデータベースアクセスは別の世界にある場合がありますが、依存関係として判断している限り、それらは同じです。
関数型プログラミングの純関数の定義を考えてみましょう。関数型プログラミングは、入力として受け取るパラメーターにのみ依存し、確定的な出力を生成する必要があると述べています。つまり、同じ引数のセットが2回与えられた場合、同じ結果を生成する必要があります。
関数がグローバル変数に依存している場合、同じセットまたは引数に対して、呼び出し間でグローバル変数の値が変更された可能性があるため、異なる出力が生成される可能性があるため、関数は純粋であるとは見なされなくなります。
ただし、グローバル変数を他の引数と同じように関数のインターフェイスの一部と見なすと、関数は確定的であると見なすことができるため、問題ではありません。問題は、これが私たちがいる瞬間まで隠されていることだけです 驚いた 一見明白な関数からの予期しない動作によって、その実装を読んで隠された依存関係。
この部分、グローバル変数が隠れた依存関係になる瞬間は、プログラマーが悪と見なすものです。これにより、コードの推論が困難になり、コードの動作を予測しにくくなり、再利用が困難になり、テストが困難になり、特に問題が発生したときにデバッグと修正の時間が増加します。
データベースへの依存関係を非表示にしても、同じことが起こります。データベースのクエリやコマンドを直接呼び出して関数やオブジェクトを作成し、これらの依存関係を隠して、グローバル変数とまったく同じ問題を引き起こすことができます。または、それらを明示的にすることもできます。これは、結局のところ、リポジトリパターン、データストア、ゲートウェイなど、多くの名前で行われるベストプラクティスと見なされています。
PS:同時実行性が関係しているかどうかなど、この比較にとって重要な他の側面がありますが、その点はここの他の回答でカバーされています。
さて、歴史的な点から始めましょう。
アセンブリとCの典型的な組み合わせで記述された古いアプリケーションを使用しています。関数はありません手順だけです。プロシージャから引数または戻り値を渡す場合は、グローバル変数を使用します。言うまでもありませんが、これを追跡することは非常に難しく、一般に、すべてのプロシージャはすべてのグローバル変数で必要なことをすべて実行できます。当然のことながら、人々は、可能であればすぐに引数と戻り値を別の方法で渡すようになりました(そうしないことがパフォーマンスクリティカルでない限り-ビルドエンジン(Duke 3D)のソースコードを確認するなど)。グローバル変数の憎しみがここで生まれました。各プロシージャがどのグローバル状態のどの部分を読み取り、変更するのかほとんど理解できず、プロシージャコールを安全にネストすることができませんでした。
これは、グローバル変数のヘイトが過去のものであることを意味しますか?結構です。
最初に、私が現在取り組んでいるプロジェクトで引数を渡すためにまったく同じアプローチを見たことがあることを言及する必要があります。 C#で2つの参照型インスタンスを渡す場合(約10年前のプロジェクト)。このようにする理由は文字通りありません。おそらく、貨物養殖か、C#の動作に関する完全な誤解から生まれたと考えられます。
より大きなポイントは、グローバル変数を追加することにより、そのグローバル変数にアクセスできるすべてのコードのスコープを拡大することです。 「メソッドを短くしておく」などの推奨事項をすべて覚えていますか? 600のグローバル変数がある場合(ここでも、実際の例:/)、すべてのメソッドスコープはそれらの600のグローバル変数によって暗黙的に展開され、誰が何にアクセスできるかを追跡する簡単な方法はありません。
間違った場合(通常の方法:))、グローバル変数は互いに結合している可能性があります。しかし、それらがどのように結合されているかはわかりません。また、グローバルな状態が常に一貫していることを保証するメカニズムもありません。重要なセクションを導入して一貫性を維持しようとしても、適切なACIDデータベースとの比較が不十分であることがわかります。
これらの問題を解決することは可能ですか?あんまり。これを処理するにはカプセル化が必要です。正しいことをするのは難しく、ソフトウェア開発を成功させるための一般的なレシピとしては、あまり良くありません:)
スコープが小さいほど、コードの理由がわかりやすくなります。グローバル変数を使用すると、最も単純なコードの断片でさえ、膨大な範囲のスコープを含めることができます。
もちろん、これはグローバルスコーピングが悪であることを意味するものではありません。これは、最初の解決策ではありません。「実装が簡単で、保守が難しい」という典型的な例です。
グローバル変数はツールであり、善にも悪にも使用できます。
データベースはツールであり、善と悪のために使用できます。
元のポスターに記されているように、違いはそれほど大きくありません。
経験の浅い学生は、バグは他の人に起こるものだと思っていることがよくあります。教師は、悪い設計にペナルティを科すための単純化された理由として「グローバル変数は悪」を使用します。 100行のプログラムにバグがないという理由だけで、同じ方法を10000行のプログラムに使用できることを学生が理解していないことは一般的です。
データベースを操作するとき、それがプログラムの目的であるため、グローバル状態を禁止することはできません。代わりに、ACIDや通常のフォームなどの詳細ガイドラインが表示されます。
人々がグローバル変数にACIDアプローチを使用したとしても、それほど悪くはありません。
一方、データベースの設計が悪ければ、悪夢になる可能性があります。
他の回答のいくつかは、データベースを使用することがなぜ良いのかを説明しようとしています。彼らは間違ってる!データベースはグローバルな状態であり、シングルトンやグローバル変数と同じくらい悪です。ローカルマップまたは配列を簡単に使用できるのに、データベースを使用するのは間違いです。
グローバル変数は、悪用のリスクを伴うグローバルアクセスを許可します。グローバル変数にも利点があります。グローバル変数は一般に、避けるべきものであると言われていますnot決して使用すべきではないものです。それらを簡単に回避できる場合は、回避する必要があります。しかし、利点が欠点を上回る場合は、もちろんそれらを使用する必要があります!*
まったく同じこと**は、グローバル変数と同様に、グローバル状態のデータベースにも当てはまります。データベースにアクセスせずに実行でき、結果のロジックが必要なすべてを実行し、同様に複雑である場合、データベースを使用すると、対応する利点なしにプロジェクトのリスクが増加します。
実際には、多くのアプリケーションは設計によりグローバル状態を必要とし、時には永続的なグローバル状態さえも必要とします-それが私たちがファイルやデータベースなどを持っている理由です。
*ここでの例外は学生です。学生がグローバル変数を使用することを禁止することは理にかなっているので、学生は代替案を学ぶ必要があります。
**一部の回答は、データベースが他の形式のグローバル状態よりも何らかの形で保護されていると誤って主張しています(問題は、グローバル変数だけではなく、明示的にグローバル状態についてです)。それはボロックです。データベースシナリオで提供される主要な保護は慣例によるものであり、他のグローバルな状態でもまったく同じです。ほとんどの言語では、const
の形式で、グローバルな状態に対する多くの追加の保護も許可されています。クラスは、コンストラクターで設定された後に状態を変更することを許可しないか、スレッド情報を取得できるゲッターとセッターです。またはプログラムの状態を考慮に入れてください。
私にとって、第一の悪はグローバルには同時実行性の問題に対する保護がないことです。グローバルでこのような問題を処理するメカニズムを追加できますが、同時実行性の問題を解決すればするほど、グローバルがデータベースを模倣し始めることがわかります。二次的な悪は使用の契約ではありません。
ある意味では、グローバル変数とデータベースの違いは、オブジェクトのプライベートメンバーとパブリックメンバーの違いに似ています(だれでもまだパブリックフィールドを使用していると想定しています)。プログラム全体をオブジェクトとして考える場合、グローバルはプライベート変数であり、データベースはパブリックフィールドです。
ここでの重要な違いは、責任の1つです。
オブジェクトを作成する場合、メンバーメソッドを管理するすべてのユーザーがプライベートフィールドが適切に動作することを保証するものと想定されています。しかし、あなたはすでに公共の場の状態についての仮定をあきらめ、それらを特に注意して扱います。
同じ仮定は、グローバル対データベースに、より広いレベルで適用されます。また、プログラミング言語/エコシステムは、プライベートv/sパブリックへのアクセス制限を、(非共有メモリ)グローバルv/sデータベースに適用するのと同じように保証します。
マルチスレッドが機能するようになると、プライベートv/sパブリックv/sグローバルv/sデータベースの概念は、スペクトルの違いにすぎません。
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
}
}
}
データベースcanはグローバルな状態ですが、常にそうである必要はありません。あなたがコントロールできないという仮定には同意しません。これを管理する1つの方法は、ロックとセキュリティです。これは、レコード、テーブル、またはデータベース全体で実行できます。別のアプローチは、データが古くなっている場合にレコードの変更を防止する、ある種のバージョンフィールドを持つことです。
グローバル変数と同様に、データベースの値は、ロックが解除されると変更できますが、アクセスを制御する方法はたくさんあります(すべての開発者に、データの変更が許可されているアカウントへのパスワードを与えないでください)。アクセスが制限されている変数がある場合、それはあまりグローバルではありません。
もちろん、グローバルは常に不適切であるとは限りません。それらは合法的な使用があるために存在します。グローバルの主な問題、およびそれらを回避するための警告の主な原因は、グローバルを使用するコードがその唯一のグローバルにアタッチされていることです。
たとえば、サーバー名を格納するHTTPサーバーを考えてみます。
サーバー名をグローバルに格納する場合、プロセスは2つの異なるサーバー名のロジックを同時に実行できません。おそらく、元の設計では一度に複数のサーバーインスタンスを実行することは考えていませんでしたが、後でそれを実行したい場合は、サーバー名がグローバルであるかどうかは簡単にはわかりません。
対照的に、サーバー名がデータベース内にある場合、問題はありません。 HTTPサーバーのインスタンスごとに、そのデータベースのインスタンスを1つ作成するだけです。サーバーの各インスタンスには、データベースの独自のインスタンスがあるため、独自のサーバー名を持つことができます。
したがって、グローバルに対する主な異論は、そのグローバルにアクセスするすべてのコードに対して1つの値のみが存在する可能性があり、データベースエントリには適用されません。同じコードで、特定のエントリに対して異なる値を持つ個別のデータベースインスタンスに簡単にアクセスできます。
その前提は間違っていると思います。データベースが(非常に大きな)コンテキストオブジェクトではなく、「グローバル状態」である必要がある理由はありません。コードがグローバル変数または固定されたグローバルデータベース接続パラメーターを介して使用している特定のデータベースにバインドしている場合、他のグローバル状態と何ら変わりはなく、悪も少なくありません。一方、データベース接続のコンテキストオブジェクトを適切に渡す場合、それはグローバルな状態ではなく、単に(広く使用されている)大きなコンテキスト状態です。
違いを測定するのは簡単です。プログラムロジックの2つのインスタンスを、それぞれ独自のデータベースを使用して、コードに侵襲的な変更を加えることなく、単一のプログラム/プロセスで実行できますか?その場合、データベースは実際には「グローバルな状態」ではありません。
これは興味深い質問だと思いますが、「グローバルステート」という用語の下で混乱している2つの主要な問題があるため、答えるのは少し難しいです。 1つは「グローバルカップリング」の概念です。それの証拠は、グローバルな状態に与えられる代替案が依存性注入であることです。問題は、DIが必ずしもグローバルな状態を排除するわけではないということです。つまり、グローバルな状態への依存関係を注入することは絶対に可能であり、一般的です。 DIが行うことは、グローバル変数と一般的に使用されるシングルトンパターンに付属する結合を削除することです。やや目立たない設計は別として、この種の結合を排除することの欠点はほとんどなく、結合を排除することの利点は、これらのグローバルへの依存関係の数とともに指数関数的に増加します。
これのもう1つの側面は共有状態です。グローバルに共有されている状態と一般的に共有されている状態の間に本当に明確な違いがあるかどうかはわかりませんが、コストとメリットははるかに微妙です。簡単に言えば、共有状態が有用であることを必要とする無数のソフトウェアシステムがあります。たとえばビットコインは、分散された方法で状態をグローバルに(文字通り)共有する非常に賢い方法です。巨大なボトルネックを作成せずに変更可能な状態を適切に共有することは困難ですが、便利です。したがって、実際に行う必要がない場合は、共有されている変更可能な状態を最小限に抑えることで、アプリケーションを簡略化できます。
したがって、データベースがグローバルとどのように異なるかという問題も、これら2つの側面に分かれています。彼らはカップリングを導入していますか?はい、可能ですが、アプリケーションの設計方法とデータベースの設計方法に大きく依存します。データベースが設計の詳細なしにグローバルカップリングを導入するかどうかについて単一の回答を得るには、要素が多すぎます。彼らが状態の共有を導入するかどうかに関しては、まあ、それは一種のデータベースの要点です。問題は、彼らがうまくやっているかどうかです。繰り返しますが、これは複雑すぎて、代替案や他の多くのトレードオフなど、他の多くの情報がないと答えられないと思います。
「グローバル変数」のような振る舞いは、データベース管理者(DBA)が支払う仕事です。
他のいくつかが指摘したように、グローバル変数の問題は恣意的なものではありません。問題は、それらを使用すると、だれがどのように変数を使用しているかを判別することが難しくなるため、プログラムの動作がますます予測不可能になることです。現代のソフトウェアは多くの柔軟な多くのことを行うように通常要求されるので、これは現代のソフトウェアにとって大きな問題です。実行中に数十億または数兆にも及ぶ複雑な状態操作を行う場合があります。そのソフトウェアが数十億または数兆の運用で何をするかについて真の声明を証明する能力は非常に価値があります。
最新のソフトウェアの場合、すべての言語は、カプセル化など、これを支援するツールを提供します。それを使用しないという選択は不必要であり、それは「グローバルは悪である」という考え方につながります。ソフトウェア開発分野の多くの地域では、それらを使用する唯一の人々は、より良いコーディング方法を知らない人々です。これは、彼らが直接問題を抱えているだけでなく、間接的に、開発者が何をしているか知らなかったことを示唆しています。他の地域では、グローバルは完全に正常です(特に、埋め込みソフトウェアは、ISRでうまく機能するため、グローバルが大好きです)。ただし、多くのソフトウェア開発者がいる中で、それらは少数派の声であるため、聞こえる唯一の声は「グローバルは悪い」です。
データベース開発は、そのような少数派の声の状況の1つです。 DBAの作業に必要なツールは非常に強力であり、その理論はnotカプセル化に根ざしています。データベースからあらゆるパフォーマンスのJiffyを取り出すには、グローバルと同様に、すべてに自由にアクセスできる必要があります。彼らの1億行(またはそれ以上)の怪しいデータベースの1つを振るうと、DBエンジンにパンチを保持させない理由がわかります。
彼らはその代価を、愛する代価を払っています。 DBAは、そのツールでは保護できないため、細部に注意を払うことでほぼ病理学を強いられます。保護の方法で最も優れているのは、ACIDまたは外部キーです。病理的でないものは、完全に使用できない、または破損している完全なテーブルのmessで自分自身を見つけます。
100kラインのソフトウェアパッケージを使用することは珍しくありません。理論的には、ソフトウェアのどのラインも、いつでもグローバルに影響を与える可能性があります。 DBAでは、データベースを変更できる100kの異なるクエリを見つけることはありません。自分から身を守るために必要な細部に注意を払って維持するのは無理でしょう。 DBAがそのような大きなものを持っている場合、彼らは意図的にアクセサを使用してデータベースをカプセル化し、「グローバルな」問題を回避し、その「安全な」メカニズムを通じて可能な限り多くの作業を行います。したがって、Pushが駆り立てると、データベースの人々でさえグローバルを回避します。それらは単にたくさんの危険を伴います、そしてjustと同じくらい強いが、それほど危険ではない代替があります。
他のすべてのものが同じであれば、壊れたガラスの上を歩き回るか、きれいに掃除された歩道の上を歩きますか?はい、割れたガラスの上を歩くことができます。はい、一部の人々はそれをやって生計を立てています。しかし、それでも、彼らに歩道を掃除させて先に進みましょう!
いくつかの違いがあります:
データベースの値canはその場で変更できます。一方、コードで設定されているグローバルの値は、アプリケーションを再デプロイしてコードを変更しない限り、cannotを変更できます。実際、これは意図的なものです。データベースは、時間の経過とともに変化する可能性のある値用ですが、グローバル変数はonlyが変化しないものおよびである必要があります。実際のデータは含まれていません。
データベース値(行、列)には、データベース内にコンテキストとリレーショナルマッピングがあります。この関係は、Jailerなどのツールを使用して簡単に抽出および分析できます。一方、グローバル変数は少し異なります。すべての使用法を見つけることができますが、all変数が他の世界と相互作用する方法を私に教えるのは不可能でしょう。
グローバル変数はfasterです。データベースから何かを取得するには、データベース接続を確立し、select to meを実行してから、データベース接続を閉じる必要があります。あなたが必要とするかもしれないどんなタイプ変換もその上に来ます。コードでアクセスされているグローバルと比較してください。
今考えられるのはこれらだけですが、まだまだあると思います。簡単に言えば、それらは2つの異なるものであり、異なる目的に使用する必要がありますです。