STANDING ON THE SHOULDERS OF GIANTS WITH JRUBY

måndag 19 mars 12

Theo @iconara
måndag 19 mars 12

Chief Architect at

måndag 19 mars 12

måndag 19 mars 12

ruby

måndag 19 mars 12

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

I’M NOT HERE TO MAKE FUN OF JAVA

just

måndag 19 mars 12

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

JRuby vs. Java
It doesn’t make you want to stab yourself

måndag 19 mars 12

måndag 19 mars 12

JRUBY ♥ JAVA A WHIRLWIND TOUR

måndag 19 mars 12

JRuby ♥ Java
stuff = TreeMap.new stuff['windmill'] = 'rocket' stuff['pirate'] = 'bees' stuff.each do |something| # redacted end

måndag 19 mars 12

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

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

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

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

JRUBY FOR REPRESSED JAVA DEVELOPERS

måndag 19 mars 12

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

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

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

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

Made up fact
Ant was designed by the same people who came up with the QWERTY layout.

måndag 19 mars 12

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

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

Made up fact
The average number of lines in a Java web application is somewhere around 100 000

måndag 19 mars 12

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

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

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> 0 row(s) in 1.2200 hbase(main):002:0> 0 row(s) in 0.0560 hbase(main):003:0> 0 row(s) in 0.0370 create 'test', 'cf' seconds put 'test', 'row1', 'cf:a', 'value1' seconds put 'test', 'row2', 'cf:b', 'value2' seconds

måndag 19 mars 12

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

Configuration
conf = configuration do base_keys :api_key, :date dimension dimension dimension dimension :path :section :country :section, :country

metric :pageviews metric :reach, :user_id, :type => :unique metric :clicks, :click?, :type => :predicate end counters = conf.build!

måndag 19 mars 12

SNEAK SOME RUBY INTO THAT ENTERPRISE APPLICATION

måndag 19 mars 12

STANDING ON THE SHOULDERS OF GIANTS WITH JRUBY

måndag 19 mars 12

LET’S STACK SOME ABSTRACTIONS ON TOP OF THEM THERE ABSTRACTIONS

måndag 19 mars 12

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

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

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

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

Our stack: Cassandra
We use a JRuby wrapper on top of Pelops github.com/iconara/eurydice

måndag 19 mars 12

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

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

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

Our stack: numbers
We process hundreds of millions of messages per day, using less than 20K lines of JRuby

måndag 19 mars 12

twitter.com/iconara architecturalatrocities.com burtcorp.com

måndag 19 mars 12

Sign up to vote on this title
UsefulNot useful