Nos Trilhos com RAILS Sylvestre Mergulhão
Necessidades Desenvolver para a web Desenvolver para a web de forma organizada Desenvolver para a web de forma fácil de manter Desenvolver para a web de forma fácil Desenvolver para a web de forma rápida Desenvolver para a web de forma (mais formas???)
Motivaçã o n 1/3 Java Muito trabalho para pouco resultado Java+Struts Muita(mesmo!) configuração e muito(mesmo!) trabalho para pouco resultado PHP Muita liberdade resulta em pouca organização
Motivaçã o n 2/3 Comparativos encontrados na Internet de um tal de framework Ruby on Rails (RoR ou apenas Rails) com o Struts. Alguns chegavam a dizer num total de 10:1 em relação a quantidade de linhas de código entre um e outro, mas sem muitos detalhes. Por que não pagar pra ver?
Motivaçã o n 3/3 Na verdade não paguei, recebi... pois estava no horário de expediente. Download e instalação de linguagem, bibliotecas, conector para o banco de dados Postgresql e o framework RoR: 1h. Desenvolvimento passo-a-passo de uma aplicação CRUD seguindo um tutorial: 1h.
Resultado Duas aplicações... Uma em Java+Struts+Hibernate Outra em Ruby on Rails O mesmo banco de dados... O mesmo cérebro...
Introdução ao Ruby
Uma linguagem que não afeta seu jeito de pensar sobre programação não vale a pena aprender Alan Jay Perlis Cientista da computação
Conceitos utilizados pelo Ruby Ruby? Oh, quanta preciosidade... DRY. Poxa, mas por que tão seco? KISS. Tomara que não seja o Last. POLS: A lógica da menor surpresa.
Algumas características Orientação a objetos sempre! Tipificação forte, mas dinâmica Atributo de classe? sempre privado... acesso s ó por métodos...
Orientação a objetos sempre! Tudo(mesmo!) é um objeto. puts "alguma coisa".upcase # imprimirá "ALGUMA COISA"
Tipificação forte, mas dinâmica num = 81 6.times do puts "#{num.class}: #{num}" num *= num end Fixnum: 81 Fixnum: 6561 Fixnum: 43046721 Bignum: 1853020188851841 Bignum: 3433683820292512484657849089281 Bignum: 11790184577738583171520872861412518665678211592275841109096961
Outros tipos Fixnum Bignum Float Range representa intervalo de valores como 1..10 ou b..e; Expressão regular representa uma expressão regular /a/ ou /^\s*[a-z]/
Um Array... meu_array = [3,6,7,10]
Um Hash... meu_hash = {:nome => 'Sylva', :telefone => '(21)8106-9960'}
Getter e setter? Simples... class Carro attr_accessor :modelo, :fabricante end
Herança e métodos/operadores class Numero < Fixnum def +(numero) 71 end end
Blocos de código 3.times { puts "Ruby rulez!" } # Irá imprimir 3 vezes # "Ruby rulez!" 3.times do # Irá imprimir 6 vezes "Ruby rulez!" puts "Ruby rulez!" puts "Ruby rulez!" end
Muitas outras funcionalidades Módulos, Mixins, tratamento de exceção, etc...
O framework Rails
O framework Rails Framework MVC 3 módulos principais:. Active Record ORM. Action Controller. Action View Utiliza os mesmos conceitos do Ruby e mais um, chamado Convention over Configuration. Configuração s ó é necessária quando não existe padrão.
Estrutura de diretórios 1/2 minha_aplicação/ /app - arquivos dos modelos, visões e controles /components - componentes reutilizáveis /config - arquivos de configuração, como de banco /db de dados, por exemplo - arquivos do schema do banco de dados /doc - Documentação gerada automaticamente /lib - código compartilhado /log - arquivos de log gerados pela aplicação /public - o diretório que é acessível pela web. Da /scripts /test /vendor visão do navegador parece que toda a aplicação roda daqui - conjunto de scripts utilitários - local para os testes de unidade, funcionais, mock objects e fixtures - códigos de terceiros, como plugins
Estrutura de diretórios 2/2 app/ /controllers - onde são colocados os controladores /helpers /models /views - onde são colocados os helpers - onde são colocados os modelos - onde são colocados arquivos de visão e templates
Active Record, o salvador! A classe que representa o modelo class Client < ActiveRecord::Base validates_uniqueness_of :login, :name validates_presence_of :login, :name, :password validates_confirmation_of :password def self.login(login, password) find(:first, :conditions => ["login =? and password =?",login,password]) end def try_to_login Client.login(self.login, self.password) end end
Active Record Requisição ao Banco de Dados Quero buscar o cliente com login sylva! oh quem poder á me ajudar? Client.find(:first, :conditions => ["login =?","sylva"]) Client.find_by_login("sylva")
Active Record Requisição ao Banco de Dados De onde surgiram os métodos 'find' e 'find_by_login'?? Eles não estão definidos na classe Client!
Simple! It's a kind of magic! \o/
Active Record Requisição ao Banco de Dados Na verdade, nem tanto... é simplesmente herança... class Client < ActiveRecord::Base......... end
Active Record Requisição ao Banco de Dados Então, nenhum código precisou ser escrito para buscar um cliente no banco. Bastou invocar o método que and it's done! é herdado do ActiveRecord
Em Hibernate... Após escrever o XML de mapeamento, gerar a fábrica de requisições, resgatar a sessão e outras coisas mais... package org.gula.persistence.dao; import java.util.arraylist; import java.util.collection; import org.gula.entity.cliente; import org.hibernate.*; import org.hibernate.criterion.expression; import org.gula.persistence.dao.daoexception; import org.gula.persistence.hibernateutil; public class ClienteDAO {... public Cliente retrieve(cliente clientepk) throws DAOException { Cliente cliente; Session session = null; try { session = HibernateUtil.currentSession(); cliente = (Cliente) session.createcriteria(cliente.class).add( Expression.eq( "login", clientepk.getlogin())).uniqueresult(); HibernateUtil.closeSession (); } catch (Exception e) { throw new DAOException(e); } return cliente; } }
Como pode-se perceber, a diferença é grande...
Active Record Mapeamento dos relacionamentos Usando-se a convenção do Rails fica simples e, SEM CONFIGURAÇÃO! class Sale < ActiveRecord::Base has_many :sale_items (...) end class SaleItem < ActiveRecord::Base belongs_to :product belongs_to :sale (...) end
Beans? Pra que feijões? Struts faz validação dos FORMULÁRIOS ActionForm ou DynaActionForm Diretamente na Action, via método validate() no ActionForm ou via Validator Framework (mais xml! )
Beans? Pra que feijões? Validação do modelo, não do formulário... Validação fica junta com o modelo. class Product < ActiveRecord::Base belongs_to :category belongs_to :manufacturer validates_uniqueness_of :nome validates_presence_of :nome validates_presence_of :category_id validates_presence_of :manufacturer_id validates_numericality_of :preco validates_numericality_of :estoque... end
Beans? Pra que feijões? Se as validações default não forem suficientes basta definir o método validate() dentro do modelo E mais! Pode ser sobrecarregado também o método validate_on_create() e validate_on_update() Os nomes seguem o POLS ;)
class Product < ActiveRecord::Base belongs_to :category belongs_to :manufacturer (...) protected def validate errors.add(:preco, 'Preço negativo') unless preco.nil? preco > 0.0 end def validate_on_create errors.add(:picture, l(:error_jpeg)) if self.imagem.empty? validate_content end def validate_on_update if self.imagem.empty? @product = Product.find(self.id) self.imagem = @product.imagem return end errors.add(:picture, l(:error_jpeg)) if validate_content end (...) end
Sessões em Rails... just KISS! Atributo session sempre disponível dentro dos controladores permite uso fácil da sessão... Como num Hash. def authorize unless session[:client_id] flash[:notice] = l(:do_login) session[:jumpto] = request.parameters redirect_to(:controller => "client", :action => "login") end end
O que foi desenvolvido? Foram desenvolvidas duas aplicações muito semelhantes na interface e que utilizam a mesma base de dados. As duas possuem as mesmas funcionalidades e operam da mesma forma do ponto de vista do usuário. Uma foi desenvolvida em Java+Struts+Hibernate. A outra em Ruby on Rails.
Comparativo numérico SLOCCount - http://www.dwheeler.com/sloccount/ CLOC - http://cloc.sourceforge.net/ Contadores de linhas de código. Ignoram linhas em branco e comentários.
Número de linhas de código 4000 3750 3500 3250 3000 2750 2500 2250 2000 1750 1500 1250 1000 750 500 250 0 Java Ruby Linhas Ruby 681 Java 3854 Relação de 1:5,66
Número de arquivos de código 45 42,5 40 37,5 35 32,5 30 27,5 25 22,5 20 17,5 15 12,5 10 7,5 5 2,5 0 Java Ruby Arquivos Ruby 24 Java 44 Relação de 1:1,833
Número de linhas de templates 900 800 700 600 500 400 300 JSP RHTML Linhas RHTML 500 JSP 875 Relação de 1:1,75 200 100 0
Número de arquivos de template 27,5 25 22,5 20 17,5 15 12,5 10 7,5 5 2,5 0 JSP RHTML Arquivos RHTML 25 JSP 26 Quase a mesma relação
Número de linhas em arquivos de configuração 275 250 225 Linhas YAML 18 XML 273 Vale a pena calcular essa relação? 200 175 150 125 100 75 50 25 0 Linhas YAML 18 XML 273 XML YAML Apenas para manter a apresentação em conformidade: 1:15. PS: Nas 18 linhas YAML estão configurados 3 bancos: devel, test e prod.
O trabalho buscou mais que ser um simples comparativo de linhas de código. Na pequena aplicação desenvolvida, o Rails mostrou como a lógica de sua implementação deixa as coisas mais simplificadas para os desenvolvedores.
Claro que usar apenas um caso como verdade universal não é correto. Mas ele se mostrou preparado para os desafios de grandes sistemas web.
Ruby on Rails: porque programação não precisa ser entediante. Fabio Akita Programador Java O futuro é livre. Open your minds.
Obrigado! Contato: Sylvestre Mergulhão sylvestre.mergulhao@uniriotec.br O futuro é livre. Open your minds.