SlideShare une entreprise Scribd logo
1  sur  61
Télécharger pour lire hors ligne
JRuby
Insights from Six Years in Production
Mark Menard	

Enable Labs
How do you get Ruby into a Java shop?

How do you move past Java to Ruby?

How do you get Ruby into a legacy Java app?

Enable Labs

!2

@mark_menard
Who are you?
Enable Labs

!3

@mark_menard
You love Ruby!

Enable Labs

!4

@mark_menard
You work in a Java shop.
Enable Labs

!5

@mark_menard
You have a client who
uses Java.

Enable Labs

!6

@mark_menard
You have to
work on
something
that uses Java.
Enable Labs

!7

@mark_menard
You have a
project that
could benefit
from true
concurrency.
Enable Labs

!8

@mark_menard
Why?

Enable Labs

!9

@mark_menard
So... what is JRuby anyway?

Enable Labs

!10

@mark_menard
But I use MRI!
What’s different?
Enable Labs

!11

@mark_menard
To Summarize
•
•
•
•
•
•
Enable Labs

A JVM is required.	

Start up is a little slower.	

Prefer pure Ruby gems, or gems that have JRuby versions. 	

Try to avoid gems with C-extensions.	

No continuations.	

No fork()	

Regular expressions use 1.9 semantics even in 1.8 mode.

•

!12

@mark_menard
What can JRuby do for you?

Enable Labs

!13

@mark_menard
Parallelism in JRuby

Enable Labs

!14

@mark_menard
my_thread = Thread.new do
(1..100_000).each { |i| i * 2 }
end
!

# Do some more work.
!

my_thread.join # Wait for my_thread to finish.

Enable Labs

!15

@mark_menard
require 'peach'
require 'benchmark'
!

overall_results = Benchmark.measure do
(1..100_000).peach(8) do |i|
1000.times do |n|
a, b = 0, 1
a, b = b, a+b
end
end
end
puts overall_results

Enable Labs

!16

@mark_menard
$ rvm use 2.0
Using /Users/mark/.rvm/gems/ruby-2.0.0-p247
$ ruby peach_example.rb
41.250000 0.060000 41.310000 ( 41.302095)
$ rvm use jruby
Using /Users/mark/.rvm/gems/jruby-1.7.5
$ ruby peach_example.rb
9.960000 0.170000 10.130000 ( 1.437000)

Enable Labs

!17

@mark_menard
Using Java Libraries

Enable Labs

!18

@mark_menard
require 'java'
require "#{File.expand_path(File.dirname(__FILE__))}/itextpdf-5.4.4.jar"
!
# Make Java classes top level constants.
java_import com.itextpdf.text.Document
Document.__persistent__ = true
java_import com.itextpdf.text.pdf.PdfWriter
java_import java.io.FileOutputStream
java_import com.itextpdf.text.Paragraph
document = Document.new
pdfWriter = PdfWriter.get_instance(document, FileOutputStream.new("document.pdf"))
document.open
document.add(Paragraph.new("Hello JRuby"))
document.close

Enable Labs

!19

@mark_menard
require 'itext'
Itext::Document.create("document.pdf") do
p "Hello from JRuby"
end

Enable Labs

!20

@mark_menard
require 'java'
require "#{File.expand_path(File.dirname(__FILE__))}/itextpdf-5.4.4.jar"
!

module Itext
# Namespace the Java classes for convenience.
java_import com.itextpdf.text.Document
Document.__persistent__ = true
java_import com.itextpdf.text.pdf.PdfWriter
java_import java.io.FileOutputStream
java_import com.itextpdf.text.Paragraph
end

Enable Labs

!21

@mark_menard
module Itext
# Re-open the *Java* Document class.
class Document
def self.create (filename, &block)
document = self.new
pdf_writer = PdfWriter.get_instance(document, FileOutputStream.new(filename))
document.open
document.instance_eval(&block)
document.close
end

!

def paragraph (content)
add(Paragraph.new(content))
end
alias_method :p, :paragraph
end
end

Enable Labs

!22

@mark_menard
require 'itext'
Itext::Document.create("document.pdf") do
p "Hello from JRuby"
end

Enable Labs

!23

@mark_menard
require 'java'
!

frame = javax.swing.JFrame.new
frame.set_default_close_operation javax.swing.JFrame::EXIT_ON_CLOSE
frame.set_size(300, 200)
frame.get_content_pane.add javax.swing.JLabel.new('Hello world!')
frame.set_visible true

Enable Labs

!24

@mark_menard
Case Studies

Enable Labs

!25

@mark_menard
Case Study 1
!

What the Client
Wanted
!

1Q2008

Enable Labs

• New functionality that was
predominantly orthogonal
to their existing app.
• Single Signon
• Faster Development Times
• Some integration at the data
level.

!26

@mark_menard
• Struts 2
• Groovy 1.0
• Jetty Running Un-war'ed
• Spring Dependency Injection XML Hell
• Struts 2 - More XML Hell

Case Study 1
!

The Technical
Environment

!

• Mostly Continuous Deployment
Enable Labs

!27

@mark_menard
Case Study 1
!

What We Used

• JRuby 1.0
• Rails 2.1
• ERB
Enable Labs

!28

@mark_menard
Case Study 1
!

What Made it
Work

Java Integration

Enable Labs

!29

@mark_menard
Case Study 1
!

The Challenges

Enable Labs

• Integrating the Signin Process
• Accessing the Spring Context
• Reusing Existing Permission
System
• Deployment
• Gem Management

!30

@mark_menard
• Initiate all signins on the Rails
side of the application.
• On success setup the HTTP
session for both the Java and
Rails sides of the app.
• Also handle signout in Rails.

Enable Labs

!31

Case Study 1
!

Integrating the
Signin Process

@mark_menard
• Create a Java object that holds a

Case Study 1
!

Accessing the
Spring Context

Enable Labs

static reference to the Spring
context, the
SpringApplicationContextFinder.
• The finder is initialized at startup
with the reference to the
context.
• Make a Ruby DSL to access
Spring.
!32

@mark_menard
public class SpringApplicationContextFinder implements ApplicationContextAware {

!
!

!

}

private static ApplicationContext CONTEXT;
/**
* This method is called from within the ApplicationContext once it is
* done starting up, it will stick a reference to itself into this bean.
* @param context a reference to the ApplicationContext.
*/
public void setApplicationContext(ApplicationContext context) throws BeansException {
CONTEXT = context;
}
/**
* Return a reference to the Spring application context.
* @return SpringApplicationContext
*/
public static Object getContext () {
return CONTEXT;
}

Enable Labs

!33

@mark_menard
module SpringSupport
def get_spring_context
@context ||= Java::lib.SpringApplicationContextFinder.getContext()
end
end

Enable Labs

!34

@mark_menard
class SomeObject
include SpringSupport
!

spring_dependency :some_spring_service
!

def do_something (arg)
!

#@some_spring_service <---- This is a Java object.
!

some_spring_service.do_something(arg)
end
end
!

result = SomeObject.new.do_something("abc")

Enable Labs

!35

@mark_menard
• Permission system written in

Case Study 1
!

Reusing Existing
Permission
System

Enable Labs

Java/Groovy.
• Still needed to be accessible
from Java/Groovy.
• Did not want to maintain two
versions of the permission
system.

!36

@mark_menard
• Use the Spring implementation

Case Study 1
!

Reusing Existing
Permission
System

of permissions.
• Check permissions in a
before_filter.
• Use the SpringSupport to get
access to the security manager.

!

Solution

Enable Labs

!37

@mark_menard
class CheckSecurityAccessService < Struct.new(:url, :user)
include SpringSupport
spring_dependency :security_manager
!

def execute
security_manager.check_security_access(build_vr_context)
end
alias_method :succeeded?, :execute
!

private
!

def build_vr_context
VRContext.new(HashMap.new('url' => url, 'user' => user))
end
!

end

Enable Labs

!38

@mark_menard
Case Study 1
!

Deployment and
Gem Management

Enable Labs

• App used Jetty un-war’ed.
• Warbler didn’t apply.
• Layout Rails app in /WEB-INF
• Used GoldSpike servlet to front
Rails. (We have since updated to
jruby-rack and a Servlet filter.)
• Vendor EVERYTHING and check it
into git.

!39

@mark_menard
• Completed work in about 3

Case Study 1
!

Success

Enable Labs

months.
• Much better test coverage.
• This module is still orthogonal to
the main app today.
• Code has been very stable.
• Code has been ported through
multiple versions of Rails.
• Almost all new functionality is
done in Rails since 1Q2008.
!40

@mark_menard
• Minimal integration with existing
application.
• Highly compartmentalized.
• Focused feature set with stable
requirements.
• Java integration worked.

Case Study 1
!

Why did it
succeed?
Enable Labs

!41

@mark_menard
Case Study 2

And Steve said, “let
there be iPhone.”

Enable Labs

!42

@mark_menard
• Client wants about 10 screens
available in the browser on the
iPhone.
• He has a trip in two weeks and
wants it working before he
leaves.

Case Study 2
!

iPhone
Enable Labs

!43

@mark_menard
• Working screens inside of a week.
• Ready for his trip in two weeks.
• Went on to be used by the field sales staff for several
years.
• Total cost far below the client’s expectation.

Case Study 2

Rails to the Rescue

!

!

iPhone

A rip roaring success

Enable Labs

!44

@mark_menard
Case Study 3
!

Porting to Ruby
First Attempt
!

A Study in Over
Enthusiasm

This JRuby is Awesome!
Let’s Port the App!
Enable Labs

!45

@mark_menard
Let’s talk
about the
brownfield.

• 388 Views
• 272 Struts 2 Actions
• 30 Spring Service Beans
• 81 Data Access Objects
• 151 Hibernate/JPA Entities
(Models)
• Not Enough Tests
• Primary implementation
language is Groovy
Enable Labs

Case Study 3
!

Porting to Ruby
First Attempt
!46

@mark_menard
Case Study 3
Current
Architecture

Enable Labs

!47

@mark_menard
• Ruby classes can implement Java
interfaces.

Case Study 3
!

Porting to Ruby
First Attempt
Enable Labs

!48

@mark_menard
public interface Person {
public String getName ();
public void setName (String name);
}
class Person
include Java::Person
!

attr_accessor :name
end

Enable Labs

!49

@mark_menard
• Ruby classes can implement Java
interfaces.
• Plug a Ruby/Rails environment
into Spring to manufacture Ruby
“beans”.

Case Study 3
!

Porting to Ruby
First Attempt
Enable Labs

!50

@mark_menard
def getInventoryManager () {
log.debug "[ RailsFactory.groovy ] : Instantiating Integration::InventoryManager"
eval "Integration::InventoryManager.newn"
}

Enable Labs

!51

@mark_menard
• Ruby classes can implement Java

Case Study 3
!

Porting to Ruby
First Attempt
Enable Labs

interfaces.
• Plug a Ruby/Rails environment
into Spring to manufacture Ruby
“beans”.
• On a case-by-case basis port
Java/Groovy Spring service
beans to JRuby.
• This was a bottom up port.
!52

@mark_menard
Rationale
Case Study 3
!

Porting to Ruby
First Attempt

Enable Labs

• No need to mess with the user
experience. The views and
controllers won’t change.
• Can do it incrementally.
• Allows Java, Groovy and JRuby
objects to just inter-play.
• Should be transparent.
!53

@mark_menard
Outcome
• Technical success, business failure.
• Did not take full advantage of our
Ruby tools.
• There was no driving business value
in doing it.

Case Study 3
!

Porting to Ruby First
Attempt

Enable Labs

!54

@mark_menard
Case Study 4
!

Porting to Rails
Part 2

Ah.... sweet incremental
success... ...mostly.

Enable Labs

!55

@mark_menard
• Do all new work in JRuby.
• Find silos of existing functionality.
• Wait for significant changes in
requirements for the silo.
• Port one silo at a time.
• Port the whole silo to JRuby.
• Write lots of tests.
• Find improvements to UI/UX that can be
rolled in for justification.
• Use SOA for non-user facing services.

Enable Labs

!56

Case Study 4
!

Porting to Rails
Part 2
@mark_menard
Case Study 4
!

Porting to Rails
Part 2

The God Object in the Closet
Enable Labs

!57

@mark_menard
The God Object in the Closet

The Strategy
!

Make the God object a web service.
Implement it in Rails.
Translate the existing Groovy code.
Port test suite to RSpec.
Refactor, refactor, refactor, refactor, refactor....
Review the spec with the client extensively.

Case Study 4

Enable Labs

Porting to Rails Part 2
!58

@mark_menard
JRuby works today.
Java integration lets you
play where MRI just can’t go.
It’s just Ruby, with Java
JVM super powers!
Enable Labs

!59

@mark_menard
Photo credits
http://www.flickr.com/photos/usfwsnortheast/5655240564/
http://www.flickr.com/photos/falcon1961/3304306800/
!

Code Color Scheme
Solarized Light
!

Syntax Highlighting Tool
http://www.andre-simon.de/doku/highlight/en/highlight.html

Enable Labs

!60

@mark_menard
Enable Labs
@mark_menard
http://www.enablelabs.com/
info@enablelabs.com
866-895-8189

Contenu connexe

Tendances

Unit-testing and E2E testing in JS
Unit-testing and E2E testing in JSUnit-testing and E2E testing in JS
Unit-testing and E2E testing in JSMichael Haberman
 
Angular Unit Testing NDC Minn 2018
Angular Unit Testing NDC Minn 2018Angular Unit Testing NDC Minn 2018
Angular Unit Testing NDC Minn 2018Justin James
 
Angular Unit Testing from the Trenches
Angular Unit Testing from the TrenchesAngular Unit Testing from the Trenches
Angular Unit Testing from the TrenchesJustin James
 
Multithreading and concurrency in android
Multithreading and concurrency in androidMultithreading and concurrency in android
Multithreading and concurrency in androidRakesh Jha
 
Google mock for dummies
Google mock for dummiesGoogle mock for dummies
Google mock for dummiesHarry Potter
 
Interpreter RPG to Java
Interpreter RPG to JavaInterpreter RPG to Java
Interpreter RPG to Javafarerobe
 
Automated Testing in Django
Automated Testing in DjangoAutomated Testing in Django
Automated Testing in DjangoLoek van Gent
 
Extending burp with python
Extending burp with pythonExtending burp with python
Extending burp with pythonHoang Nguyen
 
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit TutorialJAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit TutorialAnup Singh
 
Unit Testing RPG with JUnit
Unit Testing RPG with JUnitUnit Testing RPG with JUnit
Unit Testing RPG with JUnitGreg.Helton
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Codescidept
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy CodeRowan Merewood
 
Refactoring legacy code driven by tests - ENG
Refactoring legacy code driven by tests - ENGRefactoring legacy code driven by tests - ENG
Refactoring legacy code driven by tests - ENGLuca Minudel
 
Unit Test Your Database
Unit Test Your DatabaseUnit Test Your Database
Unit Test Your DatabaseDavid Wheeler
 

Tendances (17)

Unit-testing and E2E testing in JS
Unit-testing and E2E testing in JSUnit-testing and E2E testing in JS
Unit-testing and E2E testing in JS
 
Angular Unit Testing NDC Minn 2018
Angular Unit Testing NDC Minn 2018Angular Unit Testing NDC Minn 2018
Angular Unit Testing NDC Minn 2018
 
Angular Unit Testing from the Trenches
Angular Unit Testing from the TrenchesAngular Unit Testing from the Trenches
Angular Unit Testing from the Trenches
 
Multithreading and concurrency in android
Multithreading and concurrency in androidMultithreading and concurrency in android
Multithreading and concurrency in android
 
Google mock for dummies
Google mock for dummiesGoogle mock for dummies
Google mock for dummies
 
Interpreter RPG to Java
Interpreter RPG to JavaInterpreter RPG to Java
Interpreter RPG to Java
 
Testing in Django
Testing in DjangoTesting in Django
Testing in Django
 
Automated Testing in Django
Automated Testing in DjangoAutomated Testing in Django
Automated Testing in Django
 
ClassJS
ClassJSClassJS
ClassJS
 
Extending burp with python
Extending burp with pythonExtending burp with python
Extending burp with python
 
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit TutorialJAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
JAVASCRIPT TDD(Test driven Development) & Qunit Tutorial
 
Efficient Android Threading
Efficient Android ThreadingEfficient Android Threading
Efficient Android Threading
 
Unit Testing RPG with JUnit
Unit Testing RPG with JUnitUnit Testing RPG with JUnit
Unit Testing RPG with JUnit
 
Working Effectively With Legacy Code
Working Effectively With Legacy CodeWorking Effectively With Legacy Code
Working Effectively With Legacy Code
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
Refactoring legacy code driven by tests - ENG
Refactoring legacy code driven by tests - ENGRefactoring legacy code driven by tests - ENG
Refactoring legacy code driven by tests - ENG
 
Unit Test Your Database
Unit Test Your DatabaseUnit Test Your Database
Unit Test Your Database
 

Similaire à JRuby 6 Years in Production

Master class in modern Java
Master class in modern JavaMaster class in modern Java
Master class in modern JavaMiro Cupak
 
Beyond Fluffy Bunny. How I leveraged WebObjects in my lean startup.
Beyond Fluffy Bunny. How I leveraged WebObjects in my lean startup.Beyond Fluffy Bunny. How I leveraged WebObjects in my lean startup.
Beyond Fluffy Bunny. How I leveraged WebObjects in my lean startup.WO Community
 
Master class in modern Java
Master class in modern JavaMaster class in modern Java
Master class in modern JavaMiro Cupak
 
Monkeybars in the Manor
Monkeybars in the ManorMonkeybars in the Manor
Monkeybars in the Manormartinbtt
 
The Enterprise Strikes Back
The Enterprise Strikes BackThe Enterprise Strikes Back
The Enterprise Strikes BackBurke Libbey
 
Java interview-questions-and-answers
Java interview-questions-and-answersJava interview-questions-and-answers
Java interview-questions-and-answersbestonlinetrainers
 
PRG 420 Effective Communication - snaptutorial.com
PRG 420 Effective Communication - snaptutorial.comPRG 420 Effective Communication - snaptutorial.com
PRG 420 Effective Communication - snaptutorial.comdonaldzs37
 
PRG 420 Massive success / tutorialrank.com
PRG 420 Massive success / tutorialrank.comPRG 420 Massive success / tutorialrank.com
PRG 420 Massive success / tutorialrank.comBromleyz1
 
Burp plugin development for java n00bs (44 con)
Burp plugin development for java n00bs (44 con)Burp plugin development for java n00bs (44 con)
Burp plugin development for java n00bs (44 con)Marc Wickenden
 
把鐵路開進視窗裡
把鐵路開進視窗裡把鐵路開進視窗裡
把鐵路開進視窗裡Wei Jen Lu
 
MacRuby for Fun and Profit
MacRuby for Fun and ProfitMacRuby for Fun and Profit
MacRuby for Fun and ProfitJoshua Ballanco
 
How to Reverse Engineer Web Applications
How to Reverse Engineer Web ApplicationsHow to Reverse Engineer Web Applications
How to Reverse Engineer Web ApplicationsJarrod Overson
 
GeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testingGeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testingJakub Marchwicki
 
Javascript Common Design Patterns
Javascript Common Design PatternsJavascript Common Design Patterns
Javascript Common Design PatternsPham Huy Tung
 
Android Training For Beginner @DILO Bandung
Android Training For Beginner @DILO BandungAndroid Training For Beginner @DILO Bandung
Android Training For Beginner @DILO BandungAde Rifaldi
 

Similaire à JRuby 6 Years in Production (20)

Master class in modern Java
Master class in modern JavaMaster class in modern Java
Master class in modern Java
 
Beyond Fluffy Bunny. How I leveraged WebObjects in my lean startup.
Beyond Fluffy Bunny. How I leveraged WebObjects in my lean startup.Beyond Fluffy Bunny. How I leveraged WebObjects in my lean startup.
Beyond Fluffy Bunny. How I leveraged WebObjects in my lean startup.
 
Master class in modern Java
Master class in modern JavaMaster class in modern Java
Master class in modern Java
 
Monkeybars in the Manor
Monkeybars in the ManorMonkeybars in the Manor
Monkeybars in the Manor
 
The Enterprise Strikes Back
The Enterprise Strikes BackThe Enterprise Strikes Back
The Enterprise Strikes Back
 
Java interview-questions-and-answers
Java interview-questions-and-answersJava interview-questions-and-answers
Java interview-questions-and-answers
 
PRG 420 Effective Communication - snaptutorial.com
PRG 420 Effective Communication - snaptutorial.comPRG 420 Effective Communication - snaptutorial.com
PRG 420 Effective Communication - snaptutorial.com
 
PRG 420 Massive success / tutorialrank.com
PRG 420 Massive success / tutorialrank.comPRG 420 Massive success / tutorialrank.com
PRG 420 Massive success / tutorialrank.com
 
Migrating to Java 9 Modules
Migrating to Java 9 ModulesMigrating to Java 9 Modules
Migrating to Java 9 Modules
 
Java introduction
Java introductionJava introduction
Java introduction
 
JAVA for Every one
JAVA for Every oneJAVA for Every one
JAVA for Every one
 
Burp plugin development for java n00bs (44 con)
Burp plugin development for java n00bs (44 con)Burp plugin development for java n00bs (44 con)
Burp plugin development for java n00bs (44 con)
 
把鐵路開進視窗裡
把鐵路開進視窗裡把鐵路開進視窗裡
把鐵路開進視窗裡
 
Advanced Java Testing
Advanced Java TestingAdvanced Java Testing
Advanced Java Testing
 
Codemotion 2015 spock_workshop
Codemotion 2015 spock_workshopCodemotion 2015 spock_workshop
Codemotion 2015 spock_workshop
 
MacRuby for Fun and Profit
MacRuby for Fun and ProfitMacRuby for Fun and Profit
MacRuby for Fun and Profit
 
How to Reverse Engineer Web Applications
How to Reverse Engineer Web ApplicationsHow to Reverse Engineer Web Applications
How to Reverse Engineer Web Applications
 
GeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testingGeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testing
 
Javascript Common Design Patterns
Javascript Common Design PatternsJavascript Common Design Patterns
Javascript Common Design Patterns
 
Android Training For Beginner @DILO Bandung
Android Training For Beginner @DILO BandungAndroid Training For Beginner @DILO Bandung
Android Training For Beginner @DILO Bandung
 

Plus de Mark Menard

Let's Do Some Upfront Design - WindyCityRails 2014
Let's Do Some Upfront Design - WindyCityRails 2014Let's Do Some Upfront Design - WindyCityRails 2014
Let's Do Some Upfront Design - WindyCityRails 2014Mark Menard
 
A Tour of Wyriki
A Tour of WyrikiA Tour of Wyriki
A Tour of WyrikiMark Menard
 
Small Code - RailsConf 2014
Small Code - RailsConf 2014Small Code - RailsConf 2014
Small Code - RailsConf 2014Mark Menard
 
Small Code - Ruby on Ales 2014
Small Code - Ruby on Ales 2014Small Code - Ruby on Ales 2014
Small Code - Ruby on Ales 2014Mark Menard
 
Write Small Things (Code)
Write Small Things (Code)Write Small Things (Code)
Write Small Things (Code)Mark Menard
 
Conference of Grand Masters Tech Talk 2013
Conference of Grand Masters Tech Talk 2013Conference of Grand Masters Tech Talk 2013
Conference of Grand Masters Tech Talk 2013Mark Menard
 
Startup Lessons Learned
Startup Lessons LearnedStartup Lessons Learned
Startup Lessons LearnedMark Menard
 
Mobile Platforms and App Development
Mobile Platforms and App DevelopmentMobile Platforms and App Development
Mobile Platforms and App DevelopmentMark Menard
 
Ruby on Rails Training - Module 2
Ruby on Rails Training - Module 2Ruby on Rails Training - Module 2
Ruby on Rails Training - Module 2Mark Menard
 
Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1Mark Menard
 
Introduction to Ruby
Introduction to RubyIntroduction to Ruby
Introduction to RubyMark Menard
 
Intro to Rails ActiveRecord
Intro to Rails ActiveRecordIntro to Rails ActiveRecord
Intro to Rails ActiveRecordMark Menard
 
Behavior Driven Development with Rails
Behavior Driven Development with RailsBehavior Driven Development with Rails
Behavior Driven Development with RailsMark Menard
 
Intro to Ruby on Rails
Intro to Ruby on RailsIntro to Ruby on Rails
Intro to Ruby on RailsMark Menard
 
JRuby in a Java World
JRuby in a Java WorldJRuby in a Java World
JRuby in a Java WorldMark Menard
 

Plus de Mark Menard (15)

Let's Do Some Upfront Design - WindyCityRails 2014
Let's Do Some Upfront Design - WindyCityRails 2014Let's Do Some Upfront Design - WindyCityRails 2014
Let's Do Some Upfront Design - WindyCityRails 2014
 
A Tour of Wyriki
A Tour of WyrikiA Tour of Wyriki
A Tour of Wyriki
 
Small Code - RailsConf 2014
Small Code - RailsConf 2014Small Code - RailsConf 2014
Small Code - RailsConf 2014
 
Small Code - Ruby on Ales 2014
Small Code - Ruby on Ales 2014Small Code - Ruby on Ales 2014
Small Code - Ruby on Ales 2014
 
Write Small Things (Code)
Write Small Things (Code)Write Small Things (Code)
Write Small Things (Code)
 
Conference of Grand Masters Tech Talk 2013
Conference of Grand Masters Tech Talk 2013Conference of Grand Masters Tech Talk 2013
Conference of Grand Masters Tech Talk 2013
 
Startup Lessons Learned
Startup Lessons LearnedStartup Lessons Learned
Startup Lessons Learned
 
Mobile Platforms and App Development
Mobile Platforms and App DevelopmentMobile Platforms and App Development
Mobile Platforms and App Development
 
Ruby on Rails Training - Module 2
Ruby on Rails Training - Module 2Ruby on Rails Training - Module 2
Ruby on Rails Training - Module 2
 
Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1Ruby on Rails Training - Module 1
Ruby on Rails Training - Module 1
 
Introduction to Ruby
Introduction to RubyIntroduction to Ruby
Introduction to Ruby
 
Intro to Rails ActiveRecord
Intro to Rails ActiveRecordIntro to Rails ActiveRecord
Intro to Rails ActiveRecord
 
Behavior Driven Development with Rails
Behavior Driven Development with RailsBehavior Driven Development with Rails
Behavior Driven Development with Rails
 
Intro to Ruby on Rails
Intro to Ruby on RailsIntro to Ruby on Rails
Intro to Ruby on Rails
 
JRuby in a Java World
JRuby in a Java WorldJRuby in a Java World
JRuby in a Java World
 

Dernier

Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DaySri Ambati
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 

Dernier (20)

Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 

JRuby 6 Years in Production

  • 1. JRuby Insights from Six Years in Production Mark Menard Enable Labs
  • 2. How do you get Ruby into a Java shop? How do you move past Java to Ruby? How do you get Ruby into a legacy Java app? Enable Labs !2 @mark_menard
  • 3. Who are you? Enable Labs !3 @mark_menard
  • 4. You love Ruby! Enable Labs !4 @mark_menard
  • 5. You work in a Java shop. Enable Labs !5 @mark_menard
  • 6. You have a client who uses Java. Enable Labs !6 @mark_menard
  • 7. You have to work on something that uses Java. Enable Labs !7 @mark_menard
  • 8. You have a project that could benefit from true concurrency. Enable Labs !8 @mark_menard
  • 10. So... what is JRuby anyway? Enable Labs !10 @mark_menard
  • 11. But I use MRI! What’s different? Enable Labs !11 @mark_menard
  • 12. To Summarize • • • • • • Enable Labs A JVM is required. Start up is a little slower. Prefer pure Ruby gems, or gems that have JRuby versions. Try to avoid gems with C-extensions. No continuations. No fork() Regular expressions use 1.9 semantics even in 1.8 mode. • !12 @mark_menard
  • 13. What can JRuby do for you? Enable Labs !13 @mark_menard
  • 14. Parallelism in JRuby Enable Labs !14 @mark_menard
  • 15. my_thread = Thread.new do (1..100_000).each { |i| i * 2 } end ! # Do some more work. ! my_thread.join # Wait for my_thread to finish. Enable Labs !15 @mark_menard
  • 16. require 'peach' require 'benchmark' ! overall_results = Benchmark.measure do (1..100_000).peach(8) do |i| 1000.times do |n| a, b = 0, 1 a, b = b, a+b end end end puts overall_results Enable Labs !16 @mark_menard
  • 17. $ rvm use 2.0 Using /Users/mark/.rvm/gems/ruby-2.0.0-p247 $ ruby peach_example.rb 41.250000 0.060000 41.310000 ( 41.302095) $ rvm use jruby Using /Users/mark/.rvm/gems/jruby-1.7.5 $ ruby peach_example.rb 9.960000 0.170000 10.130000 ( 1.437000) Enable Labs !17 @mark_menard
  • 18. Using Java Libraries Enable Labs !18 @mark_menard
  • 19. require 'java' require "#{File.expand_path(File.dirname(__FILE__))}/itextpdf-5.4.4.jar" ! # Make Java classes top level constants. java_import com.itextpdf.text.Document Document.__persistent__ = true java_import com.itextpdf.text.pdf.PdfWriter java_import java.io.FileOutputStream java_import com.itextpdf.text.Paragraph document = Document.new pdfWriter = PdfWriter.get_instance(document, FileOutputStream.new("document.pdf")) document.open document.add(Paragraph.new("Hello JRuby")) document.close Enable Labs !19 @mark_menard
  • 20. require 'itext' Itext::Document.create("document.pdf") do p "Hello from JRuby" end Enable Labs !20 @mark_menard
  • 21. require 'java' require "#{File.expand_path(File.dirname(__FILE__))}/itextpdf-5.4.4.jar" ! module Itext # Namespace the Java classes for convenience. java_import com.itextpdf.text.Document Document.__persistent__ = true java_import com.itextpdf.text.pdf.PdfWriter java_import java.io.FileOutputStream java_import com.itextpdf.text.Paragraph end Enable Labs !21 @mark_menard
  • 22. module Itext # Re-open the *Java* Document class. class Document def self.create (filename, &block) document = self.new pdf_writer = PdfWriter.get_instance(document, FileOutputStream.new(filename)) document.open document.instance_eval(&block) document.close end ! def paragraph (content) add(Paragraph.new(content)) end alias_method :p, :paragraph end end Enable Labs !22 @mark_menard
  • 23. require 'itext' Itext::Document.create("document.pdf") do p "Hello from JRuby" end Enable Labs !23 @mark_menard
  • 24. require 'java' ! frame = javax.swing.JFrame.new frame.set_default_close_operation javax.swing.JFrame::EXIT_ON_CLOSE frame.set_size(300, 200) frame.get_content_pane.add javax.swing.JLabel.new('Hello world!') frame.set_visible true Enable Labs !24 @mark_menard
  • 26. Case Study 1 ! What the Client Wanted ! 1Q2008 Enable Labs • New functionality that was predominantly orthogonal to their existing app. • Single Signon • Faster Development Times • Some integration at the data level. !26 @mark_menard
  • 27. • Struts 2 • Groovy 1.0 • Jetty Running Un-war'ed • Spring Dependency Injection XML Hell • Struts 2 - More XML Hell Case Study 1 ! The Technical Environment ! • Mostly Continuous Deployment Enable Labs !27 @mark_menard
  • 28. Case Study 1 ! What We Used • JRuby 1.0 • Rails 2.1 • ERB Enable Labs !28 @mark_menard
  • 29. Case Study 1 ! What Made it Work Java Integration Enable Labs !29 @mark_menard
  • 30. Case Study 1 ! The Challenges Enable Labs • Integrating the Signin Process • Accessing the Spring Context • Reusing Existing Permission System • Deployment • Gem Management !30 @mark_menard
  • 31. • Initiate all signins on the Rails side of the application. • On success setup the HTTP session for both the Java and Rails sides of the app. • Also handle signout in Rails. Enable Labs !31 Case Study 1 ! Integrating the Signin Process @mark_menard
  • 32. • Create a Java object that holds a Case Study 1 ! Accessing the Spring Context Enable Labs static reference to the Spring context, the SpringApplicationContextFinder. • The finder is initialized at startup with the reference to the context. • Make a Ruby DSL to access Spring. !32 @mark_menard
  • 33. public class SpringApplicationContextFinder implements ApplicationContextAware { ! ! ! } private static ApplicationContext CONTEXT; /** * This method is called from within the ApplicationContext once it is * done starting up, it will stick a reference to itself into this bean. * @param context a reference to the ApplicationContext. */ public void setApplicationContext(ApplicationContext context) throws BeansException { CONTEXT = context; } /** * Return a reference to the Spring application context. * @return SpringApplicationContext */ public static Object getContext () { return CONTEXT; } Enable Labs !33 @mark_menard
  • 34. module SpringSupport def get_spring_context @context ||= Java::lib.SpringApplicationContextFinder.getContext() end end Enable Labs !34 @mark_menard
  • 35. class SomeObject include SpringSupport ! spring_dependency :some_spring_service ! def do_something (arg) ! #@some_spring_service <---- This is a Java object. ! some_spring_service.do_something(arg) end end ! result = SomeObject.new.do_something("abc") Enable Labs !35 @mark_menard
  • 36. • Permission system written in Case Study 1 ! Reusing Existing Permission System Enable Labs Java/Groovy. • Still needed to be accessible from Java/Groovy. • Did not want to maintain two versions of the permission system. !36 @mark_menard
  • 37. • Use the Spring implementation Case Study 1 ! Reusing Existing Permission System of permissions. • Check permissions in a before_filter. • Use the SpringSupport to get access to the security manager. ! Solution Enable Labs !37 @mark_menard
  • 38. class CheckSecurityAccessService < Struct.new(:url, :user) include SpringSupport spring_dependency :security_manager ! def execute security_manager.check_security_access(build_vr_context) end alias_method :succeeded?, :execute ! private ! def build_vr_context VRContext.new(HashMap.new('url' => url, 'user' => user)) end ! end Enable Labs !38 @mark_menard
  • 39. Case Study 1 ! Deployment and Gem Management Enable Labs • App used Jetty un-war’ed. • Warbler didn’t apply. • Layout Rails app in /WEB-INF • Used GoldSpike servlet to front Rails. (We have since updated to jruby-rack and a Servlet filter.) • Vendor EVERYTHING and check it into git. !39 @mark_menard
  • 40. • Completed work in about 3 Case Study 1 ! Success Enable Labs months. • Much better test coverage. • This module is still orthogonal to the main app today. • Code has been very stable. • Code has been ported through multiple versions of Rails. • Almost all new functionality is done in Rails since 1Q2008. !40 @mark_menard
  • 41. • Minimal integration with existing application. • Highly compartmentalized. • Focused feature set with stable requirements. • Java integration worked. Case Study 1 ! Why did it succeed? Enable Labs !41 @mark_menard
  • 42. Case Study 2 And Steve said, “let there be iPhone.” Enable Labs !42 @mark_menard
  • 43. • Client wants about 10 screens available in the browser on the iPhone. • He has a trip in two weeks and wants it working before he leaves. Case Study 2 ! iPhone Enable Labs !43 @mark_menard
  • 44. • Working screens inside of a week. • Ready for his trip in two weeks. • Went on to be used by the field sales staff for several years. • Total cost far below the client’s expectation. Case Study 2 Rails to the Rescue ! ! iPhone A rip roaring success Enable Labs !44 @mark_menard
  • 45. Case Study 3 ! Porting to Ruby First Attempt ! A Study in Over Enthusiasm This JRuby is Awesome! Let’s Port the App! Enable Labs !45 @mark_menard
  • 46. Let’s talk about the brownfield. • 388 Views • 272 Struts 2 Actions • 30 Spring Service Beans • 81 Data Access Objects • 151 Hibernate/JPA Entities (Models) • Not Enough Tests • Primary implementation language is Groovy Enable Labs Case Study 3 ! Porting to Ruby First Attempt !46 @mark_menard
  • 48. • Ruby classes can implement Java interfaces. Case Study 3 ! Porting to Ruby First Attempt Enable Labs !48 @mark_menard
  • 49. public interface Person { public String getName (); public void setName (String name); } class Person include Java::Person ! attr_accessor :name end Enable Labs !49 @mark_menard
  • 50. • Ruby classes can implement Java interfaces. • Plug a Ruby/Rails environment into Spring to manufacture Ruby “beans”. Case Study 3 ! Porting to Ruby First Attempt Enable Labs !50 @mark_menard
  • 51. def getInventoryManager () { log.debug "[ RailsFactory.groovy ] : Instantiating Integration::InventoryManager" eval "Integration::InventoryManager.newn" } Enable Labs !51 @mark_menard
  • 52. • Ruby classes can implement Java Case Study 3 ! Porting to Ruby First Attempt Enable Labs interfaces. • Plug a Ruby/Rails environment into Spring to manufacture Ruby “beans”. • On a case-by-case basis port Java/Groovy Spring service beans to JRuby. • This was a bottom up port. !52 @mark_menard
  • 53. Rationale Case Study 3 ! Porting to Ruby First Attempt Enable Labs • No need to mess with the user experience. The views and controllers won’t change. • Can do it incrementally. • Allows Java, Groovy and JRuby objects to just inter-play. • Should be transparent. !53 @mark_menard
  • 54. Outcome • Technical success, business failure. • Did not take full advantage of our Ruby tools. • There was no driving business value in doing it. Case Study 3 ! Porting to Ruby First Attempt Enable Labs !54 @mark_menard
  • 55. Case Study 4 ! Porting to Rails Part 2 Ah.... sweet incremental success... ...mostly. Enable Labs !55 @mark_menard
  • 56. • Do all new work in JRuby. • Find silos of existing functionality. • Wait for significant changes in requirements for the silo. • Port one silo at a time. • Port the whole silo to JRuby. • Write lots of tests. • Find improvements to UI/UX that can be rolled in for justification. • Use SOA for non-user facing services. Enable Labs !56 Case Study 4 ! Porting to Rails Part 2 @mark_menard
  • 57. Case Study 4 ! Porting to Rails Part 2 The God Object in the Closet Enable Labs !57 @mark_menard
  • 58. The God Object in the Closet The Strategy ! Make the God object a web service. Implement it in Rails. Translate the existing Groovy code. Port test suite to RSpec. Refactor, refactor, refactor, refactor, refactor.... Review the spec with the client extensively. Case Study 4 Enable Labs Porting to Rails Part 2 !58 @mark_menard
  • 59. JRuby works today. Java integration lets you play where MRI just can’t go. It’s just Ruby, with Java JVM super powers! Enable Labs !59 @mark_menard
  • 60. Photo credits http://www.flickr.com/photos/usfwsnortheast/5655240564/ http://www.flickr.com/photos/falcon1961/3304306800/ ! Code Color Scheme Solarized Light ! Syntax Highlighting Tool http://www.andre-simon.de/doku/highlight/en/highlight.html Enable Labs !60 @mark_menard