Rescuing Ruby

9d8b3e8c6babffda3cf50cc1ff8c871e?s=47 Greg Brockman
February 21, 2014

Rescuing Ruby

If you ask someone on the street what is wrong with Ruby, you will probably hear "it's too slow." However, if you talk to enough people, you will start to uncover a deeper, more insidious set of issues, such as "Ruby's conventions are poorly suited to building maintainable projects" or "there's no tooling for statically catching even the simplest bugs."

Since most people are not even aware of these issues, no one is working on improving them. No matter how fast the Ruby interpreter becomes, we will still be silently losing community members who are best positioned to ensure that Ruby continues to be relevant as languages like Go and Clojure become increasingly serious competitors.

Fortunately, with enough of a cultural shift, it is not too late to change Ruby's course. We need to write static analysers that catch what is possible within the constraints of Ruby's dynamicism. We need to standardise on a style guide and publish projects for people to emulate. In this talk, I will elaborate on these issues, and present my view on what else we as a community need to change in order to maintain Ruby's position in the long run.

9d8b3e8c6babffda3cf50cc1ff8c871e?s=128

Greg Brockman

February 21, 2014
Tweet

Transcript

  1. Rescuing Ruby Greg Brockman Stripe CTO @thegdb begin ruby rescue

    ?? end
  2. Ruby’s niche is being eaten from all directions (and not

    just because of better runtimes).
  3. “Highly productive web language which can also be systems code

    in a pinch”? ! (Python’s web libraries are getting quite good.)
  4. “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.)
  5. “Home of the most innovative web frameworks”? ! (Node.js is

    where the next generation of web frameworks, such as Meteor, are being written.)
  6. Source: modulecounts.com

  7. 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.
  8. First, expand the set of use cases.

  9. Change 1: Find areas of rapid development, and create libraries

    to make Ruby the default language.
  10. None
  11. None
  12. None
  13. Change 2: Create a standard SOA toolkit.

  14. All we need:

  15. # 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
  16. Change 3: Invest more time in Bundler.

  17. 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.
  18. Second, catch up on the ground we’ve lost.

  19. Change 4: Add standard ways of doing standard tasks (logging,

    config, etc). Just having this for Rails isn’t enough.
  20. None
  21. 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:
  22. class MyClass include Chalk::Log ! # Prints: # # Saying

    something: what="hello" def hello log.info('Saying something', what: 'hello') end end
  23. Change 5: Stop monkey-patching the language. (Refinements aren’t enough.)

  24. 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
  25. Change 6: Write static analyzers.

  26. 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() { […] }
  27. 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
  28. Change 7: Favor explictness over implicitness, and straightforward over clever.

  29. 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
  30. “Be liberal in what you accept, and conservative in what

    you send” ! — RFC 1122 ! Good for internet protocols. Less good for the application layer. <foo type="yaml"> --- :hello: world </foo> (https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-0156)
  31. Change 8: Take ownership over your users’ security.

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

  34. Imagine being able to connect to your production code and

    drop into exceptioned contexts, extract a runnable core dump, or gather statistics.
  35. Greg Brockman Stripe CTO // @thegdb