At first, people wanted to get away from Java with their FactoryFactoryFactoryCreationFactories. So they went to rails where everything was simpler.
Back then, every controller method had a URL.
This was fine, but had some corner cases where it wasn't. So they moved to explicit urls.
Everything was fine, but controllers got bloated. So stuff was moved into models and controllers became restful.
Now there's too much stuff in the models and we are back where we started and write blog posts about this cool new invention: The Factory.
I'm not saying this is bad. I'm not saying the people were wrong at any stage in this development. I'm just saying that as projects grow and people work to prevent old cold-smells from reappearing, to learn from earlier mistakes they slowly move to where they left off.
Until the abstractions get too complicated, the perceived bloat gets too bad. Then we'll see a new frameowrk and/or language grow, going through the same iterations.
Just wait.
I'm not complaining. I'm not flaming, I'm just thinking loudly.
This isn't exactly the factory pattern. It reminds me more of the service classes in Eric Evans' Domain Driven Design. It seems the author is addressing the problem of adding too many side effects to the models themselves.
This actually represents an extremely common misconception about MVC that's common among Rails developers as well as most of the other web frameworks that have chosen some form of the ActiveRecord pattern for their ORM. Model != Persistence layer.
A Model, in the classic MVC, is a model of your problem domain with classes that represent entities and services and whatever it takes to represent your business logic in code, not just a bunch entities that get saved and retrieved from the database. Your persistence layer generally lives below the model and knows how to persist your model's entities however you so choose. The ActiveRecord pattern really muddles this distinction by putting all of your persistence code right in with your business logic. It's a great pattern when you're building something simple with minimal actual business logic, but quickly becomes unwieldily when you get into more complex situations.
My thoughts exactly... and by shoving domain logic into a bunch of EntityFooServices you might end up with code that is more procedural than OO. But maybe it's just the example that was too simplistic.
It's probably just that the example is overly simple, but...
1. The spec speed up is from good mocking, not the service object approach.
2. Tying behavior to persistence is appropriate when it's appropriate, i.e. when it happens every time the object is created/updated. He's right that a slew of after_save callbacks is obnoxious, but Rails' observers already well encapsulate such behavior.
3. In this example case, logging isn't appropriate, because he doesn't want to create an activity feed when a user is created. Instead, he only creates an activity feed entry when a user is created on the website, i.e., through the controller. In that case, it would be perfectly reasonable to include the log creation as another line in the controller code in the success branch of "if User.create(params)". For this example specifically, if that happened in many controllers it could just as easily be a method in a module that was mixed into them ("create_user_and_log"), or even a User class method ("User#create_and_log"). It's a stylistic choice rather than an architectural choice.
That's not to say the approach is without merit—it definitely has some. But what you're really doing is trading a "controller level" unit test (I've always hated that they're called "functional tests" in Rails) for a regular "class level" unit test. If that sort of encapsulation floats your boat more than, say, a module for your controllers, then by all means. I just don't see anything crazy, or heretical, or awesome here.
I haven't used rails in quite some time and have been publishing with Yii lately instead. It feels very similar. I feel like the right thing to do would be to dynamically mixin behaviors based on whether you are in the console or not. Though I guess that changes behavior between tests and production which could defeat the purpose of the tests.
Right now the big ones are that our console needs to deal with permissions and there is no user logged in via the console. Simply skipping permissions modules when in the console has been one solution.
I registered just to suggest giving XKCD credit for the comic they made (and are still hosting for you to use without bothering to rehost yourself)
"That is, you don't need my permission to post these pictures on your website (and hotlinking with <img> is fine); just include a link back to this page"
I'm a (somewhat new) Rails developer now, and I'm really confused by the premise of this article.
Why are Rails test suites so slow? For a small app, one of my test suites takes about a minute for 100 tests. That's crazy!
This author seems to suggest persistence is the issue, but that doesn't make any sense to me. A disk hit is like, what, 10ms? Even if every one of my tests hit the DB once, and if there was no caching, that still would only be 1s. If I set the development database to be an in-memory SQLite, would that magically speed up my tests 100%? (I kind of doubt it.)
When I run rake tests, there seems to be some super long delay on the rake part, and not on the test part. Is the slow test speed related to loading and unloading the code in development (which apparently 1.9.2 is slow at)? Is this due to some rake bug? How would I even find out?
I've been considering this approach for some of my Django projects. Right now I have an unpleasant hybrid of fat model methods and view functions that do a bit too much - having an intermediate class somewhere would clean things up a lot. My current app does a lot of denormalisation to Redis and Solr for performance reasons, which is mostly handled in the model classes - but having a bunch of non-SQL related stuff in ORM classes makes me a bit uncomfortable.
It is a sound engineering practice to avoid using keywords as names even when the language’s parser will let you get away with it. For consistency, some developers (myself included) will avoid words like `class` and `module` even when embedded in a longer name, such as `user_class`.
I don’t use `klass`, but that’s because I’m a Java Bigco cubicle-dweller fraudulently passing himself off as a Rubyist and Javascripter. I prefer `clazz` in keeping with Sun examples.
You can accomplish the same thing without resorting to the factory pattern by simply injecting the logging behavior only in your production environment. This strategy provides the same benefit without incurring the overhead of deviating from the "Rails Way" for your development team.
[+] [-] pilif|14 years ago|reply
Back then, every controller method had a URL.
This was fine, but had some corner cases where it wasn't. So they moved to explicit urls.
Everything was fine, but controllers got bloated. So stuff was moved into models and controllers became restful.
Now there's too much stuff in the models and we are back where we started and write blog posts about this cool new invention: The Factory.
I'm not saying this is bad. I'm not saying the people were wrong at any stage in this development. I'm just saying that as projects grow and people work to prevent old cold-smells from reappearing, to learn from earlier mistakes they slowly move to where they left off.
Until the abstractions get too complicated, the perceived bloat gets too bad. Then we'll see a new frameowrk and/or language grow, going through the same iterations.
Just wait.
I'm not complaining. I'm not flaming, I'm just thinking loudly.
[+] [-] jvoorhis|14 years ago|reply
[+] [-] bkudria|14 years ago|reply
[+] [-] mikeocool|14 years ago|reply
A Model, in the classic MVC, is a model of your problem domain with classes that represent entities and services and whatever it takes to represent your business logic in code, not just a bunch entities that get saved and retrieved from the database. Your persistence layer generally lives below the model and knows how to persist your model's entities however you so choose. The ActiveRecord pattern really muddles this distinction by putting all of your persistence code right in with your business logic. It's a great pattern when you're building something simple with minimal actual business logic, but quickly becomes unwieldily when you get into more complex situations.
[+] [-] lepacheco|14 years ago|reply
[+] [-] ianterrell|14 years ago|reply
1. The spec speed up is from good mocking, not the service object approach.
2. Tying behavior to persistence is appropriate when it's appropriate, i.e. when it happens every time the object is created/updated. He's right that a slew of after_save callbacks is obnoxious, but Rails' observers already well encapsulate such behavior.
3. In this example case, logging isn't appropriate, because he doesn't want to create an activity feed when a user is created. Instead, he only creates an activity feed entry when a user is created on the website, i.e., through the controller. In that case, it would be perfectly reasonable to include the log creation as another line in the controller code in the success branch of "if User.create(params)". For this example specifically, if that happened in many controllers it could just as easily be a method in a module that was mixed into them ("create_user_and_log"), or even a User class method ("User#create_and_log"). It's a stylistic choice rather than an architectural choice.
That's not to say the approach is without merit—it definitely has some. But what you're really doing is trading a "controller level" unit test (I've always hated that they're called "functional tests" in Rails) for a regular "class level" unit test. If that sort of encapsulation floats your boat more than, say, a module for your controllers, then by all means. I just don't see anything crazy, or heretical, or awesome here.
[+] [-] epochwolf|14 years ago|reply
[+] [-] Periodic|14 years ago|reply
Right now the big ones are that our console needs to deal with permissions and there is no user logged in via the console. Simply skipping permissions modules when in the console has been one solution.
[+] [-] sugerman|14 years ago|reply
"That is, you don't need my permission to post these pictures on your website (and hotlinking with <img> is fine); just include a link back to this page"
[+] [-] epochwolf|14 years ago|reply
[+] [-] pbh|14 years ago|reply
Why are Rails test suites so slow? For a small app, one of my test suites takes about a minute for 100 tests. That's crazy!
This author seems to suggest persistence is the issue, but that doesn't make any sense to me. A disk hit is like, what, 10ms? Even if every one of my tests hit the DB once, and if there was no caching, that still would only be 1s. If I set the development database to be an in-memory SQLite, would that magically speed up my tests 100%? (I kind of doubt it.)
When I run rake tests, there seems to be some super long delay on the rake part, and not on the test part. Is the slow test speed related to loading and unloading the code in development (which apparently 1.9.2 is slow at)? Is this due to some rake bug? How would I even find out?
[+] [-] keeran|14 years ago|reply
or checking out the 1.9.3 release (I think it has one of these approaches applied).
[+] [-] simonw|14 years ago|reply
[+] [-] perlgeek|14 years ago|reply
[+] [-] raganwald|14 years ago|reply
I don’t use `klass`, but that’s because I’m a Java Bigco cubicle-dweller fraudulently passing himself off as a Rubyist and Javascripter. I prefer `clazz` in keeping with Sun examples.
[+] [-] DanielStraight|14 years ago|reply
[+] [-] oinksoft|14 years ago|reply
[+] [-] lightyrs|14 years ago|reply
[+] [-] kyledr|14 years ago|reply
[+] [-] natehop|14 years ago|reply
Here is an example of how to do this: https://gist.github.com/1122080