Improving Hexagonal Rails

259 views
Skip to first unread message

Rafael George

unread,
Sep 17, 2013, 3:53:17 PM9/17/13
to objects-...@googlegroups.com
Hello guys, 

A friend of mine and myself were discussing the other day the way Matt presented Hexagonal Rails which is just great, but we think that having two methods for each action will increase the code inside the controller, I'm talking about the methods for handling success and failures. We came with the following solution:


What do you think about this approach ? 

Matthew Rudy Jacobs

unread,
Sep 17, 2013, 4:18:51 PM9/17/13
to objects-...@googlegroups.com
I have been mulling this style for a while, and it makes sense.
Parsing around a hash of lambdas is not something we're used to doing in ruby
but its worth trying.


--
You received this message because you are subscribed to the Google Groups "Objects on Rails" group.
To unsubscribe from this group and stop receiving emails from it, send an email to objects-on-rai...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Jim Weirich

unread,
Sep 17, 2013, 4:26:40 PM9/17/13
to objects-...@googlegroups.com

On Sep 17, 2013, at 4:18 PM, Matthew Rudy Jacobs <matthewr...@gmail.com> wrote:

> I have been mulling this style for a while, and it makes sense.
> Parsing around a hash of lambdas is not something we're used to doing in ruby
> but its worth trying.

In this article (http://silkandspinach.net/2012/07/06/hexagonal-rails-hiding-the-finders/) Kevin Rutherford mentions this style. His decision was to go with explicit methods because it was easier to test (ie. asserting that call was invoked with a particular lambda argument is difficult).

YMMV

--
-- Jim Weirich / neo
-- Chief Scientist

Marten Veldthuis

unread,
Sep 18, 2013, 2:53:04 AM9/18/13
to objects-...@googlegroups.com
We use the lambda callbacks style. We decided we didnt care about
asserting the value of the lambda given, but only the behavior a
controller has when a given callback was triggered.

- Marten
(Sent from a touchscreen. Please excuse brevity and topposting)

Rafael George

unread,
Sep 18, 2013, 10:25:32 AM9/18/13
to objects-...@googlegroups.com
It's seems to me that in Kevin Rutherford's approach both the model and the use case class knows a lot about it's collaborators.

Matt Wynne

unread,
Sep 18, 2013, 12:37:36 PM9/18/13
to objects-...@googlegroups.com
I personally prefer the explicit method style over the passing lambdas style too. I can't quite put my finger on why.

--
You received this message because you are subscribed to the Google Groups "Objects on Rails" group.
To unsubscribe from this group and stop receiving emails from it, send an email to objects-on-rai...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Mike Kelly

unread,
Sep 18, 2013, 12:57:33 PM9/18/13
to objects-...@googlegroups.com

For me its because method approach enforces method granularity, which makes the various behaviours of the object easier to test in isolation.

In rails controllers where you have many different actions (and each of their listener callbacks) all in one class this can get cumbersome and difficult to follow. I think you could get the best of both worlds there by creating the explicit methods on the controller but passing them in to the service object call using `public_method`

wdyt?

Cheers,
M

Rafael George

unread,
Sep 18, 2013, 2:35:36 PM9/18/13
to objects-...@googlegroups.com
@Mike, exactly that's my problem with the approach of having an explicit call back method inside the controller, but then again probably the issue here is that the controller itself is breaking SRP; probably it could be a good idea to have an action for each controller.


On Tuesday, September 17, 2013 3:53:17 PM UTC-4, Rafael George wrote:

Steve Tooke

unread,
Sep 18, 2013, 3:10:05 PM9/18/13
to objects-...@googlegroups.com

On 18 September 2013 19:35, Rafael George <george...@gmail.com> wrote:

@Mike, exactly that's my problem with the approach of having an explicit call back method inside the controller, but then again probably the issue here is that the controller itself is breaking SRP; probably it could be a good idea to have an action for each controller.

I'm with Kevin, I prefer explicit methods because it makes it far more testable.

By passing the controller in directly as the listener you do end up with a lot of callback methods on the controller.

One way I've used to deal with this is to decorate the controller with the callbacks, something like:

class UsersController < ApplicationController 

  def create 
    CreateUser.new(User).call(params[:user], CreateResponse.new(self))
  end

  class CreateResponse < SimpleDelegator
    def user_created(user)
      flash[:notice] ="The user was created successfully" 
      redirect_to :index

    end

    def user_creation_failed(user)
      render 'new', locals: { user: user }

    end
  end
end

class CreateUser
   def initialize(users_repository)
     @users_repository = users_repository
   end

   def call(attributes: {}, listener)
      user = @users_repository.new attributes

      if user.save
        listener.user_created(user)

      else
        listener.user_creation_failed(user) unless user.save
      end
   end
end

This gives me the ability to test the callbacks in isolation, and it keeps my controllers very simple.

The decorated controller gives you access to all of the controller methods you need. It doesn‘t allow you to set instance variables, but I don’t mind being explicit about what I pass through to the views in the locals hash.



On Tuesday, September 17, 2013 3:53:17 PM UTC-4, Rafael George wrote:
Hello guys, 

A friend of mine and myself were discussing the other day the way Matt presented Hexagonal Rails which is just great, but we think that having two methods for each action will increase the code inside the controller, I'm talking about the methods for handling success and failures. We came with the following solution:


What do you think about this approach ? 

--
You received this message because you are subscribed to the Google Groups "Objects on Rails" group.
To unsubscribe from this group and stop receiving emails from it, send an email to objects-on-rai...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

--
Heavies Limited
Registered Number: 7612561
Registered Address: Parmenter House, 57 Tower Street, Winchester SO23 8TD

Rafael George

unread,
Sep 18, 2013, 3:15:56 PM9/18/13
to objects-...@googlegroups.com
Interesting approach Steve, will try that one out ;-)


On Tuesday, September 17, 2013 3:53:17 PM UTC-4, Rafael George wrote:

Mike Kelly

unread,
Sep 18, 2013, 3:18:17 PM9/18/13
to objects-...@googlegroups.com
Yeah I think decoration is a decent option in light of the convention
for controllers that have a lot of actions. I fear all that
indirection might not be to everyone's taste (although, it doesn't
actually bother me that much).

fwiw, here's what I meant by using `public_method`:

https://gist.github.com/mikekelly/6613879

Cheers,
M
Mike

http://twitter.com/mikekelly85
http://github.com/mikekelly
http://linkedin.com/in/mikekelly123

Steve Tooke

unread,
Sep 18, 2013, 3:18:32 PM9/18/13
to objects-...@googlegroups.com
Graham Ashton has a great post talking through a hexagonal refactoring that he did

Rafael George

unread,
Sep 19, 2013, 10:58:01 AM9/19/13
to objects-...@googlegroups.com
@Mike, also very interesting approach that way you don't have to explicitly call methods names from the service if you pass self as a parameter, the only thing that I notice that I don't quite get is the need of using public_method for the User model, can you explain that a little bit?


On Tuesday, September 17, 2013 3:53:17 PM UTC-4, Rafael George wrote:

Mike Kelly

unread,
Sep 19, 2013, 11:02:38 AM9/19/13
to objects-...@googlegroups.com
it's a small point of style, rather than sending a new message to a
class object, I prefer to send a call message to a factory object.
Both are equally valid, I probably should've just left it how it
was..! ;)

Cheers,
M
> --
> You received this message because you are subscribed to the Google Groups
> "Objects on Rails" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to objects-on-rai...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.



--

Chris Zwickilton

unread,
Sep 19, 2013, 12:11:14 PM9/19/13
to objects-...@googlegroups.com
Steve,

I absolutely love this method and have been using it for over a year.  I was inspired by Matt Wynne's Hexagonal Rails approach, and was wondering who had come up with this particular flavor.  Thanks for presenting it again.  I've added one more level of indirection, though, after being inspired by the blueprint analogy in Uncle Bob's talk on Architecture, The Lost Years.  My controllers call a factory to return the use case needed to fulfill the request. 

I also like to pass the explicit broken out parameters, so the use case objects don't have to know how to break down a hash, and the testing is more clear.  There is obviously a limit to this, but the bulk of my project is an API, so there isn't a lot of information coming in for the most part.

Then, when looking at the structure of the Rails project, you can see all of the use cases for the different themes of the system, and it is quite clear what it is doing, and what each use case is responsible for.

So my version of your example looks like https://gist.github.com/chris-zwickilton/6625578

I've found that the Responder objects can be used across many different calls on the same controller, since the use cases are passing the appropriate object back, or errors in the case of failure.

Chris

Kris Leech

unread,
Sep 20, 2013, 7:19:09 AM9/20/13
to objects-...@googlegroups.com
Chris Zwickilton wrote:

So my version of your example looks like https://gist.github.com/chris-zwickilton/6625578

Is UserUseCaseFactory there just to make testing easier?

Chris Zwickilton

unread,
Sep 20, 2013, 11:36:41 AM9/20/13
to objects-...@googlegroups.com
Kris this is a great question, and one that we've been debating recently on the team.  Originally I built it this way with the wide-eyed idealism of trying to achieve:

- Controllers knowing nothing about ActiveRecord objects
- Dependency injection for both the controllers and use cases (The Factory could be replaced with a different one for testing, or other environments)
- Separation of construction from use
- A clean break between layers, keeping all business logic in use cases, and all http request/response in controllers with one place where it was coded to tie them together (Factory)

It turns out that in practice, I didn't take it far enough.  The two issues that have cropped up are:

- the isolated unit tests for the use cases required far too much mocking because of the AR objects they used
- The extra level of indirection made it slightly more challenging for other developers to go in and quickly get to the place they needed to add/fix functionality

The first one is solvable by removing the AR layer, and maybe that means having POROs that the use cases use, and any persistence is done through some repository layer.  Since AR combines both, you are left with a lot of ugly coupling, and for me, mocking in this case.  I've heard many good suggestions on this list for how to beat that problem, I just haven't done it.

Since I have not solved that first problem, it makes the second issue more prominent.  However, there are several examples in the Factory of different use cases and implementations being returned depending on the environment.  This has been very helpful, for instance, when dealing with 3rd party integrations.  In Development mode, it's nice to not call Facebook and BalancedPayments with each transaction that would normally use them.

The quest for a great "not-the-rails-way" architecture continues.  I can tell you though, that this pattern used throughout this project has made velocity unbelievably higher then in a previous project I inherited where it was all old school rails way.


--
Reply all
Reply to author
Forward
0 new messages