
Objectify: A Better Way to Build Rails Applications - juliehache
http://jamesgolick.com/2012/5/22/objectify-a-better-way-to-build-rails-applications.html
======
judofyr
Someone has to say it: Damn, this looks fucking ridiculous!

First we have the _false_ modularity. You see a bunch of separate stuff
(classes, methods, whatever) and think "Wow, nice, now we can reuse this all
over the place!" The truth is that these policies/services/renderers are going
to be complected; you're going to create them in triplets as you implement
your application. Moving things around doesn't make them modular. They can
only be modular if the author actually implements them in a modular way (and
you can do that in Rails today).

The DI-framework can't handle _change_ at all:

    
    
        class CurrentUserResolver
          def initialize(user_finder = User)
            @user_finder = user_finder
          end
    
          # note that resolvers themselves get injected
          def call(session)
            @user_finder.find_by_id(session[:current_user_id])
          end
        end
    

What if I later need the cookies/params to detect user session? If I changes
the #call method, every single test breaks.

And then there's the added complexity. Now I need to keep track of the route-
mapping, default policy, route policies, the route service and the route
renderer. Which are now in several different files. And there's not even a
clean class-to-file mapping to help me locate it.

Oh, and the premise of testability. Well, this makes it very easy to test
units itself, but the more you split your projects into smaller units, the
more bugs occur when you mix the units. Sure, you can get your precious fast
test runs (and a nice green test), but in reality you're only testing a single
unit of a complected app.

EDIT: This reminds my of Rick Hickey's quote from keynote at RailsConf2012:

""We can make the same exact software we are making today with dramatically
simpler stuff—dramatically simpler languages, tools, techniques, approaches.
Like really radically simpler—radically simpler than Ruby which seems
simple.""

~~~
nicholasjhenry
When you start a comment off with a sentence like that, you lose all
credibility.

~~~
primatology
I don't necessarily think so. He draws you in with said outrageous remark and
proceeds to raise some good points.

~~~
nicholasjhenry
It doesn't really invite discussion. If you were the original author of the
blog post would you engage with the author of the comment?

~~~
primatology
Good point. There are friendlier (better?) ways to discuss flaws.

------
stiff
This is not object-oriented at all, unless you learned about object-
orientation from Java and its monster frameworks, this is basically a form of
data-flow programming. OO is about message passing, here the "objects" do not
pass any messages at all, the supposed "objects" _are_ the messages, and the
routing of those messages takes place in the configuration in routes.rb, so
the objects do almost no message-passing between themselves at all! It is
ironic to see this advertised as "better OOP practices for rails apps".

Having said this, I respect the attempt, the problem it tries to solve
certainly does exist to some extent, and the solution cannot be completely
dismissed very easily.

But please, please, do learn both A) basic history and B) basic theory of the
field you are working in. If you try to reinvent everything you decrease your
chances of contributing something new manyfold.

~~~
jamesgolick
I've read at least a dozen papers on the history of OO, not to mention books
and papers on current practices. This is what I came up with. I made what I
think is a pretty coherent argument for why in the article. I'd love to hear
your refutation of the points I made in there.

~~~
stiff
You have to think a bit more about what OO really is about. How would
properties of your solution differ if you instead of classes split all the
code into many very small global methods? The essence of OO is objects freely
passing messages between themselves, if you fix all the message routing and
put it in a central place you are not doing OO anymore, you loose the most
fundamental properties, for example:

<http://en.wikipedia.org/wiki/Dynamic_dispatch>

You also don't have encapsulation anymore, since to be able to perform the
majority of the work in the services, the services have to operate directly on
data owned by other objects.

How can you combine the policies in ways other than a simple logical AND? How
do you combine services?

Others have also already pointed out other issues.

Please don't be offended by the above. Software engineering is unfortunately a
field where some valuable content is buried underneath loads of BS, since it
is so easy to "philosophize" about it even with just basic programming
experience and this leads other people learning the field to easy
misconceptions. I do not want to discredit the work you put into this and it
might be that in some form something valuable will come from some of the
ideas. It is an interesting problem to work on and for me it was an
interesting solution to think about, I just don't think you are there yet.

~~~
jamesgolick
> You have to think a bit more about what OO really is about.

If you want to have a respectful debate, I'm completely game. If you'd prefer
to continue with your incredibly condescending tone, then I'll bow out here.

~~~
ryeguy
You need to grow thicker skin, that first sentence was in no way condescending
and gives you no reason to just ignore the rest of his comment.

~~~
telemachos
No. It may be unintentional, but the tone of stiff's comments is highly
condescending.

Exhibit A: Whatever you think about James's choices in this library, he has
_clearly_ thought a lot about OOP. It's just silly to start a comment with
"You have to think a bit more about what OO really is about."

------
aamar
Probably worth bringing up Steve Yegge's 2006 "Execution in the Kingdom of the
Nouns": [http://steve-yegge.blogspot.com/2006/03/execution-in-
kingdom...](http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-
nouns.html)

I don't think there is a single right answer that is applicable in all cases.
But over time, I've come to believe that as a default, code works well when it
resembles how you'd ideally explain the service to an extremely intelligent,
non-technical person with domain experience. This makes for code that is easy
to understand, collaborate around, and modify given changing objectives.

That means creating "Policy" and especially "Service" models--extra nouns--
very sparingly. For example, an Elevator was once a nounification of a verb,
but people understood it, so it makes sense as a class. ElevatorDoor's good
too, but ElevatorDoorOpeningService is probably not good. This is absolutely
at odds with strict application of the Single Responsibility Principle.

~~~
aculver
The "Ubiquitous Language" is the label I've seen applied to the idea you're
describing. For example:
<http://martinfowler.com/bliki/UbiquitousLanguage.html>

This idea of having an ubiquitous domain language and keeping applications and
APIs RESTful have been two of the most beneficial ideas I've incorporated into
my development in recent years.

------
cletus
FWIW there's already a library called Objectify that's a Java-based ORM (lite)
for AppEngine:

<http://code.google.com/p/objectify-appengine/>

If you want your project to be found easily (on search engines) I always
suggest:

1\. Prefer a made up word to a non-English word (or a word in any live
language for that matter); and

2\. Don't choose a name that something else in the same or similar space
shares. They've been around longer. It's just going to make your life harder.

YMMV.

~~~
stickfigure
Furthermore, it's the top Google hit for 'objectify'.

~~~
iamgilesbowkett
Do you really think the OP had SEO as a priority?

Likewise I disagree with the idea that these two projects share the same
space. A Java ORM and a Rails metaframework for avoiding ORM are not things
which have a lot in common. I think the last time I observed a Rails hacker
saying anything about AppEngine was 2007 or something.

~~~
stickfigure
It will certainly cause confusion. This is just decidedly uncool.

As the lead developer of the Objectify project, and someone who makes a living
through consulting related to Objectify, I am highly annoyed. I'm also talking
to a trademark attorney to find out my options.

~~~
iamgilesbowkett
Jesus, dude, why not just talk to OP instead? Any lawyer will tell you that if
you can resolve your differences peacefully out of court, you should. This
seems to be some kind of hair-trigger litigiousness thing you've got on going
here.

~~~
stickfigure
Relax, it's not like I'm setting a court date. I just prefer to know where I
stand before I open my mouth, and I happen to work with lawyers who specialize
in this kind of thing. Research before action, no?

------
akmiller
Why are people building frameworks to sit on top of yet another framework to
try to write cleaner more maintainable code???

What is wrong with writing your core application logic physically removed from
any of these frameworks. Why do people insist on fitting their application
into the Rails framework or any other web framework.

Write your core application code in Ruby (or your language of choice), package
it in another gem, use tools and patterns we've had all along to plug that
code into a dependency for persistence (if needed)...communicate with it
through a standard API that you define for your delivery mechanism (i.e.
Rails).

I just don't get this idea of trying to contain my application code within the
confines of a specific framework.

------
aculver
"Single responsibility principle (SRP): ... ActiveRecord::Base already has a
responsibility: persistence."

Wrong. I'm hearing this more and more, but let's be clear: Active Record as a
design pattern, before Rails, has _always_ been a joining of business logic
_and_ persistence. (<http://martinfowler.com/eaaCatalog/activeRecord.html>)
It's always been in violation of the single responsibility principle. If you
want to avoid that, don't use Active Record! Use a Data Mapper, which
specifically separates Mappers and Finders from Domain model classes.
(<http://martinfowler.com/eaaCatalog/dataMapper.html>)

I'm not saying you can't move logic out into reusable modules or whatever is
being recommended here, but please don't make it out like people are in the
wrong when they're using the library or framework the way it was designed to
be used.

~~~
jamesgolick
The point I was making was that you can use the library in a different way
successfully.

------
regularfry
Can't say I'm a fan of single-method classes. They always make me ask "why
isn't this just a method?"

~~~
jamesgolick
Because of SRP.

~~~
rbxbx
At first I thought this was an attempt at trolling, but then I noticed that
Mr. Golick is the commenter so therefor I must assume serious intent.

Care to give an answer better than "some book some java dudes wrote 20 years
ago said so"?

While I generally agree with SRP, when that single responsibility can be
expressed in a single function, I don't see the win with have a class
dedicated to it. Smells of pedant OO nonsense.

Is not instantiation etc a cross-cutting concern that violates SRP in this
instance?

~~~
manuscreationis
> Is not instantiation etc a cross-cutting concern that violates SRP in this
> instance?

Right.

Which is why hes also recommending the use of DI.

It's hard to strike a balance between a strong design which takes a lot of
time to work within, and one that just allows you to get things done, but once
your project begins to grow in size and complexity, and testing becomes even
more important, these things really do start to matter.

It's difficult to internalize until it's bitten you on the ass, hard.

That said, if you have a large amount of single method classes, you might need
to take a look at why you need them and find a better approach (which will
vary from project to project).

~~~
jamesgolick
> It's hard to strike a balance between a strong design which takes a lot of
> time to work within, and one that just allows you to get things done, but
> once your project begins to grow in size and complexity, and testing becomes
> even more important, these things really do start to matter.

The whole point of objectify is that it actually makes it pretty reasonable to
work this way right off the jump. I would have a hard time believing that it's
really any more work to build an objectify app than it is to build a vanilla
rails app - at least once you become accustomed to the paradigm.

> That said, if you have a large amount of single method classes, you might
> need to take a look at why you need them and find a better approach (which
> will vary from project to project).

I don't buy that. My project has hundreds of single method classes and it's by
far the best factored non-trivial application I've ever seen (anecdotal,
obviously, but so it goes).

~~~
manuscreationis
>The whole point of objectify is that it actually makes it pretty reasonable
to work this way right off the jump. I would have a hard time believing that
it's really any more work to build an objectify app than it is to build a
vanilla rails app - at least once you become accustomed to the paradigm.

Sure. I wasn't saying otherwise. What I meant was, in a general sense (prior
to really seeing the benefits first hand), it can be hard for people to
justify the trade off when they feel like they can just "get it done faster"
with a more ad-hoc approach to things. I didn't mean to imply Objectify was
some how more difficult (I haven't used it, so I wouldn't dare comment on it
in such a way).

>I don't buy that. My project has hundreds of single method classes and it's
by far the best factored non-trivial application I've ever seen (anecdotal,
obviously, but so it goes).

Agree to disagree, with a caveat. I'm not against having a large amount of
"Helper" or in the case of what I'm most familiar with, "Extension" classes
(godbless you, .NET Extension classes), but I think if you have so many that
they comprise most of your code base, maybe you could consolidate some of them
(and maybe you couldn't).

Personally, I try to keep 100% of my core business logic inside of "Service"
style classes, and then anything that is more of a helper (in that it performs
some work, but not "business logic", and does not require or alter internal
state) in either a static helper, or an Extension on the type itself.

For example, I usually end up adding a .ToStart/EndOfDay/Week/Month suite of
methods to the datetime object of most of my projects. A "DateTime Service"
would be overkill, but an extension method (which is just veneer over a static
helper) fits the model perfectly, in that it returns a new copy of the
existing datetime, leaving the original intact.

But at this point we're getting pretty deep into the comment tree, so feel
free to email me from my profile if you want to go more into the issue - I
love shooting the shit over this kind of stuff. Regardless of any minor
difference of opinions, I think what you're trying to bring to the rails
community is to be commended.

~~~
jamesgolick
> Regardless of any minor difference of opinions, I think what you're trying
> to bring to the rails community is to be commended.

Thanks a lot, man.

------
manuscreationis
When I was first trying to learn about rails, I asked a friend who had been
developing in it for a while about things like DI, and separation of concerns.
He told me that those were things you used in Java and .Net because the
languages just weren't as... I'm struggling to remember the exact term he
used, but essentially "open" or "un-restricted".

He echoed the phrase I've seen elsewhere "Ruby just doesn't need that".

I disagreed with him then, and still do. People like to claim that OOP breeds
cargo cult programming and overly cumbersome abstractions upon abstractions
(and it can), but some times you really do need that kind of approach to make
a large scale project testable and maintainable.

I'm glad to see there are Ruby devs who can see the value in using these kind
of approaches. I honestly believe it's the kind of thing you think is a major
waste of time, until you are shown the benefit first hand, and you experience
the change. Then you start to understand that by spending a significant deal
of time up front building your infrastructure, you can save a lot of time down
the road.

I know that's how it was for me years back.

~~~
jes5199
He probably used the word "expressive", which is how we used to excuse ruby's
problems.

It's pretty clear, by now, that we (the ruby community) were wrong about how
to maintain projects over time without getting mired in complexity.

------
nyrb
Objectify is a nice framework, but after reading the examples in README made
me feel like I am required to take extra iterations: create new responder
files, write more codes for each Responder class, etc. This approach is little
tedious.

I personally think that writing reusable libraries using Decorator/Presenter
patterns or Modules with ActiveSupport::Concern is simple approach.

Avdi's slides: [https://speakerdeck.com/u/avdi/p/making-little-classes-
out-o...](https://speakerdeck.com/u/avdi/p/making-little-classes-out-of-big-
ones)

I highly recommend Objects on Rails book: <http://objectsonrails.com/>

------
aantix
>One in particular is something I've been thinking about and

>refining for a while now [3]. In this approach, persistence

>objects remain extremely thin, and business logic is

>encapsulated in lots of very simple objects known as

>“services” and “policies”. Not all objects in this

>methodology will fit in to one of those two categories,

>but they are two of the most important concepts.

I've seen this division of labor outlined in this DestroyAllSoftware
screencast :
[https://www.destroyallsoftware.com/screencasts/catalog/fast-...](https://www.destroyallsoftware.com/screencasts/catalog/fast-
tests-with-and-without-rails)

As can be implied by the title, one of the side effects of keeping your
service logic in their own separate plain Ruby classes is that you don't have
to load Rails as dependency which means tests can run _really_ fast.

~~~
regularfry
Yeah, services are one of the types that have leaked out of DDD (and probably
leaked into it from somewhere else).

------
kreek
Isn't this the command pattern, except instead of 'execute' you use 'call'?

Update: not saying that's a bad thing I used to be a Flex developer and all
the frameworks used MVCS (Robotlegs being my favorite). Controllers are all
commands and Services are used to retrieve data.

------
drumdance
"The more responsibilities an object has, the _more complex its behaviour_
becomes, and is therefore more difficult to prove and reason about."

Emphasis mine. I don't think this has to be true. Yes, models get fatter, but
the responsibilities will have to be implemented _somewhere_ and to me it's
simpler and easier to debug when it's as close to the domain model as possible
instead of in some abstract/generic model.

Of course, if you have policies and services that apply across domains, then
by all means break them out and recompose as necessary in the the models

------
_pius
Relevant: [http://weblog.jamisbuck.org/2008/11/9/legos-play-doh-and-
pro...](http://weblog.jamisbuck.org/2008/11/9/legos-play-doh-and-programming)

------
perlpimp
Not quote Donald K. but I've seen my share of optimizing rails apps that
points to the fact that each class added is extra 2-4 megs of RAM. This sort
of discouraging rule, looking ahead writing well tested app that does follow
SRP and other nifty "literate" practices might cost you big time, tell me if I
am wrong.

------
amalag
This replaces the controller with classes for each action, a Service? Then
responders are automatically called and they do renders.

Sounds nice, would be fine with it as a default, but not sure it warrants
doing a big change for me.

~~~
jamesgolick
You can move over slowly by building new components using objectify, and
leaving the rest of your legacy app the way it is, if you like. It's designed
specifically to be able to coexist with what you've got.

------
brunoc
I don't get why these models get bloated. If there's a language that makes it
east break up classes into any number of components, surely that's Ruby!
Mixins, open classes, modules, etc..

~~~
jamesgolick
Mixins/modules and open classes do not separate your class in to multiple
components - merely multiple files. As I explain in the article, for separate
components to be useful, they have to be "protected" from each other -
encapsulation, in other words.

~~~
aphyr
Mixins (well, as they're supposed to be used) _do_ provide encapsulation;
specifically, they enforce the boundary between _instance scope_ (e.g. access
to instance vars) and _method interface_. I view them as a part of a coupling
continuum:

[instance methods] --- [composed subclasses] --- [mixins] --- [the outside
world]

But Modules provide more than that. module_function allows for unattached
namespaced functions which can be referenced by full name, relative name, _or_
imported into the local scope. Great way to express functions which are
decoupled from instance state--much like the services and policies you're
advocating for. It's an under-appreciated aspect of the language, I think.

------
jordo37
Does this actually perform faster by being on top of rails or would we need a
new Ruby framework to get the most speed optimizations from the services and
policies?

------
iamgilesbowkett
I have a prejudicial assumption that if you don't know the problem Objectify
solves, you haven't worked with a Rails app which has A) a large code base B)
a large, active user base and C) a bunch of different features.

The vast majority of people who scale Rails sites (as far as I can tell) do so
by breaking their apps into services. ActiveRecord god-objects do not make
that step in an app's life cycle easy, and separating persistence from
business models is likely to be your first important step when refactoring for
scalability. Fragmenting a User model bloated beyond all hope of sanity is
almost a rite of passage at this point.

I often think the only Rails developer who hasn't found ActiveRecord bloat to
be an irritation and an obstacle to scaling is DHH, and although that makes
his opinion on the subject even more valuable than it would normally be, he
doesn't talk about it enough in my opinion. Pretty much everyone else, as far
as I can tell, responds to Rails scaling issues by creating services in
Sinatra and/or divorcing business modeling from persistence logic.

I want someone to challenge my prejudicial assumption here, most of all
because I appear to be saying "Rails can't scale," which is BS, but also
because I'm very tempted not to take this discussion seriously at all if it
doesn't address this point. It's just _the_ crucial point in my opinion. I
like the whole OOP thing but to me the decision to use something like
Objectify is all about scalability. That doesn't just mean performance; it
also means retaining readability when you have a lot of code. Single
Responsibility Principle makes code readable.

~~~
stiff
I worked in Rails for the last 6 years professionally, and for the last 4
years on a single application. There are lots of ways to tackle this problem,
but it really depends what precisely you have inside those models and there
are certainly no universal silver bullets. Lots of people who complain about
this underuse Rails features, external plugins etc. I think two good ways to
deal with the problem are:

\- Splitting out logical pieces of behaviour into separate modules, especially
the ones less central to the core responsibilities of the class. If you look
at Rails itself (it's great Ruby code, I highly recommend really reading it),
this is the way it is structured, ActiveRecord::Base provides tons of
functionality as a single class, yet it still is very neatly laid out into
many well-separated modules. See e. g.:

<https://gist.github.com/1014971>

[http://api.rubyonrails.org/classes/ActiveSupport/Concern.htm...](http://api.rubyonrails.org/classes/ActiveSupport/Concern.html)

<https://github.com/jakehow/concerned_with>

<http://blog.waxman.me/extending-your-models-in-rails-3>

Deciding what things would fit well into external modules and what modules to
create is a new skill to be learned, but I think it can work well once you do
learn it.

\- Things that aren't part of business logic but just handle some more
technical matters should be extracted into plugins and not be directly part of
the models (for example: special kinds of validations).

\- There is the whole world of OO techniques and patterns that can be applied
here just like anywhere else. For example you can extract complicated
algorithms into separate classes or use value objects:

[http://api.rubyonrails.org/classes/ActiveRecord/Aggregations...](http://api.rubyonrails.org/classes/ActiveRecord/Aggregations/ClassMethods.html)

~~~
iamgilesbowkett
hey man, re:

"If you look at Rails itself (it's great Ruby code, I highly recommend really
reading it)"

I've worked with a member of Rails core, and frequent committers. I've spoken
at 10 Ruby conferences at least, maybe 20. I'm familiar with the Rails code
base. I once rewrote a few small pieces of ActiveRecord from memory for a
stupid project because my wifi was dead.

I agree about it being worth reading, I just want to slow you down there for a
second. Otherwise we're going to end up pulling things out and measuring them.
I took the time to check your links, although I'd seen most of them already.
I'm familiar with concerns and although I think your links are germane I'd
have to disagree with this part:

"Deciding what things would fit well into external modules and what modules to
create is a new skill to be learned"

As I think I've learned the skill.

What I'm saying basically is that I think you missed the mark in terms of
guessing my background but I believe it was an honest mistake.

Egos aside, I agree that modularity matters. And I must admit I had a painful
reminder about that skill recently when I built something around ActiveRecord
and then refactored ARec out of the picture for performance reasons (the gains
were staggering). It would have been less painful with better modularity, but
I don't think the pain relief from using concerns would have been particularly
great in this instance. Non-zero, but insignificant.

I don't care that much about OOP theory, but the pragmatic issues Objectify
addresses seem to come up for people all the time. A year ago Steve Klabnik
and a few other people were talking about this and I noticed it then how it
was echoing James Golick's (the OP) posts about limiting ActiveRecord's role
from a few years before that.

There basically seem to me to be three trends in discussion of scaling Rails:
1) "Rails can't scale" FUD, 2) DHH saying "just add hardware and/or caching",
and 3) this idea of decoupling persistence from modeling, basically, reining
in ActiveRecord, which I've heard from people like James Golick, Steve
Klabnik, Gary Bernhardt, and I think Xavier Shay. Paul Dix wrote a great book
about making Rails apps service-oriented, the Thoughtbot guys touch on it in
their antipatterns book as well, and it's not exactly a coincidence that for
many Rails apps the only gem more crucial than ActiveRecord is Delayed Job or
Resque.

~~~
stiff
When I say "If you look at Rails itself" I do not mean you in particular, I
mean in general for people wondering about the problem a good lesson is
checking out the Rails code, similarly "a new skill to be learned" in the
sense that it is different from traditional OO modelling most people come
from. I know your blog and I've seen you discussing concerns in some other
place, so I do appreciate your background. Maybe being irritated about bad
ideas makes me come up more abrasive than usual.

Anyway, the whole discussion so far was about dealing with the problem of
large (in terms of code size) models, so I assumed by "scalability" you mean
scalability in terms of being able to handle very large code bases, not
performance issues. I do not understand how the approach presented here would
result in performance improvements? I've commented elsewhere on the problems
associated with it, others did as well in a fairly convincing way I think. I
do not deny that problems with scaling both in the performance sense and in
the code size sense do exist, I just do not see how Objectify solves any of
them and I do see how many problems it introduces.

As for breaking your app down into separate HTTP services, I agree this can be
useful in some situations, but it is completely different from the approach
outlined in Objectify, for one you still get a chance to do (almost) normal OO
modelling and structure the code in a reasonable way, even if the message
passing is done via HTTP and not simply via Ruby method calls.

