web-dev-qa-db-ja.com

なぜグローバルステートはそんなに悪いのですか?

これを始める前に、抽象化と依存性注入の概念をよく知っているとしましょう。ここで目を開ける必要はありません。

まあ、私たちのほとんどは、(あまりにも)本当に理解せずに「グローバル変数を使用しないでください」または「シングルトンはグローバルであるため、悪である」と何度も言います。しかし、本当に不吉なグローバル状態についてisは何が悪いのでしょうか?

たとえば、システムフォルダーのパスやアプリケーション全体のデータベース資格情報など、アプリケーションのグローバル構成が必要だとします。

その場合、これらの設定をアプリケーション全体で一般的に利用できる、ある種のグローバルスペースで提供する以外に、良い解決策はありません。

虐待それは悪いことですが、グローバルスペースは本当に[〜#〜] that [〜#〜]悪ですか?もしそうなら、どんな良い代替案がありますか?

353
Madara's Ghost

非常に簡単に言うと、プログラムの状態を予測できなくなります。

詳しく説明すると、同じグローバル変数を使用するオブジェクトが2つあるとします。いずれかのモジュール内でランダム性のソースを使用していない場合、メソッドを実行する前にシステムの状態がわかっていれば、特定のメソッドの出力を予測(したがってテスト)できます。

ただし、いずれかのオブジェクトのメソッドが、共有グローバル状態の値を変更する副作用を引き起こした場合、もう一方のオブジェクトでメソッドを実行すると、開始状態がわかりません。メソッドを実行したときにどのような出力が得られるかを予測できなくなったため、テストすることはできません。

学術レベルでは、これはそれほど深刻に聞こえないかもしれませんが、コードを単体テストできることは、その正しさ(または少なくとも目的への適合性)を証明するプロセスの主要なステップです。

現実の世界では、これはいくつかの非常に深刻な結果をもたらす可能性があります。グローバルデータ構造にデータを入力する1つのクラスと、そのデータ構造のデータを使用し、その状態を変更するか、プロセスでデータを破棄する別のクラスがあるとします。 populatorクラスが完了する前にプロセッサクラスがメソッドを実行すると、その結果、プロセッサクラスは処理するデータが不完全になる可能性があり、populatorクラスが処理していたデータ構造が破損または破壊される可能性があります。これらの状況でのプログラムの動作は完全に予測不可能になり、おそらく壮大な損失につながります。

さらに、グローバルな状態はコードの読みやすさを損ないます。コードに明示的に導入されていない外部依存関係がコードにある場合、コードの保守を担当する人は誰でも、コードの出所を見つけるためにコードを探しに行く必要があります。

どのような選択肢が存在するかについては、グローバル状態をまったく持たないことは不可能ですが、実際には、通常、グローバル状態を、他のすべてをラップする単一のオブジェクトに制限することが可能であり、スコープルールに依存して参照することはできません使用している言語の特定のオブジェクトに特定の状態が必要な場合は、コンストラクターに引数として渡すか、セッターメソッドで明示的に要求する必要があります。これは、依存性注入と呼ばれます。

使用している言語のスコープルールにより、すでにアクセスできる状態で渡すのはばかげているように見えるかもしれませんが、その利点は非常に大きいです。誰かがコードを分離して見れば、それが必要とする状態とそれがどこから来るのかは明らかです。また、コードモジュールの柔軟性、したがってさまざまなコンテキストで再利用する機会に関して、大きなメリットがあります。状態が渡され、状態への変更がコードブロックに対してローカルである場合、任意の状態を渡し(それが正しいデータ型である場合)、コードで処理できます。このスタイルで記述されたコードは、簡単に交換できる緩く関連付けられたコンポーネントのコレクションのように見える傾向があります。モジュールのコードは、どのようにそれを処理するかだけで、状態がどこから来るのかを気にする必要はありません。状態をコードブロックに渡す場合、そのコードブロックは分離して存在できますが、グローバル状態に依存している場合はそうではありません。

他の多くの理由があり、国家の通過が地球規模の国家に依存するよりもはるかに優れている理由はたくさんあります。この答えは決して包括的なものではありません。なぜグローバルな状態が悪いのかについての本全体を書くことができるでしょう。

293
GordonM

可変グローバル状態は多くの理由で悪です。

  • 可変グローバル状態からのバグ-多くのトリッキーなバグは、可変性によって引き起こされます。プログラムのどこからでも突然変異によって引き起こされる可能性のあるバグは、正確な原因を追跡することがしばしば困難であるため、さらに厄介です
  • 貧弱なテスト可能性-変更可能なグローバル状態がある場合は、作成するすべてのテストに対してそれを構成する必要があります。これはテストを難しくします(そして、人々である人々はそれゆえそれを行う可能性が低くなります!)。例えばアプリケーション全体のデータベース資格情報の場合、1つのテストが他のすべてとは異なる特定のテストデータベースにアクセスする必要がある場合はどうなりますか?
  • 非柔軟性-コードの一部にグローバル状態で1つの値が必要だが、別の部分に別の値(トランザクション中の一時的な値など)が必要な場合はどうなりますか?あなたは突然あなたの手に嫌なリファクタリングをしました
  • 関数の不純-「純粋な」関数(つまり、結果が入力パラメーターのみに依存し、副作用がない関数)は、より大きなプログラムを推論して作成するのがはるかに簡単です。変更可能なグローバル状態を読み取るまたは操作する関数は本質的に不純です。
  • コード内包-多くの可変グローバル変数に依存するコードの動作は、理解するのがはるかに困難です-コードの動作について推論する前に、グローバル変数との可能な相互作用の範囲を理解する必要があります。場合によっては、この問題は扱いにくくなることがあります。
  • 同時実行の問題-変更可能なグローバル状態は、通常、同時状況で使用するときに何らかの形式のロックを必要とします。これは正しく行うのが非常に難しく(バグの原因です)、コードがかなり複雑になります(維持するのが難しい/コストがかかります)。
  • パフォーマンス-同じグローバル状態で複数のスレッドが継続的にbashを実行すると、キャッシュの競合が発生し、システム全体の速度が低下します。

変更可能なグローバル状態の代替:

  • 関数パラメーター-見過ごされがちですが、関数をより適切にパラメーター化することは、グローバルな状態を回避するための最良の方法です。それはあなたに重要な概念的な質問を解決することを強います:この機能がその仕事をするためにどんな情報が必要とするか?すべての関連情報をラップする一連の関数に渡すことができる「コンテキスト」と呼ばれるデータ構造を持つことは、意味がある場合があります。
  • 依存性注入-関数パラメーターの場合と同じですが、少し前に行われます(関数の呼び出しではなくオブジェクトの構築時)。ただし、依存関係が可変オブジェクトである場合は注意してください。これにより、可変グローバル状態と同じ問題がすぐに発生する可能性があります。
  • 不変のグローバル状態はほとんど無害です-事実上定数です。しかし、それが本当に一定であり、後でそれを変更可能なグローバル状態に変えたくならないようにしてください!
  • Immutable singletons-インスタンス化が必要になるまでインスタンス化を延期できることを除いて、不変のグローバル状態とほとんど同じです。たとえば、高価な1回限りの事前計算を必要とする大きな固定データ構造。ミュータブルなシングルトンはもちろんミュータブルなグローバル状態と同等であり、したがって邪悪です:-)
  • 動的バインディング-Common LISP/Clojureなどの一部の言語でのみ使用できますが、これにより、他のスレッドに影響を与えない(通常はスレッドローカルベースで)制御されたスコープ内で値を効率的にバインドできます。現在の実行スレッドのみが影響を受けることがわかっているので、これはある程度、グローバル変数と同じ効果を得る「安全な」方法です。これは、たとえば、それぞれが独立したトランザクションを処理する複数のスレッドがある場合に特に役立ちます。
140
mikera
  1. いまいましいアプリ全体がそれを使用している可能性があるため、それらを再び分解することは常に非常に困難です。グローバルを変更する場合は、すべてのコードを変更する必要があります。これは、単純に型名をgrepにして、どの関数がそれを使用しているかを見つけることができるよりもはるかに保守上の悩みです。
  2. マルチスレッドを破壊する隠された依存関係を導入するため、それらは悪いです。
  3. グローバル変数の状態は常に完全に信頼できません。これは、すべてのコードがそれに何かをする可能性があるためです。
  4. テストは本当に難しいです。
  5. それらはAPIの呼び出しを困難にします。 「APIを呼び出す前にSET_MAGIC_VARIABLE()を呼び出すことを覚えておく必要があります」とは、誰かがそれを呼び出すのを忘れた場合の乞食です。 APIを使用するとエラーが発生しやすくなり、見つけにくいバグが発生します。これを通常のパラメーターとして使用することにより、呼び出し元に値を適切に提供させることができます。

参照を必要とする関数に参照を渡すだけです。それほど難しくありません。

62
DeadMG

「状態」と言った場合、通常は「変更可能な状態」を意味します。そして、グローバルな変更可能な状態は完全に悪です。なぜなら、それはプログラムの任意の部分が他の部分に影響を与える可能性がある(グローバル状態を変更することによって)だからです。

未知のプログラムのデバッグを想像してみてください。関数Aは特定の入力パラメーターに対して特定の動作をしますが、同じパラメーターに対しては動作が異なる場合があります。グローバル変数xを使用していることがわかります。

xを変更する場所を探し、それを変更する場所が5つあることを確認します。次に、関数Aがどのような場合に何を行うかを確認してください。

34
sleske

あなたは自分の質問に答えました。それらは「乱用」されると管理するのが困難ですが、それらを封じ込める方法を知っている人が適切に使用されると、有用であり、[ある程度]予測できます。グローバルのメンテナンスやグローバルへの変更は、通常、悪夢であり、アプリケーションのサイズが大きくなるにつれて悪化します。

グローバルが唯一のオプションであり、簡単な修正であるという違いを理解できる経験豊富なプログラマcanを使用すると、問題が最小限になります。しかし、それらの使用に伴って発生する可能性のある無限の可能性のある問題は、それらの使用に対するアドバイスを必要とします。

編集:私の意味を明確にするために、グローバルは本質的に予測不可能です。予測不能なものと同様に、予測不能性を抑えるための対策を講じることができますが、実行できることには常に制限があります。これに加えて、比較的未知の変数を処理する必要があるプロジェクトに参加する新しい開発者の面倒、グローバルの使用に対する推奨事項は理解できるはずです。

9
orourkek

シングルトンには多くの問題があります-私の頭の中で2つの最大の問題があります。

  • 単体テストは問題になります。グローバルな状態は、あるテストから次のテストへと汚染される可能性があります

  • 「1つだけ」というハードルールを適用します。これは、変更できなかったとしても、突然適用されます。次に、グローバルにアクセス可能なオブジェクトを使用したユーティリティコード全体を変更する必要があります。

そうは言っても、ほとんどのシステムにはビッググローバルオブジェクトが必要です。これらは、大きくて高価なアイテム(例:データベース接続マネージャー)、または広範囲にわたる状態情報(ロック情報など)を保持するアイテムです。

シングルトンの代わりに、起動時にこれらのビッググローバルオブジェクトを作成し、このオブジェクトにアクセスする必要のあるすべてのクラスまたはメソッドにパラメーターとして渡すことができます。

ここでの問題は、あなたが「小包を渡す」という大きなゲームに終わることです。コンポーネントとその依存関係のグラフがあり、一部のクラスは他のクラスを作成し、生成されたコンポーネント(または生成されたコンポーネントのコンポーネント)がそれらを必要とするために、それぞれが一連の依存関係コンポーネントを保持する必要があります。

新しいメンテナンスの問題が発生します。例:突然、「WidgetFactory」コンポーネントのグラフの奥に、モックアウトしたいタイマーオブジェクトが必要になります。ただし、「WidgetFactory」は「WidgetCreationManager」の一部である「WidgetBuilder」によって作成され、1つだけが実際に使用する場合でも、このタイマーオブジェクトを認識する3つのクラスが必要です。あなたは自分をあきらめてシングルトンに戻したいと思っていることに気づき、このタイマーオブジェクトをグローバルにアクセス可能にするだけです。

幸いなことに、これはまさに依存性注入フレームワークによって解決される問題です。作成する必要のあるクラスをフレームワークに伝えるだけで、リフレクションを使用して依存関係グラフがわかり、必要なときに各オブジェクトが自動的に構築されます。

したがって、要約すると、シングルトンは不適切であり、代替案は依存性注入フレームワークを使用することです。

キャッスルウィンザーをたまたま使用しましたが、あなたは選択の自由を失います。利用可能なフレームワークのリストについては、2008年から このページ を参照してください。

9
Andrew Shepherd

まず最初に、依存性注入が「ステートフル」であるためには、シングルトンを使用する必要があるため、これが何らかの形で代替案であると言っている人々は誤っています。人々は常にグローバルコンテキストオブジェクトを使用しています...たとえば、セッションステートでさえ、本質的にグローバル変数です。依存性注入によるかどうかに関係なくすべてを渡すことが常に最良の解決策とは限りません。現在、大量のグローバルコンテキストオブジェクト(IoCコンテナーを介して挿入されたシングルトン)を使用する非常に大規模なアプリケーションで作業しており、デバッグが問題になることはありません。特にイベントドリブンアーキテクチャでは、変更されたものを渡すのではなく、グローバルコンテキストオブジェクトを使用することが推奨されます。あなたが尋ねる人に依存します。

あらゆるものが悪用される可能性があり、それはアプリケーションのタイプにも依存します。たとえば、Webアプリで静的変数を使用することは、デスクトップアプリとはまったく異なります。グローバル変数を回避できる場合は、そうする必要がありますが、場合によっては、それらの用途があります。少なくとも、グローバルデータが明確なコンテキストオブジェクトに含まれていることを確認してください。デバッグに関する限り、コールスタックと一部のブレークポイントは解決できません。

グローバル変数を盲目的に使用することは悪い考えであることを強調したいと思います。関数は再利用可能である必要があり、データがどこから取得されるかを気にする必要はありません。グローバル変数を参照すると、関数が特定のデータ入力に結合されます。これが渡される必要がある理由であり、依存関係の注入が役立つ理由ですが、(シングルトンを介して)集中化されたコンテキストストアを処理しています。

ところで、一部の人々は、Linqの作成者を含め、依存性注入は悪いと思っていますが、それでも、私を含め、人々がそれを使用するのを妨げるものではありません。最終的に経験はあなたの最高の教師になります。ルールに従う時とそれらを破る時があります。

8

ここで他のいくつかの答えはmutableimmutableglobalを区別するため状態、私はevenimmutableglobal variables/settings is an ananyanceであると主張します。

質問について考えてみましょう:

...たとえば、システムフォルダーのパスやアプリケーション全体のデータベース資格情報など、アプリケーションのグローバル構成が必要だとします。 ...

そう、小さなプログラムの場合、これはおそらく問題ではありませんが、少し大きい大きなシステムのコンポーネントでこれを行うとすぐに、自動化された書き込みすべてのテスト(同じプロセス内で実行される)が同じグローバル構成値で動作する必要があるため、テストは突然難しくなります。

すべての構成データが明示的に渡される場合、コンポーネントのテストがはるかに簡単になり、複数のテストのグローバル構成値bootstrapを並列で行う方法を心配する必要はありません。

5
Martin Ba

なぜグローバルステートはそんなに悪いのですか?

Mutableグローバル状態は悪です。なぜなら、私たちの脳が一度に複数のパラメーターを考慮に入れ、それらをタイミングの観点と値の観点の両方から組み合わせて何かに影響を与える方法を理解するのは非常に難しいためです。

したがって、プログラムの実行中に変更される外部の理由がいくつかあるオブジェクトのデバッグまたはテストは、非常に困難です。何十ものこれらのオブジェクトをまとめて考える必要がある場合はもちろんです。

3
guillaume31

実際のアプリケーションでは、状態は避けられません。好きなようにまとめることができますが、スプレッドシートにはセル内のデータが含まれている必要があります。インターフェースとしての機能のみでセルオブジェクトを作成できますが、セルのメソッドを呼び出してデータを変更できる場所の数は制限されません。オブジェクト階層全体を構築してインターフェースを非表示にしようとすると、コードの他の部分できないデフォルトでデータを変更できます。それは、それを含むオブジェクトへの参照が勝手に渡されるのを防ぎません。また、それだけでは同時実行性の問題が解消されません。データへのアクセスを拡大することは困難になりますが、実際にはグローバルで認識されている問題が解消されるわけではありません。誰かが状態の一部を変更したい場合、グローバルな状態または複雑なAPIを介してそれを実行します(後者は阻止せず、阻止するだけです)。

グローバルストレージを使用しない本当の理由は、名前の衝突を避けるためです。同じグローバル名を宣言する複数のモジュールをロードする場合、未定義の動作(単体テストがパスするためデバッグが非常に難しい)またはリンカーエラー(C-リンカーが警告するか、これで失敗するのでしょうか?).

コードを再利用したい場合は、別の場所からモジュールを取得し、同じ名前のモジュールを使用しているために誤ってグローバルに踏まないようにする必要があります。または、幸運でエラーが発生した場合、コードの1つのセクションのすべての参照を変更して衝突を防ぐ必要はありません。

3
phkahler

安全で堅牢なシステム設計のために設計された言語は、グローバルmutable状態を完全に取り除くことがよくあります。 (おそらく、これはグローバルがないことを意味します。不変オブジェクトはある意味で、状態遷移を持たないため、実際にはステートフルではありません。)

Joe-E は1つの例であり、David Wagnerがその決定を次のように説明しています。

オブジェクトにアクセスできる人の分析と最小特権の原則は、機能がグローバル変数に格納されている場合、両方とも破壊され、プログラムのどの部分でも読み取り可能になる可能性があります。オブジェクトがグローバルに利用可能になると、分析の範囲を制限することはできなくなります。オブジェクトへのアクセスは、プログラム内のどのコードからも差し控えることができない特権です。 Joe-Eは、グローバルスコープに機能がなく、不変のデータのみが含まれていることを確認することで、これらの問題を回避します。

それについて考える一つの方法は

  1. プログラミングは分散推論の問題です。大規模なプロジェクトのプログラマは、プログラムをいくつかの部分に分割する必要があります。
  2. スコープが小さいほど、推論が容易になります。これは、システムの特性を証明しようとする個人および静的分析ツールと、システムの特性をテストする必要があるテストの両方に当てはまります。
  3. グローバルに利用できる重要な権限のソースは、システムのプロパティを推論することを困難にします。

したがって、グローバルに変更可能な状態では、

  1. 堅牢なシステムを設計し、
  2. システムの特性を証明するのが難しい
  3. テストが実稼働環境と同様の範囲でテストされていることを確認するのが困難です。

グローバルな変更可能な状態は DLL hell に似ています。時間の経過とともに、大規模なシステムのさまざまな部分には、共有されている可変状態の部分とは微妙に異なる動作が必要になります。 DLL地獄と共有された変更可能な状態の不整合を解決するには、異種チーム間の大規模な調整が必要です。これらの問題は、最初にグローバルな状態が適切にスコープ指定されていれば発生しません。

3
Mike Samuel

1つには、シングルトンの場合とまったく同じ問題が発生する可能性があります。今日の「私が1つだけ必要なグローバルなもの」のように見えるものは、突然、将来もっと必要なものに変わります。

たとえば、システム全体に対して1つのグローバル構成が必要なため、今日、このグローバル構成システムを作成します。数年後、別のシステムに移植すると、誰かが「一般的なグローバル構成が1つとプラットフォーム固有の構成が1つあれば、うまくいくかもしれません」と言います。突然あなたはあなたのグローバル構造をグローバルではなくするためにこのすべての仕事をしているので、あなたは複数のものを持つことができます。

(これはランダムな例ではありません...これは私が現在いるプロジェクトの設定システムで起こりました。)

非グローバルなものを作成するコストは通常​​取るに足​​らないものであることを考えると、そうするのはばかげています。あなたはただ未来の問題を生み出しています。

3
Gort the Robot

不思議なことに、もう1つの問題は、アプリケーションが「グローバル」ではないため、アプリケーションのスケーリングが困難になることです。グローバル変数のスコープはプロセスです。

複数のプロセスを使用したり、複数のサーバーで実行したりして、アプリケーションをスケールアップしたい場合はできません。少なくとも、すべてのグローバルを除外して、それらを他のメカニズムで置き換えるまでは。

3
James Anderson

グローバルはそれほど悪くありません。他のいくつかの回答で述べられているように、それらの本当の問題は、今日、あなたのglobalフォルダパスが、明日、いくつかのうちの1つになる可能性があることです。または何百もの。簡単な1回限りのプログラムを作成している場合は、簡単な場合はグローバルを使用してください。ただし、一般的には、1つだけが必要だと思っている場合でも、複数を許可する方法があります。突然twoデータベースと通信する必要がある大規模で複雑なプログラムを再構築する必要があるのは楽しいことではありません。

しかし、それらは信頼性を損なうことはありません。プログラム内の多くの場所から参照されているAnyデータは、予期せず変更された場合に問題を引き起こす可能性があります。列挙子は、列挙しているコレクションが列挙の途中で変更されると窒息します。イベントキューイベントは互いにトリックを再生できます。スレッドは常に大混乱を引き起こす可能性があります。ローカル変数または不変フィールドでないものはすべて問題です。グローバルはこの種の問題ですが、非グローバルにすることで修正することはできません。

ファイルに書き込もうとしていて、フォルダーパスが変更された場合、変更と書き込みを同期させる必要があります。 (問題が発生する可能性のある1000のことの1つとして、パスを取得すると、そのディレクトリが削除され、フォルダパスが適切なディレクトリに変更され、削除されたディレクトリに書き込もうとします。)フォルダパスはグローバルであるか、プログラムが現在使用している1000のうちの1つです。

キューのさまざまなイベント、さまざまなレベルの再帰、またはさまざまなスレッドからアクセスできるフィールドには、実際の問題があります。単純にするため(そして単純化するため):ローカル変数は適切で、フィールドは不適切です。しかし、以前のグローバルはまだフィールドになるので、この(非常に重要ですが)この問題はグローバルフィールドの善または悪のステータスには適用されません。

追加:マルチスレッドの問題:

(イベントキューや再帰呼び出しでも同様の問題が発生する可能性がありますが、マルチスレッド化は明らかに最悪です。)次のコードを検討してください。

if (filePath != null)  text = filePath.getName();

filePathがローカル変数またはなんらかの定数である場合、filePathがnullであるため、プログラムの実行時にnotが失敗します。チェックは常に機能します。他のスレッドはその値を変更できません。 その他の場合、保証はありません。私がJavaでマルチスレッドプログラムを書き始めたとき、私はいつもこのような行でNullPointerExceptionsを受け取りました。 Any他のスレッドはいつでも値を変更でき、多くの場合変更されます。他のいくつかの答えが指摘するように、これはテストに深刻な問題を引き起こします。上記のステートメントは10億回も機能し、広範囲にわたる包括的なテストを経て、本番環境で1度爆発します。ユーザーは問題を再現することはできません。また、ユーザーが何かを見ていると確信し、それを忘れてしまうまで、問題は再発しません。

グローバルには間違いなくこの問題があり、完全に排除するか、定数またはローカル変数で置き換えることができる場合、それは非常に良いことです。ステートレスコードをWebサーバーで実行している場合は、可能です。通常、マルチスレッドの問題はすべてデータベースで発生します。

ただし、プログラムでユーザーアクションから次のユーザーアクションまでを記憶する必要がある場合は、実行中のスレッドからアクセスできるフィールドがあります。グローバルをそのような非グローバルフィールドに切り替えても、信頼性は向上しません。

2
RalphChapin

グローバル変数が良いか悪いかは分からないが、グローバルステートを使用していない場合は、おそらく多くのメモリを浪費しているということを説明する。特に、クラスを使用してそれらの依存関係をフィールドに格納する場合。

グローバルな状態の場合、そのような問題はなく、すべてがグローバルです。

例:次のシナリオを想像してください:「ボード」と「タイル」のクラスで構成される10x10グリッドがあります。

OOPのようにしたい場合は、おそらく「ボード」オブジェクトを各「タイル」に渡します。「タイル」には、座標を格納する2つの「バイト」タイプフィールドがあるとしましょう。 。1つのタイルに対して32ビットマシンで必要なメモリの合計は、(1 + 1 + 4 = 6)バイトになります。x座標用に1、y座標用に1、ボードへのポインタ用に4となります。これにより、合計600になります。 10x10タイル設定のバイト

ボードがグローバルスコープにある場合、各タイルからアクセス可能な単一のオブジェクトは、各タイルごとに2バイトのメモリ(xおよびy座標バイト)を取得するだけで済みます。これは200バイトしか与えません。

したがって、この場合、グローバル状態のみを使用すると、メモリ使用量の1/3が得られます。

これは、他のものに加えて、グローバルスコープがC++のような(比較的)低レベルの言語にまだ残っている理由だと思います

1
luke1985

すべてのグローバルな状態を簡単に確認してアクセスできる場合、プログラマーは必ずそうすることになります。得られるのは暗黙のうちにあり、依存関係を追跡するのが困難です(int blahblahは、配列fooが何でも有効であることを意味します)。基本的に、すべてを個別にいじることができるため、プログラムの不変条件を維持することはほぼ不可能です。 someIntにはotherIntとの関係があります。これは管理が難しく、いつでも直接変更できるかどうかを証明することが困難です。

とはいえ、それは可能ですが(一部のシステムではそれが唯一の方法であったときに遡ります)、それらのスキルは失われます。彼らは主にコーディングと命名規則を中心に展開しています-フィールドは正当な理由で進んでいます。コンパイラーとリンカーは、クラス/モジュールの保護された/プライベートなデータの不変条件をチェックする作業を、マスタープランに従ってソースを読み取るために人間に依存するよりも優れています。

1
anon

グローバルな状態で考慮すべきいくつかの要因があります。

  1. プログラマーのメモリ空間
  2. 不変のグローバル/書き込みグローバル。
  3. 可変グローバル
  4. グローバルへの依存。

グローバルが多いほど、重複が発生する可能性が高くなり、重複が同期しなくなったときに問題が発生します。すべてのグローバルをあなたの虚偽の人間の記憶に保つことは、必要であり苦痛の両方になります。

イミュータブル/書き込みは1回で十分ですが、初期化シーケンスエラーに注意してください。

可変グローバルは不変グローバルと間違われることが多い…

グローバルを効果的に使用する関数には、追加の「隠し」パラメーターがあり、リファクタリングが困難になります。

グローバルな状態は悪いことではありませんが、確かなコストがかかります。利益がコストを上回っているときに使用してください。

0
jmoreno