Slide 1

Slide 1 text

Rescuing Ruby Greg Brockman Stripe CTO @thegdb begin ruby rescue ?? end

Slide 2

Slide 2 text

Ruby’s niche is being eaten from all directions (and not just because of better runtimes).

Slide 3

Slide 3 text

“Highly productive web language which can also be systems code in a pinch”? ! (Python’s web libraries are getting quite good.)

Slide 4

Slide 4 text

“A good place to write prototyping code before writing in a ‘serious’ language like C++”? ! (Go is making it easy to write “serious” code, so prototyping languages are becoming less compelling.)

Slide 5

Slide 5 text

“Home of the most innovative web frameworks”? ! (Node.js is where the next generation of web frameworks, such as Meteor, are being written.)

Slide 6

Slide 6 text

Source: modulecounts.com

Slide 7

Slide 7 text

So, what can we do to reverse the trend and prevent Ruby becoming another Perl? ! This talk proposes one possible set of (occasionally radical) changes, but what’s most important is that we as a community don’t just sit idly by. ! All examples are just isolated illustrations — I don’t mean to point fingers.

Slide 8

Slide 8 text

First, expand the set of use cases.

Slide 9

Slide 9 text

Change 1: Find areas of rapid development, and create libraries to make Ruby the default language.

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Change 2: Create a standard SOA toolkit.

Slide 14

Slide 14 text

All we need:

Slide 15

Slide 15 text

# Thrift IDL: # # namespace rb Example.Thrift # # service ExampleInterface { # string example(1: string arg); # } ! class ExampleServer < Chalk::Thrift::Server::Base interface Example::Thrift::ExampleInterface set :port, 1337 ! def example(arg) 'hi' end end

Slide 16

Slide 16 text

Change 3: Invest more time in Bundler.

Slide 17

Slide 17 text

Run `bundle install` to install missing gems. How much time do we spend staring at this: The Bundler API is great, but there’s a lot of work to be done on the implementation.

Slide 18

Slide 18 text

Second, catch up on the ground we’ve lost.

Slide 19

Slide 19 text

Change 4: Add standard ways of doing standard tasks (logging, config, etc). Just having this for Rails isn’t enough.

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

loop do begin break if @stopping || @network_is_down run_once [...] rescue Exception => e puts e.class.name puts e.message puts e.backtrace end end Right now the path of least resistance looks like this:

Slide 22

Slide 22 text

class MyClass include Chalk::Log ! # Prints: # # Saying something: what="hello" def hello log.info('Saying something', what: 'hello') end end

Slide 23

Slide 23 text

Change 5: Stop monkey-patching the language. (Refinements aren’t enough.)

Slide 24

Slide 24 text

Right::AWS: ! ! ! ! ! ! Rails 3: Example via http://yehudakatz.com/2010/11/30/ruby-2-0-refinements-in-practice/ class String def camelize() self.dup.split(/_/).map{ |word| word.capitalize }.join('') end end ! ! ! class String def camelize(first_letter = :upper) case first_letter when :upper then ActiveSupport::Inflector.camelize(self, true) when :lower then ActiveSupport::Inflector.camelize(self, false) end end end

Slide 25

Slide 25 text

Change 6: Write static analyzers.

Slide 26

Slide 26 text

Go Oracle: ! ▶ Found a call path from root to (*github.com/stripe-ctf/ octopus/harness.Harness).querier ! ▶ (*github.com/stripe-ctf/octopus/harness.Harness).querier ▶ static method call from (*github.com/stripe-ctf/octopus/harness.Harness).Start ▶ static method call from (*github.com/stripe-ctf/octopus/director.Director).Start ▶ static method call from github.com/stripe-ctf/octopus.main func (h *Harness) querier() { […] }

Slide 27

Slide 27 text

While it’s impossible to get 100% coverage, we can write tools for all the sane cases. (If your analyzer can’t understand it, a human probably can’t either.) ! Proof-of-concept: https://github.com/gdb/ruby-static- checker

Slide 28

Slide 28 text

Change 7: Favor explictness over implicitness, and straightforward over clever.

Slide 29

Slide 29 text

def method_missing(*m) regex = m.first.to_s.match(/^find_(all_)?(country_| countries_)?by_(.+)/) super unless regex ! countries = self.find_by($3, m[1], $2) $1 ? countries : countries.last end ! […] ! def find_by(attribute, value, obj = nil) self.find_all_by(attribute.downcase, value).map do | country| obj.nil? ? country : self.new(country.last) end end

Slide 30

Slide 30 text

“Be liberal in what you accept, and conservative in what you send” ! — RFC 1122 ! Good for internet protocols. Less good for the application layer. --- :hello: world (https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-0156)

Slide 31

Slide 31 text

Change 8: Take ownership over your users’ security.

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

Third, build tooling and applications that other languages can’t replicate.

Slide 34

Slide 34 text

Imagine being able to connect to your production code and drop into exceptioned contexts, extract a runnable core dump, or gather statistics.

Slide 35

Slide 35 text

Greg Brockman Stripe CTO // @thegdb