31 comments

[ 3.4 ms ] story [ 50.8 ms ] thread
I completely agree! As a "framework-less" Java developer where I had written apps with 100k+ LOC, the application code is always separated from the web layer. When I started Rails I scratched my head for days trying to figure where the application code should reside.

I hope this turns into a best practice.

(comment deleted)
Sounds like you shouldn't be using Rails if this is your philosophy. I'm of the school of thought that if you're going to use a framework when building an app, then you should lean on it for just about any task that it will let you. Especially if you're using a well-maintained and widely used framework like Rails. There are multiple benefits to this approach. For one thing, it makes it easier to onboard new team members. There are tons of people who are Rails experts, and are very familiar with its paradigms and features. People like this can very quickly get up to speed with just about any Rails project. A large team can also communicate and work much more efficiently if they are all using the same code structure/helpers/etc. If you're a one man show, it might work just fine for you to build specialized gems for all of your "application" (though the line you've drawn between application and framework seems pretty vague) though there is going to be a fundamental lack of structure to your entire project. It'll make sense to you for a little while until it gets so big that even you don't understand it. It's going to be difficult to perceive test coverage, and in practice, all those little gems are going to vary pretty wildly in structure.

You'd be better off just using Sinatra and including ActiveRecord, and whatever other Rails libraries you want to use.

  > Sounds like you shouldn't be using Rails if this is your philosophy.

  > You'd be better off just using Sinatra and including
  > ActiveRecord, and whatever other Rails libraries you want 
  > to use.
What seriously? Something doesn't fit inside Rails' neat cutouts so obviously the solution is to get rid of Rails? This smacks of "if you don't like Rails, go somewhere else." Just because you're using a framework doesn't mean you can't do anything outside of it, ever!

I mean, take Rails. It gives you a LOT of convenient stuff that you wouldn't want to throw away wholesale, but if you have a Customer model and a Card model, where do you put the checkout code? It could go in either place.

A great solution is to put it into lib/checkout.rb and write a custom Checkout class that manages how Customers and Carts interact. Not only does this make it super-easy to test outside of ActiveRecord, but it consolidates the code in one common place, and you haven't tossed out Rails for no reason.

> if you don't like Rails, go somewhere else

Exactly. Makes perfect sense to me. If you're not going to lean on the framework, why even use the entire stack? You can pick and choose the parts of it you like, and want to use under the context of something like Sinatra which is meant for that sort of thing.

> but if you have a Customer model and a Card model, where do you put the checkout code? It could go in either place.

You can put it in either place. I'm not sure I understand why just because there's some flexibility on where you can put method X you should just work completely outside of the framework.

Edit: But this is a different point than the original debate though. I think the blog author goes way too far in avoiding using the framework.

You can pick and choose the parts of rails as well. I have a rails 3.1 app that doesn't use active_record at all, but it does use active model and encapsulates the service layer in model objects.
"A great solution is to put it into lib/checkout.rb and write a custom Checkout class that manages how Customers and Carts interact."

That is significantly different than implementing a service layer, which "defines an application's boundary with a layer of services that establishes a set of available operations and coordinates the application's response in each operation." In your typical ServiceLayer style app, most of the calls are just direct passthroughs to the domain model.

Frankly, the controller layer is a sufficient service layer for many complex applications, as it handles different clients and request types. There is often foolishness in putting too much of that logic in a single controller method, but it is wrong to suggest that adding the overhead of the service layer pattern in place of referencing the domain model from the controller fixes this (putting it in lib certainly makes a bit more sense).

The example given in the article is a bit of a horror show. It's probably not a service layer. I am sure a bit is left out, but it's going to convoluted lengths to avoid putting anything in the domain model. Dynamically extending individual instances of employee to add a pay_date method? Creating a new instance of the service on each request- when it could be done with static methods?

Sadly, it doesn't make sense to model your whole domain twice. Let's see what the employee service used to list, add, update, and remove employees is like. Any real system is going to end up with a domain model object to represent a payroll, which is where this logic could go.

The root problem is Uncle Bob just doesn't like the ActiveRecord pattern- in which case just use a different ORM.

If you have customer and credit card model, I'd implement the checkout process inside Order and OrderItem model classes. It would probably use an AASM state machine to represent the progress through the purchase etc.
Working against Rails, or any framework, is definitely going to cause pain. On the other hand, Rails is not perfect and I, like the OP, have been noticing a number of voices lately worrying about building large Rails apps. Which is awesome, because either Rails will adapt or something new will come along to fill the need.

Sinatra + cherry picking rails lib might work great if you've built a few apps like that, but it would nice to package this approach in a framework which guides people down this road.

Personally, I feel that Rails could evolve to the point where the approved path involves using some adapter (like a service layer) to talk to ActiveRecord. I've written about how Java accomplishes this in comparison to ActiveRecord: http://casestatement.tumblr.com/post/11514731433/javas-jpa-f...

  > Working against Rails, or any framework, is definitely 
  > going to cause pain.
There is a huge difference between working "against" a framework and working outside, or better yet alongside of it.

You want a Service layer that abstracts logic from database commands? You can absolutely do that while still taking advantage of the entirety of Rails. Your controllers and views are instantiating your objects and not ActiveRecord objects, but that's not a crime.

Rails is not your application framework. It is not well-suited to being your application framework. We have exactly this problem in the Python world, where people lean on Django for everything, and insist on making everything interoperate with Django's view of the way the world should be.

It doesn't work. Factor out as much as you can and make as much of your code into units as possible. You want to be able to test your code, run it and inspect it, and have it overall be very non-magical.

In Rails, the application belongs in app/, not lib/ or a gem. If this does not meet your admittedly obsessive design concerns then I suggest not using Rails.
+1 For being a Rails hipster that we all love to hate.
You do understand that when the author says "your app" what is meant is "the domain or business logic that drives decisions."

Seriously, what's with the attitude? There's more than one way to architect software and Rails doesn't cover every single base. Pulling business logic out of your ActiveRecord models and into separate classes makes it easier to test and easier to manage code that interacts with more than one model.

Lighten up.

I'm not typically a Ruby/Rails programmer, but this seems to me like a different take on good advice I was given a while back: "Whenever possible, build libraries, not apps."

If my code does anything at all which might be decoupled from this particular program or webapp, I try to break it out into a library, which I then call from the app I'm working on. This sometimes results in some extra work when working on that project, but it's saved me plenty of times in the long run.

edit: typo

It's one thing pull elements into libraries it another thing to put the whole model layer into the lib directory,
i go one step further, and put the domain layer behind a network interface (http or other) with a versioned API. IMO, trapping behavior inside a single application is just as bad as tying it to a framework. the domain layer needs to be available to the entire organization.

rails is just a tool to build a front-end app. i have many of those on my project. some rails, some sinatra. if they want to access shared behavior or data, they include the appropriate gem which knows how to access a particular API.

I would only reach for service-oriented architecture after the application is very mature and it is apparent which parts will benefit by moving to their own services.
or the moment you have more than one application running. (which for many products is day #1)
I'd like to hear more on how you setup your service architecture afex (if time permits). Sounds like exactly what I'm trying to accomplish. Thanks in advance!
I find rails in particular to be very easy to just "api all the things" right off the bat. Add in some nice authentication / authorization with something like devise and CanCan and you will be saved from the headache of bolting an api onto your app as an afterthought.
I think the bottom line with this is you shouldn't be using a framework as the entire architecture of your application. Frameworks usually are designed to do a few things very well, in the case of web frameworks, they provide the mechanisms needed to receive http requests and return responses elegantly along with rendering output from the server-side language into an HTML format. Beyond that, there is a much larger world of application architecture and design that goes beyond any "canned" framework. Web frameworks are great and very much fill a need but they aren't a panacea to make every project trivial.
I'm not particularly familiar with rails (or even web or client/server in general -- I'm more of an embedded/systems type) but this post gives me a strong feeling of the youth of today rediscovering the lessons of yesterday, to wit, properly abstracting the application from presentation.
Indeed. "Services" often sound suspiciously like well-dressed subroutines.
It seems that people forget what "model" (in MVC) really means. A model (in general) is a simplification of the world. The world is so complex that you can't possibly reason about it at once, so you split it up into smaller models that are easier to understand. It's exactly the same in MVC: the model is the definition of your application's world; a simplification that your computer can work with.

Yes, Rails ship with ActiveRecord, which makes it dead simple to define data models that you need to store, but the app/models/ is far from limited to only data storage. app/models is about the business logic of your application. It seems to me that all of the files the article wanted to place under lib/ actually belongs under app/models.

Yes, I agree that it's nice to be able to test your application outside of Rails, but whether you place the files under app/models or lib/ doesn't change that. Yes, it might be useful to abstract it out to a gem, and then you can move it into a lib/-directory (since there is no MVC of a Ruby library), but as long as you're inside the realm of a Rails application you should put everything that's related to the business logic in app/models.

So, in summary:

If it's related to the BUSINESS LOGIC of your app: Put it in app/models.

If it's just GENERAL stuff: Put it in lib/ (or better: create a gem out of it).

Say you're writing an app that has simple business logic. Easy, you put that logic into model. Then you realize you need to write much more business logic code. No problem, model. But your model classes are getting fat and it looks ugly. So you refactor the code into modules.

Now somebody is browsing your code and they are ripping their hair off, because there's a method on Order object and there are 6 modules included in the Order object.

Before you realize it, you're violating not only MVC but also OOP.

If you used Services, you could model nice controller/manager classes in OOP manner, with responsibilities nicely distributed. These are your controllers. Rails controllers are just the HTTP interface.

I'm not suggesting that you should create modules and include these into your ActiveRecord-models. Feel free to create any kind of class/module/object/whatever, but as long it's related to the business logic put it under app/models.
That's fine, let's not get pedantic here. If you want to put your non-database-backed stuff lib/ and the ActiveRecord bits in app/models, fine. If you want to shove them all in app/models, that's good too.

There's really no argument for or against; either way the code should be documented with tests and a README.

Totally agree on the concept, but not on the implementation. It's time for a #norails revolution. Rails expresses the needs of domain-driven applications very poorly. My response to this article: http://bit.ly/n9DFi6