4 ms·
Crazy, Heretical, and Awesome: The Way I Write Rails Apps
- raganwald 17y agoThe challenge raised is that logging does not belong in the model object. Well, I agree with that. I'm writing a Go game now, and I have notifications sent to players when certain things happen, and I don't think they belong in the model either. So do I need service objects? Well, I don't know what the author of this fine post calls them, but I am using the Observers baked into Rails, a pattern that goes back to Smalltalk in the 1980s. I tell Rails that my NotificationObserver is observing my Game and Action models, and the concern of notification is separated from the concerns of playing games. Is "Observer" the wrong word? Or worse, the wrong pattern?
- jamesgolick 17y agoIn retrospect, logging was absolutely the wrong example for this article. I intend to follow up with a better example. In the case of logging, an observer may or may not be appropriate depending on the specifics of your application. In your Go app, it sounds like a NotificationObserver makes perfect sense. The broader point that I was trying to make in the article was that coupling all of your business logic to your persistence objects is a bad idea. It couples all of the concerns together, and with larger codebases, makes for slow tests and code that's difficult to reason about and debug. If your business logic lives outside of your persistence layer, service objects can be a great way to coordinate several objects necessary to complete some user action. Observers can work quite well too. As long as business logic is decoupled from persistence, I think a big step has been made towards better code.
- qaexl 17y agoTo me, the Service example you gave was actually another form of a controller, albiet one that is not a classic, HTTP-oriented, stateless controller. I have not thought this through yet -- but I suspect the state machines that manage lifecycles would be better implemented as separate set of controllers; "services" is an OK name for this abstraction, but there is probably a better one. Rails 3 makes it easier to swap out controllers and routers. (It also loads everything under app/ by default, so you can name app/observers or app/services without having to add in extra load paths by hand). It should not be difficult to implement a parallel workflow engine, for example, that uses a shared persistence stack (models) yet manages data lifecycle, and respond to messages rather than stateless RESTful resource APIs. Good thoughts, good article.
- _pius 17y agoWhen reading your article, I immediately thought back to Jamis Buck's repudiation of formal dependency injection in Ruby: http://weblog.jamisbuck.org/2008/11/9/legos-play-doh-and-programming http://weblog.jamisbuck.org/2008/11/9/legos-play-doh-and-pro... I'd be curious to hear your thoughts on that piece.
- regularfry 17y agoIt's slightly worrying that applying a fairly standard set of patterns should be "crazy" or "heretical." This is one of the things I worry about in Rails - people seem content to shove everything in an ActiveRecord subclass and hope for the best. Still, at least doing the right thing is not only possible, but generally easy once you've broken your mind out of the prescriptions of the framework.
- jamesgolick 17y agoI'm totally with you. The title was tongue in cheek.
- mickeyben 17y agoI don't really get what's awesome, crazy or herethical ...