October 21, 2014

Ruby InsideRaptor: A Forthcoming Ruby Web Server for Faster App Deployment

Peter Cooper @ 2014/10/21 01:20 PM

Raptor bills itself as a new Ruby "app server” and it claims to blow everything else out of the water performance-wise (by between 2-4x!) whether that’s Unicorn, Puma, Passenger, or even TorqueBox on JRuby. The bad news for now is there’s no source or repo yet and only a handful of people (including me) have been given a sneak peek, although a public beta is promised on November 25th.

The history of Ruby webapp deployment

The deployment of Ruby (and therefore Rails) webapps was a painful mess for years, a state I lamented 7 years ago in No True ‘mod_ruby’ is Damaging Ruby’s Viability on the Web. Thankfully, shortly thereafter a number of projects came out to make life easier, the most famous being Phusion Passenger (then known as mod_rails) in April 2008.

Things have continued to improve gradually over the years, with Passenger getting consistently better, and new approaches such as those offered by Unicorn and Puma, using JRuby, as well as proxying through Nginx, coming into the picture.

Enter Raptor

Raptor, a new entry to the burgeoning world of Ruby Web servers, boasts some compelling features. "Visibility" is cited as a key feature so that you can look ‘into’ your app and analyze its performance as easily as possible using a JSON API (so building your own tools around the API should be simple). Raptor also uses the HTTP parser from Node which itself was derived from Nginx’s HTTP parser; both are renowned for their speed and stability. Raptor boasts a zero-copy, concurrent, evented architecture which makes it efficient memory and IO-wise - so even if you have slow clients or a slow network, these won’t bring your app server to a stuttering standstill.

Another feature that jumped out at me is integrated caching. Raptor doesn’t rely on an external services like memcached or Redis at all, but is truly internal and optimized specifically for Web workloads. If you’ve never set up caching before, this could provide a big boost as with Raptor it’ll be available “out of the box”.

The initial results seem promising. Fabio Akita has already shared some early benchmark results which broadly mirror my own experience (disclaimer: as someone with rather little experience and authority in benchmarking, my benchmarks are oriented around Raptor’s own benchmarking suite) but, as always, YMMV and such benchmarks are often criticized.

The waiting game..

The team behind Raptor promise they’ll be releasing some interesting blog posts soon about the technology behind it, including how the cache is implemented and has been optimized, how the zero-copy system works and how it’ll benefit your code, and similar things. So keep an eye on rubyraptor.org, especially around November 25th.

October 16, 2014

Ruby InsideRuby’s Unary Operators and How to Redefine Their Functionality

Peter Cooper @ 2014/10/16 09:34 AM

In math, a unary operation is an operation with a single input. In Ruby, a unary operator is an operator which only takes a single 'argument' in the form of a receiver. For example, the - on -5 or ! on !true.

In contrast, a binary operator, such as in 2 + 3, deals with two arguments. Here, 2 and 3 (which become one receiver and one argument in a method call to +).

Ruby only has a handful of unary operators, and while it's common to redefine binary operators like + or [] to give your objects some added syntactic sugar, unary operators are less commonly redefined. In my experience, many Rubyists aren't aware that unary operators can be redefined and.. technically you can't "redefine an operator" but Ruby's operators frequently use specially named methods behind the scenes, and as you'll know.. redefining a method is easy in Ruby!

A Quick Example with -@

Let's ease into things with the - unary operator. The - unary operator is not the same thing as the - binary operator (where a binary operator has two operants). By default, the - unary operator is used as notation for a negative number, as in -25, whereas the - binary operator performs subtraction, as in 50 - 25. While they look similar, these are different concepts, different operators, and resolve to different methods in Ruby.

Using the - unary operator on a string in irb:

> -"this is a test"
NoMethodError: undefined method `-@' for "this is a test":String

The String class doesn't have unary - defined but irb gives us a clue on where to go. Due to the conflict between the unary and binary versions of -, the unary version's method has a suffix of @. This helps us come up with a solution:

str = "This is my STRING!"

def str.-@
  downcase
end

p str     # => "This is my STRING!"
p -str    # => "this is my string!"

We've defined the unary - operator by defining its associated -@ method to translate its receiving object to lower case.

Some Other Operators: +@, ~, ! (and not)

Let's try a larger example where we subclass String and add our own versions of several other easily overridden unary operators:

class MagicString  String
  def +@
    upcase
  end

  def -@
    downcase
  end

  def !
    swapcase
  end

  def ~
    # Do a ROT13 transformation - http://en.wikipedia.org/wiki/ROT13
    tr 'A-Za-z', 'N-ZA-Mn-za-m'
  end
end

str = MagicString.new("This is my string!")
p +str         # => "THIS IS MY STRING!"
p !str         # => "tHIS IS MY STRING!"
p (not str)    # => "tHIS IS MY STRING!"
p ~str         # => "Guvf vf zl fgevat!"
p +~str        # => "GUVF VF ZL FGEVAT!"
p !(~str)      # => "gUVF VF ZL FGEVAT!"

This time we've not only redefined -/-@, but the + unary operator (using the +@ method), ! and not (using the ! method), and ~.

I'm not going to explain the example in full because it's as simple as I could get it while still being more illustrative than reams of text. Note what operation each unary operator is performing and see how that relates to what is called and what results in the output.

Special Cases: & and *

& and * are also unary operators in Ruby, but they're special cases, bordering on 'mysterious syntax magic.' What do they do?

& and to_proc

Reg Braithwaite's The unary ampersand in Ruby post gives a great explanation of &, but in short & can turn objects into procs/blocks by calling the to_proc method upon the object. For example:

p ['hello', 'world'].map(&:reverse)  # => ["olleh", "dlrow"]

Enumerable#map usually takes a block instead of an argument, but & calls Symbol#to_proc and generates a special proc object for the reverse method. This proc becomes the block for the map and thereby reverses the strings in the array.

You could, therefore, 'override' the & unary operator (not to be confused by the equivalent binary operator!) by defining to_proc on an object, with the only restriction being that you must return a Proc object for things to behave. You'll see an example of this later on.

* and splatting

There's a lot of magic to splatting but in short, * can be considered to be a unary operator that will 'explode' an array or an object that implements to_a and returns an array.

To override the unary * (and not the binary * - as in 20 * 32), then, you can define a to_a method and return an array. The array you return, however, will face further consequences thanks to *'s typical behavior!

A Full Example

We've reached the end of our quick tour through Ruby's unary operators, so I wanted to provide an example that shows how to override (or partially override) them that should stand as its own documentation:

class MagicString < String
  def +@
    upcase
  end

  def -@
    downcase
  end

  def ~
    # Do a ROT13 transformation - http://en.wikipedia.org/wiki/ROT13
    tr 'A-Za-z', 'N-ZA-Mn-za-m'
  end

  def to_proc
    Proc.new { self }
  end

  def to_a
    [self.reverse]
  end

 def !
   swapcase
 end
end

str = MagicString.new("This is my string!")
p +str                   # => "THIS IS MY STRING!"
p ~str                   # => "Guvf vf zl fgevat!"
p +~str                  # => "GUVF VF ZL FGEVAT!"
p %w{a b}.map &str       # => ["This is my string!", "This is my string!"]
p *str                   # => "!gnirts ym si sihT"

p !str                   # => "tHIS IS MY STRING!"
p (not str)              # => "tHIS IS MY STRING!"
p !(~str)                # => "gUVF VF ZL FGEVAT!"

It's almost a cheat sheet of unary operators :-)

A Further Example: The TestRocket

TestRocket is a tiny testing library I built for fun a few years ago. It leans heavily on unary operators. For example, you can write tests like this:

+-> { Die.new(2) }
--> { raise }
+-> { 2 + 2 == 4 }

# These two tests will deliberately fail
+-> { raise }
--> { true }

# A 'pending' test
~-> { "this is a pending test" }

# A description
!-> { "use this for descriptive output and to separate your test parts" }

The -> { } sections are just Ruby 1.9+ style 'stabby lambdas' but, with assistance from Christoph Grabo, I added unary methods to them so that you can prefix +, -, ~, or ! to get different behaviors.

Hopefully you can come up with some more useful application for unary methods on your own objects ;-)

Ryan DavisHappy Birfday to me!

2014/10/16 01:13 AM

Today is my Fourteenth Year Anniversary with Ruby! Yay!

823 gem releases (up by 93), 9805 commits (up by 823), and bazillions of test runs later, and I’m still going strong. Rawr!

September 12, 2014

Ryan DavisOne Reservoir Nerd Left

2014/09/12 07:00 PM

reservoir_nerd.png

And then there was one. (2,060 days later, a bit slower than the movie).

Unlike last time, this time it’s just me. 23 years experience, 14 (next month) in ruby, I’m available and looking.

I would love to wind up doing more open source work, or helping to optimize your people/processes/codes. I’ll be speaking at gogaruco next week. If you’re nearby, you should come talk to me.

June 04, 2014

RubyLoveIntro to my possible Ruby Book

2014/06/04 07:00 AM

My own history

I have been coding since I was thirteen, when my Father came home with old IBM clone that he traded for during the 80’s barter craze. Being nearly forty years old now, I have stubbed my toe and left it bleeding in more than a dozen languages now. If I were a construction worker instead of a knowledge worker, I would probably be missing fingers, toes, and possibly a hand or leg.

When I look at my whole career in code, I see a common theme. From BASIC, to C to C++, to VB, to Javascript to C# to Ruby I have been writing imperative, stateful code for my whole career. I have lived with loops, state mutation, and C syntax, and was blissfully unaware of anything else as I had skipped the CS degree and opted to go directly into the workforce at eighteen.

I worked through the 90s as the Internet was in it’s very early years. I had a Geocities page for my Warcraft tips and strategies. It probably didn’t blink, but it must have been fugly. I worked for companies that turned email into snail mail, companies who turned snail mail into email, and companies who made adware for Windows machines and a little bit of everything in between.

When I coded in C, we hated those ‘weird’ C++ guys. We would tease them about using a language before the improvement, since it wasn’t ++C. Then I joined that group to write DCOM and COM+ for Intel. We made fun of the VB programmers. Then I became a VB programmer when ASP exploded, since it was essentially VBScript, and I don’t like context switches. Then it was semi-colons that were stupid.

By the time I got to Ruby I hated working with the Microsoft stack. The guy that introduced me to Ruby in 2006 was working in C# with me, and constantly opined at the lack of jobs in Ruby and LISP. We hacked a bit during lunches, but I never had time to get serious about Ruby, as I worked at a startup. Like 80 hours a week worked at a startup.

He never made fun of anything in languages. He didn’t point out differences in the languages in a snide way. Every tool had uses, and every language had interesting points and beautiful aspects. It was almost his attitude alone that made me want to work with Ruby. The language seemed very much like this programmer. Friendly, smart, concise, and there wasn’t a lot of, no you cannot do this, you shouldn’t do that.

I was introduced to the concepts in LISP and some functional programming by him as well. He also was a versed smalltalker. He really opened my eyes. Then I got a Ruby job and moved to Amsterdam for it. I can’t even remember this guy’s name beyond Courtney, but I will forever be grateful to what he shared with me.

Debugging

I have spent more hours in my life with debug statements, than probably anything else, except possibly sleeping or growing older. I used to think that this was just the state of things. You wrote some code, then you ran it, and it either, A) ran and acted as expected or B) politely suggested I write some debug statements to what was really going on.

Debugging is basically detective work. When the code you interact with is convoluted, and obfuscated through constant laziness and ignorance, you constantly have new mysteries to solve. The mystery you really are solving here is not syntax, it is not structure, it is almost always state, and the way that state is formed and managed.

Why state is hard to reason and debug

When I speak of state what I am really speaking of, are memory addresses. In the early days of computers, memory was very pricey and in limited supply due to space. This meant programmers were forced to write efficient code, and efficiency meant small size and fast speed. So developers wouldn’t think twice about reusing a memory address instead of allocating more, it was in fact preferred given the space you needed was equal or less to what was already allocated.

Still today, programmers will reassign a variable over and over, changing it’s state. Memory is now very cheap and machines have lots of capacity, and yet variables are rewritten habitually. And not just setting something else to that memory address, but also changing what was there originally.

So imagine we have a Person class. The class has several pieces of internal state, we will just focus on ‘name’ and ‘favorite_color’, for our example, I will use my Uncle Bob, because he has taught me so much.

So I create a person class instance, Bob. Then I save him off to a database, the how doesn’t really concern us, so I will just use a descriptive stand-in double.

Then later on, I find that I need to fill in the last name as well and then re-save it:

But then later on again, I alter it again, but adding some other field and overwrite it again. And so on and so forth.

Now trying to rationalize about the state of that object is difficult because it changes and changes and there is no audit trail of what it used to be like. It is like a video stream that cannot be rewound.

Immutability

I will now do the same thing as above, but this time, I will create new copies of Bob before I alter his state:

I now need to change his name to his full name, so I create a clone, alter that clone, then save.

Now I change it again, this time because we find out my Uncle’s favorite color is, in fact, green.

But you might say, what about in the database we are ignoring? What about primary keys? It isn’t the concern here, but you could use last updated at and update a join table with a static guid, and the current id, but again, not the point here.

Now I want you to think of this process not as a video stream that cannot be rewound, but a set of many still snapshots. If you were combine the stills, you could recreate the stream again. However, if you want to, you can lay these versions of my Uncle together out in front of you on a desktop and see all states of Uncle Bob before you at once, and not be stuck debugging the current state of him.

In a way, this style of state management gives you an almost superhuman power of all seeing, where you can look at a person and instead of seeing them as they are you can see all versions of them as any given state of time. Pretty cool, next you might be able to dodge bullets!

The death of a generation of programmers

For the entirety of computing up until 2012-2013, memory and speed were doubling every year as noted by “Moore’s law”. During that time, the amount of abstraction, or layer on layer of code to make dealing with the complexities of voltages and gates and registers easier on up to windowing tools and the GUI.

These two have gone at about the same pace, the latter being limited by the former. However, seeing “ahead” of time by measuring the slow of growth per cycle, the CPU industry changed gears and instead of making the single core much faster, they bundled cores together to create a multi-core architecture.

Programmers who do not adapt to this new age of multi-core will cease to be hireable and their families will starve like in a Dickens’ novel. Do not let this happen to you!

The multi-core, memory address problem

Now that processors are no longer growing exponentially, and multi-core architecture has taken over, we have threads that operate against different cores. One core can accessed at the same time as other cores, which is where they get their speed improvement over the single core.

Yet there is only one memory register. Well, this is not entirely true, but there is likely only one memory register your application has access to. That means you could have something like the following:

So I create Bob again, but this time, pretend this is going to happen on core 1:

Bob’s favorite color is about to change again, but it will be done by core 2:

Then core 1 tries to access their copy again, but wait…. it is not in an unexpected state. It was modified by another core, and this can create race conditions that include memory corruption.

That is a highly over-simplified explanation because I am not a hardware engineer nor are the absolute internals of the CPU our domain. What you should gather here is that a developer can no longer ignore threads and multiple cores or how they might interact with each other. We need to write software that naturally works in this brave new world.

To do so, we dig into the braver old world, where smart people have already figured out the problem and the solution before it even existed. In this book I will help guide you on a path from the imperative to the explicit, and the object oriented to the functional. These concepts are not polar, they are orthogonal, that is, you can plug them into each other for a hybrid experience.

Let’s embark into the magical world of value objects, immutability, hybrid functional programming, threads, and homoiconicity, but do so in the comfortable and familiar, friendly world of Ruby!

June 01, 2014

RubyLoveRubyLoveLive Sunday Sessions

2014/06/01 07:00 AM

This week we started to outside-in, TDD some code towards a static website generator. Here is the video!

May 31, 2014

RubyLoveRefactoring conditionals out of your code

2014/05/31 07:00 AM

Today I will be doing something a little different.

I have prepared some Ruby code to show how conditionals can breed like rabbits, and how to spay and neuter those bunnies before it gets out of control.

Along with the code, there is a screencast or as I will call it, a RubyLovecast. In the video, I will walk you through several revisions of the code, first showing how conditionals grow, then how to take a weedwacker to them.

I am looking for feedback, so tweet that shit at @thatrubylove and hit me hard. My plan is to take a weeks worth of feedback and then ‘reshoot’ the screencast, taking your input into account.

So until next week’s rubylovecast…. love and hacking

May 26, 2014

RubyLoveI am now a till time Ruby/Rails coach

2014/05/26 07:00 AM
  • Please note, I am not accepting students…. unless I suppose you have an exceptional mind.

I have to apologize for being away so long. I ended a relationship that had drug on for far too long and going nowhere, and at the same time I decided that I will no longer accept clients that refuse to place the proper amount of importance on quality and training.

The two of those catalysts essentially derailed my life and then gave me a hovercraft instead! I started mentoring @ codementor.io and then was convinced by a friend of mine to also become a full time mentor @ bloc.io.

Needless to say, I have been very, very busy.

Along with now mentoring about 12 people from various sources (we do 2 hour sessions monday through thursday and students chose from the morning or evening session) I have been speaking with awesome developers who have been my heroes.

I have been gleening their thoughts about my thoughts and about their own and others thoughts… honestly, it is a lot like Primer of the mind for developers. It has been a blast. For instance, here is myself and one of my heroes, J.B. Rainsberger discussing my Ruby Manifesto.

I promise I will post another in depth very soon. My question for my readers…. What do you want to learn? Also, would you like to join me every Sunday 12pm to 2pm CST for live sessions?

Let me know on twitter please. @thatrubylove

May 21, 2014

Charles Oliver NutterJRubyConf.eu 2014!

Charles Nutter (noreply@blogger.com) @ 2014/05/21 11:44 AM
I'm thrilled to announce that we'll have another edition of JRubyConf.eu this year!

Last year's event was a great success. We had a two-day conference in Berlin immediately before Eurucamp 2013, with two speakers from the core team (myself and Tom Enebo) and a whopping fifteen non-core speakers. A great event was had by all.

This year, we've decided to pull the event back to its roots, as part of Eurucamp 2014. We'll return to the single-track, single-day event co-located with and immediately preceding Eurucamp on 1st August. We really wanted to bring JRuby back to Rubyists, and we're looking forward to hanging out at Eurucamp the whole weekend!

Why not visit Eurucamp early and spend a day learning about JRuby with the best JRubyists in Europe?

If you're interested in attending, tickets are available for only €99 at the Eurucamp ticket site now!

We're also looking for speakers from the JRuby community. You can submit to the CFP (which ends Sunday 28 May) using the Eurucamp CFP app.

Looking forward to seeing you at JRubyConf and Eurucamp this summer!

May 02, 2014

Ryan DavisCatching Up

2014/05/02 07:00 PM

I realize that is has been a hellishly long time since I last updated this thing.

When last we met I brain-dumped most of my emacs setup and then promptly disappeared. I know that at least a few of you have used that to good effect and that’s been encouraging.

But since then, I’ve had some fun.

Gems:

I’ve done 63 gem releases in the last 6ish months, mostly thanks to a bunch of generous contributors. In all it includes 6 major, 109 minor, and 65 bug fixes. Fan-fucking-tastic! This brings a bunch of my more stable projects up to date for 2.0 & 2.1: autotest-rails, flog, graph, image_science, minitest-bacon, minitest-focus, minitest_tu_shim, omnifocus, omnifocus-github, rubygems-sandbox, RubyInline, vlad, ZenTest, and ZenWeb.

I spent a lot of time focusing on 2 of my favorite gems: hoe & minitest.

Hoe & Minitest

Hoe makes it a breeze to manage all my gems and really is the reason why I can do what I do with so many projects. It is incredibly important to me that my projects don’t have any duplication across them. By using Hoe, any changes that happen across my projects happen in one place only. DRY at its finest.

Minitest went through a complete rewrite for version 5 early last year. Thanks to a lot of people for contributing to minitest and helping make it what it is today. The architecture is vastly improved over minitest 4 and it shows. Ever since the v5 rewrite, I absolutely love this project and thank you all for it.

Language Love

ruby_parser has seen some serious love in that time, as well as some love for its supporting projects.

For the supporting projects, sexp_processor got some nice refactorings from other projects, including adding MethodBasedSexpProcessor from Flog. ruby2ruby was extended to 2.0 and 2.1 support. The nice thing about these guys was how cleanly designed they were to begin with so they didn’t see too much over the last year.

But… For ruby_parser… which saw 17(!!) releases in 2012 but only 5 in 2013… I got a bit burnt out on the project, but I’ve had a bit of a comeback. I’ve done 5 releases already this year. I’ve added support for 2.0 and initial support for 2.11. But most importantly, I rewrote the hand-written lexer from scratch using a brand new project: oedipus_lex.

Oedipus Lex

Oedipus Lex is my independent lexer fork of Rexical. Rexical was in turn a fork of Rex. While Oedipus Lex is a cleanroom re-implementation of rexical, but it is also massively extended including proper ruby regexp support, predicate method prerequisites, grouping for extra performance, shortcuts on state changes, and action methods. I love this project for what it has done to the maintainability of ruby_parser, but more importantly, Oedipus Lex makes ruby_parser roughly 60% faster than my highly-optimized hand-written lexer.

Talks:

I had a lot of fun on the conference circuit in the last year.

Last year, I gave Let’s Write an Interpreter! at both MWRC and GoGaRuCo. I spoke about Minitest & Rails in Chicago. And I spoke about craftsmenship and tools at cascadia.

So far this year I’ve given one talk at MWRC, Nerd Party v3.1, which was my take on Seattle.rb’s format and how it can work for you.

  1. Please! if you want to help out with ruby_parser (or flog/flay/etc), I could use a PR for the new rational & imaginary lexemes!

October 24, 2013

Ryan Davis9000 Commits

2013/10/24 07:00 PM

I just committed the 9000th commit to my perforce repo. Woot!

% p4 counter change
9000

Time between 1000s. You can see some burnout/slowdown between 2009-06 to 2012-02, but it’s been maintaining >1000 per year since then.

% p4 changes | grep "Change .000" | cut -f4 -d\   | ruby -rdate -e 'puts $stdin.read.lines.map { |s| Date.parse s }.each_cons(2).map { |a, b| [a, (a - b).to_i].join " " }'
2013-10-24 335
2012-11-23 294
2012-02-03 436
2010-11-24 540
2009-06-02 358
2008-06-09 489
2007-02-06 655
2005-04-22 1065

Granted, # of commits or commits / day is a stupid metric to follow if you’re trying to measure productivity… but since I’m not trying to game my own system, this ain’t bad.

October 18, 2013

Ryan DavisTime Machine Repair

2013/10/18 07:00 PM

Turn off time machine on all involved parties, then:

% sudo chflags -R nouchg greed.sparsebundle
% sudo emacs -q -nw greed.sparsebundle/com.apple.TimeMachine.MachineID.plist

  # Setting VerificationState to 0 and removing RecoveryBackupDeclinedDate

% sudo hdiutil attach -nomount -noverify -noautofsck -readwrite greed.sparsebundle
% tail -f /var/log/fsck_hfs.log

  # wait for regular check to finish... if it passes, go for it, otherwise:

% sudo fsck_hfs -drfy /dev/diskXs2

  # once you're done:

% hdiutil detach  /dev/diskXs2

For me, everything fixed itself so I was able to skip the last step.

From: http://www.garth.org/archives/2010,07,16,124,fixing-time-machine-sparsebundle-network-backup-errors.html

October 15, 2013

Ryan DavisHappy Birfday to me!

2013/10/15 10:04 PM

Today is my Thirteen Year Anniversary with Ruby! Yay!

780 gem releases (up by 150), 8982 commits (up by 1146), and bazillions of test runs later, and I’m still going strong. Rawr!

July 30, 2013

Ryan DavisTriage Applescript for OmniFocus

2013/07/30 07:00 PM

I have a bunch of omnifocus tasks that tell me to go review my projects’ issue trackers. Each one has a note with a url in it that is hyperlinked. Unfortunately, omnifocus doesn’t let you cmd-click the url to open in the background. It’s incredibly aggravating that you have to flip back and forth between safari and omnifocus over and over. It is even worse when you do it across spaces (I always have omnifocus fullscreened).

I wrote this applescript (blech) because I couldn’t take it anymore and omnigroup has ignored my bug report for 2+ years now. All it does is go through each task in the current window and open a new Safari tab for each note that starts with “http”.

I hope it helps bring sanity to someone else.

tell application "Safari"
	activate
	
	tell application "OmniFocus"
		set urls to note of value of leaves of content of window 1
	end tell
	
	make new document
	
	repeat with aUrl in urls
		if aUrl starts with "http" then
			make new tab at end of window 1 with properties {URL:aUrl}
		end if
	end repeat
	
	delete tab 1 of window 1
	
end tell

I have this in the script menu titled “Triage”. Enjoy

July 25, 2013

Ruby InsideThis Month in Ruby: PeepCode Acquired, Rails 3.2.14, And More

Peter Cooper @ 2013/07/25 08:16 PM

Welcome to a roundup of Ruby news, articles, videos, and more, for July 2013 cobbled together from my e-mail newsletter, Ruby Weekly.

Highlights include: PeepCode acquired by Pluralsight, Practicing Ruby archives made public, Rails 3.2.14, and an interesting interview with Matz.

Featured

The First Four Volumes of Practicing Ruby, Now Available Online
Practicing Ruby is a high quality, paid Ruby journal run by Gregory Brown, but he's made archives of over 60 articles available to the public. There's a ton of stuff to enjoy here.

PeepCode Acquired by Pluralsight
Ruby and Rails screencasting pioneer Geoffrey Grosenbach has announced he has sold Peepcode to Pluralsight, a large online training provider.

The Plan for RSpec 3
RSpec 2.0 was released in October 2010 and RSpec 2.14 will be the last RSpec 2 feature release. Work on RSpec 3 has begun and Myron Marston shares what's going to be involved.

Rails 3.2.14 RC1 and RC2 Released
A variety of bug fixes for Rails 3.2 arrived in 3.2.14 RC1 with one minor regression fixed in RC2. Final due soon.

The Future of Computing - An Interview with Matz
Last year, Ruby's creator Yukihiro 'Matz' Matsumoto released a book called The Future of Computing (only in Japanese, I believe) and did an interview with a Chinese publisher. Fred Wu has translated it into English.

RSpec 2.14 Released
Myron Marston unveils the last 2.x feature release of the popular spec framework and announces work is well underway for the future RSpec 3. 2.14 includes a new feature called 'spies' which is shown off here.

Functional Programming and Ruby
At GoRuCo 2013, Pat Shaughnessy gave a 40 minute talk comparing Haskell (a functional language) to Ruby and looked at how to implement common functional patterns in Ruby. Well explained and backed by good slides.

Reading

Streaming with Rails 4
Saurabh Bhatia looks at Rails 4's support for live streaming (the ability to send partial requests out to the client on the fly).

Reading the Ruby Source to Understand Rails Idiosyncrasies
I'm not sure you always need to dig quite so deep but Eno Compton takes an interesting journey through MRI's source code to see the difference between Range#cover? and Range#include?

Speed Up Heroku Deploys
Alex MacCaw was suffering from slow deploys to Heroku but he found a workaround.

Shoes 4 – A Progress Report
Shoes was a graphical toolkit put together by Why the Lucky Stiff that made it simple to create GUI apps in Ruby. Since Why disappeared, others have picked up work on it, and Shoes 4 is set to be a complete rewrite.

Put Yourself on Rails with A Push of A Button
A technique for quickly bringing up a workspace for doing Rails work (including terminals, a Rails console, a Rails server, etc.)

Multitenancy with Rails: An E-book by Ryan Bigg
Ryan Bigg, of Rails in Action fame, is writing an e-book about building a multi-tenanted Rails app.

Incremental Redesign with Rails
Lars Klevan shows how to use prepend_view_path to make in-progress redesigns on a production codebase simpler.

How to Declutter Your 'lib' Directory
If you have an established Rails project, its 'lib' folder might be getting a little full. Kuba Suder looks at ways to clean it up and put things elsewhere.

Design Patterns: The Template Method Pattern
An introductory Ruby-oriented look at arguably the simplest design pattern.

Object Oriented Rails: Writing Better Controllers
Damien Le Berrigaud of Pivotal Labs tries to avoid stubs and mocks and leans on dependency injection to test his controllers' code.

Vimscript And You
HashRocket's Jonathan Jackson demonstrates how you can use RSpec against Vim to aid in the development of a Vim plugin with Vimscript.

MotionPhrase: Next Level Localization for RubyMotion Applications
PhraseApp is a translation management tool for producing multilingual Web sites, Rails apps, etc, but it also works for localizing RubyMotion apps too, as demonstrated here.

Ruby's Eigenclasses Demystified
Andrea Singh looks at Ruby's quirky 'eigenclasses' (a.k.a. metaclasses) and explains things in both code and diagrams. Dates from 2011 but worth revisiting.

The Self-Pipe Trick Explained
Jesse Storimer shows off a cute Unix trick/technique in Ruby.

Practical RSpec Wrapping
Why would you want to use around hooks in RSpec? Dru Riley explains.

Using PostgreSQL's 'hstore' in A Rails Application on Engine Yard Cloud
If you want to take advantage of schemaless features without abandoning your relational database, using 'hstore' within Postgres is a great option. Here's an introduction on using the hstore PostgreSQL extension in a Rails app.

Implementing Subdomain and Custom Domain Support in Rails
A look at how one development team implement subdomain and custom domain features in their Rails app.

Events

dotRB: The Largest Ruby Conference in France (October 18, Paris)
Following on from a successful 'dotJS' JavaScript event comes dotRB. Announced speakers so far include Steve Klabnik, Konstantin Haase, and Brian Ford.

Watching

11 Talks from La Conf Paris
Some big names to enjoy here including Yehuda Katz, Amy Hoy, Sandi Metz, and Steve Klabnik.

Deathmatch: Bundler vs Rubygems.org
At GoRuCo 2013, Andre Arko told the story of the quest to make 'bundle install' faster.

How to Set Up RSpec
A well produced 6 minute screencast.

To Know A Garbage Collector
Mike Bernstein discusses his experiments with MRI Ruby's garbage collector, his investigations into other languages and the influence of their GC implementations, the history of the subject, and more.

Kata and Analysis with Jim Weirich
From RubyConf India 2013 comes a live coding session by the inimitable Jim Weirich where he walks through the popular 'roman numeral' conversion kata using TDD along the way.

Aaron 'tenderlove' Patterson's RubyConf India 2013 Keynote
An hour with Ruby and Rails core contributor Aaron 'tenderlove' Patterson covering esoteric Ruby stuff and Postgres to career advice and cats. Warning: The audio is rather poor here and cuts out entirely for the second half so don't waste your time if this will drive you crazy.

5 Minutes of EuRuKo 2013
European Ruby conference (EuRuKo) took place in Athens last month and Clemens Helm has put together a 5 minute collection of clips and insights from the event. Includes Matz, Xavier Noria, Benjamin Smith, Pat Shaughnessy and Steve Klabnik.

Nokogiri: History and Future
Nokogiri is the most popular way to parse and process XML in Ruby and at GoRuCo 2013, Mike Dalessio gave a short 11 minute talk on the origins of the project, how to determine if it suits you, and looks at some of the tooling around it.

Libraries, Code and Tools

Upton: A Web Scraping Framework
A Ruby-based web-scraping framework that abstracts away the common parts of web scraping so developers can concentrate on the unique parts of their project.

LanguageFilter: Detect and Optionally Filter Multiple Categories of Language
Wave goodbye to sex, hatred, profanity, violence, etc, in your app.

Lita: A Ruby Chat Bot with Redis-based Storage
Can be twisted to work with any chat service and extended with plugins.

Pkgr: Make A Debian Package Out of A Rails App in 5 Minutes
A high-level tool that turns Rails applications into native Debian packages.

Flynn - Open Source Platform As A Service, Powered by Docker
Flynn is an as-yet-unreleased Heroku-inspired system to simplify deploying and maintaining apps. Instead of using complex config management systems, Flynn allows self-serve management of containerized deployments. The creator is currently trying to raise money to work on the project.

Jobs

Software Craftsperson at Bendyworks
If you're the type of person who learns new languages as a matter of course, contributes to open source for fun, and ships code with a calm and collected professionalism: you seem like our kind of developer. Join our world-class team in Madison, Wisconsin.

Senior backend- / API-developer at Rabble (Stockholm, Sweden)
Tired of bullshit ads? Help us develop Sweden's leading app for mobile offers, where customers and businesses meet on equal terms! Join us in the heart of Stockholm to play with geospatial data and Ruby API's all day long!

Ruby on Rails developer at SupaDupa (London, UK)
We're looking for an experienced Ruby on Rails developer to join the small team behind SupaDupa.me, an e-commerce platform aimed at creatives. Excited about the challenge of working on the full stack, from front-end dev to system administration? Get in touch!

Ruby Programmer: IT and System Automation
Want to change the future of education? We are trying to build an awesome team that enjoys challenges and results. Interested? Come work with us in beautiful Switzerland.

Ruby Developers at HouseTrip (London, UK)
Want to work with a 18-person team of passionate Ruby developers who love good code and care for their product in central London? We are currently hiring. Ranked by Wired Magazine the number two start-up in London (2012), HouseTrip is Europe’s largest holiday rental booking website!

Last but not least..

ruby -run -e httpd . -p5000
Run a local HTTP server with a single line of Ruby. Just one character longer than the classic python -m SimpleHTTPServer but more obviously flexible (plus, it's Ruby ;-)).

July 17, 2013

Ryan DavisMy Emacs Setup, pt 8: Ruby and Outline

2013/07/17 07:00 PM

This is part 8 of My Emacs Setup.

I’ve got a bitch of a file I have to maintain. One of the methods is ~650 lines long. It flogs out at 1200 (industry average for non-rails methods is ~10). It is horrible but there is little-to-nothing that I can do in ruby to make it better. No, the refactoring mantra isn’t applicable here… That’s an argument for another day.

The point is, it is huge and I have to maintain / understand / navigate it. Emacs has a bunch of tools to index files and jump around to definitions and the like, but this is inside one method so they don’t help. Emacs also has a ton of various outlining tools, but none of them work with ruby because ruby’s syntax is a serious PITA. I may have finally found a compromise that works well enough.

Add this to your enh-ruby-mode or ruby-mode hook:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(defun ruby-outline-level ()
  (or (and (match-string 1)
           (or (cdr (assoc (match-string 1) outline-heading-alist))
               (- (match-end 1) (match-beginning 1))))
      (cdr (assoc (match-string 0) outline-heading-alist))
      (- (match-end 0) (match-beginning 0))))

(set (make-local-variable 'outline-level) 'ruby-outline-level)

(set (make-local-variable 'outline-regexp)
     (rx (group (* " "))
         bow
         (or "begin" "case" "class" "def" "else" "elsif" "end"
             "ensure" "if" "module" "rescue" "when" "unless")
         eow))

(outline-minor-mode)

Then add this to your outline-minor-mode hook:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(require 'outline-magic)

(defun outline-cycle-fast ()
  "Emulates 2 hits of outline-cycle, giving me what I want to see 90% of the time"
  (interactive)

  (hide-subtree)
  (show-entry)
  (show-children)
  (setq this-command 'outline-cycle-children))

(let ((map outline-minor-mode-map))
  (define-key map (kbd "M-o M-o") 'outline-cycle)
  (define-key map (kbd "M-o o")   'outline-cycle-fast))

Now you can go to the top of a huge if/elseif/else block and hit M-o o and it’ll collapse to the top level items, which is a lot more navigable for me than a raw 650 line method. Now I can drill down individual branches and only expand (using M-o M-o) the subsection I want to see at the time. Now it looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
    loop do # START OF CASE
      if src.scan(/[\ \t\r\f\v]/) then # \s - \n + \v
        self.space_seen = true
        next
      elsif src.check(/[^a-zA-Z]/) then
        if src.scan(/\n|#/) then...
        elsif src.scan(/[\]\)\}]/) then...
        elsif src.scan(/\!/) then...
        elsif src.scan(/\.\.\.?|,|![=~]?/) then...
        elsif src.check(/\./) then...
        elsif src.scan(/\(/) then...
        elsif src.check(/\=/) then...
        elsif src.scan(/\"(#{ESC_RE}|#(#{ESC_RE}|[^\{\#\@\$\"\\])|[^\"\\\#])*\"/o) then...
        elsif src.scan(/\"/) then # FALLBACK...
        elsif src.scan(/\@\@?#{IDENT_CHAR_RE}+/o) then...
        elsif src.scan(/\:\:/) then...
        elsif ! is_end? && src.scan(/:([a-zA-Z_]#{IDENT_CHAR_RE}*(?:[?!]|=(?==>)|=(?![=>]))?)/) then...
        elsif src.scan(/\:/) then...
        elsif src.check(/[0-9]/) then...
        elsif src.scan(/\[/) then...
        elsif src.scan(/\'(\\.|[^\'])*\'/) then...
        elsif src.check(/\|/) then...
        elsif src.scan(/\{/) then...
        elsif src.scan(/->/) then...
        elsif src.scan(/[+-]/) then...
        elsif src.check(/\*/) then...
        elsif src.check(/\</) then...
        elsif src.check(/\>/) then...
        elsif src.scan(/\`/) then...
        elsif src.scan(/\?/) then...
        elsif src.check(/\&/) then...
        elsif src.scan(/\//) then...
        elsif src.scan(/\^=/) then...
        elsif src.scan(/\^/) then...
        elsif src.scan(/\;/) then...
        elsif src.scan(/\~/) then...
        elsif src.scan(/\\/) then...
        elsif src.scan(/\%/) then...
        elsif src.check(/\$/) then...
        elsif src.check(/\_/) then...
        end
      end # END OF CASE

July 11, 2013

Ryan DavisMy Emacs Setup, pt 7: Q & A (1)

2013/07/11 07:00 PM

This is part 7 of My Emacs Setup.

In my last post I asked for suggestions on what to blog about next. I got some questions that I thought were interesting so I’m answering them here:

JEG asks:

I have a ton of specific questions. Here are just a few:

Awesome! Keep throwing them at me.

  • Do you use emacserver and emacsclient?

I certainly have in the past, I pretty much don’t nowadays. This is mostly because I run almost all of my shells within emacs, making emacsclient (mostly) unnecessary. Open prompts are relative to the current directory of whatever buffer you’re in (including shells) and you can open globs, so rather than doing emacsclient lib/*.rb I can just type C-x C-f lib/*.rb RET.

That said, I do fire up M-x server-start once in a while and run emacsclient from Terminal.app. Because I’m running the server from the GUI emacs, I can get Terminal.app communicating over to the GUI and feel more comfortable.

  • How do you handle integration with the OS X clipboard? (Especially, if you said yes above.)

As I said, I generally use the GUI anyways so clipboard integration Just Works(tm).

I do like having save-interprogram-paste-before-kill set to t via custom. That makes the OS integration a bit smoother.

  • What do you use for .erb files?

Nothing. I try not to work on view code (and people thank me for that). If I did, I’d prolly try out MMM again. I didn’t like the older alternatives.

  • Do you indent manually or with an automatic tool?

Um… I use ruby-mode or enh-ruby-mode (or whatever language’s mode) to do indentation for me with plain TAB. I’m not sure if that’s what you’re asking.

JD asks:

  • How much to you rely on [c|e]tags for navigation in projects?

I love exuberant ctags and have a script called retag that does-what-I-want 99% of the time. That said, I don’t use tags that much because most of my projects are limited in scope enough and have sane file layout that it isn’t strictly necessary.

I do recommend using tags to all newcomers to emacs tho. I think it is a very powerful tool (esp once you start using pop-tag-mark to go back from whence you came).

  • Any tricks/best practices for expanding text? I’m a long-time user of dabbrev-expand, but feel like I might be missing some opportunities by not using hippie-expand.

Ah! yes! I have the following in rwd-expand.el:

1
(eval-after-load "dabbrev" '(defalias 'dabbrev-expand 'hippie-expand))

Then, I set hippie-expand-try-functions-list to:

1
2
3
4
5
6
7
8
9
10
11
'(try-expand-all-abbrevs
  try-expand-list
  try-expand-dabbrev-visible
  try-expand-dabbrev
  try-expand-dabbrev-all-buffers
  try-expand-dabbrev-from-kill
  rwd-try-expand-tag
  try-complete-lisp-symbol-partially
  try-complete-lisp-symbol
  try-complete-file-name-partially
  try-complete-file-name)

I believe that the defaults for hippie-expand are pretty good by themselves, but IIRC, I reordered some of them to suit my needs a bit better. It could probably still use some tweaking, but this works for me well enough that it stays off my radar.

Thanks - love the series.

Thank you!

July 03, 2013

Ryan DavisMy Emacs Setup, pt 6: What Next?

2013/07/03 07:00 PM

This is part 6 of My Emacs Setup.

Um. So… I’ve blogged the top-level architecture of my emacs setup. I have a lot of emacs stuff left. Rather than go through every file, what would you guys like to see? Comment below and I’ll try to make it happen.

Ryan Davisruby_parser, flog, & flay now have ruby 2.0 support

2013/07/03 07:00 PM

With yesterday’s release of ruby parser 3.2.0 both flog and flay automatically pick up the ability to parse ruby 2.0 syntax. Enjoy and please file issues if you come across anything.

June 29, 2013

Ruby InsideDoes the GIL Make Your Ruby Code Thread-Safe?

Jesse Storimer @ 2013/06/29 05:16 PM

This is a guest post by Jesse Storimer. He teaches the Unix fu workshop, an online class for Ruby developers looking to do some awesome systems hacking in Ruby and boost their confidence when it comes to their server stack. Spots are limited, so check it out the class while there's still room. He's also the esteemed author of Working with Unix Processes, Working with TCP Sockets and Working with Ruby Threads.

There are some misconceptions in the Ruby community about this question surrounding MRI's GIL. If you only take one thing away from this article today, let it be this: The GIL does not make your Ruby code thread-safe.

But you shouldn't take my word for it.

This series started off just trying to understand what the GIL is at a technical level. Part 1 explained how race conditions could occur in the C code that's used to implement MRI. Yet, the GIL seemed to eliminate that risk, at least for the Array#<< method we looked at.

Part 2 confirmed that the GIL did, in fact, make MRI's native C method implementations atomic. In other words, these native implementations were free from race conditions. These guarantees only applied to MRI's native C functions, not to the Ruby that your write. So we were left with a lingering question:

Does the GIL provide any guarantee that your Ruby code will be thread-safe?

I've already answered that question. Now I want to make sure that the misconception doesn't go any further.

Race conditions redux

Race conditions exist when some piece of data is shared between multiple threads, and those threads attempt to act on that data at the same time. When this happens without some kind of synchronization, like locking, your program can start to do unexpected things and data can be lost.

Let's step back and recap how such a race condition can occur. We'll use the following Ruby code example for this section:

class Sheep
  def initialize
    @shorn = false
  end

  def shorn?
    @shorn
  end

  def shear!
    puts "shearing..."
    @shorn = true
  end
end

This class definition should be nothing new. A Sheep is not shorn when initialized. The shear! method performs the shearing and marks the sheep as shorn.

sheep = Sheep.new

5.times.map do
  Thread.new do
    unless sheep.shorn?
      sheep.shear!
    end
  end
end.each(&:join)

The bit of code creates a new sheep and spawns 5 threads. Each thread races to check if the sheep has been shorn? If not, it invokes the shear! method.

Here's the result I see from running this on MRI 2.0 several times.

$ ruby check_then_set.rb
shearing...
$ ruby check_then_set.rb
shearing...
shearing...
$ ruby check_then_set.rb
shearing...
shearing...

Sometimes the same sheep is being shorn twice!

If you were under the impression that the GIL made your code 'just work' in the presence of multiple threads, this should dispel that. The GIL can make no such guarantee. Notice that the first time running the file, the expected result was produced. In subsequent runs, unexpected output was produced. If you continued running the example, you'll see still different variations.

These unexpected results are due to a race condition in your Ruby code. It's actually a common enough race condition that there's a name to describe this pattern: a check-then-set race condition. In a check-then-set race condition, two or more threads check a value, then set some state based on that value. With nothing to provide atomicity, it's possible that two threads race past the 'check' phase, then both perform the 'set' phase.

Recognizing race conditions

Before we look at how to fix this, first I want you to understand how to recognize this. I owe @brixen for introducing to me the terminology of interleavings in the context of concurrency. It's really helpful.

Remember that a context switch can occur on any line of your code. When switching from one thread to another, imagine your program being chopped up into a set of discrete blocks. This sequential set of blocks is a set of interleavings.

At one end of the spectrum, it's possible that there's a context switch after every line of code! This set of interleavings would have each line of code interleaved. At the other end of the spectrum, it's possible that there are no context switches during the body of the thread. This set of interleavings would have all the code in its original order for each thread. In between these two ends, there are lots of ways that your program can be chopped up and interleaved.

Some of these interleavings are OK. Not every line of code introduces a race condition. But imagining your programs as a set of possible interleavings can help you recognize when race conditions do occur. I'll use a series of diagrams to show this code may be interleaved by two Ruby threads.

Just to make the diagrams simpler, I replaced the shear! method call with the code from the body of the method.

Consider this diagram the legend for the ones to follow; the code highlighted in red is the set of interleavings from Thread A, the code highlighted in blue is the set of interleavings from Thread B.

Now let's see how this code could be interleaved by simulating context switches. The simplest case is if neither thread is interrupted during the course of executing this code. This would result in no race conditions and would produce the expected output for us. That might look like this:

Now I've organized the diagram so you can see the sequential ordering of events. Remember that the GIL locks around the execution of Ruby code, so two threads can't truly run in parallel. The ordering of events here is sequential, starting at the top and working down.

In this interleaving, Thread A did all of its work, then the thread scheduler triggered a context switch to Thread B. Since Thread A had already done the shearing and updated the shorn variable, Thread B didn't have anything to do.

But it isn't always this simple. Remember that the thread scheduler could trigger a context switch at any point in this block of code. This time we just got lucky.

Let's look at a more nefarious example, one that would produce unexpected output for us.

In this possible interleaving, the context switch occurs right at a point that can cause trouble. Thread A checks the condition and starts shearing. Then the thread scheduler schedules a context switch and Thread B takes over. Even though Thread A already performed the shearing, it didn't get a chance to update the shorn attribute yet, so Thread B doesn't know about it.

Thread B checks the condition for itself, finds it to be false, and shears the sheep again. Once it finishes, Thread A is scheduled again and finishes execution. Even though Thread B set shorn = true when it ran through the code, Thread A does it again because it picks up exactly where it left off.

A sheep getting shorn twice may not seem like much to care about, but replace sheep with invoice, and shearing with collecting payment; we would have some unhappy customers!

I'll share one more example to illustrate the non-deterministic nature of things here.

This just adds more context switches, so each thread progresses a little bit at a time, but keeps switching back and forth. Let your mind take this to its logical conclusion, it's possible for a context switch to happen on any line of the program. The interleaving that occurs can also be different each time the code is executed, so it may produce the expected result on one iteration, and an unexpected result the next time around.

This is really a great way to think about race conditions. When you're writing multi-threaded code, you want to be thinking about how the program might be chopped up and interleaved, and the effects of various interleavings. If it seems that some interleavings will lead to incorrect results, you should re-think your approach to the problem or introduce synchronization with Mutex.

This is terrible!

At this point it seems fitting to tell you that you can make this code example thread-safe by introducing synchronization with Mutex. It's true, you can do that. But I intentionally cooked up this example to prove a point;  it's terrible code. You shouldn't write code like this in a multi-threaded environment.

Whenever you have multiple threads sharing a reference to an object, and making modifications to it, you're going to run into trouble unless you have some kind of locking in place to prevent a context switch from happening in the middle of the modification.

However, this particular race condition is easily solvable without explicitly using locks in your code. Here's one solution using Queue:

require 'thread'

class Sheep
  # ...
end

sheep = Sheep.new
sheep_queue = Queue.new
sheep_queue << sheep

5.times.map do
  Thread.new do
    begin
      sheep = sheep_queue.pop(true)

      sheep.shear!
    rescue ThreadError
      # raised by Queue#pop in the threads
      # that don't pop the sheep
    end
  end
end.each(&:join)

I left out the Sheep implementation because it's the same. Now, instead of each thread sharing the sheep object and racing to shear it, the Queue provides the synchronization.

If you run this against MRI, or any of the other truly parallel Ruby implementations, it will produce the expected result every time. We've eliminated the race condition in this code. Even though all the threads may call the Queue#pop method at more-or-less the same time, it uses a Mutex internally to ensure that only one thread can receive the sheep.

Once this single thread receives the sheep, the race condition disappears. With just one thread, there's no one else to race with!

The reason I suggest using Queue instead of a lock is that its simpler to use a Queue correctly. Locks are notoriously easy to get wrong. They bring new concerns like deadlocking and performance degradations when used incorrectly. Using a data structure is like depending on an abstraction. It wraps up the tricky stuff in a more restrictive, but simpler API.

Lazy initialization

I'll just quickly point out that lazy initialization is another form of the the check-then-set race condition. The ||= operator effectively expands to

@logger ||= Logger.new

# expands to 

if @logger == nil
  @logger = Logger.new
end

@logger

Look at the expanded version and imagine where the interleavings could occur. With multiple threads and no synchronization, it's definitely possible for that @logger to be initialized twice. Again, initializing a Logger twice may not be a problem in this case, but I have seen bugs like this in the wild that do cause issues.

Reflections

I want to leave you with some lessons at the end of all this.

4 out of 5 dentists agree that multi-threaded programming is hard to get right.

At the end of the day, all that the GIL guarantees is that MRI's native C implementations of Ruby methods will be executed atomically (but even this has caveats). This behaviour can sometimes help us as Ruby developers, but the GIL is really there for the protection of MRI internals, not as a dependable API for Ruby developers.

So the GIL doesn't 'solve' thread-safety issues. As I said, getting multi-threaded programming right is hard, but we solve hard problems every day. One way that we work with hard problems is with good abstractions.

For example, when I need to do an HTTP request in my code, I need to use a socket. But I don't usually use a socket directly, that would be cumbersome and error-prone. Instead, I use an abstraction. An HTTP client provides a more restrictive, simpler API that hides the socket interactions and associated edge cases from me.

If multi-threaded programming is hard to get right, maybe you shouldn't be doing it directly.

"If you add a thread to your application, you've probably added five new bugs in doing so."

- Mike Perham

We're seeing more and more abstractions around threads. An approach that's catching on in the Ruby community is the Actor model of concurrency, with the most popular implementation being Celluloid. Celluloid provides a great abstraction that marries concurrency primitives to Ruby's object model. Celluloid can't guarantee that your code will be thread-safe or free from race conditions, but it wraps up best practices. I encourage you give Celluloid a try.

These problems that we're talking about aren't specific to Ruby or MRI. This is the reality of programming in a multi-core world. The number of cores on our devices is only going up, and MRI is still figuring out its answer to this situation. Despite its guarantees, the GIL's restriction on parallel execution seems like the wrong direction. This is part of MRI's growing pains. Other implementations, like JRuby and Rubinius, are running truly parallel with no GIL.

We're seeing lots of new languages that have concurrency abstractions built-in at the core of the language. The Ruby language doesn't have any of this, at least not yet. Another benefit of relying on abstraction is that the abstractions can improve their implementation, while your code remains unchanged. For example, if the implementation of Queue switched from relying on locks to using lock-free synchronization, your code would reap the benefits without any modification.

For the time being, Ruby developers should educate themselves about these issues! Learn about concurrency. Be aware of race conditions. Thinking about code as interleavings can help you reason about race conditions.

I'll leave off with a quote that's influencing much of the work being done in the larger field of concurrency today:

Don't communicate by sharing state; share state by communicating.

Using data structures for synchronization supports this; the Actor model supports this. This idea is at the core of the concurrency model of languages like Go, Erlang, and others.

Ruby needs to look to what's working in other languages and embrace it. As a Ruby developer, you can do this today by trying out and supporting some of these alternative approaches. With more people on board, these approaches could become the new standard for Ruby.

Thanks to Brian Shirai for reviewing a draft of this.

Last updated at 2014/10/25 11:19 AM | Presented by Aredridel and Christoffer Sawicki | Hosted at The Internet Company