[GOOS] GOOS in Ruby

167 views
Skip to first unread message

Uberto Barbini

unread,
Jan 27, 2011, 3:39:59 PM1/27/11
to growing-object-o...@googlegroups.com
Hi,

I'm wondering if there is some resource about writing code GOOS style
in Ruby (and Javascript).
I'm not so fluent in Ruby and I never write a big application with it,
I'm wondering how to use TDD in Ruby in the best way for example
without interfaces.

cheers

Uberto

James Martin

unread,
Jan 27, 2011, 4:20:20 PM1/27/11
to growing-object-o...@googlegroups.com
Brian Marick made a start at a Ruby translation of the sniper app from GOOS, which you can find on Github[1]. He got tests and implementation done up to page 182. The end to end tests are written as Cucumber features.

I had the tests running in Ruby 1.8.7 but doubt it would work out of the box on 1.9.2. 

Steve Freeman

unread,
Jan 27, 2011, 5:32:09 PM1/27/11
to growing-object-o...@googlegroups.com
David Chemlinsky traded a couple of messages about it, but now he's got a real job perhaps he's too busy :)

S

Matt Wynne

unread,
Jan 28, 2011, 3:57:12 AM1/28/11
to growing-object-o...@googlegroups.com
The style of TDD which Ruby's RSpec community generally practices is very similar, IMO, to the approach that Steve and Nat have described in the GOOS book.

The RSpec Book [1] is a great guide, not only in how to use RSpec the tool, but how to use it to help drive good OO Ruby code.

[1] http://www.amazon.com/RSpec-Book-Behaviour-Development-Cucumber

On 27 Jan 2011, at 20:39, Uberto Barbini wrote:

cheers,
Matt

ma...@mattwynne.net
07974 430184

James Martin

unread,
Jan 30, 2011, 4:30:10 PM1/30/11
to growing-object-o...@googlegroups.com
+1 for The RSpec Book, which doubles as one of the best guides to Cucumber that I've seen.

Uberto Barbini

unread,
Jan 31, 2011, 4:03:37 AM1/31/11
to growing-object-o...@googlegroups.com
I've read the book and I liked it very much.

Still it doesn't explain very much how to "grow" your applications.

Maybe it's just me but I'd like some more examples about how to design
your objects in the best way (aka Alan Kay's OOP) in Ruby.

cheers

Uberto

tcrayford

unread,
Feb 28, 2011, 11:50:18 AM2/28/11
to Growing Object-Oriented Software
Whilst java is very different from ruby, a lot of GOOS still applies
to ruby. The only major difference that would affect the style
presented in GOOS is the lack of explicit interfaces. I've never
really found that a problem though, you just have to take some more
care when thinking about interfaces.

On Jan 31, 9:03 am, Uberto Barbini <ube...@ubiland.net> wrote:
> I've read the book and I liked it very much.
>
> Still it doesn't explain very much how to "grow" your applications.
>
> Maybe it's just me but I'd like some more examples about how to design
> your objects in the best way (aka Alan Kay's OOP) in Ruby.
>
> cheers
>
> Uberto
>
>
>
>
>
>
>
> On Sun, Jan 30, 2011 at 10:30 PM, James Martin <jimmymar...@gmail.com> wrote:
> > +1 for The RSpec Book, which doubles as one of the best guides to Cucumber
> > that I've seen.
>

Steve Freeman

unread,
Feb 28, 2011, 1:36:24 PM2/28/11
to growing-object-o...@googlegroups.com
I would hope that some of the principles apply. If people really wanted, I expect they could do some reflecto-magic to at least make sure that the implicit interfaces were consistent, and maybe cross-reference their implementors.

S

On 28 Feb 2011, at 16:50, tcrayford wrote:
Whilst java is very different from ruby, a lot of GOOS still applies
> to ruby. The only major difference that would affect the style
> presented in GOOS is the lack of explicit interfaces. I've never
> really found that a problem though, you just have to take some more
> care when thinking about interfaces.

Steve Freeman

Winner of the Agile Alliance Gordon Pask award 2006
Book: http://www.growing-object-oriented-software.com

+44 (0) 797 179 4105
M3P Limited. http://www.m3p.co.uk
Registered office. 2 Church Street, Burnham, Bucks, SL1 7HZ.
Company registered in England & Wales. Number 03689627

Uberto Barbini

unread,
Mar 2, 2011, 4:50:15 AM3/2/11
to growing-object-o...@googlegroups.com, Steve Freeman
I read "the spec book" several months ago only because I'm testing a
java app with cucumber, so I didn't put attention on the ruby testing
and mocking part. ;)

Now I have much clearer... still there is this missing "interface" part.

for example from the page 217 example:

describe Statement do
it "uses the customer's name in the header (with a mock)" do
customer = mock("customer")
customer.should_receive(:name).and_return("Dave Astels")
statement = Statement.new(customer)
statement.header.should == "Statement for Dave Astels"
end
end


that's all and fine, but when I go to implement customer class, I
haven't any clue about needed methods and their parameters other than
go to all the tests and check which one I used.

moreover if in a test I mock customer in a slightly different way like:

customer.should_receive(:fullname).and_return("Dave Astels")

I won't know until my integration tests fail.

I'd like to know if someone already worked in this way on Ruby and can
share his best practices.

On Mon, Feb 28, 2011 at 7:36 PM, Steve Freeman <st...@m3p.co.uk> wrote:
> I would hope that some of the principles apply. If people really wanted, I expect they could do some reflecto-magic to at least make sure that the implicit interfaces were consistent, and maybe cross-reference their implementors.

do you have something specific in mind with "implicit interface"?


cheers

Uberto

J. B. Rainsberger

unread,
Mar 2, 2011, 4:25:40 PM3/2/11
to growing-object-o...@googlegroups.com, Uberto Barbini, Steve Freeman
On Wed, Mar 2, 2011 at 04:50, Uberto Barbini <ube...@ubiland.net> wrote:

I read "the spec book" several months ago only because I'm testing a
java app with cucumber, so I didn't put attention on the ruby testing
and mocking part. ;)

Now I have much clearer... still there is this missing "interface" part.

for example from the page 217 example:

describe Statement do
 it "uses the customer's name in the header (with a mock)" do
   customer = mock("customer")
   customer.should_receive(:name).and_return("Dave Astels")
   statement = Statement.new(customer)
   statement.header.should == "Statement for Dave Astels"
 end
end


that's all and fine, but when I go to implement customer class, I
haven't any clue about needed methods and their parameters other than
go to all the tests and check which one I used.

moreover if in a test I mock customer in a slightly different way like:

   customer.should_receive(:fullname).and_return("Dave Astels")

I won't know until my integration tests fail.

I'd like to know if someone already worked in this way on Ruby and can
share his best practices.

Write stuff down. This is true whether working in Ruby or Java or C#. When I stub a method, I know I need a contract test that justifies the stubbed return value. I write down that I need to do that. When I set an expectation on a method, I know I need to test that method with those parameters. I write down that I need to do that.
-- 
J. B. (Joe) Rainsberger :: http://www.jbrains.ca :: http://blog.thecodewhisperer.com
Diaspar Software Services :: http://www.diasparsoftware.com
Author, JUnit Recipes
2005 Gordon Pask Award for contribution to Agile practice :: Agile 2010: Learn. Practice. Explore.

James Martin

unread,
Mar 2, 2011, 6:41:49 PM3/2/11
to growing-object-o...@googlegroups.com, Uberto Barbini, Steve Freeman
On Wed, Mar 2, 2011 at 8:50 PM, Uberto Barbini <ube...@ubiland.net> wrote:
I read "the spec book" several months ago only because I'm testing a
java app with cucumber, so I didn't put attention on the ruby testing
and mocking part. ;)

Now I have much clearer... still there is this missing "interface" part.

for example from the page 217 example:

describe Statement do
 it "uses the customer's name in the header (with a mock)" do
   customer = mock("customer")
   customer.should_receive(:name).and_return("Dave Astels")
   statement = Statement.new(customer)
   statement.header.should == "Statement for Dave Astels"
 end
end


There's an RSpec extension project called 'aidmock'[1], which attempts to help with this problem. From the (tl;dr) readme:

"Aidmock runs after each test you do. It will get the mocks/stubs defined by your test and match these doubles with the interface you have defined for that object. If your mock doesn’t respect your interface, it will raise an error, preventing you from having a false positive."

So long as you're /always/ running your specs (which of course you should be), then eventually Aidmock will point out that your interfaces don't match up. 

I've only briefly tried it out and haven't used it extensively so can't say how easy or effective it is in practice. 

 

that's all and fine, but when I go to implement customer class, I
haven't any clue about needed methods and their parameters other than
go to all the tests and check which one I used.

moreover if in a test I mock customer in a slightly different way like:

   customer.should_receive(:fullname).and_return("Dave Astels")

I won't know until my integration tests fail.

I'd like to know if someone already worked in this way on Ruby and can
share his best practices.

Language features and libraries might /help/ you fulfil the contracts defined in your test-double collaboration tests but as with any language, it's probably best to write things down and be mindful of the fact that every time you write a collaboration test, you then have an obligation to write the contract tests for the implementors of that interface.


Thanks,
James.


Uberto Barbini

unread,
Mar 3, 2011, 7:44:32 AM3/3/11
to James Martin, growing-object-o...@googlegroups.com, Steve Freeman
Thank you James,

I'll check that.

>> I won't know until my integration tests fail.
>>
>> I'd like to know if someone already worked in this way on Ruby and can
>> share his best practices.
>
> Language features and libraries might /help/ you fulfil the contracts
> defined in your test-double collaboration tests but as with any language,
> it's probably best to write things down and be mindful of the fact that
> every time you write a collaboration test, you then have an obligation to
> write the contract tests for the implementors of that interface.

yes of course.

but I'd like to play around with the interface for some tests before
trying to implement it.

With Ruby I could add directly methods to an new Object without
bothering of using Mocks at all, still I see that they're using in
Rspec, so I'd like to "steal" the best practices from masters
shortcutting months of experience with my own mistakes. ;)


cheers

Uberto

tcrayford

unread,
Mar 3, 2011, 9:40:25 AM3/3/11
to Growing Object-Oriented Software
My real query here is how to name classes, and how to show a class'
responsibilities. In Java, you use interfaces for showing
responsibilities, and classes are just particular implementations of
those responsibilities. In Ruby however, I'm wondering wether to name
classes after the particular implementation, or the abstraction it
implements.

That was very hard to say in the abstract, so I'll throw up a specific
example. I have a class that represents an AuctionHouse, but posts
things to the actual warehouse over XMPP. In Java, I'd likely have a
AuctionHouse interface, and an XMPPAuctionHouse implementation. In
Ruby however, I can't name the responsibility like that, so do I name
my class AuctionHouse or XMPPAuctionHouse?

My current thinking is that you call the class AuctionHouse (because
that's what external users of the abstraction want to know), but then
when I read the code for class, it seems weird because it is all about
XMPP details.

Matt Wynne

unread,
Mar 3, 2011, 9:46:04 AM3/3/11
to growing-object-o...@googlegroups.com

On 3 Mar 2011, at 14:40, tcrayford wrote:

> My real query here is how to name classes, and how to show a class'
> responsibilities. In Java, you use interfaces for showing
> responsibilities, and classes are just particular implementations of
> those responsibilities. In Ruby however, I'm wondering wether to name
> classes after the particular implementation, or the abstraction it
> implements.
>
> That was very hard to say in the abstract, so I'll throw up a specific
> example. I have a class that represents an AuctionHouse, but posts
> things to the actual warehouse over XMPP. In Java, I'd likely have a
> AuctionHouse interface, and an XMPPAuctionHouse implementation. In
> Ruby however, I can't name the responsibility like that, so do I name
> my class AuctionHouse or XMPPAuctionHouse?
>
> My current thinking is that you call the class AuctionHouse (because
> that's what external users of the abstraction want to know), but then
> when I read the code for class, it seems weird because it is all about
> XMPP details.

In Ruby, you can do this

class XmppAuctionHouse
...
end

AuctionHouse = XmppAuctionHouse

Now your clients can do `AuctionHouse.new` and they don't know that they're actually getting an instance of the XmppAuctionHouse. I use this mechanism for injecting stubs in test environments.

Alternatively, you can make AuctionHouse a module with the common implementation in a class ActionHouse::Base, then have modules like AuctionHouse::Xmpp that you mix to compose the ActionHouse that you want:

auction_house = AuctionHouse::Base.new.extend(AuctionHouse::Xmpp)

This gives more control to the client, but exposes more of your internals to them.


>
> On Feb 28, 6:36 pm, Steve Freeman <st...@m3p.co.uk> wrote:
>> I would hope that some of the principles apply. If people really wanted, I expect they could do some reflecto-magic to at least make sure that the implicit interfaces were consistent, and maybe cross-reference their implementors.
>>
>> S
>>
>> On 28 Feb 2011, at 16:50, tcrayford wrote:
>> Whilst java is very different from ruby, a lot of GOOS still applies
>>
>>> to ruby. The only major difference that would affect the style
>>> presented in GOOS is the lack of explicit interfaces. I've never
>>> really found that a problem though, you just have to take some more
>>> care when thinking about interfaces.
>>
>> Steve Freeman
>>
>> Winner of the Agile Alliance Gordon Pask award 2006
>> Book:http://www.growing-object-oriented-software.com
>>
>> +44 (0) 797 179 4105
>> M3P Limited. http://www.m3p.co.uk
>> Registered office. 2 Church Street, Burnham, Bucks, SL1 7HZ.
>> Company registered in England & Wales. Number 03689627

cheers,
Matt

ma...@mattwynne.net
07974 430184

tcrayford

unread,
Mar 3, 2011, 12:52:18 PM3/3/11
to Growing Object-Oriented Software
The aliasing thing sounds interesting. It certainly fixes the naming
problem, which is the only problem I have with the lack of interfaces
right now.

The modules less so. I dislike inheritance quite a bit (for all the
problems discussed at length). Module inclusion is inheritance in
sheeps clothing.
> m...@mattwynne.net
> 07974 430184

Andrew Premdas

unread,
Mar 5, 2011, 1:04:54 PM3/5/11
to growing-object-o...@googlegroups.com
On 3 March 2011 17:52, tcrayford <tcra...@gmail.com> wrote:
The aliasing thing sounds interesting. It certainly fixes the naming
problem, which is the only problem I have with the lack of interfaces
right now.

The modules less so. I dislike inheritance quite a bit (for all the
problems discussed at length). Module inclusion is inheritance in
sheeps clothing.

No it isn't. You could just as easily think of module inclusion as composition, though not perhaps with the current examples that are being given. You could also think of it as a mechanism for multiple inheritance like in C++. What modules in Ruby give you is far more power to create a meaningful set of objects than Java's rather restrictive approach. You just don't yet know the full extent of that power!

Part of your problem is that there is too much inheritance in your original design, and you haven't uncovered the missing class you can use to make you design use composition.  Your AuctionHouse has two seperate responsibilities, Auction stuff, and remote communication stuff. If you used composition you could say that your AuctionHouse has a Notifier (for want of a better name). Now you can have NullNotifier, XMPPNotifier, PigeonNotifier, and you can just mix any one of them into your AuctionHouse. All these Notifier could extend from Notifier::Base which would define your notification api. Finally you have a number of ways to add Notification to your AuctionHouse class. 

Unfortunately I don't know yet the full extent of what you can do in Ruby. I can think of at least 3 different ways of utilising Notifiers with AuctionHouse's, and expect there are several more (Matt's class aliasing was new to me :) )

Finally what if your AuctionHouse needed to Audit as well. How would you deal with the need to post to two (or more) different things?

HTH

Andrew



--
------------------------
Andrew Premdas

Guilherme Silveira

unread,
Mar 6, 2011, 4:42:48 AM3/6/11
to Growing Object-Oriented Software
Mixing in a module with one method to do "template method based
composition" might be ok, as described here:
http://fabiokung.com/2010/05/06/ruby-and-dependency-injection-in-a-dynamic-world/

Although I still feel like its service location (not inversion of
control).

Unfortunately mixing in a module involves all inheritance related
complications. Starting from coupling you with the entire module
private methods and variable definitions. That means, that lack of
encapsulation and total coupling to the module's internal code.

Therefore, IMHO, using mix-in to add a little bit more than a method
seems like going to the nasty way of composing behavior.

> No it isn't. You could just as easily think of module inclusion as
> composition,
The problem is, including 55 modules and ending up with a class which
has 300+ methods is composing behavior. But composing behavior of half
of your app into one huge object.

> though not perhaps with the current examples that are being
> given.
Agreed. But I still dont see how it achieve something that can't be
achieved without "new" and DI on construction.

> What modules in Ruby give you is far more power to create a
> meaningful set of objects than Java's rather restrictive approach. You just
> don't yet know the full extent of that power!
Just a joke: the power is 56 modules and 300 methods? :)

Regards


On 3월5일, 오후4시04분, Andrew Premdas <aprem...@gmail.com> wrote:

Uberto Barbini

unread,
Mar 6, 2011, 2:28:20 PM3/6/11
to growing-object-o...@googlegroups.com, tcrayford
On Thu, Mar 3, 2011 at 3:40 PM, tcrayford <tcra...@gmail.com> wrote:
>
> My real query here is how to name classes, and how to show a class'
> responsibilities. In Java, you use interfaces for showing
> responsibilities, and classes are just particular implementations of
> those responsibilities. In Ruby however, I'm wondering wether to name
> classes after the particular implementation, or the abstraction it
> implements.


A friend suggested me this video on SOLID Ruby:
http://confreaks.net/videos/185-rubyconf2009-solid-ruby

I think that what Jim Weirich calls protocols are a very good solution
but I'm not sure about write about them in the documentation is
enough.

But I can easily imaging to have a test on my Furnace class checking
that it implements OnOffDevice protocol using something like

furnace.repond_to?(:on, :off)


cheers

Uberto

Andrew Premdas

unread,
Mar 8, 2011, 10:12:48 AM3/8/11
to growing-object-o...@googlegroups.com
2011/3/6 Guilherme Silveira <guilherme...@gmail.com>

Mixing in a module with one method to do "template method based
composition" might be ok, as described here:
http://fabiokung.com/2010/05/06/ruby-and-dependency-injection-in-a-dynamic-world/

Although I still feel like its service location (not inversion of
control).

Unfortunately mixing in a module involves all inheritance related
complications. Starting from coupling you with the entire module
private methods and variable definitions. That means, that lack of
encapsulation and total coupling to the module's internal code.

Therefore, IMHO, using mix-in to add a little bit more than a method
seems like going to the nasty way of composing behavior.

> No it isn't. You could just as easily think of module inclusion as
> composition,
The problem is, including 55 modules and ending up with a class which
has 300+ methods is composing behavior. But composing behavior of half
of your app into one huge object.

Yes you can use modules in a stupid way. But you don't have to, and it doesn't reflect badly on modules, or their inclusion mechanism.

> though not perhaps with the current examples that are being
> given.
Agreed. But I still dont see how it achieve something that can't be
achieved without "new" and DI on construction.

Here you are applying Java idioms to Ruby - its something I keep on doing as well. There is no need for DI in Ruby see blog posts by Jamis Buck about this.
 
> What modules in Ruby give you is far more power to create a
> meaningful set of objects than Java's rather restrictive approach. You just
> don't yet know the full extent of that power!
Just a joke: the power is 56 modules and 300 methods? :)

:) 

I may be out of line here, but I think maybe part of the problem is trying to apply GOOS to Ruby. Maybe it would be better to learn Ruby and then see if GOOS is applicable to it.

All best

Andrew

Uberto Barbini

unread,
Mar 8, 2011, 10:24:06 AM3/8/11
to growing-object-o...@googlegroups.com
> I may be out of line here, but I think maybe part of the problem is trying
> to apply GOOS to Ruby. Maybe it would be better to learn Ruby and then see
> if GOOS is applicable to it.

my take is that some parts yes, some parts no, but I don't know which! ;)

anyway much more than in DI and interfaces, Ruby is different for the
metaprogramming abilities.

For example how can you grow a DSL guided by tests?


cheers

Uberto

Matt Wynne

unread,
Mar 9, 2011, 6:52:26 AM3/9/11
to growing-object-o...@googlegroups.com

I grow DSLs by refactoring mostly. If I have tests in the right places, I can refactor a DSL out of code that already works without changing the tests, and then when I want to start using the DSL somewhere else, I write new tests against the DSL's interface to lock down the behaviour that's being shared.

Guilherme Silveira

unread,
Mar 9, 2011, 10:55:43 AM3/9/11
to Growing Object-Oriented Software
> For example how can you grow a DSL guided by tests?
You can system-test them and grow them accordingly, pretty much the
way the book proposed the skeleton for the first test and then
extracted unit tests.

What I personally dislike is the over-engineering of some magic.
Instead of using metaprogramming to do composition, a simple new would
suffice. No tricks. Just four words away (def initialize end new).
Instead, the BaseMethodsClassMethodsBIgWordsLoadsOfLinesPattern is
used.

IMHO, over engineering.

Regards

Nat Pryce

unread,
Mar 9, 2011, 5:16:51 PM3/9/11
to growing-object-o...@googlegroups.com, Guilherme Silveira
On 9 March 2011 15:55, Guilherme Silveira <guilherme...@gmail.com> wrote:
>> For example how can you grow a DSL guided by tests?

Hmmm... that's a good idea for a book...

--Nat

--
http://www.natpryce.com

Jamie

unread,
Mar 10, 2011, 3:43:53 AM3/10/11
to Growing Object-Oriented Software
Let's do it. DSLs guided by tests. Start with an open source
project... we built a DSL for finance, bumping curves, stripping,
etc., using interface chaining. We could reproduce that...

BTW, you grow the DSL like you grow anything. If you want to write a
DSL in the old fashioned way, you can use the latest equivalants of
Lex and Yacc (I think Bison and something else in Java). The
structure of the language is captured in BNF - <name> =
<firstname><lastname>. You write a unit test for each rule. So, you
get <firstname> passing, then <lastname> and then compose those tests
into <name>. As your language grows, so do your tests, and you end up
having a mirror test DSL emerging. As you get close to completion,
your tests are for full segments of the language. It's a really
interesting process, writing a language. Superficially it's daunting,
but the step wise process takes care of itself. Also, there's a
really beautiful symmetry between the language rules and the tests.
It's a programmers dream, a bounded problem, clear exits and entrances
and no need to work with other people.

Steve Metsker covers testing in his 2001 book, Building Parsers in
Java. It's not a great book, and that chapter is rudimentary, but it
gives and idea.

I think that DSL are always grown, but we could put together a modern
take on it. We could just bind together 10 essays and it'd sell.




On Mar 9, 11:16 pm, Nat Pryce <nat.pr...@gmail.com> wrote:

Uberto Barbini

unread,
Mar 10, 2011, 5:06:42 AM3/10/11
to growing-object-o...@googlegroups.com, Nat Pryce, Guilherme Silveira
On Wed, Mar 9, 2011 at 11:16 PM, Nat Pryce <nat....@gmail.com> wrote:
> On 9 March 2011 15:55, Guilherme Silveira <guilherme...@gmail.com> wrote:
>>> For example how can you grow a DSL guided by tests?
>
> Hmmm... that's a good idea for a book...

Yes!!

just to be clear, it's not difficult to test your DSL while it grows,
the hard part (well for me at least) is how to use your tests for
guide its grow.

For example, take somethink like Sinatra and move it till you have
your webapp completely defined as DSL, something like


when requestFor listOf Customer do
fetch first(pagination.size) Customers
display customers in evenOddRows Grid
end


cheers

Uberto

Guilherme Silveira

unread,
Mar 10, 2011, 6:04:50 AM3/10/11
to growing-object-o...@googlegroups.com
So we are not talking about unit testing the DSL, is it so?
If so, is it different from the current dsl's built using test first + refactor?

Regards

Guilherme Silveira
Caelum | Ensino e Inovação
http://www.caelum.com.br/

Reply all
Reply to author
Forward
0 new messages