What will the post-Rails contraction be that will lead us to designing good systems? GOOS or functional programming

193 views
Skip to first unread message

philip schwarz

unread,
Feb 10, 2013, 5:50:38 PM2/10/13
to growing-object-o...@googlegroups.com
Tweeted yesterday by Anthony Green (https://twitter.com/anthonycgreen): What will the post-Rails contraction be that will lead us to designing good systems? #GOOS or #FP ?http://www.youtube.com/watch?v=NftT6HWFgq0  -@garybernhardt

The screencast dates back to June 2012. Just posting this for people like me who might have missed it.

Matteo Vaccari

unread,
Feb 18, 2013, 7:22:37 AM2/18/13
to growing-object-o...@googlegroups.com
On Sun, Feb 10, 2013 at 11:50 PM, philip schwarz <philip.joh...@googlemail.com> wrote:
Tweeted yesterday by Anthony Green (https://twitter.com/anthonycgreen): What will the post-Rails contraction be that will lead us to designing good systems? #GOOS or #FP ?http://www.youtube.com/watch?v=NftT6HWFgq0  -@garybernhardt

The screencast dates back to June 2012. Just posting this for people like me who might have missed it.


Hello Philip,

thanks for the link.

I watched the video. His starting example gives me a strong sense of "this is not how I would do it".  The example code I transcribed from the video is

describe Sweeper do
  context "when a subscription is expired" do
    let(:bob) do
      stub(:active => true, :paid_at => 2.months.ago)
    end
    let(:users) { [bob] }
    before { User.stub(:all) { users } }
   
    if "emails the user" do
      UserMailer.should_receive(:billing_problem).with(bob)
      Sweeper.sweep
    end
  end
end

As the GOOS examples are in Java, the above might look unfamiliar to people here, but I think you get the idea.  The point is that the User class (which in Rails would perform the duty of the repository of users) is stubbed so that when we ask it for "all" the users, it returns the single user "bob", which is also a stub.

The presenter goes on to lament how this test, while being a fast and isolated unit test, might also be unreliable, due to the fact that it depends on stubbing and mocking behaviour that might be different in the production implementation.

To me, this is an example of the pain I feel when I see people trying hard to do TDD and then struggling with something like this.  Gary Bernhardt goes on to explain that to overcome the problems in this example, we should move to a more functional style.  FP is OK with me, but you should not use an example of bad OO to conclude that OO is bad in general.

Why is this bad OO and bad TDD?  
  • It tries to be a unit test and an integration test at the same time
  • There is no connection between the expectation and the action performed.  Why is it that the Sweeper should send emails?  Where does it get access to the list of users?  Where does it get access to the mailer?  The ugly convention in Rails is that everything is accessed through globally-available class objects (ruby classes are the new singleton)
  • Where is the business rule being tested?  
What do you all think?

Matteo 

Uberto Barbini

unread,
Feb 18, 2013, 8:22:52 AM2/18/13
to growing-object-o...@googlegroups.com
It's years since I used rails but I agree with your analysis.

I've also see the same kind of errors done in Clojure, so I'm not sure
why functional style should improve it.

Moreover Matteo knows I think that using functional style inside OO
architecture can give us a better OO (as in GOOS examples), so I don't
see at all the problem of choice.

Uberto
> --
>
> ---
> You received this message because you are subscribed to the Google Groups
> "Growing Object-Oriented Software" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to growing-object-oriente...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

J. B. Rainsberger

unread,
Feb 18, 2013, 11:57:31 AM2/18/13
to growing-object-o...@googlegroups.com
On Mon, Feb 18, 2013 at 8:22 AM, Matteo Vaccari <vac...@pobox.com> wrote:
On Sun, Feb 10, 2013 at 11:50 PM, philip schwarz <philip.joh...@googlemail.com> wrote:
Tweeted yesterday by Anthony Green (https://twitter.com/anthonycgreen): What will the post-Rails contraction be that will lead us to designing good systems? #GOOS or #FP ?http://www.youtube.com/watch?v=NftT6HWFgq0  -@garybernhardt

The screencast dates back to June 2012. Just posting this for people like me who might have missed it.


Hello Philip,

thanks for the link.

I watched the video. His starting example gives me a strong sense of "this is not how I would do it".  The example code I transcribed from the video is

describe Sweeper do
  context "when a subscription is expired" do
    let(:bob) do
      stub(:active => true, :paid_at => 2.months.ago)
    end
    let(:users) { [bob] }
    before { User.stub(:all) { users } }
   
    if "emails the user" do
      UserMailer.should_receive(:billing_problem).with(bob)
      Sweeper.sweep
    end
  end
end

As the GOOS examples are in Java, the above might look unfamiliar to people here, but I think you get the idea.  The point is that the User class (which in Rails would perform the duty of the repository of users) is stubbed so that when we ask it for "all" the users, it returns the single user "bob", which is also a stub. 

The presenter goes on to lament how this test, while being a fast and isolated unit test, might also be unreliable, due to the fact that it depends on stubbing and mocking behaviour that might be different in the production implementation.

The presenter says that this is isolated? Wow, we're not using the same language.

      UserMailer.should_receive(:billing_problem).with(bob)
      Sweeper.sweep

Bang! You're dead. The relationship between Sweeper.sweep() and UserMailer.billing_problem() is entirely implicit. I'd use the term MAGIC to describe it. There's nothing isolated about this test. I'd expect something more like this:

it "notifies when it sweeps"
sweep_listener = mock("sweep listener")
sweeper = Sweeper.new
sweeper.add_sweep_listener(sweep_listener)
sweep_listener.should_receive(:swept).with(some_unknown_arguments)
sweeper.sweep
end

I assume there will be variations, like "in this situation, I'll notify with that event object". Here is where you design what the sweeper might have to notify the world about.

Then I have

bob = real User value object representing Bob, as long as it isn't ActiveRecord
userMailer = mock("user mailer")
action = MailUserAboutBillingProblemSweepListener.new(userMailer, …)
userMailer.should_receive(:billing_problem).with(bob)
action.swept(arguments that correspond to a billing problem with Bob)

and its variations, for all the ways we need to respond to sweep() notifications.

That, friends, is what "isolated" means.
-- 
J. B. (Joe) Rainsberger :: http://www.myagiletutor.com :: http://www.jbrains.ca ::
http://blog.thecodewhisperer.com
Free Your Mind to Do Great Work :: http://www.freeyourmind-dogreatwork.com

Ben Biddington

unread,
Feb 18, 2013, 1:45:50 PM2/18/13
to growing-object-o...@googlegroups.com

Got more on Bernhardt's solution?

--

Nat Pryce

unread,
Feb 18, 2013, 2:34:11 PM2/18/13
to growing-object-o...@googlegroups.com
Interesting talk but I'm not entirely convinced. 

I like the observation that very flexible languages will encourage their users to produce a lot of little libraries of syntactic sugar that then get abandoned. But there is no shortage of abandoned open-source libraries in the Java space either. Maybe it's a function of the size of the user base rather than the expressiveness of the language.

Also the history's a bit suspect. Java is definitely a "capability" language not a "suitability" language. It was designed to allow the safe execution of untrustworthy code loaded over the network, and Gosling cut out the parts of C++ that impeded that. However, very few people use Java for what it was designed (remember Jini?), so I guess it got adopted as a "suitability" language even if it wasn't designed as one.

And as for the conclusion: why not both? I've found that it works well to run functional business logic in GOOS-style "tell don't ask" objects that do event-driven I/O.

--Nat

On Sunday, February 10, 2013, philip schwarz wrote:
Tweeted yesterday by Anthony Green (https://twitter.com/anthonycgreen): What will the post-Rails contraction be that will lead us to designing good systems? #GOOS or #FP ?Capability vs. Suitability by Gary Bernhardt  -@garybernhardt

The screencast dates back to June 2012. Just posting this for people like me who might have missed it.

--
 
---
You received this message because you are subscribed to the Google Groups "Growing Object-Oriented Software" group.
To unsubscribe from this group and stop receiving emails from it, send an email to growing-object-oriente...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 


--
http://www.natpryce.com

Ben Biddington

unread,
Feb 19, 2013, 1:08:55 PM2/19/13
to growing-object-o...@googlegroups.com

Alexandre Aquiles

unread,
Feb 22, 2013, 2:22:16 PM2/22/13
to growing-object-o...@googlegroups.com
And as for the conclusion: why not both? I've found that it works well to run functional business logic in GOOS-style "tell don't ask" objects that do event-driven I/O.
 
Michael Feathers wrote about this idea in his article Tell Above, and Ask Below:

Object-orientation is better for the higher levels of a system, and functional programming is better for the lower levels.


And it seems that you put this idea in passing in GOOS. As our fellow Philip Schwarz quoted GOOS in the comments:

"(...) we find that we tend towards different programming styles at different levels in the code. Loosely speaking, we use the message-passing style we’ve just described between objects, but we tend to use a more functional style within an object, building up behavior from methods and values that have no side effects.

Features without side effects mean that we can assemble our code from smaller components, minimizing the amount of risky shared state. Writing large-scale functional programs is a topic for a different book, but we find that a little immutability within the implementation of a class leads to much safer code and that, if we do a good job, the code reads well too".

The quote is in chapter 6 "Object-Oriented Style", section "Internals vs. Peers", box "Different Levels of Language".


Alexandre Aquiles

Nat Pryce

unread,
Feb 23, 2013, 12:36:07 PM2/23/13
to growing-object-o...@googlegroups.com
Another way I find functional style works well with OO is composing objects. I much prefer to write pure functions to build object graphs than use stateful builders. That way it's easier to compose the composers, as it were.

Colin Vipurs

unread,
Feb 23, 2013, 12:35:06 PM2/23/13
to growing-object-o...@googlegroups.com
Nat,

Could you give us an example of that?
Maybe she awoke to see the roommate's boyfriend swinging from the
chandelier wearing a boar's head.

Something which you, I, and everyone else would call "Tuesday", of course.
Reply all
Reply to author
Forward
0 new messages