I had a talk with someone on the #ruby-lang channel the other day about @@class_variables
. It all started when a user asked what's the best way to keep track of connected users to his server (I slightly simplified it, but that's the gist of it).
So, I suggested:
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
However, somone said that the use of global state here is considered bad practice.
I understand why a global state is bad for something that relies on multiple back-ends, because the global part of global state stops being so global, and becomes localised to that one back-end. Or that it interferes with dependency injection.
I really can't think of any other reason why this is bad, though. And, if concurrency ever becomes an issue (there's a need for multiple back-ends), then we can update the code to use Redis (or something similar).
Also, I found this question on programmers.sxc, but it doesn't help me understand why the above code is considered so bad? Also, what would be the alternative?
Global state is bad for a couple of reasons you didn't mention:
The specific form of global state you mention, @@
variables, is also bad for a Ruby specific reason:
@@
variables in Ruby are shared between a class and all it's subclasses. So even though you think that it is encapsulated, it isn't. This is especially bad if someone subclasses your User
class, and declares a variable @@list
for storing unrelated data. Ruby won't complain, and the state of the entire User class tree is compromised. Class Encapsulation: If you need global state, have a class maintain it with setters and getters. This invalidates points 2 and 3, along with the @@
probelm because it uses class @
variables. Example:
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