2

先日、#ruby-lang チャンネルの誰かと について話しました@@class_variables。すべては、あるユーザーが、自分のサーバーに接続しているユーザーを追跡する最善の方法は何かと尋ねたときに始まりました (少し単純化しましたが、それが要点です)。

だから、私は提案しました:

class User
  @@list = {} #assuming he wants to look up users by some type of ID

  def initialize(user_id, ...)
    @@list[user_id] = self
    #...
  end
end

ただし、ここでグローバル状態を使用することは悪い習慣と見なされると誰かが言いました。

複数のバックエンドに依存するものにとってなぜグローバル状態が悪いのか、私は理解しています。なぜなら、グローバル状態のグローバル部分がグローバルではなくなり、その 1 つのバックエンドにローカライズされるからです。または、依存性注入を妨害すること。

とはいえ、これが悪い理由は他に思いつきません。また、同時実行性が問題になった場合 (複数のバックエンドが必要な場合)、Redis (または同様のもの) を使用するようにコードを更新できます。

また、この質問をprogrammers.sxcで見つけましたが、上記のコードがなぜそれほど悪いと考えられているのか理解するのに役立ちませんか? また、代替手段は何ですか?

4

1 に答える 1

4

なぜ悪いのですか?

あなたが言及しなかったいくつかの理由により、グローバルな状態は悪いです:

  1. 信頼できない: サード パーティのコードを含め、プログラム内のあらゆるものが変数を変更する可能性があるため、変数を挿入してから 1 秒後にそこに何かが存在することに依存することはできません。
  2. カプセル化を破る:ユーザーのグローバルリストがある場合、プログラムの他の部分はそれにアクセスするために User クラスを通過する必要があります。そうしないと、誰もがデータを直接操作することになり、これは悪い考えです。
  3. 変更が難しい: グローバルな状態を、たとえばハッシュではなく配列にする必要があることがわかった場合は、不運です。変更するアクセサーがないため、それを使用するコードのすべての部分を変更する必要があります。
  4. これはもう少し抽象的ですが、それでも:関数の純度: グローバルな状態を導入すると、以前は純粋だった多くの関数が不純になります。C のようなコンパイル済み言語は純粋な関数を大幅に最適化できるため、これは一般的に悪いことであり、Ruby ではメソッドのテストがはるかに難しくなるため悪いことです。

あなたが言及したグローバル状態の特定の形式である@@変数も、Ruby固有の理由で悪いです:

  • 奇妙な継承セマンティクスがあります。Ruby@@変数は、クラスとそのすべてのサブクラスの間で共有されます。カプセル化されていると思っていても、そうではありません。これは、誰かがあなたのクラスをサブクラス化し、無関係なデータを格納するためUserの変数を宣言した場合に特に悪いことです。@@listRuby は文句を言わず、User クラス ツリー全体の状態が危うくなります。

他に何ができますか?

  • 依存性注入: データをグローバルに維持することなく、データを必要とする人に渡すだけです。
  • クラスのカプセル化: グローバルな状態が必要な場合は、セッターとゲッターを使用してクラスを維持します。@@これは、クラス@変数を使用するため、problem とともにポイント 2 と 3 を無効にします。例:

    class User
      class << self
        @list = {}
        def add_user(uid, user)
          #Do validation here
          @list[uid] = user
        end
        #More methods like add_user
      end
      def initialize(user_id, ...)
        User.add_user(user_id, self)
      end
    end
    
于 2013-10-06T15:01:05.147 に答える