

The problem with controllers - karmajunkie
http://karmajunkie.com/blog/2012/05/07/the-problem-with-controllers/

======
ecoffey
This is a good read, and something I agree with. The command pattern that
you're showing here almost feels like the "write" inverse to the Presenter
"read" action.

The way I've been thinking about it for myself is to imagine your Domain
Objects as this 3D space of object relationships and interactions. So a
Presenter cuts a 2D plane through that space and let's you view from a certain
perspective.

In the case of Commands, you're taking a certain perspective and mutating that
3D space through it.

Not sure if that helps anyone else :-)

Also the focused_controller project looks really interesting as well. I was
working on my own web framework, that made Actions first class objects as
well. And since it was built on this slick IoC library, your Actions could
just declare they need this Command, or these two Services to complete the
request and they would automagically get them. I really like the idea of "one
object(graph) to represent accomplishing a task", and then just having that
object(graph) go do the work.

------
kastephens
The problem isn't controllers. Controller are responsible for mediating the
behavior presented to external actors, not defining complex "business" logic.

Complex logic interacts with complex object graphs, not individual models.
Therefore, complex logic does not belong in models or controllers (or views).
Complex logic belongs in instantated objects (not modules) that represent
complex logic. This style may also be known as the "Strategy" Design Pattern.

Strategy objects can have state during their activities, this is why they
should be instantiated.

Strategy objects simplify testing because they can be connected with any
object graph that presents the same interfaces as the target object graphs.

This leads to interchangable Strategy objects that represent generic behavior
which can be applied to actual, simulated or speculative object graphs.

------
PaulHoule
Kinda funny, I settled in on a "command" architecture for PHP apps around 2001
because the ORM kind of model always has some big semantic gap in it.

------
Stwerner
Slightly off-topic, but does anyone have any resources for learning more about
these and other design patterns that show up on HN from time to time?

~~~
karmajunkie
Design Patterns in Ruby would probably be a good place to start, then the
original GoF Design Patterns book, along with Enterprise Design Patterns which
came later.

Also check out the DDD/CQRS google group:
<http://groups.google.com/group/dddcqrs>

~~~
Stwerner
Thank you! I had seen the Design Patterns in Ruby book when I looked around on
Amazon, but wasn't sure if it would be a good choice. Ordered now, though.

------
papsosouid
The issue of model code creeping into controllers is common with rails and
rails-style frameworks precisely because they are not MVC frameworks. MVC was
a pattern created for making GUI apps in smalltalk in the 70s/80s. It has
gradually been warped and twisted since then, especially when people tried to
cludge it onto web development. The resulting thing doesn't really resemble
MVC at all, and certainly doesn't deliver the benefits MVC was created to
deliver.

MVC is a triangle, rails style frameworks are a line. This is called MVA
(Model-View-Adapter). The "adapter" being in between the view and the model
who can only interact with the adapter and not each other. The second issue is
that in adapting MVC to the web, many frameworks continued with the "one
controller per view" notion, despite that being done because of the
limitations imposed when creating GUI apps. There is no need for multiple
controllers in a web app, all input comes in the same way no matter what view
the user is seeing. In fact, the user doesn't even need to be seeing a view,
there is nothing tying a view to what actions are possible, you can always
submit any http request you want. Your "routes" are your controller, there is
no need for a second level of controllers on top of that.

The goal of MVC was to expose model functionality to the user directly so they
could understand and work with the domain model clearly and easily. Controller
meant "controls the input and output" not "controls the users experience". The
guy who created MVC considers naked objects style frameworks to be the closest
thing to MVC for the web, not rails style MVA frameworks.

And there is something very weird about this statement:

>On top of that, it’s very common to see logic pushed down into the model

Of course that is common, that is what is supposed to happen. Models are not
"stupid containers to pretend to kinda represent my DB sorta but not really".
Models are the business logic. Models are the actual application. You are
modelling the domain, not modelling the database. The model is the domain, it
is all the business logic. The view is the way we present information to the
user. The controller is the part that handles input and output. Very simple
and effective system, but very poorly understood and virtually never used any
more.

~~~
karmajunkie
The problem with "logic getting pushed down into the model" and the gist of
the statement is that not all logic is domain logic. Reaching out and touching
facebook for a status update, for example, is not domain logic and doesn't
belong in a model. And while I agree that we should be modeling the domain,
not the database, I think its clear from working on a lot of complex and
legacy applications over the last several years rails developers model what
the database allows, not the actual domain, thanks to the widespread
acceptance of ActiveRecord as the only tool in that toolchest.

I'm in 100% agreement WRT to MVC—Rails' idea of MVC was never really MVC as
MVC was originally envisioned.

~~~
papsosouid
I don't understand the distinction of "not domain logic". If your application
requirements are "when user does X, update facebook" then that is clearly part
of the domain and should absolutely be in the models.

~~~
karmajunkie
Oh, i disagree with that completely. A user having a status is domain logic.
Pulling that status from an external dependency is decidedly not.

~~~
endersshadow
How is it not? What draws the line between domain logic and non-domain logic?
It would seem to me that, by definition, anything your application does would
fall into that application's domain, right? What other domain would it be in?
Where would you put a request to a third party for supplemental data, if not
in the models?

~~~
karmajunkie
If it were part of your domain, it'd be part of your application. Connection
to facebook by definition is outside the scope of your domain. You can take a
couple of different strategies to it, but in general the best way to handle
that is to introduce a class whose responsibility is to connect to facebook
and return a status (generally speaking, a Service) and something like a
Command or Job that accesses the FacebookService and updates your user model.

Part of the problem with speaking about domains here (aside from being
nonspecific about something that is by its very nature quite specific) is that
Rails has an extraordinariliy half-assed approach to domain oriented design (I
don't want to use 'DDD' here just to avoid buzzwords). Developers have been
told for years to just push it into the model because all the work belongs
there, but that's BS. a LOT of the work has no business being there.

~~~
papsosouid
It is part of the application, and thus part of the domain. A class that is
responsible for getting status updates from facebook is part of your model.
The way you say "updates your user model" makes it seem like you are thinking
about the model as modelling the database. You keep saying this "has no
business being in the model", but you haven't supported that in any way. Why
doesn't it belong in the model?

~~~
karmajunkie
[HN is weird. wouldn't let me post on this earlier, and I was moving it to
your post now when you replied.]

Its not a part of your application. You have to connect to facebook over a
network to get to it. That data is very clearly NOT a part of your
application. Now if a facebook profile is actually a part of your domain in
some way, you're going to have a class specifically to manage that. Connecting
to the network to update that still isn't a part of that class's
responsibility. Look at it this way: if there were someone who knew everything
about your problem area, would their knowledge of the behavior of the data
include reaching out to facebook and pulling it in over a network connection?
almost certainly not, unless your domain is that of a browser. If your domain
is something like klout, for example, your domain is going to include concepts
like profiles, connections, posts, etc. Its not going to include anything
involving Net::HTTP.

~~~
saurik
[For future reference, you often cannot reply to a post very soon after it is
posted from the tree view, but if you click "link" you will be able to reply
from the page that zooms in on just that one post.]

As I describe in more detail in my other post, but will put more succinctly
and from a different standpoint here: you are confusing the conversation by
treating "model" vs. "domain" as if they were equivalent concerns (then to
rely on arguments that things outside the domain must be outside the model),
while the (possibly quite valuable) school of thought you are invoking puts
the "domain" as only part of the model and defines other components that
happily include your connections to external state.

~~~
karmajunkie
Fair enough—i've been using model in the same sense that Rails tends to, which
is to say AR models. All the same, if we're going to use 'model' to refer to
any number of classes dealing with application logic (regardless of whether
its domain logic) then I return to my earlier argument that the Facebook
connection example definitely lies outside the domain (and should also lie
outside any AR models used) and that it should belong in a service class used
by the application logic. I think we're talking in the same direction but
terminology is getting in the way.

