quinta-feira, 7 de janeiro de 2010

Como realmente testar: asserções

Falei bastante sobre testes nos dois últimos posts, conceituei testes funcionais e de unidade, falei sobre como criar fixtures, mas faltou a prática de verdade: como usar tudo isso para testar tudo?

Como já disse, testes são conjuntos de asserções. Uma asserção verifica se os parâmetros indicados nela estão válidos, se não estiverem ela retorna uma Falha. O teste executa asserção por asserção, se alguma falhar ele é interrompido, aponta a falha e diz qual das asserções falharam. Se o teste encontrar qualquer erro de sintaxe ou de execução, em vez de retornar uma falha, ele retorna um Erro. Isso já faz ter uma noção simples: caso haja uma Falha, houve erro de lógica, caso haja um Erro, houve erro de codificação.

O exemplo mais básico de asserção é o assert, que verifica se o parâmetro passado é true (lembrem-se que, em Ruby, tudo o que não for nil ou false é verdadeiro.

Porém, apenas com assert não dá para fazer tanta coisa. Sim, podemos ver se uma validação está funcionando corretamente (sim, eu prometo explicar validações), podemos ver se um objeto é igual ao outro usando operadores lógicos, podemos ver se um objeto é instância de determinada classe. Mas fazer tudo isso com assert torna as coisas mais ilegíveis, e é um tanto mais difícil identificar para que serve uma certa asserção. Por isso, existem vários tipos de asserções utilizáveis.

Para aprender outros tipos de asserções, vamos ter alguma ideia de outras funcionalidades para o modelo Pessoa. Digamos que você queira um método que diga o salário líquido da pessoa. Digamos que, caso a pessoa receba menos de 200 reais ela não pague imposto algum. Se o salário for maior ou igual a 200 e menor que 300 ela pague 10% de imposto, se e for 300 ou maior ela pague 20% (impostos tão baixos? Sonho de todo brasileiro...).

Antes de TUDO, vamos abrir aquela fixture para termos dados para testar. Apague tudo o que estiver na fixture e digite isso:

<% for i in (1..4) %>
pessoa_<%= i %>:
  id: <%= i %>
  nome: pes_<%= i %>
  salario: <%= i * 100 %>
  data_nascimento: <%= Date.civil(1980, i, i) %>
<% end %>


Sim, bem parecido com o último exemplo, mas dessa vez há apenas quatro dados.

Agora, ao teste.

Abra o arquivo test/unit/pessoa_test.rb

Insira, abaixo do método definido anteriormente, o seguinte código:

def test_salario_liquido_correto
  assert_equal 100, pessoas(:pessoa_1).salario_liquido
  assert_equal 180, pessoas(:pessoa_2).salario_liquido
  assert_equal 240, pessoas(:pessoa_3).salario_liquido
  assert_equal 320, pessoas(:pessoa_4).salario_liquido
end


Lembram que eu ensinaria como acessar dados da fixture? Aí está. O método tem o mesmo nome do arquivo que guarda os dados (se o arquivo for pessoas.yml, o método é pessoas), e para recuperar um registro específico, você passa como parâmetro o símbolo equivalente à definição do registro.

Por exemplo, no velho exemplo do "programador" (não mude o código da fixture, ok?):

programador:
  id: 1
  nome: Yuri Albuquerque
  salario: 100.00
  data_nascimento: <%= Date.civil(1989, 11, 9) %>

Você acessaria o registro com pessoas(:programador). Sim, simples assim.

Ao fazer isso, você tem uma instância do modelo, e pode chamar qualquer método dele. Por isso o pessoas(:pessoa_1).salario_liquido, eu estou acessando um método da instância do modelo Pessoa.

E atente para a ordem dos parâmetros dada. Ela não é imprescindível, mas, por padrão, o valor esperado vem antes do valor real.

Agora abra o console, vá até o diretório da aplicação e digite

rake


Depois de um tempo você verá que o teste indicou um Erro. E era isso que você deveria esperar, afinal, você tentou acessar um método que não existe (salario_liquido).

Se ele não existe, vamos criá-lo.

Abra o arquivo app/models/pessoa.rb

Lembre-se que esse arquivo define tudo do modelo, seus métodos de instância, seus métodos de classe, suas validações, seus atributos. Se você for um bom programador de Rails, vai fazer boa parte das implementações no Modelo e deixar o controlador cuidar apenas dos redirecionamentos. Não é o meu caso, infelizmente.

Acrescente esse método à classe:

def salario_liquido
  return(salario) if salario < 200
  return(salario * 0.9) if salario >= 200 and salario < 300
  return(salario * 0.8) if salario >= 300
end


Creio que eu não precise explicar o que esse método faz. Rode o rake novamente e veja seu teste apontar um sucesso.

É óbvio que assert e assert_equal não são os únicos métodos dos testes de unidade do Rails. Existem métodos para as mais diversas situações. Vamos a alguns deles:

  • assert_not_equal(obj1, obj2): é o oposto de assert_equal, verifica se os parâmetros dados são diferentes
  • assert_same(obj1, obj2): levemente diferente de assert_equal. Verifica se ambos os objetos têm o mesmo endereço de memória
  • assert_not_same(obj1, obj2): verifica se os objetos não são os mesmos
  • assert_nil(obj): verifica se o objeto está vazio, ou seja, nil
  • assert_not_nil(obj): verifica se o objeto não está vazio
  • assert_match(regex, str): verifica se a string passada combina com a Expressão Regular passada (Expressões Regulares são um assunto comprido, complexo, que enchem livros e livros. Não é o objetivo desse blog detalhá-las).
  • assert_no_match(regex, str): verifica se a string passada não combina com a Expressão Regular passada
  • assert_in_delta(expect, actual, delta): verifica se os números passados estão equivalentes dentro da faixa de tolerância delta dada.
  • assert_throw(symbol) { block }: verifica se o bloco de código "lança" (throw) o símbolo. Blocos de código são uma característica da linguagem Ruby, caso não conheça, sugiro pesquisar sobre eles imediatamente. Mas funciona como passagem de código por "parâmetro".
  • assert_raise(exception1, exception2, ...) { block }: verifica se o bloco de código retorna os erros (exceptions) dados
  • assert_nothing_raised(exception1, exception2, ...) { block }: verifica se o bloco não retorna nenhum dos erros dados
  • assert_instance_of(classe, objeto): verifica se o objeto percence à classe dada.
  • assert_kind_of(classe, objeto): verifica se o objeto percence a alguma classe filha da classe dada.
  • assert_respond_to(objeto, symbol): verifica se o objeto possui o método com o mesmo nome do símbolo.
  • assert_operator(obj1, operator, obj2): verifica se é possível executar obj1.operator(obj2)
  • assert_send(array): verifica se o método listado na array[1], executado no objeto na array[0], com os parâmetros na array[2] em diante retornam true. Sim, bem confuso. Mas não se preocupem muito com esse, por enquanto, particularmente nunca me foi necessário. Tentarei dedicar um post a ele, assim que aprendê-lo exatamente.
  • flunk: sempre retorna uma falha. Bom para indicar testes incompletos.
Lembre-se de testar tudo o que for possível no seu código. Os guias do Ruby on Rails (guias.rubyonrails.pro.br) sugerem fazer pelo menos um teste para cada validação e para cada método. David H. Hansson (de novo o autor de Programando Rails "A Bíblia", vocês vão me ver fazendo várias referências a esse livro) vai ainda mais longe, sugerindo fazer um teste para cada asserção, e pelo menos uma asserção por método. Ele sugere dessa forma porque você saberá exatamente o que está testando, e saberá o que deve corrigir caso algo dê errado.

Particularmente, não uso essa aproximação. Já me basta saber qual asserção falhou quando elas estão agrupadas em testes um pouco mais gerais. Testo mais por situações.

Um bom exemplo é quando lidei com um sistema de autenticação. Fiz um teste para verificar se o usuário logava quando os dados estavam corretos, e outro para verificar se ele NÃO logava quando algum dado estava incorreto. Claro que poderia ter ido um pouco mais longe, e feito um teste para verificar se ele não logava caso o e-mail estivesse incorreto, outro caso a senha estivesse incorreta, outro caso ambos estivessem incorretos, e assim por diante.

Mas agrupar as asserções de testes mais parecidos num único teste não me trouxeram muitos problemas. Com o tempo, você (e sua equipe, claro) vão desenvolver sua própria técnica de testes, e é importante que todos concordem com a forma como tudo está sendo testado.

O importante é programar satisfeito.

quarta-feira, 6 de janeiro de 2010

Para evitar o tédio, fixtures

Duas coisas aconteceriam se você fizesse testes apenas como ensinei no último post: tédio seria a primeira, porque você precisaria criar novas instâncias dos Modelos o tempo todo. A segunda seria a falta de instâncias de Modelos das tabelas que não fazem parte do teste (o que também geraria tédio, já que você precisaria criar cada uma dessas instâncias).

Para resolver isso, existem as fixtures.

Mas o que são fixtures, afinal?

São arquivos YML (Yet another Markup Language, não confundir com XML) que definem instâncias dos modelos. Os arquivos são criados quando você gera os modelos (exatamente como os testes de unidade), mas ficam "vazios", apenas com comentários ensinando a usá-los.

Criar instâncias de uma classe com uma fixture é fácil. Digamos que você queira criar uma instância que você acesse com "programador" (você verá como acessar fixtures mais tarde, então não se preocupe com isso, por enquanto). Tudo o que você precisaria fazer é abrir o arquivo pessoa.yml na pasta test/fixtures, apague tudo o que estiver no arquivo, e digite:



programador:
  id: 1
  nome: Yuri Albuquerque
  salario: 100.00
  data_nascimento: <%= Date.civil(1989, 11, 9) %>



Atente para a identação, ela deve ser dois espaços, e não TAB.

As fixtures são uma maneira bastante concisa de se armazenar dados de testes. Elas são intuitivas para quem vê, são carregadas sempre que os testes são inicializados, e não apresentam muitas dificuldades de acesso.

Porém têm algumas desvantagens. Elas tornam as suítes (conjuntos) de testes lentas; permitem dados inválidos; é complicado manter um grande número de dados em fixtures; e elas são frágeis, no sentido de que uma alteração numa fixture pode afetar o resultado dos seus testes (desvantagens tiradas do livro Programando Rails, "A Bíblia", de David H. Hansson).

Todavia, você pode evitar praticamente tudo com um certo cuidado. Para evitar lentidão, crie apenas fixtures estritamente necessárias (obviamente, isso também evita um grande número de dados). Para evitar dados inválidos, evitem escrever dados inválidos (afinal, você tem total controle sobre o que está numa fixture). Quanto à fragilidade, tome cuidado redobrado com todos os seus testes, o seria uma atitude boa mesmo que você não usasse fixtures.

Finalmente, explicando o código anterior. Boa parte é lógico e intuitivo. A primeira linha indica que toda a identação seguinte será armazenada numa instância "programador". Cada uma das linhas seguintes define um campo da instância.

Mas... o que quer dizer dizer aquele <%= Date.civil(1989, 11, 9) %> ali no meio? É algo bem simples, na verdade. Chama-se expressão. Quando você inicializar as fixtures (o que é feito automaticamente quando você inicia seus testes com rake), o Ruby se encarregará de substituir todo o código entre <%= %> pela string equivalente.

Nesse caso, <%= Date.civil(1989, 11, 9) %> vai ser lido como 1989-11-09.

Mas... por que escrever expressões, quando você pode inserir o dado que você quer?

Lembrem-se: a fixture não filtra dados inválidos. O uso de expressões é uma das muitas formas de evitar a inserção de dados inválidos. Além do quê, muitas vezes o uso de uma expressão é imprescindível, como verá a seguir.

Você deve estar pensando agora "se o Ruby reconhece o código dentro da expressão, eu posso usá-la para fazer um loop e criar várias instâncias de uma vez?". Não. Não pode. A expressão SEMPRE vai ser convertida em string, então tentar executar um loop vai resultar em nil. "Que pena", você deve estar pensando. "Eu gostaria muito de poder gerar dados automaticamente, em vez de digitá-los à exaustão".

E você pode. Só não vai usar expressões para isso, e sim scriplets.

Scriplets são muito parecidos com expressões, inclusive na sintaxe. A principal diferença é que eles NÃO são convertidos em strings, então você pode usá-los para gerenciar códigos e variáveis diretamente no arquivo, e inclusive criar loops.

Um scriplet é definido entre <% %>. Sim, é só tirar o sinal de igual. Vamos dizer que você queira definir cinco fixtures quaisquer de Pessoa. Você pode muito bem, em vez de digitar de uma por uma, fazer isso:


<% for i in (1..5) %>
pessoa_<%= i %>:
  id: <%= i %>
  nome: pes_<%= i %>
  salario: <%= i * 100 %>
  data_nascimento: <%= Date.civil(1980, i, i) %>
<% end %>


Como tudo no Ruby, há mais de uma maneira de escrever a mesma coisa. Minha forma preferida é substituir <% for i in (1..5) %> por <% 1.upto 5 do |i| %>, mas isso não vem ao caso. O que importa é como o Ruby vai enxergar sua fixture depois do processamento, e será assim:


pessoa_1:
  id: 1
  nome: pes_1
  salario: 100
  data_nascimento: 1980-01-01

pessoa_2:
  id: 2
  nome: pes_2
  salario: 200
  data_nascimento: 1980-02-02

pessoa_3:
  id: 3
  nome: pes_3
  salario: 300
  data_nascimento: 1980-03-03

pessoa_4:
  id: 4
  nome: pes_4
  salario: 400
  data_nascimento: 1980-04-04

pessoa_5:
  id: 5
  nome: pes_5
  salario: 500
  data_nascimento: 1980-05-05


Claro que a quantidade de fixtures vai contra a ideia de fazer apenas a quantidade necessária, mas é só um exemplo didático, então não há problemas.

E mais uma dica: lembre-se sempre das expressões e dos scriplets. Eles vão ser SEMPRE necessários, mesmo quando você não estiver fazendo testes

sábado, 12 de dezembro de 2009

Unit tests para testar modelos

Agora aprofundarei mais no assunto Unit Tests. Na verdade, o uso desse termo no Rails é incorreto, porque "testes de unidade" fazem testes de mecanismos e/ou objetos de forma independente do restante do sistema.

Em outras palavras, quando você faz um teste de unidade, testa apenas aquela unidade do sistema. Caso você necessite de interação com outros objetos nesse tipo de teste, você recorre a objetos mock, que seriam simulações ou simplificações dos objetos reais.

Esse isolamento é necessário para manter as interfaces do objeto simples e o código limpo, com um design simplificado.

No Rails, por outro lado, esse isolamento não ocorre. Por quê? Não tenho certeza. Mas, na prática, o funcionamento dos testes de unidade no Rails não diferem tanto quanto um teste de unidade comum, já que você provavelmente não vai chamar nenhuma função de um modelo diferente do testado. A diferença acaba sendo que você não se utiliza de mocks (o que pode até ser algo bom).

No Rails, os testes de unidade testam os modelos (lembra deles?). Vamos criar um modelo para fazer um teste simples do Rails.

Primeiro, abra o console (ou prompt) e vá ao diretório raíz do seu projeto. Depois, digite:
ruby script/generate model Pessoa nome:string data_nascimento:date salario:decimal

Explicando: a pasta script contém várias utilidades para ajudá-lo na criação da sua aplicação. O script "generate" gera o que você mandar ele gerar, seja um modelo, um controlador, migração ou scaffold. Explicarei tudo isso em posts futuros.

O parâmetro model serve para especificar que o que você está gerando é um modelo. Pessoa diz qual é o nome do modelo. Os outros definem os atributos do mesmo (e da respectiva tabela).

Agora, digite
rake db:migrate


Quando você gera um modelo, também gera uma migração (na pasta db/migrate) respectiva àquele modelo. A migração gera a tabela no banco de dados, com o comando acima. Bem mais simples que digitar todo o SQL, não?

Junto com o modelo gerado, também é criado um teste de unidade na pasta test/unit. Abra-o. Ele já possui uma asserção, que sempre retornará verdadeiro. Digite
rake

No console e você verá um sinal de sucesso. Não é o que queremos, por enquanto.

Abra o teste (em test/unit/pessoa_test.rb). Apague as linhas


test "the truth" do
  assert true
end

Agora vamos começar a testar, mesmo. Por enquanto, não temos nenhuma funcionalidade especial em mente, então vamos começar com uma interessante. O usuário só pode se cadastrar se ele digita um nome.

Onde havia o código anterior, digite.


def test_usuario_cadastrou_um_nome
  pessoa = Pessoa.new
  pessoa.salario = 1000.00
  pessoa.data_nascimento = Date.civil(1989,11,9)
  assert !pessoa.save
end

Esse código é bem simples. Se vocês não sabem o que é "def", voltem ao Ruby antes de estudar Rails, é simplesmente a definição de um método. Todos os métodos da classe que começam com "test" são o teste, em si. Todas as asserções dentro do teste serão analizadas, e caso todas sejam válidas, o teste contará como um sucesso.

As três linhas seguintes são óbvias: estamos declarando uma pessoa e definindo um salário e uma data de nascimento para ela.

A linha "assert !pessoa.save" é a chave do teste. Assert é uma asserção (que eu tanto falei há algumas linhas e ainda não expliquei). Asserções validam o que há dentro delas. Se realmente for algo válido, a asserção retorna um sucesso. Senão, ela pára o teste e avisa que houve uma falha.

A asserção mais simples é "assert", que verifica se o que está dentro dela é true.

O que nos leva à questão: o método pessoa.save retorna um boolean?

A resposta é sim. Sempre que o Rails tenta salvar um registro no banco de dados, ele retorna true caso ele tenha conseguido e false caso não tenha conseguido. Nesse caso, nós queremos que retorne false, porque não queremos que ele consiga salvar o registro, já que o nome da pessoa não foi definido. Por isso o "!" antes de pessoa.save, ele simboliza "não" em muitas linguagens de programação, inclusive Ruby.

Vá no console e digite rake novamente. Você vai ver o teste falhar.

"Tudo isso para um teste falho? Mas não queríamos fazer um programa, afinal de contas?"

Novamente, estamos testando ANTES de fazer o código que vai validar o teste. Isso é o que chamamos de Test-Driven Development, ou Desenvolvimento Orientado a Testes. Sempre que você for programar, primeiro faz os testes automatizados, roda-os, vê falharem, e faz os códigos o mais simples possíveis para passarem nos testes.

Dessa forma, você terá um sistema simples, legível e com o mínimo de bugs.

Agora vamos fazer o teste retornar um sucesso.

Abra o arquivo app/models/pessoa.rb. Insira dentro da classe a linha


validates_presence_of :nome


Essa linha é bem óbvia. É um validador, e vai verificar se o usuário lembrou de digitar seu próprio nome. Não se preocupe com isso, por enquanto, também vou explicar em posts futuros.

Rode o rake de novo e veja o teste retornar um sucesso. Parabéns! Você fez um teste de unidade!

No próximo post, explicarei fixtures e como elas podem melhorar seus testes.

sexta-feira, 4 de dezembro de 2009

Testando seus modelos no Rails - parte 1

Vou começar com uma citação do livro Programando Rails "A Bíblia", de Obie Fernandes. A citação é de "Wilson":
Escrever aplicações sem testes faz de você uma pessoa má, incapaz de amar

Exagero, certo? É... talvez não. Rails foi feito com testes em pensamento. Os desenvolvedores testam incansavelmente todas as funcionalidades, você não pode submeter um código novo sem um respectivo teste funcional ou de unidade. Por isso o framework conta com uma biblioteca de testes poderosa, a Test::Unit, da família xUnit, muito usada em várias linguagens, incluindo .NET, Java e C++.

Mas testar pra quê?

Verdade seja dita, a pergunta deveria ser "por que não testar?". Hoje, com a ascenção dos métodos ágeis de programação, testes automatizados têm se tornado importantíssimos. Algumas metodologias, como XP (eXtreme Programming) obrigam você a programar os testes ANTES de programar a aplicação, em si.

Agora você deve estar pensando "mas você não respondeu à pergunta. Para quê testar? Eu programo muito bem, confio no meu código, ele não vai dar erro".

Vai. Mesmo com todos os testes automatizados e profissionais da qualidade de software, o usuário final VAI encontrar erros no programa, e vai se irritar com isso ou se aproveitar disso.

Por que programar testes antes de programar a aplicação? Não faz sentido, o que vai ser testado?

Na verdade, adotar essa ideia de programar primeiro os testes já facilitou a vida de muita gente. Programando os testes, você saberá o que o programa deverá fazer (pois você terá nos testes os resultados que devem ser retornados); o teste funcionará como uma documentação rápida das capacidades do programa/ acúmulo de erros no decorrer do projeto costumam ocorrer (o que torna as coisas mais difíceis de serem rastreadas e corrigidas), mas se você fizer testes serão detectados mais cedo; e, além de tudo isso, há de se lembrar que Ruby é uma linguagem interpretada. Se você não executar testes, como saber se você não cometeu nenhum erro de sintaxe?

Serei sincero. Eu não costumo programar testes antes de programar a aplicação. Mas isso já me fez recomeçar projetos inteiros do zero por excesso de bugs. Então, acredite quando eu digo que testes automatizados são muito úteis para tornar as coisas menos complexas.

Ok, agora vamos começar com a mão na massa. Abra a pasta /test do seu projeto. Você verá as seguintes pastas e arquivo:





Para quem está acostumado com nomenclaturas de testes automatizados, os nomes mudam um pouco. Por partes:

  • Fixtures - Essas são as vilãs heróicas. Muita gente não gosta de fixtures, mas a utilidade delas é imensa. Fixtures são dados escritos como um arquivo YML (que explicarei na próxima parte) que serão carregados pelo banco de dados de teste para executar qualquer teste que você queira. Cuidado ao referenciar uma fixture dentro da outra: nunca se sabe qual é a fixture que será lida pelo banco de dados primeiro.

  • Functional - Functional tests, no Rails, são bem semelhantes a functional tests normais, mas são focados em controladores. Esse tipo de teste deve capturar os requerimentos do usuário e deve cuidar para que esses requerimentos sejam preenchidos. Imagine-se fazendo casos de uso, muitos e muitos casos de uso. Quando você finalmente termina... não acontece nada, só tem um monte de bolinhas. No caso de um functional test, você cria testes semelhantes a caso de uso, e faz a aplicação de forma que passe nos testes feitos! Enquanto unit tests testam sob um ponto de vista da programação, functional tests testam sob ponto de vista do usuário. O que quer dizer que você deve ver se o sistema está rodando conforme as necessidades do usuário. Sim, isso quer dizer que eles são essenciais.

  • Integration - Integration tests têm um significado parecido com o tradicional. Permitem a você testar grandes cadeias de código e ver se cada uma das partes do código trabalham bem em conjunto. Provavelmente serão pouco usados, por serem necessários em casos bem específicos e lentos.

  • Performance - É um nome bem sugestivo. Performance tests testam o quanto sua aplicação está demorando para atender aos requisitos, e onde elas mais estão demorando. Bem útil, não?

  • Unit - Unit tests são bem diferentes no Rails com relação à nomenclatura normal. Enquanto normalmente representam testes de funcionalidades isoladas, sob ponto de vista do programador (no sentido de que o programador imagina determinada função ou objeto e vai testá-la), no Rails representam Functional Tests de Modelos. Apenas isso. Você pode referenciar um Modelo num teste de outro sem problemas. É meio confuso usar o termo "Unit test" para um teste que, na verdade, é funcional. Mas se você ignorar isso vai viver bem. :)


Os testes de Rails são executados com o banco de dados site_test (ou comercio_test, ou hotel_test, ou qualquer nome que você tenha colocado na aplicação). É bem difícil fazer um teste que não envolva banco de dados, então não é recomendável.

No próximo post eu ensinarei a programar os testes e a executá-los.

terça-feira, 1 de dezembro de 2009

Aplicações Rails

Agora que o Rails está pronto para trabalhar, vamos estudar a estrutura básica de uma aplicação Rails.

Antes de mais nada, você precisa aprender a CRIAR uma aplicação Rails.

Abra seu prompt de comando (se for usuário de Windows) ou terminal (se for usuário de Linux) e digite:
rails site

Isso vai criar toda a estrutura básica da sua aplicação. O primeiro parâmetro apenas avisa que o que você quer é criar uma aplicação Rails. O segundo diz o nome da aplicação.

Agora que a estrutura está criada, vou explicar alguns conceitos para que você possa entender o que significa cada uma das pastas. Certos conceitos, como bancos de dados, deveriam ser conhecidos antes de você querer se aprofundar em desenvolvimento web, então não vou me aprofundar neles. Mas existem princípios que não são amplamente conhecidos, como os já citados DRY e REST.

Antes de mais nada, vamos ter consciência do que é MVC. É um padrão de arquitetura que tenta dividir as responsabilidades da aplicação em três divisões: uma delas se encarregará dos dados (Model, ou Modelo); a outra do layout e apresentação (View, ou Visualização) e o último serve de "cola" entre os dois, processando eventos e entradas de usuário, enviando-os para modelos, ou pegando os dados do modelo e aplicando-os às visualizações (o Controller, ou Controlador).

MVC é a base do Rails. Todo o framework foi projetado e construído pensando em torná-lo o mais compatível possível com este padrão. E o melhor de tudo: conseguiu. Vamos ver como logo, logo.

O DRY (Seco) é outro elemento importantíssimo para o Rails, e significa algo tão simples quanto o que o nome indica: Don't Repeat Yourself (Não Repita a Si Mesmo). Como ficaria muito estranho chamá-lo de NRaSM, continuemos chamando de DRY. O que o DRY quer dizer é que você deve, ao máximo, evitar fazer o mesmo código duas ou mais vezes, o que torna a manutenção do site muito mais fácil, já que você não vai precisar se preocupar em esquecer de alterar um código duplicado.

Isso é quase sempre possível. Quase porque o sistema de herança do Rails não é tão bom, então se você tiver um sistema com dois tipos de usuário, digamos, Professor e Aluno, você vai precisar fazer o mesmo código de autenticação para ambos. É algo que considero um defeito do Rails e espero que seja corrigido em versões futuras.

Se eu estiver errado e houver uma forma de fazer isso, por favor, avisem-me.

E, finalmente, o REST, o conceito mais complicado dos três. Representational State Transfer (Transferência de Estado Representacional) se refere a um conjunto de recursos (geralmente, páginas HTML, mas pode ser RSS, XML, imagens, ou qualquer outra coisa que vier à sua cabeça) onde realizamos ações CRUD (Create, Read, Update, Destroy; ou Criar, Ler, Atualizar e Destruir). No fim das contas, todas as ações em uma aplicação de banco de dados podem se resumir a essas, por isso REST é tão útil em Rails (que é um framework web para aplicações focadas em bancos de dados, afinal).

Com esses conceitos explicados, vamos à aplicação.

Abrindo o diretório da sua aplicação, você verá essas pastas:











Explicarei o que cada uma significa.
  • app armazena tudo diretamente relacionado à aplicação. Ou seja: os Modelos, as Visualizações e os Controladores (entendeu agora? Hã? Hã?). Se você abri-la, você verá uma pasta para cada uma dessas divisões e uma pasta helper. Esta pasta serve apenas para armazenar funções que puderem ser usadas em qualquer parte da aplicação. Não se preocupe muito com ela.
  • config armazena dados sobre a inicialização da aplicação (boot.rb), sobre o gerenciador de banco de dados usado (database.yml), sobre os ambientes de desenvolvimento (environment.rb) e sobre as rotas (routes.rb). Não se preocupem com nada disso, explicarei em posts futuros.
  • db armazena tudo o que está relacionado ao banco de dados. Também explicarei como mais tarde.
  • doc armazena a documentação gerada com o comando rake doc:app. Também explicarei mais tarde.
  • lib armazena qualquer módulo do Ruby que você queira usar na sua aplicação.
  • log armazena o log do servidor. Simples assim.
  • public armazena todas as informações estáticas da aplicação, incluindo HTML estática, CSS, imagens e Javascript.
  • script armazena os scripts utilitários do Rails, como um script para rodar o servidor e outro para criar um novo modelo ou um novo controlador. Explicarei mais tarde (sim, eu sei que tô deixando muita coisa para mais tarde, mas o post JÁ ESTÁ grande assim).
  • test armazena os testes de unidades que serão usados na aplicação. Muito útil para quem se utiliza de desenvolvimento ágil. Adivinha só? Vou explicar mais tarde.
  • tmp armazena o cache e as sessões da aplicação.
  • vendor armazena quaisquer plugins instalados.

Como podem ver, o Rails organiza ao máximo sua aplicação. Imagine-se programando numa aplicação ASP: você mesmo teria que criar as pastas e os arquivos, e geralmente o faria de forma caótica. Depois de um tempo, você já não saberia mais encontrar o que quer que seja na aplicação.

Com Rails, como você pode ver, encontrar tudo fica mais fácil. Especialmente quando ele tem um utilitário para gerar a documentação.

Isso é tudo por hoje. No próximo post, explicarei scaffold.

domingo, 29 de novembro de 2009

rails NovoUsuario -d sqlite3

Creio que antes de começar a ensinar o que são essas siglas que mencionei no último post, é mais importante dizer como iniciar e configurar o Ruby on Rails.

Mesmo sendo usuário de Windows, recomendo a você ler o tutorial para os usuários de Ubuntu, pois eu explico alguns conceitos que podem parecer novos a você.

Usuários de Ubuntu



Se você é usuário de Ubuntu, como eu, instalar tudo é fácil: basta instalar os pacotes ruby-full e build-essential, com esse comando:
sudo aptitude install ruby-full build-essential

Isso vai instalar toda a base do Ruby (a linguagem de programação usada no Ruby on Rails), como o irb (console do Ruby), rdoc (gera documentação a partir do código Ruby) e, principalmente, o RubyGems (gerenciador de pacotes do Ruby).

Você não vai instalar nenhuma extensão do Ruby através do apt ou do Synaptic (ou através de instaladores executáveis, no caso do Windows), e só vai compilar do código se não existir versão no repositório do Ruby. Você deve, ao máximo, instalar todas as extensões, incluindo o Rails, através do RubyGems. Como fazer isso? Com o comando gem.

Primeiro, atualize o RubyGems:
sudo gem update --system

Depois, instale o Rails, incluindo todas as dependências:
sudo gem install rails -y

O -y significa a mesma coisa que --include-dependencies, não importa qual dos dois você vai usar.

Depois de instalado o Rails, você deve instalar o SQLite3:
sudo aptitude install sqlite3

E o driver para Ruby:
sudo gem install sqlite3-ruby

Estou usando SQLite3 como exemplo porque é um gerenciador de Banco de Dados muito leve e de fácil uso, ótimo para o aprendizado do Ruby, mas nada recomendado para aplicações sérias. Nesse caso, o Ruby também tem drivers para MySQL, PostgreSQL, entre outros SGBD's. Ensinarei a instalá-los em posts futuros.

Pronto, seu ambiente Rails está pronto para ser usado.

Usuários de Windows



Antes de mais nada: recomendei que lesse a seção anterior, mesmo sendo usuário de Windows. Você deve ter visto um termo que talvez tenha soado estranho: "gerenciador de pacotes". O que seria isso?

Um gerenciador de pacotes é apenas um programa que instala, atualiza e remove "pacotes" (aplicações pré-compiladas). Ou seja: você não precisa ficar se preocupando em acessar o site do Rails sempre que uma nova versão sair, basta atualizar o RubyGems. Simples, não?

O Rails não tem uma performance tão boa no Windows quanto no Linux, e isso é perceptível. É muito mais fácil integrá-lo com Apache no Linux e no Mac OS, inclusive. Mas, se você está apenas aprendendo, o Windows pode ser uma boa opção, porque o servidor de testes do Rails (o WEBrick) não precisa ser configurado.

Primeiro, você deve baixar o binário do Ruby 1.8 em http://www.ruby-lang.org/pt/downloads/
Facilmente localizável, basta baixar o One-Click Installer. Não baixe a versão 1.9. As versões com a segunda numeração ímpar são sempre experimentais, e servem apenas para testar as funcionalidades que poderão ser implementadas na versão seguinte (que, no caso, será a 2.0). Por isso, o Rails não tem suporte ao Ruby 1.9.

Depois, baixe o SQLite. Procure em http://www.sqlite.org/download.html a seção Precompiled Binaries For Windows. Baixe os arquivos sqlite-3_6_20.zip e sqlitedll-3_6_20.zip e descompacte-os para C:\Ruby\bin (ou qualquer outro diretório onde o Ruby esteja instalado). Acredite, tudo fica mais fácil se você deixá-los nesse diretório.

Depois, instale as gems como explicado na seção de usuários de Linux, abrindo o prompt de comando e digitando:
gem update --system
gem install rails -y
gem install sqlite3-ruby

Repare que no Windows você não digita o sudo.

Se esses comandos não funcionarem, digite
cd c:\Ruby\bin

E tente de novo.


Pronto, agora o Rails está instalado e você pode começar a usá-lo.

sábado, 28 de novembro de 2009

Introdução

Comecei a programar com Rails há pouco tempo, ainda esse ano. Creio que eu não tenha completado um semestre de uso.

Ainda assim, aprendi a usar tantos recursos, de forma tão rápida e limpa, que fiquei impressionado. Os códigos são curtos, simples, e inteligíveis; usar Ajax com Rails é tão fácil quanto não usar; a organização torna tudo mais fácil de manter e consertar; usar diferentes SGBD's é mais fácil que instalar uma aplicação pelo Synaptic, entre diversos outros milagres do DRY, REST e MVC, que explicarei mais tarde.

É incrível a curva de aprendizagem desse framework. Em poucas semanas estava conseguindo usá-lo, e quanto mais aprendo sobre ele, mais fácil ele se torna, ao contrário da maioria das bibliotecas e API's.

Não, não tenho toda uma carga de experiência para ensinar qualquer coisa. Mas tenho experiẽncia para ajudar iniciantes em caminhos que eu sofri MUITO para encontrar soluções. DRY e REST são ótimos, mas às vezes é difícil encontrar uma solução assim sem ajuda.

E eu espero aprender mais do que pretendo ensinar. O ensino é um aprendizado, afinal.