Jruby - Ruby em Ambientes 100% Java

2,526 views

Published on

Apresentação realizada no CaelumDay RJ 2011 (02/07/2011)

Published in: Technology, Education

Jruby - Ruby em Ambientes 100% Java

  1. 1. Tirando o máximo da JVM com Ruby Hugo Roque Sergio Azevedo Junior hugo.roque@caelum.com.br sergio.junior@caelum.com.br hugolnx.com sagadoprogramador.com.br @hugolnx @sergioazevedoSaturday, July 2, 2011
  2. 2. Nós não somos o Douglas Campos @qmxSaturday, July 2, 2011
  3. 3. Tirando o máximo da JVM com Ruby Hugo Roque Sergio Azevedo Junior hugo.roque@caelum.com.br sergio.junior@caelum.com.br hugolnx.com sagadoprogramador.com.br @hugolnx @sergioazevedoSaturday, July 2, 2011
  4. 4. Ruby em Ambientes 100% Java Hugo Roque Sergio Azevedo Junior hugo.roque@caelum.com.br sergio.junior@caelum.com.br hugolnx.com sagadoprogramador.com.br @hugolnx @sergioazevedoSaturday, July 2, 2011
  5. 5. JavaSaturday, July 2, 2011
  6. 6. 10 anos de mercado multiplataforma compilado JVM Java bibliotecas frameworks JIT estático comunidadeSaturday, July 2, 2011
  7. 7. Java - classe Tarefa public class Tarefa{ private Long id; private String descricao; private Calendar dataFinalizacao; public Long getId(){ return this.id; } public void setId(Long id){ this.id = id; } public String getDescricao(){ return this.descricao; } public void setDescricao(String descricao){ this.descricao = descricao; } public String getDataFinalizacao(){ return this.dataFinalizacao; } public void setDataFinalizacao(Calendar novaData){ this.dataFinalizacao = novaData; } }Saturday, July 2, 2011
  8. 8. Java - Usando a classe Tarefa public class TesteTarefa{ public static void main(String[] args){ Tarefa tarefa = new Tarefa(); tarefa.setId(10); tarefa.setDescricao("Criar gerenciador de tarefa"); System.out.println("tarefa:"+tarefa.getId()+ "-" + tarefa.getDescricao()); } }Saturday, July 2, 2011
  9. 9. RubySaturday, July 2, 2011
  10. 10. dinâmico poderoso interpretado elegante Ruby modinha flexivel comunidade emo Orientado a ObjetosSaturday, July 2, 2011
  11. 11. dinâmico poderoso interpretado elegante Ruby hum..vai dizer que Java não serve mais? modinha flexivel comunidade emo Orientado a ObjetosSaturday, July 2, 2011
  12. 12. Ruby - classe Tarefa class Tarefa def getId() return @id end def setId(id) @id = id end def getDescricao() return @descricao end def setDescricao(descricao) @descricao = descricao end def getDataFinalizacao() return @dataFinalizacao end def setDataFinalizacao(novaData) @dataFinalizacao = novaData; end endSaturday, July 2, 2011
  13. 13. Ruby - classe Tarefa class Tarefa def getId() return @id A grande vantagem então é não end declarar os tipos das variaveis e def setId(id) @id = id niveis de acesso? end def getDescricao() return @descricao end def setDescricao(descricao) @descricao = descricao end def getDataFinalizacao() return @dataFinalizacao end def setDataFinalizacao(novaData) @dataFinalizacao = novaData; end endSaturday, July 2, 2011
  14. 14. Ruby - classe Tarefa class Tarefa def getId() return @id end Existem vantagens como def setId(id) expressividade @id = id end def getDescricao() return @descricao end def setDescricao(descricao) @descricao = descricao end def getDataFinalizacao() return @dataFinalizacao end def setDataFinalizacao(novaData) @dataFinalizacao = novaData; end endSaturday, July 2, 2011
  15. 15. Ruby - classe Tarefa class Tarefa def getId() return @id end Existem vantagens como def setId(id) expressividade @id = id end def getDescricao() return @descricao end def setDescricao(descricao) @descricao = descricao end def getDataFinalizacao() return @dataFinalizacao end def setDataFinalizacao(novaData) @dataFinalizacao = novaData; end endSaturday, July 2, 2011
  16. 16. Ruby - classe Tarefa class Tarefa def id return @id end def id=(id) @id = id end def descricao return @descricao end def descricao=(descricao) @descricao = descricao end def data_finalizacao return @data_finalizacao end def data_finalizacao=(novaData) @data_finalizacao = novaData; end endSaturday, July 2, 2011
  17. 17. Ruby - classe Tarefa class Tarefa def id return @id end def id=(id) @id = id end def descricao return @descricao end def descricao=(descricao) @descricao = descricao end def data_finalizacao return @data_finalizacao end def data_finalizacao=(novaData) @data_finalizacao = novaData; end endSaturday, July 2, 2011
  18. 18. Ruby - Usando a classe Tarefa tarefa = Tarefa.new tarefa.id = 10 tarefa.descricao = "Criar gerenciador de tarefa" puts "tarefa: #{tarefa.id} - #{tarefa.descricao}"Saturday, July 2, 2011
  19. 19. Ruby - Usando a classe Tarefa r’s tarefa = Tarefa.new Se tte tarefa.id = 10 tarefa.descricao = "Criar gerenciador de tarefa" puts "tarefa: #{tarefa.id} - #{tarefa.descricao}"Saturday, July 2, 2011
  20. 20. Ruby - Usando a classe Tarefa r’s tarefa = Tarefa.new Se tte tarefa.id = 10 tarefa.descricao = "Criar gerenciador de tarefa" puts "tarefa: #{tarefa.id} - #{tarefa.descricao}" ’s et ter G Parênteses opcionais + Syntax Sugar = código mais expressivo.Saturday, July 2, 2011
  21. 21. Ruby - classe Tarefa class Tarefa def id return @id end def id=(id) @id = id end def descricao return @descricao end def descricao=(descricao) @descricao = descricao end def data_finalizacao return @data_finalizacao end def data_finalizacao=(novaData) @data_finalizacao = novaData; end endSaturday, July 2, 2011
  22. 22. Ruby - classe Tarefa class Tarefa def id return @id end def id=(id) @id = id end def descricao return @descricao end def descricao=(descricao) @descricao = descricao end def data_finalizacao return @data_finalizacao end def data_finalizacao=(novaData) @data_finalizacao = novaData; end endSaturday, July 2, 2011
  23. 23. Ruby - classe Tarefa class Tarefa def id return @id end Com metaprogramação diga def id=(id) @id = id adeus aos repetidos “get’s/set’s” end def descricao return @descricao end def descricao=(descricao) @descricao = descricao end def data_finalizacao return @data_finalizacao end def data_finalizacao=(novaData) @data_finalizacao = novaData; end endSaturday, July 2, 2011
  24. 24. Ruby - classe Tarefa class Tarefa attr_accessor :id, :descricao, :data_finalizacao end hahahahaha. Hum....Saturday, July 2, 2011
  25. 25. E com Banco de Dados?Saturday, July 2, 2011
  26. 26. Java - classe Tarefa com Hibernate @Entity class Tarefa{ @Id @GeneratedValue private Long id; private String descricao; private Calendar dataFinalizacao; public Long getId(){ return this.id; } public void setId(Long id){ this.id = id; } public String getDescricao(){ return this.descricao; } public void setDescricao(String descricao){ this.descricao = descricao; } public String getDataFinalizacao(){ return this.dataFinalizacao; } ... }Saturday, July 2, 2011
  27. 27. Ruby - classe Tarefa com BD class Tarefa < ActiveRecord::Base end Menos código aindaSaturday, July 2, 2011
  28. 28. E com Aplicações Web?Saturday, July 2, 2011
  29. 29. Web Dev - Java x RubySaturday, July 2, 2011
  30. 30. Vamos largar o Java e migrar para Ruby e Rails ?!Saturday, July 2, 2011
  31. 31. Mas antes, Tem coisas que precisamos saber.Saturday, July 2, 2011
  32. 32. Ruby - Desvantagens ‣ Performance ‣ Ruby é lento, =~ 10x mais lento que Java ‣ Totalmente interpretado (sem JIT Compiler) ref: http://shootout.alioth.debian.org/u64q/benchmark.php?test=all&lang=yarv&lang2=javaSaturday, July 2, 2011
  33. 33. Ruby - Desvantagens ‣ Garbage Collection ‣ Não eficiente para aplicações Server Side. “ 99.999% is a bit over-exaggerated, but it is true that garbage collection algorithm of YARV and MRI focus for throughput on non-memory extensive short-running programs, and GC of REE is not suitable for those programs.” Yukihiro Matsumoto ref: http://www.ruby-forum.com/topic/215163#934681 ref: http://jabberwocky.eu/2010/09/03/ruby-garbage-collection/Saturday, July 2, 2011
  34. 34. Ruby/Rails - DesvantagensSaturday, July 2, 2011
  35. 35. Ruby/Rails - Desvantagens Deploy ‣ Heroku ‣ https://github.com/heroku/herokuSaturday, July 2, 2011
  36. 36. Ruby/Rails - Desvantagens Deploy o é gem Nã ta ‣ Heroku van des ‣ https://github.com/heroku/herokuSaturday, July 2, 2011
  37. 37. Ruby/Rails - Desvantagens Deploy o é gem Nã ta ‣ Heroku van des ‣ https://github.com/heroku/heroku ‣ Engine Yard ‣ https://github.com/engineyard/engineyardSaturday, July 2, 2011
  38. 38. Ruby/Rails - Desvantagens Deploy o é gem Nã ta ‣ Heroku van des ‣ https://github.com/heroku/heroku ‣ Engine Yard não m ém age amb ant ‣ https://github.com/engineyard/engineyard T esv é dSaturday, July 2, 2011
  39. 39. Ruby/Rails - Desvantagens Deploy o é gem Nã ta ‣ Heroku van des ‣ https://github.com/heroku/heroku ‣ Engine Yard não m ém age amb ant ‣ https://github.com/engineyard/engineyard T esv é d ‣ Outros ‣ capistrano? ‣ rpm? ‣ deb?Saturday, July 2, 2011
  40. 40. Ruby/Rails - Desvantagens Deploy o é gem Nã ta ‣ Heroku van des ‣ https://github.com/heroku/heroku ‣ Engine Yard não m ém age amb ant ‣ https://github.com/engineyard/engineyard T esv é d ‣ Outros ‣ capistrano? sim ‣ rpm? A qui pode a cê blem vo ro ‣ deb? r p teSaturday, July 2, 2011
  41. 41. Java = Burocrático Ruby/Rails = lento E agora?Saturday, July 2, 2011
  42. 42. Java = Burocrático Ruby/Rails = lento E agora? Só falta mudar pra .netSaturday, July 2, 2011
  43. 43. .net ??? Tira essa farda preta porque você é moleque!!!Saturday, July 2, 2011
  44. 44. Uma implementação 100% Java da linguagem RubySaturday, July 2, 2011
  45. 45. Java como plataforma ref: http://www.slideshare.net/sifra/jruby-enterprise-20Saturday, July 2, 2011
  46. 46. JRuby - FeaturesSaturday, July 2, 2011
  47. 47. JRuby - Features ‣ Roda na JVM ‣ Threads Nativas ‣ JIT ( Just In Time compiler ) ‣ O melhor GC do mundoSaturday, July 2, 2011
  48. 48. JRuby - Features ‣ Roda na JVM ‣ Threads Nativas ‣ JIT ( Just In Time compiler ) ‣ O melhor GC do mundo ‣ Permite o uso das bibliotecas e classes Java ‣ JDBC, Servlets, Hibernate ‣ seus prórprios JAR’sSaturday, July 2, 2011
  49. 49. JRuby - Features ‣ Roda na JVM ‣ Threads Nativas ‣ JIT ( Just In Time compiler ) ‣ O melhor GC do mundo ‣ Permite o uso das bibliotecas e classes Java ‣ JDBC, Servlets, Hibernate ‣ seus prórprios JAR’s ‣ Suporta RubygemsSaturday, July 2, 2011
  50. 50. JRuby - Features ‣ Roda na JVM ‣ Threads Nativas ‣ JIT ( Just In Time compiler ) ‣ O melhor GC do mundo ‣ Permite o uso das bibliotecas e classes Java ‣ JDBC, Servlets, Hibernate ‣ seus prórprios JAR’s ‣ Suporta Rubygems ‣ Suporta RailsSaturday, July 2, 2011
  51. 51. JRuby - Features ‣ Roda na JVM ‣ Threads Nativas ‣ JIT ( Just In Time compiler ) ‣ O melhor GC do mundo ‣ Permite o uso das bibliotecas e classes Java ‣ JDBC, Servlets, Hibernate ‣ seus prórprios JAR’s ‣ Suporta Rubygems ‣ Suporta Rails ‣ Deixa até você usar Ruby com WindowsSaturday, July 2, 2011
  52. 52. Legal! Mas e aquele papo de Ruby no Java?Saturday, July 2, 2011
  53. 53. Vejamos algumas situações do dia a diaSaturday, July 2, 2011
  54. 54. JRuby - Cenário 1 Importar planilha Empresa 100% Java precisa fazer uma carga de dados a partir de uma planilha excel.Saturday, July 2, 2011
  55. 55. Uma solução comum seria usar Java + Apache POI ref: http://poi.apache.orgSaturday, July 2, 2011
  56. 56. Importar Planilha - Java + Apache POI import org.apache.poi.hssf.usermodel.*; //mais imports public class ExcelReadExample { public static void main(String[] args) throws Exception { String filename = "..data.xls"; List sheetData = new ArrayList(); FileInputStream fis = null; try { fis = new FileInputStream(filename); HSSFWorkbook workbook = new HSSFWorkbook(fis); HSSFSheet sheet = workbook.getSheetAt(0); Iterator rows = sheet.rowIterator(); while (rows.hasNext()) { HSSFRow row = (HSSFRow) rows.next(); Iterator cells = row.cellIterator(); List data = new ArrayList(); while (cells.hasNext()) { HSSFCell cell = (HSSFCell) cells.next(); data.add(cell); } sheetData.add(data); } } catch (IOException e) { e.printStackTrace(); } finally { if (fis != null) { fis.close(); } } showExelData(sheetData); } //mais código aindaSaturday, July 2, 2011
  57. 57. Importar Planilha - Java + Apache POI import org.apache.poi.hssf.usermodel.*; //mais imports public class ExcelReadExample { public static void main(String[] args) throws Exception { String filename = "..data.xls"; List sheetData = new ArrayList(); FileInputStream fis = null; try { fis = new FileInputStream(filename); HSSFWorkbook workbook = new HSSFWorkbook(fis); HSSFSheet sheet = workbook.getSheetAt(0); Iterator rows = sheet.rowIterator(); while (rows.hasNext()) { HSSFRow row = (HSSFRow) rows.next(); Iterator cells = row.cellIterator(); List data = new ArrayList(); while (cells.hasNext()) { HSSFCell cell = (HSSFCell) cells.next(); data.add(cell); } sheetData.add(data); } } catch (IOException e) { e.printStackTrace(); } finally { if (fis != null) { fis.close(); } } showExelData(sheetData); } //mais código aindaSaturday, July 2, 2011
  58. 58. JRuby pode desburocratizar este códigoSaturday, July 2, 2011
  59. 59. Importar Planilha - JRuby + Apache POI require java require "lib/dom4j-1.6.1" require "lib/poi-3.7-20101029" require "lib/poi-ooxml-3.7-20101029" require "lib/poi-ooxml-schemas-3.7-20101029" require "lib/xmlbeans-2.3.0" //imports inp = FileInputStream.new(./dados.xlsx) wb = WorkbookFactory.create(inp) sheet = wb.sheet_at 0 nomes = [] rows = sheet.rowIterator() rows.each do |row| cells = row.cellIterator cells.each do |cell| nomes << cell end end nomes.each{ |nome| puts nome }Saturday, July 2, 2011
  60. 60. Importar Planilha - JRuby + Apache POI require java require "lib/dom4j-1.6.1" require "lib/poi-3.7-20101029" require "lib/poi-ooxml-3.7-20101029" require "lib/poi-ooxml-schemas-3.7-20101029" require "lib/xmlbeans-2.3.0" //imports inp = FileInputStream.new(./dados.xlsx) wb = WorkbookFactory.create(inp) sheet = wb.sheet_at 0 nomes = [] rows = sheet.rowIterator() rows.each do |row| cells = row.cellIterator cells.each do |cell| nomes << cell end end nomes.each{ |nome| puts nome }Saturday, July 2, 2011
  61. 61. Importar Planilha - JRuby + Apache POI require java require "lib/dom4j-1.6.1" require "lib/poi-3.7-20101029" require "lib/poi-ooxml-3.7-20101029" require "lib/poi-ooxml-schemas-3.7-20101029" require "lib/xmlbeans-2.3.0" //imports inp = FileInputStream.new(./dados.xlsx) wb = WorkbookFactory.create(inp) sheet = wb.sheet_at 0 nomes = [] rows = sheet.rowIterator() rows.each do |row| cells = row.cellIterator cells.each do |cell| nomes << cell end end nomes.each{ |nome| puts nome }Saturday, July 2, 2011
  62. 62. Importar Planilha - JRuby + Apache POI require java require "lib/dom4j-1.6.1" require "lib/poi-3.7-20101029" require "lib/poi-ooxml-3.7-20101029" require "lib/poi-ooxml-schemas-3.7-20101029" require "lib/xmlbeans-2.3.0" //imports inp = FileInputStream.new(./dados.xlsx) wb = WorkbookFactory.create(inp) sheet = wb.sheet_at 0 nomes = [] rows = sheet.rowIterator() rows.each do |row| cells = row.cellIterator cells.each do |cell| nomes << cell end end nomes.each{ |nome| puts nome }Saturday, July 2, 2011
  63. 63. Importar Planilha - JRuby + Apache POI require java require "lib/dom4j-1.6.1" require "lib/poi-3.7-20101029" require "lib/poi-ooxml-3.7-20101029" require Melhorou mas não se esqueça: "lib/poi-ooxml-schemas-3.7-20101029" require "lib/xmlbeans-2.3.0" Com JRuby você pode usar gems //imports inp = FileInputStream.new(./dados.xlsx) wb = WorkbookFactory.create(inp) sheet = wb.sheet_at 0 nomes = [] rows = sheet.rowIterator() rows.each do |row| cells = row.cellIterator cells.each do |cell| nomes << cell end end nomes.each{ |nome| puts nome }Saturday, July 2, 2011
  64. 64. jruby-poi ref: http://github.com/kameeoze/jruby-poiSaturday, July 2, 2011
  65. 65. Importar Planilha - JRuby + jruby-poi require rubygems require poi workbook = POI::Workbook.open(./dados.xlsx) rows = workbook.worksheets.first.rows nomes = [] rows.each do |row| nomes << row[0].value unless row.index == 0 end nomes.each{ |nome| puts nome }Saturday, July 2, 2011
  66. 66. Importar Planilha - JRuby + jruby-poi require rubygems require poi workbook = POI::Workbook.open(./dados.xlsx) rows = workbook.worksheets.first.rows nomes = [] rows.each do |row| nomes << row[0].value unless row.index == 0 end nomes.each{ |nome| puts nome }Saturday, July 2, 2011
  67. 67. Importar Planilha - JRuby + jruby-poi require rubygems require poi workbook = POI::Workbook.open(./dados.xlsx) rows = workbook.worksheets.first.rows nomes = [] rows.each do |row| nomes << row[0].value unless row.index == 0 end nomes.each{ |nome| puts nome }Saturday, July 2, 2011
  68. 68. Importar Planilha - JRuby + jruby-poi require rubygems require poi workbook = POI::Workbook.open(./dados.xlsx) rows = workbook.worksheets.first.rows nomes = [] rows.each do |row| nomes << row[0].value unless row.index == 0 end nomes.each{ |nome| puts nome }Saturday, July 2, 2011
  69. 69. Importar Planilha - JRuby + jruby-poi require rubygems require poi workbook = POI::Workbook.open(./dados.xlsx) rows = workbook.worksheets.first.rows nomes = [] rows.each do |row| nomes << row[0].value unless row.index == 0 end nomes.each{ |nome| puts nome } Gem Wins!!!Saturday, July 2, 2011
  70. 70. JRuby - Cenário 2 Criar Web Service Empresa 100% Java Precisa expor os dados de sua aplicação Web Struts2 na webSaturday, July 2, 2011
  71. 71. Uma solução sofisticada seria usar: Java + JAX-RS http://jsr311.java.net/nonav/releases/1.1/index.htmlSaturday, July 2, 2011
  72. 72. Web Service- Java + JAX-RS //imports aqui... @Path("/tarefa") public class TarefaResource { private Session session; @Context private UriInfo uriInfo; public TarefaResource() { this.session = new HibernateUtil().getSession(); } @GET @Path("{sigla}") @Produces( {MediaType.APPLICATION_XML }) public String getTarefas() { TarefaDao dao = new TarefaDao(this.session); Tarefa Tarefa = dao.listaTarefas(); String xml = new TarefaXMLAssembler().convertTarefaToXML(Tarefa, uriInfo); return xml; } //... }Saturday, July 2, 2011
  73. 73. Web Services JRuby WaySaturday, July 2, 2011
  74. 74. JRuby - Sinatra Sinatra é uma DSL para criação de aplicações web. ref: http://www.sinatrarb.com/ ref: https://github.com/sinatra/sinatra/Saturday, July 2, 2011
  75. 75. Web Service- Estrutura do projetoSaturday, July 2, 2011
  76. 76. Web Service- JRuby + Sinatra require rubygems require sinatra require java config.ru require jruby-rack require lib/fj21-tarefas require lib/mysql-connector-java-5.1.7-bin require lib/xstream-1.3 import br.com.caelum.tarefas.dao.TarefaDAO import br.com.caelum.tarefas.modelo.Tarefa import com.thoughtworks.xstream.XStream import com.thoughtworks.xstream.io.xml.DomDriver import java.util.List get /tarefas do tarefas = TarefaDAO.new.lista serializer = XStream.new(DomDriver.new) serializer.alias(tarefas, List.java_class) serializer.alias(tarefa, Tarefa.java_class) [200,{"Content-Type"=>"application/xml"}, serializer.to_xml(tarefas)] end set :environment, :production run Sinatra::ApplicationSaturday, July 2, 2011
  77. 77. Web Service- JRuby + Sinatra require rubygems require sinatra require java config.ru require jruby-rack require lib/fj21-tarefas require lib/mysql-connector-java-5.1.7-bin require lib/xstream-1.3 import br.com.caelum.tarefas.dao.TarefaDAO import br.com.caelum.tarefas.modelo.Tarefa import com.thoughtworks.xstream.XStream import com.thoughtworks.xstream.io.xml.DomDriver import java.util.List get /tarefas do tarefas = TarefaDAO.new.lista serializer = XStream.new(DomDriver.new) serializer.alias(tarefas, List.java_class) serializer.alias(tarefa, Tarefa.java_class) [200,{"Content-Type"=>"application/xml"}, serializer.to_xml(tarefas)] end set :environment, :production run Sinatra::ApplicationSaturday, July 2, 2011
  78. 78. JRuby - Sinatra para executar o projeto basta fazer um: rackup e um servidor será iniciado na porta 9292 de localhost ref: http://www.sinatrarb.com/ ref: https://github.com/sinatra/sinatra/Saturday, July 2, 2011
  79. 79. JRuby - Sinatra Ao fazer a requisição: curl localhost:9292/tarefas obteremos a seguinte resposta:Saturday, July 2, 2011
  80. 80. Muito Bom! Mas como eu faço deploy no Tomcat?Saturday, July 2, 2011
  81. 81. warbler ref: https://github.com/nicksieger/warblerSaturday, July 2, 2011
  82. 82. JRuby - Warbler gem install warblerSaturday, July 2, 2011
  83. 83. JRuby - Warbler gem install warbler warble configSaturday, July 2, 2011
  84. 84. JRuby - Warbler Warbler::Config.new do |config| warble.rb config.dirs = %w(lib) config.includes = FileList["server.rb"] config.war_name = "tarefasWS" endSaturday, July 2, 2011
  85. 85. JRuby - Warbler Warbler::Config.new do |config| warble.rb config.dirs = %w(lib) config.includes = FileList["server.rb"] config.war_name = "tarefasWS" endSaturday, July 2, 2011
  86. 86. JRuby - Warbler Warbler::Config.new do |config| warble.rb config.dirs = %w(lib) config.includes = FileList["server.rb"] config.war_name = "tarefasWS" endSaturday, July 2, 2011
  87. 87. JRuby - Warbler Warbler::Config.new do |config| warble.rb config.dirs = %w(lib) config.includes = FileList["server.rb"] config.war_name = "tarefasWS" endSaturday, July 2, 2011
  88. 88. JRuby - Warbler warble warSaturday, July 2, 2011
  89. 89. ConclusãoSaturday, July 2, 2011
  90. 90. Conclusão - Java como Plataforma Você não precisa mudar de emprego para programar com Ruby ref: http://www.slideshare.net/sifra/jruby-enterprise-20Saturday, July 2, 2011
  91. 91. Conclusão - Java como Plataforma Aceite o Java como Plataforma. ref: http://www.slideshare.net/sifra/jruby-enterprise-20Saturday, July 2, 2011
  92. 92. Conclusão - Seja PoliglotaSaturday, July 2, 2011
  93. 93. Obrigado Hugo Roque Sergio Azevedo Junior hugo.roque@caelum.com.br sergio.junior@caelum.com.br hugolnx.com sagadoprogramador.com.br @hugolnx @sergioazevedoSaturday, July 2, 2011

×