

Ruby Best Practices (full book available for download) - figured
http://blog.rubybestpractices.com/posts/gregory/022-rbp-now-open.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+RubyBestPractices+%28Ruby+Best+Practices+-+Blog%29&utm_content=Google+Reader

======
sandal
For the tl;dr crowd, this will take you straight to the PDF:

<http://sandal.github.com/rbp-book/pdfs/rbp_1-0.pdf>

(But please read the article, it provides context :)

~~~
ddemchuk
you provided a tl;dr link to a BOOK???! haha, wednesday morning irony ftw

~~~
sandal
Hah, the irony here did not escape me. But good point.

So... here's the tl;dr; for the book itself:

"Ruby provides many ways to do things, many of them decent. But some are
usually better than others, depending on the context."

------
figured
I recommend this book whole heartily. I have been reading the chapters as they
have been released, an excellent resource.

------
bgraves
So, is this the full version of the O'Reilly book [1] or something different?
I'm curious about the business end of this project: did you sell this PDF
before giving it away for free? How much revenue have you brought in? How much
time have you spent writing/compiling/editing this book in it's current state.
It seems like a very highly regarded book (judging from the Amazon reviews) so
perhaps I am just out of the loop on this one, but I find the business aspect
of these ventures most interesting.

[1][http://www.amazon.com/s?ie=UTF8&tag=mozilla-20&index...](http://www.amazon.com/s?ie=UTF8&tag=mozilla-20&index=blended&link_code=qs&field-
keywords=Ruby%20Best%20Practices&sourceid=Mozilla-search)

~~~
sandal
It is exactly what was used to generate the print book, just with some web
enabled features like links. And yes, this is the PDF you'd get if you buy it
from O'Reilly.

Marketing-wise, it was a gamble, because the open source release date wasn't
contingent on sales or anything like that. We launched the book and gave a 9
month exclusive rights period to O'Reilly.

This at least takes into account the fact that most books sell the majority of
their copies in the first month or two, but I didn't have like a minimum sales
number before I could open source the book or anything like that. In fact, the
print book says right in the front cover that it'd be open sourced in March.

The book did okay sales wise, not great, but not horrible. It definitely did
worse than it should given that (at least from the looks of it) people really,
really like it. But this isn't really up to the readers, it's up to the
distributor. Basically, much of our sales come from wholesale, and with paper
book stores on the decline, and the saturation of the market with Ruby books
over the last couple years, it was hard to convince them to pick up a lot of
copies of the book.

As of right now, I am just about at the point of clearing my advance. I will
share specific numbers at some point, but let's just say that the advance
probably works out to minimum wage or less when compared to the amount of
effort put in.

Interestingly enough, the gradual week by week release of chapters really led
to a nice spike in sales, coming from what was essentially a steady decline
except for a spike around the holidays. So actually, I think open sourcing the
book was good for sales in that regard. Since it might be hard to find the
book on the shelves in a book store, this gives people a chance to "try before
they buy".

Unfortunately, because my book was selling above average as an ebook, I've
probably effectively killed those sales today. Then again, maybe people will
still buy the Kindle and Iphone editions, who knows.

At the end of the day, I think neither O'Reilly nor myself expected this book
to be a big bread winner. I love the book because it embodies the most
interesting things I've learned from the smartest people I know, and I think
that comes through in the writing. I wrote the book because the idea popped
into my head fully formed and demanded to be put out on paper. So that was my
biggest win.

But from an authors perspective, RBP has given me a great boost in exposure. I
already had name recognition in the inner circles of Ruby community, but after
writing the book, I find more opportunities from folks I probably wouldn't
have been able to reach otherwise. This has been good for my open source
projects, and good for my work.

I'm glad I did this, and it worked out well. I'd recommend it to others, for
sure. Of course, buying the book will make O'Reilly happy, so go ahead and do
that if you want :)

~~~
bgraves
Thank you for the details! Much appreciated.

Even though you may not have been paid a "fair wage" for the work that you put
into this book, it sounds like you are very happy with the outcome and the
experience and the future benefits that you will undoubtedly reap from this
project.

Congratulations and thanks again!

~~~
sandal
Actually, I don't think my advance was unfair. I self published a book a
couple years ago and it was a logistical nightmare. When you think about what
a publisher actually does, it's really a daunting task.

I think there was a post here on HN about that recently, but I can't remember
the link. The author who wrote it described pretty much the exact process I
went through, even though I think he was working with another publisher...

~~~
jellisjapan
Could you explain a little bit more about the "logistical nightmare" aspect of
self-publishing? I'm thinking about self-publishing a book of my own, so I'd
love to hear more about the obstacles you came across and how publishers make
it easier.

~~~
sandal
Well, I think that it can be profitable, especially if going EBook only. There
is some great advice on it here:

<http://macournoyer.com/blog/2010/03/01/promote-cyopl/>

But for me, I didn't want to spend a ton of time and effort on marketing, and
my topic was a niche within a niche at the time (I wrote the Ruport Book with
Mike Milner -- ruportbook.com).

After a year or so, instead of being thousands in the black, we were hundreds
in the red, even though the book sold a few hundred copies. So we just made it
available at cost and closed the doors at that point.

This may be because the HTML version was available for free when we started.
It may be because we set price points very low (I think our PDF was like $8),
it may be because I started an LLC and wasted tons of money on absurd taxes
just for keeping the doors open. It was a bunch of epic fail on the business
side of things, and that at least taught me a lesson.

I talked to O'Reilly and though they were very inflexible about certain things
(due dates, typesetting, etc), they were open to change pretty much everything
that mattered to me, and did. As a result, my book shipped _early_ and at a
much higher quality level than I could imagine doing myself.

Of course, I could tell you stories about other publishers I either pitched
ideas for, did tech editing with, or wrote chapters for that'd make your head
spin. So I wouldn't say that professional publishers are good across the
board, just O'Reilly pretty much let me run with my ideas and ended up being
very accomodating.

This may have something to do with the fact that I blogged and wrote articles
with them for a while before writing a book, and because my editor is also a
friend of mine from the Ruby community. But I know folks who have pitched
O'Reilly cold and had similarly positive experiences, so I don't think that's
the case.

Ultimately, publishing is going to be what you make of it. Self-publishing
gives you full control, but it also gives you full responsibility. I think you
can make money on it if you market effectively, and I think it can be a
worthwhile if you really want to do something unique.

But for me, someone who just wanted to get some ideas out there and maybe make
a buck or two in the process, doing all of the work of self publishing really
was horrible.

------
richcollins
Keyword arguments via hashes is certainly not a best practice for "Beautiful
API Design". Sending messages is part and parcel to good OO design. Code that
deconstructs hashes to emulate keyword arguments is invariably hideously
complicated.

~~~
sandal
I agree with you from a language design standpoint, but seriously, I doubt you
have much Ruby experience if you're saying this. And if that's the case, you
really don't have a basis to be commenting on my book in such a critical and
dismissive way.

Using positional arguments for more than two or so things creates connascence
of position, which quickly becomes annoying.

Using block based DSLs so that you can break things down into small functions
that each do their part is a good way around this, but these tend to be hard
to extend dynamically.

Typically well designed Ruby systems provide both: Pseudo keyword arguments
for dynamic needs, and some DSL-type syntax for pleasing the eyes.

Yes, it sucks that we don't have real keyword arguments. But no, it's not
nearly as bad as you think.

~~~
richcollins
I've been using Ruby since 2005 and I am a top 100 contributor to Rails
(<http://contributors.rubyonrails.org/>). Rails design suffers for its heavy
use of "keyword arguments".

 _positional arguments for more than two or so things creates connascence of
position_

Which is precisely the reason that you shouldn't pass more than two arguments
to a method (unless you are creating a list or hash for their intended
purpose). If you have more than two arguments to a method, it's a sign that
you should reify them into an object.

 _Using block based DSLs so that you can break things down into small
functions that each do their part is a good way around this_

Why do people love making things complicated by misusing blocks. Just create
an object and set slots on it. Blocks are best used for delaying computation,
not setting up state.

I think that Zed Shaw's essay on the "Master" and the "Expert" is applicable
here: <http://www.zedshaw.com/essays/master_and_expert.html>

~~~
sandal
Wow, and this is exactly the kind of douchebaggery I was trying to get away
from in my book. You know, I think on the first page I mention that the answer
to "what the best way" to do something in Ruby is always "it depends". The
notion that you can follow singular design principles in all situations is
absurd, if you ask me.

Context is king, and what you've done is taken a single point from my book,
ripped out its context, strawmanned it to death, and used it to bolster you're
own "Top 100 rails" status.

I encourage readers to actually see what I had to say in the book by
downloading the PDF before taking these arguments too seriously. If there are
some constructive examples to be shown that seem promising and pass peer
review, they'll definitely make it into the open source version.

It might even be worth it to write up a section describing the tradeoffs that
richcollins has pointed out, but it's definitely not something as universal as
he makes it sound.

~~~
richcollins
_used it to bolster you're own "Top 100 rails" status._

I've mostly stopped using Rails and Ruby in favor of Io, so I have no interest
in bolstering my Rails status. I was just providing evidence to counter your
assertion that I was a Ruby newb.

 _The notion that you can follow singular design principles in all situations
is absurd, if you ask me._

I agree that "it depends", but using Hashes as arguments has become idiomatic
Ruby, which is unfortunate in most cases.

~~~
sandal
I wasn't assuming you were a newb, just that you didn't have much exposure to
what are commonly regarded as well designed Ruby libraries. It didn't occur to
me that you'd have had that exposure and yet sound as if you were shocked and
appalled about what is common practice.

I still would really like to see examples of well designed open source Ruby
projects that follow what you consider to be decent design principles. I think
that'd make a much stronger case for your argument, and might open my eyes to
something that's been in a blind spot.

Personally, I feel like a certain amount of API design is bound to what
consumers will expect. We can certainly stretch and shift their tendencies,
but if we fly in the face of them, our perfection in a vacuum will never be
appreciated.

~~~
richcollins
Which libraries do you consider well designed? I'll let you know how I think
that they could be improved.

~~~
sandal
I've already written an entire book on this and given it away for free. I
suggest you read it and write a review. Be specific, and show good
counterexamples. I'll be happy to link you when you do.

Until then, stop acting like you're some sort of authority (NOTE: This is not
to claim _I_ am -- because I'm not and no one is.) I just think it'd make
sense to put your ideas into a bit of context so people can see that you're
not just being critical for the sake of being critical.

~~~
richcollins

        #from your book
        
        def distance(*points)
          case(points.length)
          when 2
            x1,y1,x2,y2 = points.flatten
          when 4
            x1,y1,x2,y2 = points
          else
            raise ArgumentError, "Points may be specified as [x1,y1], [x2,y2] or x1,y1,x2,y2"
          end
          Math.hypot(x2 - x1, y2 - y1)
        end
    
        puts distance(1, 2, 5, 6)
        puts distance([1, 2], [5, 6])
    
        # why would you choose to make a complicated interface that requires a complicated implementation?
    
        # simple, clear interfaces that allow for simple implementations
        # are almost always preferrable to complicated ones that save a
        # keystrokes through syntax
    
        class Point
          attr_accessor :x
          attr_accessor :y
      
          def initialize
            self.x = 0
            self.y = 0
          end
      
          def self.with(x, y)
            new.set(x, y)
          end
      
          def set(x, y)
            self.x = x
            self.y = y
            self
          end
      
          def distance_to(a_point)
            Math.hypot(a_point.x - x, a_point.y - y)
          end
        end
    
        puts Point.with(1, 2).distance_to(Point.with(5, 6))

~~~
sandal
So you mean that you prefer this:

Point.with(1, 2).distance_to(Point.with(5, 6))

Over this?

distance [1,2], [5,6]

I guess it depends on how many interesting things you wanted to do with
points. As things get more complicated, maybe something like this is
worthwhile, but I don't feel that making everything an explicit object is
categorically better.

But the section you're quoting is among the most contrived examples that RBP
gives, it's mainly just part of a list of the different sorts of argument
processing Ruby offers and the trade-offs betweeen them.

Maybe you skimmed and missed that, or maybe you read through and chose to
ignore that detail.

~~~
stevedekorte
The problems I have with "distance [1,2], [5,6]" are:

0\. It breaks the fundamental OO convention and doesn't encapsulate logic and
data.

1\. It's not clear what it means unless you look up the docs.

2\. It's implementation is complex, making it more difficult to understand and
maintain

3\. It fails to separate concerns, making it less extensible/modifiable. e.g.
What if you wanted to override the setting behavior? You couldn't do it in one
place.

------
daveungerer
The sandal username on GitHub sounded familiar, so I checked and realised its
the same sandal that does the Prawn PDF library:
<http://github.com/sandal/prawn>

That gives the book some extra credibility in my eyes.

EDIT: OK, now that I've read the foreward, I see Matz himself mentions
Gregory's work on Prawn. Doh.

~~~
sandal
Yes, I started Prawn via the "Ruby Mendicant" project:
<http://majesticseacreature.com/mendicant/>

I'm still active in the project as a maintainer. But really, these days you
have Brad Ediger, James Healy, and Daniel Nelson, along with about 60+
contributors to thank for where Prawn is heading.

My job is mostly to sit around naming things, and warning people about the
fragility of the early code I wrote. But we will have a 1.0 plan soon, and no
matter who does the work, that'll be good for everybody.

------
onewland
This looks sweet. Thanks sandal (for writing)/figured (for posting).

------
Pistos2
Thank you for writing this, and thanks for open sourcing it.

~~~
sandal
The Ruby community has taught me so much, it seems the reasonable thing to do.
Also, old books tend to go out of print, and then die sad, lonely out-of-date
deaths.

Maybe this will keep RBP moving forward, and keep it alive.

------
sandal
BTW, going to experiment with using a wiki page for collecting reader
questions. Once I have a few lined up, I'll cut a blog post reply on the RBP
blog.

<http://wiki.github.com/sandal/rbp-book/questions-for-gregory>

------
erikpukinskis
Here's a copy on Google Docs. I hate PDFs:

[https://docs.google.com/fileview?id=0B8mB_WI1jRkCMzgyZWY5MzY...](https://docs.google.com/fileview?id=0B8mB_WI1jRkCMzgyZWY5MzYtOTM0NC00YTRiLTg3NWMtZDU1MTdmM2QzNzU0&hl=en)

~~~
sandal
I'll run the book through asciidoc's html generator soon enough, but thanks
for doing this for now.

Looks like it loses some quality on translation to Google docs, though...

------
jamesbritt
Sweet! Thanks, Greg.

