Cairo Noleto

Cuidado com Model-View-Controller

| Comments

Um assunto recorrente nas listas de discussão é sobre MVC, esse pattern) que é a base para quase todos os framewok atuais. Quem usa Ruby On Rails sabe “Fat Models, Slim Controls” por que é um comportamento imposto pelo criador do framework e praticamente por todos que utilizam.

O que acontece é que em outros frameworks (CodeIgniter por exemplo) te deixam mais livres e as pessoas acabam fazendo as coisas certas em lugares errados. O pattern por si só diz que é necessário colocar a lógica para os models e os controllers fazerem o fluxo das informações irem de um lugar para outro, mas não é bem isso que acontece.

E como a discussão foi em uma lista de CodeIgniter, ele ainda peca por isso. O CodeIgniter usa MVC, mas o framework da a liberdade para você fazer o que quer. Eu vejo aplicações que reutilizam controllers e não fazem uso dos helpers, eu vejo aplicações que fazem uso dos controllers, mas que os models deveriam fazer.

Helpers serve para você tirar a lógica de views, models servem para ter a lógica da aplicação, quem ainda não entedeu, lógica de views são apenas lógicas de controle, algo como if - else, switch - case, “div com o login da aplicação”, e coisas nas views que se vai repetir em toda a aplicação. Os models servem para fazer autenticação da aplicação, para verificarem se o usuário está cadastrado no banco de dados, para calcularem a quantidade de juros de uma venda a prazo, enfim, tudo aquilo que está ligado a lógica da aplicação.

Se repita menos (Don’t Repeat Yourself), use helpers, construa bons models, limpem seus controllers, seja um melhor profissional e uma pessoa menos estressada no final do dia (coisas simples nos deixam mais felizes que coisas complexas), use da simplicidade.

Benchmarks: Como vou saber se está bom ou ruim?

| Comments

Esta foi a pergunta que um amigo me fez no GTalk, eu respondi a ele mas gostei do assunto, é um bom assunto para começar 2009.

Como vou saber se está bom ou ruim um benchmark?! Simples, assim como muita coisa na vida, tudo depende do ponto de vista. A grande maioria dos benchmarks são sobre performance, tecnologia X é mais rápido do que Y ou framework U é mais rápido do que framework K.

Mas existem alguns benchmarks específicos como framework Y é mais fácil de fazer manutenção do que framework Z ou o tamanho dos arquivos gerados. Enfim, todos os propósitos dos benchmarks são apenas para demonstrar o lado bom e o ruim de uma tecnologia e levantar dados que facilitam na escolha dessas tecnologias.

Se você está indeciso de sobre qual tecnologia escolher, pesquise todos os benchmarks que existem sobre esta tecnologia em comparações a outras, se ainda não estiver satisfeito, faça seus próprios benchmarks e no final faça um levantamento junto com a sua equipe e discuta todos os pontos.

Se vocês puderem pelo menos uma vez ir a São Paulo, vão!

| Comments

Não é brincadeira, é sério! Vocês não precisam morar lá, mas devem conhecer São Paulo e seus lugares mais obscuros!

No último final de semana eu fui a São Paulo para participar do PHP Conference 2008 (Em breve, um resumo sobre o evento), eu fiquei na casa do Klederson. O apartamento dele é dentro do coração de São Paulo, próximo a Av. Paulista e perto de tudo!

Por ser perto de tudo, sai caminhando pela cidade assim que cheguei, a impressão é muito boa. Limpa (As ruas, não o ar), cheia de gente de todos os tipos e sempre alguma coisa para fazer.

Eu fui a um #NoB, no El Malak, depois de passar na porta e caminhar até quase o final da rua e depois de ter perguntando a umas pessoas em um bar se lá estava acontecendo o #NoB.

Conheci Mirian Bottan, Marco Gomes, Sabine e mais algumas pessoas que não me lembro o nome xD depois do #NoB saímos e pronto!

Na sexta levantei cedo e conheci de perto o sistema de transporte da cidade, totalmente interligado, e cheguei a Osasco de trem.

E no sábado, após o evento, consegui dar umas voltas de carro pela cidade, eu mesmo dirigindo, com o meu tio louco!

Depois de dar um susto no papai e na mamãe, dizendo que eu estava perdido e procurando uma parada de ônibus para ir para o aeroporto, quase em cima da hora, cheguei ao aeroporto internacional de guarulhos e tomei o rumo de casa.

Deixando para trás uma bela cidade, gigante, por sinal, com muita coisa para fazer e muita coisa para aproveitar, fico agradecido as pessoas que me ajudaram por lá e para as pessoas que eu conheci fica meu grande prazer.

P.S. No final da viagem, eu pedi ao piloto do 737-800 para tirar umas fotos na cabine, coisa de Nerd. Então ele me explicou que não podia, mas pediu a camera para filmar a aterrissagem em Fortaleza, ele só filmou 2:17 por quê tinha acabado a bateria :( mas para a minha sorte, um dos pilotos desembarcou em Fortaleza, e o mesmo piloto me chamou para voltar para Teresina dentro da cabine, mas sem eu tirar foto e nem filmar. Como Nerd que sou, fiquei muito feliz em viajar como terceiro piloto de um 737-800 por alguns minutos!!

Está chegando, PHP Conference!

| Comments

Essas últimas semanas está sendo corrida Estou acertando todos os detalhes para o PHP Conference, e é por que ainda não cheguei por lá, quando chegar, terá mais coisas para fazer :)

Esse post é para apenas lembrá-los que a Add4 Comunicação estará fazendo parte do PHP Conference e nós queremos vocês com a gente :)

Eu chego em São Paulo no dia 27. Tem um #NoB marcado, quero ir, alguém me leva?! :P

O PHP Conference vai acontecer nos dias 27, 28 e 29 e será recheada de PHPzeiros e Nerds. Espero conhecer muita gente boa.

Nos encontramos lá :)

Mídias alternativas - A vida além dos 30 segundos

| Comments

Esse foi o tema da mesa redonda na semana de comunicação da semana de Comunicação. Estava lá eu ( :P ), Thiago Emérito, Igor Drey e Itallo Victor.

Bom, eu falei um pouco sobre minha experiência com a Web 2.0 e como você pode utiliza-la para lucro (não apenas para diversão).

Eu já esperava que a maior parte do tempo nós quatro falaríamos e que em algumas partes quem estava lá, iria contribuir, mas eu não esperava que seriam umas quatro pessoas (de mais de 40). A impressão que eu tive é que essas pessoas ainda não entraram de cabeça dentro do novo mundo, ou que ainda não tiveram o interesse necessário para fazer esse tipo de coisa.

Uma coisa que eu sempre falo para todos é que vocês devem estar atentos as mudanças mundiais, acompanhar bolsa de valores, política, novas tecnologias, enfim, se manter atualizado frente ao mundo. Fazendo isso você está preparado para qualquer desafio, independente da sua área de atuação.

Tradução: Rails Database Migrations - Parte IV

| Comments

Esta é a última parte da tradução desse artigo sobre as Migrations do Rails. Antes de se desfrutarem da leitura quero dizer-lhes que se encontrar erros de português ou a tradução com sentido diferente, por favor, comuniquem-me! Avisem-me por email, twitter (caironoleto), ou qualquer mensageiro!! :P

6. Armazenando esquemas e você

6.1 Quais são os arquivos do esquema?

Migrações, poderosas como são, não são fontes autorizada para o esquema do seu banco de dados. Esse papel cabe ao schema.rb ou ao um arquivo SQL gerado pelo Active Record através da análise do banco de dados. Este arquivo não foi projetado para ser editado, ele é uma representação do estado atual do banco de dados.

Não é necessário (e isto é um erro propenso) para implantar uma nova instancia de uma aplicação repetindo o histórico inteiro da migração. É mais simples e rápido apenas carregar dentro do banco de dados a descrição do esquema atual.

Por exemplo, esta é a forma de como o banco de dados de testes é criado: o banco de dados atual de desenvolvimento é excluído (tanto para o schema.rb ou para development.sql) e então carregado dentro do banco de dados de teste.

Arquivos de esquema também são uteis se deseja olhar rapidamente quais atributos o objeto do Active Record possui. Estas informações não está no código do modelo e frequentemente está espalhado pelas várias migrações mas está resumido no arquivo de esquema. O plugin annotate_models, adiciona automaticamente cada (e atualiza) um dos comentários no início de cada modelo resumindo o esquema, que pode ser de seu interesse.

6.2 Formas de armazenar o esquema

Existe duas formas de armazenar o esquema. Uma é setar em config/environment.rb atribuindo o config.active_record.schema_format, que pode ser :sql ou :ruby.

Se :ruby é selecionada então o esquema será armazenado em db/schema.rb. Se você olhar este arquivo você verá que não encontrará um pouco mais do que uma grande migração:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ActiveRecord::Schema.define(:version => 20080906171750) do
  create_table "authors", :force => true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "products", :force => true do |t|
    t.string   "name"
    t.text     "description"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "part_number"
  end
end

De muitas formas é exatamente isso. Este arquivo é criado pela examinação do banco de dados e expressado em estruturas usando create_table, add_index e assim por diante. Por causa da independência do banco de dados ele deve carregar dentro de qualquer banco de dados que o Active Record suporta. Isso poderia ser muito útil se você quiser distribuir a aplicação para rodar em vários banco de dados.

Existe porém uma desvantagem: schema.rb não expressa itens específicos de banco de dados como constraints de chaves estrangeiras, triggers ou stored procedures. Enquanto na migração você pode executar SQL customizadas, o esquema armazenado não pode reconstituir essas atribuições do banco de dados. Se você usar recursos como este, então você deve atribuir o esquema para :sql.

Em vez de usar o esquema de armazenamento do Active Record a estrutura será armazenada usando uma ferramenta específica do banco de dados (pela tarefa rake db:structure:dump) dentro de db/#\{RAILS_ENV\}_structure.sql. Por exemplo para o PostgreSQL a utilidade pg_dump é usada e para o MySQL este arquivo irá conter a saída de SHOW CREATE TABLE para as várias tabelas. Carregando este esquema é uma simples questão de executar as declarações SQL contida dentro.

Por definição irá fazer uma copia perfeita da estrutura do banco de dados mas isso vai impedir o carregamento do esquema dentro de outros banco de dados que não seja um dos utilizados para criá-lo.

6.3 Armazenamento de esquema e controle de código

Por causa da autoridade do código do seu esquema de banco de dados, é altamente recomendado que você verifique dentro de seu controle de código.

7. Active Record e Integridade Referencial

O Active Record é a maneira inteligente de permanecer em seus modelos, não no banco de dados. Alguns recursos como triggers ou constraints de chaves estrangeiras, que empurra alguma inteligência de volta para os banco de dados não são muito usados.

Validações como validates_uniqueness_of é uma forma de seus modelos podem valer a integridade dos dados. A opção :dependent em associações adiciona aos modelos automaticamente destruir os objetos filhos que seus pais são destruídos. Como tudo que funciona a nível de aplicação, estes não podem garantir integridade referencial e algumas pessoas aumentam com constraints de chaves estrangeiras.

Apesar de o Active Record não fornecer todas as ferramentas para trabalhar diretamente com todos os recursos, o método execute pode ser usado para executar SQL arbitrárias. Há também uma série de plugins como redhillonrails que adicionam suporte a chaves estrangeiras para o Active Record (incluindo suporte para destruir chaves estrangeiras no schema.rb)

Mesa redonda hoje!

| Comments

Olá, fui convidado para participar de uma mesa redonda na semana de Comunicação da faculdade CEUT.

O assunto da mesa será Mídias Alternativas - vida além dos 30 segundos. Falaremos sobre como a internet pode ajudar a aumentar suas iniciativas de marketing e de como ela pode ser altamente lucrativa.

Vou falar sobre alguns cases que considero bastante interessantes, vai ser uma ótima experiência. Então se você está querendo um local agradavél com uma conversa boa é só aparecer lá às 17:00 no horário de verão brasileiro :P

Cake: Codeigniter mAKE!

| Comments

Olá, hoje eu lancei o cake e ele tem esse nome por que é um acrônimo de CodeIgniter mAKE.

Mas o que ele faz?

Ele aumenta a velocidade para você trabalhar com CodeIgniter. Ele tem a mesma funcionalidade dos scripts/generate do Ruby On Rails, apenas criando uma estrutura para seu projeto CodeIgniter.

Ele cria magicamente controllers, views e models.

E o que ele gera?

Bom, no momento ele está gerando controllers e models, e com um aperitivo a mais, ele está gerando também as views passada como parâmetro para gerar os controllers.

Outra coisa ele está o seguindo padrão nomeController.php e o nome da classe como NomeController, para os models está criando as classes como nome.php e Nome.

As views estão sendo geradas em nome_controller/ com o sufixo _view.php, algo como nome_controller/index_view.php.

Ele é verboso, então ele vai dizendo o que está sendo feito a cada passo.

Como faço pra usar?!

Eu escrevi um Read Me bem simples, assim mesmo para quem não está muito bem no inglês possa entender.

O que eu espero para o futuro?

Atualmente só tem suporte ao linux e ao macOS, então quem se interessar em portar para funcionar no windows, fique a vontade ;) (Os scripts que geram os arquivos estão em php então independe de OS para funcionar, o que falta é o script funciona no windows, que se não me engano é necessário fazer os bats e configurar a PATH, isso é quase a solução :).

Bom, primeiramente vou ajustar para também gerar rotas padrões para cada controller.

Depois vou adicionar opções como nomenclaturas diferentes.

Vou adicionar também um suporte para gerar os testes para controllers e models.

E gostaria de incluir a opção de baixar a versão mais nova do CodeIgniter e criar a estrutura do projeto, algo como cake app nomeDaApp e cake update.

O projeto está sobre licença Creative Commons 3.0, você pode usar comercialmente, modificar e distribuir, apenas mantendo meus créditos!

e o mais importante: VOCÊ PODE CONTRIBUIR, só ir lá no github, fazer um git clone e depois me mandar um pull request ou um patch :P

Até a próxima!

Namespaces em PHP e a confusão!

| Comments

A semana passada foi movimentada no PHP. Para quem ainda não sabe Namespaces é a forma conveniente de agrupar e distribuir bibliotecas, para quem já programa em Java são os velhos pacotes e quem programa em ruby são os módulos.

E só agora o PHP está querendo colocar no seu Core o uso de namespaces, que vai ser uma boa forma de programar, adicionando mais paradigmas legais em PHP.

Mas a grande confusão que se teve na semana passada, foi sobre a forma de requisitar os Namespaces.

No início, seu uso seria com 3 dois pontos ( ::: ), depois mudaram para 2 dois pontos ( :: ) e viram que haveria conflito com chamadas estáticas e por fim decidiram o uso de uma barra invertida ( \ ), como por exemplo:

  • MeuNameSpace:::metodo();

  • MeuNameSpace::metodo();

  • MeuNameSpace\metodo();

Mas com isso surgiu vários problemas como poder ser facilmente trocado por \ é usada para escapar strings entre outros problemas. Aqui você pode ver com detalhes a discussão sobre NameSpaces.

Depois de toda essa discussão, quem já estava querendo no próximo release utilizar namespaces, pode ir tirando o cavalinho da chuva :P

Agora é aguardar e observar as próximas decisões do CoreTeam do PHP.

Tradução: Rails Database Migrations - Parte III

| Comments

Esta é a terceira parte da tradução do artigo Rails Database Migrations. Mais uma vez, antes de desfrutarem da leitura, quero dizer-lhes que se encontrar erros de português ou a tradução com sentido diferente, por favor, comuniquem-me! Avisem-me por email, twitter (@caironoleto), ou qualquer mensageiro!! :P

4. Rodando migrações

Rails fornece um conjunto de tarefas rake para trabalhar com as migrações, que se resume em rodar alguns conjuntos de migrações. A tarefa rake mais relatada que você provavelmente usará é db:migrate. Na sua forma mais básica certamente rodará o método up para todas as migrações que ainda não foram rodadas. Se não existir migrações ele sai.

Se você especificar uma migração, o Active Record irá rodar as migrações requeridas (up ou down) até que ela tenha chegado nessa versão específica. A versão é o prefixo numérico do nome de uma migração. Por exemplo para migrar até a versão 20080906120000 execute

rake db:migrate VERSION=20080906120000

Se a versão for maior do que a versão corrente (ou seja, está migrando para cima) irá rodar o método up de em todas as migrações acima e incluindo a versão 20080906120000, se a migração for para baixo, então será executado os métodos down de todas as migrações para baixo até, mas não incluindo, 20080906120000.

4.1 Reversão

Uma tarefa comum é regressar a última migração, por exemplo, se você cometeu um engano e deseja corrigi-lo. Ao invés de monitorar o método down com a migração anterior, você pode rodar

rake db:rollback

Isso irá rodar o método down da migração mais recente. Se você precisa se desfazer de várias migrações, você pode fornecer o parâmetro STEP:

rake db:rollback STEP=3

irá rodar o método down das 3 últimas migrações.

A tarefa db:migrate:redo é um atalho para fazer uma reversão e a migração de volta. Assim como na tarefa db:rollback você pode usar o parâmetro STEP se você precisar voltar em mais de uma versão, por exemplo

rake db:migrate:redo STEP=3

Nenhuma dessas tarefas Rake fazem qualquer coisa que você não poderia fazer com db:migrate, são simplesmente mais convenientes, desde que você não precise especificar explicitamente de uma migração para outra.

Finalmente, a tarefa db:reset irá destruir sua base de dados, recria-la e carregar o schema atual dentro dela.

4.2 Especificando uma migração

Se você precisa especificar uma migração para cima ou para baixo, as tarefas db:migrate:up e db:migrate:down irão fazer isso. Basta especificar a versão apropriada e a migração correspondente e terá seu método up ou down invocado, por exemplo

rake db:migrate:up VERSION=20080906120000

irá rodar o método up da migração 20080906120000. Estas tarefas checa se a migração já tenha sido executada, se por exemplo db:migrate:up VERSION=20080906120000 não irá fazer nada se o Active Record acreditar que 20080906120000 já tenha sido executada.

4.3 Sendo comunicativo

Por padrão, as migrações falam exatamente o que elas estão fazendo e o tempo de duração. Uma migração criando uma tabela e adicionando um index produz uma saída como esta

1
2
3
4
5
6
7
8
9
10
11
== 20080906170109 CreateProducts: migrating ===================================

-- create_table(:products)

   -> 0.0021s

-- add_index(:products, :name)

   -> 0.0026s

== 20080906170109 CreateProducts: migrated (0.0059s) ==========================

Vários método fornecem para você o controle tudo isto:

  • suppress_messages suprime qualquer mensagem gerada pelo bloco
  • say saída de texto (o segundo argumento controla se é recortado ou não)
  • say_with_time saída de texto com o tempo utilizado pelos blocos. Se o bloco retornar um inteiro, assume-se que este é o número de linhas afetadas.

Por exemplo, esta migração

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class CreateProducts < ActiveRecord::Migration
  def self.up
    suppress_messages do
      create_table :products do |t|
        t.string :name
        t.text :description
        t.timestamps
      end
    end
    say "Created a table"
    suppress_messages {add_index :products, :name}
    say "and an index!", true
    say_with_time 'Waiting for a while' do
      sleep 10
      250
    end
  end

  def self.down
    drop_table :products
  end
end

gera a seguinte saída

1
2
3
4
5
6
7
8
9
10
11
12
13
== 20080906170109 CreateProducts: migrating ===================================

-- Created a table

   -> and an index!

-- Waiting for a while

   -> 10.0001s

   -> 250 rows

== 20080906170109 CreateProducts: migrated (10.0097s) =========================

Se você quiser que o Active Record mantenha-se em silêncio, então execute rake db:migrate VERBOSE=false irá suprimir qualquer saída.

5. Usando Models nas suas migrações

Ao criar ou atualizar dados na sua migração, muitas vezes, é tentador utilizar um de seus models. Afinal eles existem para fornecer acesso fácil nos dados subjacentes. Isto pode ser feito mas um certo cuidado devem ser observados.

Considere por exemplo a migração que usa o modelo Product para atualizar a linha na tabela correspondente. Alice depois atualiza o modelo Product, adicionando uma nova coluna e uma validação. Bobs volta do feriado, atualiza o código e roda as migrações pendentes com rake db:migrate, incluindo o modelo que é utilizado para o Product. Quando o código é atualizado e só então o modelo Product possui a atualização adicionada pela Alice. O banco de dados entretanto não é atualizado e assim não possui a coluna e então gerará um erro, por que a validação para esta coluna ainda não existe.

Frequentemente eu preciso atualizar as linhas no banco de dados sem escrever SQL pelas minhas mãos. Eu não estou usando qualquer especialidade do modelo. Um padrão para isso é definir uma cópia do modelo dentro da própria migração, por exemplo

1
2
3
4
5
6
7
8
9
10
11
12
class AddPartNumberToProducts < ActiveRecord::Migration
  class Product < ActiveRecord::Base
  end

  def self.up
    ...
  end

  def self.down
    ...
  end
end

A migração possuirá uma própria copia do modelo Product e não mais precisará saber sobre o modelo Product definido na própria aplicação.

5.1 Lidando com as mudanças no modelo

Por razões de performance, as informações sobre as colunas de um modelo é cacheada. Por exemplo, se você adicionar a coluna na tabela e tentar usar o modelo correspondente para inserir uma nova linha, ele pode tentar usar as informações antigas. Você pode forçar o Active Record para reler a informação da coluna com o método reset_column_information, por exemplo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class AddPartNumberToProducts < ActiveRecord::Migration
  class Product < ActiveRecord::Base
  end

  def self.up
    add_column :product, :part_number, :string
    Product.reset_column_information
    ...
  end

  def self.down
    ...
  end
end