When Ruby Best Practices first entered roughcuts, I passed on a couple copies to some reviewers to see what they thought, and Peter Cooper summed things up pretty accurately:
Gregory gave me a copy of the first three chapters to look over, and they're well crafted. This definitely isn't a reference book, a "cook book" or any sort of book you merely "dip" into. It's designed to be read by the chapter. The first chapter, Driving Code Through Tests, for example, takes you on a journey through the world of testing in Rubyland from motivation through to best practices - it's a full introduction to a single topic.
Each chapter in RBP is designed to challenge the reader to become immersed in the topic. To do this, I always start off with code from real projects, not just some abstract examples to show off the features of some aspect of Ruby.
I follow up these case studies with some more general topics that provide broader understanding. Whenever I can find a real example that explains the topic better than a constructed one, I go with it. Sometimes the situation demands simplified or abstract examples, but you’ll find this book to contain far fewer of these than what you might in your average reference book.
Though that might sound similar to a cook book in some ways, this book is really quite different. There is very little code in the book that you can just copy and paste into your application and be off and running. Instead, the purpose of including real code examples is to help you learn how to think about the problems they solve. If you were expecting a cookie cutter list of “Do this, not that” comments, RBP is probably not for you.
But this all seems to be shrouded in mystery still, and the purpose of this post was to get rid of those vibes, not perpetuate them. So without further ado, here’s a chapter by chapter walk through what you’ll find in the book.
This chapter was originally written in RSpec, but later ported to vanilla Test::Unit. It starts off by showing a warning sign of what code with poor testability can look like, and then goes on to walk through the life-cycle of a relatively simple Prawn patch as I drive things forward through tests. Both of these examples are based off of real stories, not just things I thought up after the fact.
The chapter assumes you have a basic understanding of how tests work, so the focus is primarily on improving the way you write your tests and manage your overall test suite. I touch on everything from coding up custom assertions to when mocks / stubs might be helpful.
OSS Projects Discussed: Test::Unit, RSpec, Prawn, ActiveSupport, FlexMock, Rake, Nokogiri, and the code running this blog (Blaag)
In this chapter, we start off by looking at the powerful Table() method from Prawn and how it’s implemented. This is basically a convenience constructor that dynamically changes its behavior based on the arguments you give it and whether or not you provide a block. Though it’s far from magical, it’s one of the better interfaces I’ve designed, so it was a good place to kick off the chapter.
We focus on the fundamentals in this chapter, leaving the highly dynamic tricks for later. The emphasis is placed on what you can achieve with nothing more than Ruby’s flexible argument processing and the ability to pass around codeblocks as ordinary objects.
Although this chapter doesn’t have as much code from real Ruby projects as the other chapters do, it does put together a nifty little TCPServer based message handler, which ends up with a pretty smooth interface in the end. Here’s a sneak peek of what that looks like:
Server.run do
handle(/hello/i) { "Hello from server at #{Time.now}" }
handle(/goodbye/i) { "Goodbye from server at #{Time.now}" }
handle(/name is (\w+)/) { |m| "Nice to meet you #{m[1]}!" }
end
This chapter might not have any surprises in store for seasoned Rubyists, but those who aren’t used to the level of flexibilty Ruby affords you will be sure to learn some new tricks.
OSS Projects Discussed: Ruport
This is possibly the most hard-core chapter in the book. Even though RBP is a Ruby 1.9.1 book from the ground up, we explore in the case study one of the most clever hacks to ever be used in Ruby 1.8, BlankSlate. This bit of code is part of the builder gem, and provides an abstract base class that hides most of the functionality in Object. The beautiful thing about BlankSlate is that it provides a way to restore these features selectively. To accomplish this task, a whole slew of dynamic Ruby techniques are used.
This chapter is no slouch when it comes to discussing real code, as we move on from BlankSlate wildness to discuss all sorts of dynamic techniques used in other projects. I discuss the how and why behind Prawn.generate, show an example of a ActiveSupport core extension, look at how RubyGems overrides Kernel#require, hint at the mysteries hidden in Camping, and round things off by looking at Fatty, the underlying formatting engine that will power Ruport 2.
In addition to these examples from the wild, we also show how to build up some parts of a simple test framework, including our own test harness and stubbing mechanism. Finally, this chapter ends with a challenge to help evaluate the reader’s understanding, which I hope is a fun addition.
OSS Projects Discussed: BlankSlate (via XML::Builder), Prawn, Ruport, PDF::Writer, ActiveSupport, RubyGems, Camping, Fatty
This chapter is mostly based on a training session I gave with James Edward Gray II at Lone Star RubyConf 2008. It kicks things off to show how to do line based file processing with state tracking, using Prawn’s AFM parser as an example.
This chapter focuses mainly on the merit of Ruby for scripting needs, covering a few utilities I use day to day, ranging from scraping stock market quotes off of google to simplifying the task of vendoring a project from GitHub. Some love is also given to useful tools such as the Tempfile standard library, and good strategies such as atomic saves for destructive I/O operations.
OSS Projects Discussed: Prawn’s port of the perl library Font::AFM
Although Ruby isn’t an ideal language for formal functional programming, there are plenty of techniques that do translate well so long as you are willing to exercise a little poetic license. In this chapter, we look at MenTaLguY’s lazy.rb, in addition to some tools built on top of the examples from James Gray’s Higher Order Ruby blog series, which was in turn translated from the book Higher Order Perl by MJD.
Along the way, I’ve snuck in a few practical examples from my day to day work, as well as some more Prawn code. While functional purists may come up empty handed after reading this, most others will gain some valuable skills that make sense in the context of Ruby. To set the tone, I certainly don’t suggest you should go around freezing your objects all willy nilly just to avoid state modification. :)
OSS Projects Discussed: lazy.rb, Prawn, and several of the objects in JEG2’s “Higher Order Ruby” Series
This appendix is meant to help catch the major gotchas when it comes to writing code for Ruby 1.9 that will also work on 1.8. I cover briefly some of the things to watch out for, but focus more on the process of back-porting and how to keep things clean and manageable.
The remaining chapters listed here have not been publicly released yet to Rough Cuts reader, so I reserve my right to be cloak and dagger about them. But I do want to give people at least a glimpse of what they’ll see in the next 4-6 weeks before the final draft is complete.
Debugging techniques without ever needing a debugger. Performance measurement and tuning. Basically, ways to get yourself out of trouble when things go wrong.
Our internationalization / localization chapter. I will be talking primarily about the m17n functionality in Ruby 1.9, but also evaluating some localization strategies.
Writing good Ruby is about more than just technically proficient code. How you organize and manage a project also come into play. This chapter will talk about how to keep a project running smooth even when it grows and becomes complex. This will draw on conventions and tools that are in common use across open source Ruby projects, some you may already know about if you’ve released any software to the community.
A fun walk through ten of my favorite standard libraries that come with Ruby. Just for fun, I’ll be releasing sections 2, 3, 5, and 7 to this blog in the coming days. This appendix is meant to demonstrate to the user just how diverse Ruby’s standard library really is, so it’s less of a reference and more of a show-and-tell session.
This book isn’t really a “Do this, not that” guide, as I mentioned before. But enough people asked me to talk about anti-patterns that I feel a short appendix of some basic things you really shouldn’t do in Ruby is in order. I hate the title though, so if someone suggests a better one, I can probably swing you a free copy of the book, or at least email you a PDF.
This chapter list is pretty much finalized, but there is still room for changes. Please pick up the roughcut so you can begin to offer feedback. For those who need more convincing, after I release some of the sections from the stdlib appendix, I might be able to leak a full chapter. If you could pick just one of these for all to see, which one would it be?
Keep in mind the whole book will become a community resource 9 months after print under a Creative Commons license. So anything you do to help now will eventually make it’s way out to the community. All said, that’s one of the main reasons why it has been a blast working on this book, and I hope that you enjoy it when it hits the shelves.
I’m excited to hear what you think, so please drop a comment while you’re here!
Written by Gregory Brown on 2009.02.06 at 14:33 | Responses