Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Standing on the Shoulders of Giants with JRuby

Standing on the Shoulders of Giants with JRuby

Presentation given at Software Passion Summit, March 2012

Theo Hultberg

April 14, 2012
Tweet

More Decks by Theo Hultberg

Other Decks in Programming

Transcript

  1. TL;DR Most of you are Java developers Writing Java is

    tedious There’s truckloads of great Java libraries The JVM is awesome Ruby is awesome ∴ JRuby FTW måndag 19 mars 12
  2. JRuby vs. vanilla Ruby Real threads A working GC Every

    Java, Scala and Ruby library ever made All the JVM awesomeness, JIT, the lot måndag 19 mars 12
  3. JRuby — Java stuff = TreeMap.new stuff['windmill'] = 'rocket' stuff['pirate']

    = 'bees' stuff.each do |something| # redacted end måndag 19 mars 12
  4. JRuby — Java require 'java' require 'rabbitmq-client.jar' import 'com.rabbitmq.client.ConnectionFactory' factory

    = ConnectionFactory.new() factory.setUri('amqp://localhost:5672/') connection = factory.newConnection() måndag 19 mars 12
  5. JRuby — Java require 'java' require 'rabbitmq-client.jar' import 'com.rabbitmq.client.ConnectionFactory' factory

    = ConnectionFactory.new factory.uri = 'amqp://localhost:5672/' connection = factory.new_connection måndag 19 mars 12
  6. JRuby — Java class Worker < Thread def run puts

    'Hard work, no play' end end # or class Worker include Runnable def run puts 'Hard work, no play' end end måndag 19 mars 12
  7. JRuby — Java pool = Executors.new_fixed_thread_pool(3) memes = LinkedBlockingQueue.new 10.times

    do pool.submit do open('http://api.autome.me/text').read.each_line do |meme| memes << meme end end end pool.shutdown pool.await_termination(3, TimeUnit::DAYS) memes.each { |m| puts(m) } måndag 19 mars 12
  8. Made up fact 84% of Java devs don’t write tests

    because it’s way too much extra code to type. måndag 19 mars 12
  9. Testing public class Person { public final String firstName; public

    final String lastName; public Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public String getFullName() { return String.format("%s %s", firstName, lastName); } // omg I’m already bored } måndag 19 mars 12
  10. Testing class TestPerson < Test::Unit::TestCase def setup @person = Person.new('James',

    'Gosling') end def test_full_name assert_equal('James Gosling', @person.full_name) end end # this is TestUnit, it’s part of the stdlib måndag 19 mars 12
  11. Testing describe Person do describe '#full_name' do before do @person

    = Person.new('James', 'Gosling') end it 'is the first name and the last name with a space in-between' do @person.full_name.should == 'James Gosling' end end end # this is RSpec, read more at rspec.info måndag 19 mars 12
  12. Made up fact Ant was designed by the same people

    who came up with the QWERTY layout. måndag 19 mars 12
  13. Automation <?xml version="1.0"?> <project name="MyProject" default="dist" basedir="."> <description> simple example

    build file </description> <!-- set global properties for this build --> <property name="src" location="src"/> <property name="build" location="build"/> <property name="dist" location="dist"/> <target name="init"> <!-- Create the time stamp --> <tstamp/> <!-- Create the build directory structure used by compile --> <mkdir dir="${build}"/> </target> <target name="compile" depends="init" description="compile the source "> <!-- Compile the java code from ${src} into ${build} --> <javac srcdir="${src}" destdir="${build}"/> </target> <target name="dist" depends="compile" description="generate the distribution"> <!-- Create the distribution directory --> <mkdir dir="${dist}/lib"/> <!-- And don’t get me started on Maven, $%&@*! --> <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file --> måndag 19 mars 12
  14. Automation require 'ant' src_dir = 'src' build_dir = 'build' dist_dir

    = 'dist' timestamp = Time.now task :init do mkdir_p build_dir end task :compile => :init do ant.javac :srcdir => src_dir, :destdir => build_dir end task :dist => :compile do mkdir_p "#{dist_dir}/lib" ant.jar :jarfile => "#{dist_dir}/lib/MyProject-#{timestamp}.jar", :basedir => build_dir end task :clean do rm_rf build_dir rm_rf dist_dir måndag 19 mars 12
  15. Made up fact The average number of lines in a

    Java web application is somewhere around 100 000 måndag 19 mars 12
  16. Don’t make it so hard get '/' do erb :index

    end post '/register' do stuff.save(params[:name], params[:email], params[:shoe_size]) redirect '/thanks' end get '/thanks' do @name = params[:name] erb :thanks end # this is Sinatra, read more at sinatrarb.com måndag 19 mars 12
  17. Pack it up in a WAR and ship it $

    warbler war # warbler can be found at github.com/jruby/warbler # also check out torquebox.org, and github.com/trinidad/trinidad måndag 19 mars 12
  18. Make a console $ hbase shell HBase Shell; enter 'help<RETURN>'

    for list of supported commands. Type "exit<RETURN>" to leave the HBase Shell Version 0.90.4-cdh3u2, r, Thu Oct 13 20:32:26 PDT 2011 hbase(main):001:0> create 'test', 'cf' 0 row(s) in 1.2200 seconds hbase(main):002:0> put 'test', 'row1', 'cf:a', 'value1' 0 row(s) in 0.0560 seconds hbase(main):003:0> put 'test', 'row2', 'cf:b', 'value2' 0 row(s) in 0.0370 seconds måndag 19 mars 12
  19. Monitoring require 'jmx' client = JMX.connect(:port => 7199) storage_service =

    client['org.apache.cassandra.db:type=StorageService'] storage_service.keyspaces.each do |keyspace| puts keyspace end memory_mbean = client['java.lang:type=Memory'] puts memory_mbean.heap_memory_usage.used memory_mbean.gc måndag 19 mars 12
  20. Configuration conf = configuration do base_keys :api_key, :date dimension :path

    dimension :section dimension :country dimension :section, :country metric :pageviews metric :reach, :user_id, :type => :unique metric :clicks, :click?, :type => :predicate end counters = conf.build! måndag 19 mars 12
  21. Our stack: RabbitMQ We use the Java driver, with a

    JRuby interface we call HotBunnies github.com/ruby-amqp/hot_bunnies måndag 19 mars 12
  22. Our stack: RabbitMQ require 'hot_bunnies' connection = HotBunnies.connect(:host => 'localhost')

    channel = connection.create_channel queue = channel.queue('test_queue') queue.bind('test_exch', :routing_key => 'hi') subscription = queue.subscribe(:ack => true, :blocking => false) do |headers, msg| # do awesome stuff end måndag 19 mars 12
  23. Our stack: MongoDB Go listen to David’s talk tomorrow We

    use the Ruby driver, because we wouldn’t get anything done otherwise måndag 19 mars 12
  24. Our stack: MongoDB BasicDBObject doc = new BasicDBObject(); doc.put("name", "MongoDB");

    doc.put("type", "database"); doc.put("count", 1); BasicDBObject info = new BasicDBObject(); info.put("x", 203); info.put("y", 102); doc.put("info", info); coll.insert(doc); vs. coll.insert( 'name' => 'MongoDB', 'type' => 'database', 'count' => 1, 'info' => {'x' => 203, 'y' => 102} ) måndag 19 mars 12
  25. Our stack: Cassandra We use a JRuby wrapper on top

    of Pelops github.com/iconara/eurydice måndag 19 mars 12
  26. Our stack: Cassandra Mutator mutator = Pelops.createMutator(pool); Column nameColumn =

    mutator.newColumn("name", "Dan"); Column ageColumn = mutator.newColumn("age", Bytes.fromInt(33)); List<Column> columns = mutator.newColumnList(nameColumn, ageColumn); mutator.writeColumns(columnFamily, rowKey, columns); mutator.execute(ConsistencyLevel.ONE); vs. columns = {'name' => 'Dan', 'age' => 33} column_family.update(row_key, columns, :consistency_level => :one) måndag 19 mars 12
  27. Our stack: Akka Scala is nice, but we’ve got better

    things to do than to wait for code to compile Akka is awesome, so we created Mikka github.com/iconara/mikka måndag 19 mars 12
  28. Our stack: Akka class Ping < Mikka::Actor def pre_start @pong

    = context.actor_of(Pong) @pong << :ping end def receive(message) context.reply(:ping) end end class Pong < Mikka::Actor def receive(message) context.reply(:pong) end end ping = Mikka.actor_of(Ping).start måndag 19 mars 12
  29. Our stack: numbers We process hundreds of millions of messages

    per day, using less than 20K lines of JRuby måndag 19 mars 12