To add some real value, by this I mean that I've run into this crap a lot. In Java, sometimes I want the ability to have a function which returns other functions based on an input. This is doable in a variety of languages other than Java.
In Java, I didn't call it such, but I ended up writing a FactoryFactory. (I am not proud.) I had one layer of abstraction to produce Foo objects with a certain configuration, and a layer above that to parameterize the creation of a Foo-creator. sigh. Scar tissue indeed.
I'm starting to get a pretty good feel for it, but what are the criteria that you use to determine if a class should be stateless or not?
module Foo
def self.some_stateless_method
...
end
end
Foo.some_stateless_method
class MyController
include Foo
def index
some_stateless_method
end
end
and so forth.People think of modules as being mixins, but they're actually just function namespaces--which you can happen to bind into class contexts via include/extend.
I tend to use class methods where:
a.) The class exists, because you want state, and
b.) The function operates principally on, or is only useful in, the context of that class, but
c.) The function isn't bound to the object's state.
That last requirement is fuzzy, since the call semantics are different: self.class.foo is awkward, so I'll often write instance methods which don't actually depend on the state, just taking advantage of the local namespace.
I am writing a class to represent a car. I need to know if the cars doors are opened or closed. The `open` or `closed` attribute is the state of the car, so it makes sense that the Car object would have that state.
Now compare that to the use of `LanguageDetector` from the example:
LanguageDetector.new(@comment).set_language
Presumably this object is keeping a reference to the comment for it's internal state. When I'm dealing with an object, I like to say in my head "language detector, can you tell me the language for some text?". Nothing in my question gave the text a 1:1 relationship with the language detector. Since my question did not identify a relationship, I would not make the comment a part of the LanguageDetector object. I'd rather write something like this: detector = LanguageDetector.new
language = detector.detect_language(@comment)
@comment.language = language
What might the LanguageDetector actually want to have as it's state? I think maybe things like encodings, or particular languages it supports. The question I ask is "language detector, what encodings or languages do you support?", and the relationship becomes clear. For example: detector = LanguageDetector.new(:encodings => [...], :languages => [...])
# etc
I hope that makes sense, and that I don't sound too crazy (talking to myself and whatnot).I find stateless code easier to reason about.
1. Testability. Isolating these bits of application logic and testing them on their own has proven less prone to issues than including it all in, say, controller methods or helpers, which get messy over time.
2. Swappability. Okay, sure, you may never need a second kind of CommentPoster, but you never know. Keeping things like this stateful and properly abstracted out saves me plenty of time as the app's requirements get more complex.
It's not exactly premature optimization if I always follow this pattern and know exactly how it will work. (Sometimes it's just an unused optimization.) To me, there is very little added complexity, and if anything it makes it a bit easier in the long run.
2. Swapping implementations is easier: would you rather pass a function, or an object with a single function? This ties back in to testing: it's easier to create a test variant of a function than it is to create a new class.
Don't get me wrong: state is great, and I use it all over the place. I generally avoid it, though, unless the state is needed, simpler to understand, or more concise.