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
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
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
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
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