terça-feira, 18 de dezembro de 2012

WEB Advent

Alguém aí já ouviu falar do PHP Advent (que aparentemente este ano mudou o nome para WEB Advent)?

Todo mês de dezembro, desde de 2007, várias pessoas são convidadas a escreverem artigos com dicas, conselhos, truques e o que mais estiver em suas mentes. Tem conteúdo sobre desenvolvimento de software, web, design, php etc. Os artigos são muito interessantes e são escritos por pessoas conhecidas na comunidade. Não perca mais tempo e acesse o WEB Adevent 2012. Lá tem links para os anos anteriores também.

segunda-feira, 26 de novembro de 2012

O Google cai e a internet cai!

Hoje 26/09/2012 na parte da tarde serviços da Google como busca, e-mail e o youtube apresentaram instabilidade quando se tentava acessá-los.

Notei duas coisas engraçadas no meu local de trabalho, primeiro foi uma garota que achou que a internet tinha "caído". O que até pode ser considerada uma reação normal quando muitas pessoas deixam a página inicial do browser apontada para o serviço de busca da Google (Se bem que neste particular caso de hoje os servidores da Google estavam retornando uma página de erro informando o status 502. Acho que ela é um pouco leiga na área).

Outra coisa que notei foi que muitas pessoas não conhecem ou não se interessam por outras ferramentas de busca. Durante os vários minutos em que o serviços de busca não estavam funcionando a maioria resolveu que era era o momento ideal para uma um lanche ou tomar um café. Serviços como bing ou yahoo não são lembrados.

Durante este sabático do serviço de busca da Google eu deve ter feito pelo menos umas 5 buscas, principalmente relacionadas a referência de funções PHP ou exemplos de código para alguma tarefa. Acontece que meu serviço de busca padrão é o pouco conhecido DuckDuckGo. Preocupações relacionadas ao efeito "bolha" me levaram a esta decisão.

Mas não pensem que sou algum radical que não usa mais a busca google. Na verdade ainda devo fazer mais buscas no google, no DuckDuckGo basta adicionar "!g" na frente dos termos de busca para que eu seja redirecionado para lá. Uso muitos serviços da Google que hospeda este blog, meu e-mail e muitos vídeos que assisto no youtube. Eu só tento evitar fazer buscas logado com minha conta Google, sempre tenho dois browsers abertos um com e-mail e Google Talk e outro para minhas buscas.

domingo, 25 de novembro de 2012

A Essencial e Difícil Arte de se Ler Código

Nas minhas andanças pela internet encontrei um artigo bem interessante chamado:
Most Programmers Can't Read Code

Ou seja "A maioria dos programadores não conseguem ler código". Na verdade o que o autor do artigo realmente enfatiza é que a maioria dos programadores não conseguem ler código e compreendê-lo de modo efetivo.

No artigo são citadas várias razões para esta conclusão como a percepção de que é mais fácil escrever código do que lê-lo. Ou que na hora de se ler o código temos que manter muito mais coisas em nossas mentes como as varáveis, estruturas de dados e o design do código em geral. Ainda temos o caso onde a diferença de experiência entre o programador que escreveu o código e o programador que está lendo-o entra em jogo.

Eu realmente acho a atividade de se ler código legado, ou seja, código que não foi escrito por você ou que você escreveu a mais de uma semana, muito difícil de ser dominada de modo efetivo. Quando eu encontro um trecho de código que acho particularmente difícil de se compreender, seja por eu não se tão esperto quanto o cara que o escreveu ou o contrário, eu sempre achei a ajuda de debuggers providencial. A possibilidade de se ver a execução das instruções linha por linha, acompanhar as mudanças nos valores de variáveis e também acompanhar o fluxo de execução torna a carga mental muito mais amena. Não importa qual linguagem de programação você usa, aprenda a usar um debugger para ajudá-lo nestas horas. E claro, pratique suas habilidades lendo muito código!

E você? Tem alguma técnica particular que usa na hora de ler código?

domingo, 28 de outubro de 2012

Uma nova função PHP por dia

Já viu aquelas pessoas que na intenção de melhorar seu vocabulário tentam aprender uma nova palavra por dia? Com disciplina é uma prática fácil e eficiente de rapidamente expandir seu vocabulário.

Acho que é uma abordagem interessante para se aprender mais sobre as funções nativas do PHP. E olha que já existe muita coisa implementada. Algumas vezes já vi funções criadas por programadores que já existem nativamente no PHP. E quantas vezes ficamos nos perguntando se já existe uma função que pode fazer o que nós queremos?

A minha dica é que podemos utilizar a técnica de uma nova função PHP por dia. Apenas para efeitos de estudo, obviamente você não vai achar um uso prático imediato para a maioria das funções que você estudar. E é obvio que também você não vai memorizar exatamente como a função funciona, sua lista de parâmetros etc. Isso serve mais para se criar uma lista de "referências" de funções. Uma vez que você gasta algum tempo lendo sobre uma nova função, ela ficará guardada em algum lugar de sua memória e um dia, quando você se deparar com uma situação onde a função pode ser usada, seu cérebro terá maiores chances de fazer a conexões necessárias e assim você se lembrará que já existe uma função que realiza aquela tarefa.

Para ajudar a achar sua função PHP do dia, escrevei este pequeno script que usa dicas que já falei sobre o manual php e a quantidade de funções existentes no PHP.

Basicamente o script escolhe uma função aleatoriamente das funções "internal" do PHP, funções nativas, e te leva para a página do manual sobre ela. Acredito que o script pode ser facilmente alterado caso você queira mudar a browser usado ou obter o conteúdo de outra forma.

terça-feira, 2 de outubro de 2012

Achando a chave primária anterior e posterior de uma chave primária existente

Estava eu trabalhando em uma pequena aplicação e o cliente me pediu para acrescentar um recurso onde ele poderia navegar entre os registros um a um. É um esquema muito parecido com grids de dados. Você está no registro número 50 e tem dois botões, um te leva para o registro 49 e outro para o registro 51.

Pensei rapidamente e primeira solução que veio foi obter todos os id's da tabela ordenados e desta forma usando o id atual obter o id imediatamente anterior e o id imediatamente posterior. Lembrando que os id's podem ter "falhas" entre eles, o registro depois do id 25 pode ser o registro de id número 30. Não é uma solução eficiente mas como a aplicação é pequena, vai ser usada por um pequeno número de usuários e aplicando o princípio "Premature Optimization is the root of all Evil" eu decidi deixar assim mesmo.

Mas mais tarde eu voltei a pensar sobre isso: "Puxa vida! Retornar 5000 valores para se usar apenas dois deles?! Deve existir uma solução que seja pelo menos elegante para este problema!". E existe! É possível retornar o id anterior e posterior de um dado id com apenas uma consulta, e aqui está ela:

Que legal! Vai retornar somente o que preciso e não tem problemas com "falhas" entre os valores e caso o valor não exista será retornado NULL. Tudo o que você tem a fazer é passar o id de referência para que possam ser encontrados os valores imediatamente anterior e posterior a ele, neste exemplo eu passei o valor 100 os valores retornados foram 99 e 101.

Eu não fiz nenhum teste de performance sério, mas usando a tabela students do banco de dados do post anterior sobre transações, que tem 5000 registros, a consulta por todos os id's demora em média 92ms no meu computador (o explain da consulta indica uma leitura de todos os registros da tabela como era de se esperar). Esta nova consulta que retorna apenas o que precisamos levou apenas 12ms em média para retornar os resultados. Eu não conheço muito sobre sql ou bancos relacionais, portanto, é bem provável que existam formas melhores de se fazer o que eu fiz, mas espero que este pequeno exemplo possa ajudá-los.

terça-feira, 11 de setembro de 2012

Aplicações com muitas Transações Concorrentes

Uma vez uma pessoa com quem trabalhei, por um breve período, me contou uma experiência que ela teve ao reescrever a lógica de uma aplicação diretamente no banco de dados. Eles passaram a usar triggers, stored procedures e funções que eram escritas e executadas no servidor de banco de dados. Eu perguntei a esta pessoa qual foi a razão deles terem feito isso. A pessoa me explicou que eles tiveram problemas de forçar a consistência das regras da aplicação quando muitos usuários acessavam a aplicação ao mesmo tempo. Por exemplo: A aplicação era usada em uma universidade para permitir que os alunos se registrassem para diferentes disciplinas. Ela reforçava regras para limitar a quantidade de alunos por disciplina e também para evitar que os alunos escolhecem disciplinas com horários conflitantes.

A pessoa envolvida nesta reescrita me explicou que não era possível reforçar as regras da aplicação somente na linguagem de programação cliente. Que em ambientes como muitas transações concorrentes a aplicação cliente do banco de dados vez ou outra vai ler dados obsoletos e gerar resultados errados. Eu não estava tão certo quanto esta pessoa de que isso era verdade. Eu sei que os bancos de dados providenciam comandos, que podem ser iniciados a partir do cliente, para iniciar transações e persistir os dados envolvidos ou simplesmente não persistir nada. E também temos os níveis de isolamento de transações.

Eu resolvi escrever um pequeno programa para testar se é realmente impossível escrever lógica de negócios usando uma linguagem de programação cliente, em um ambiente de muitas transações concorrentes. Para simular as muitas transações concorrentes eu vou usar o utilitário Apache Benchmark ou ab.

O banco de dados (dump postgres) é bem simples e consiste de apenas três tabelas: students(id, name, date_of_birth), courses(id, name, workload) e students_courses(id_student, id_course). O servidor é postgres versão 8.4. Quanto aos dados temos 5000 estudantes e 500 cursos. A regra de negócio bem simples, cada curso pode ter no máximo 10 estudantes registrados. Ou seja, na tabela sutdents_courses um curso pode ter no máximo 10 linhas com seu id na coluna id_course.

Quando o código da aplicação é executado ele escolhe um estudante e um curso ao acaso e tenta registrar este estudante para este curso escolhido. Primeiro a aplicação faz uma verificação para ver se o curso está disponível (verifica se existem menos de 10 estudantes registrados para o curso). Caso o curso esteja lotado o estudante não é registrado. Caso contrário uma linha é inserida na tabela students_courses.

A minha primeira tentativa foi usando PHP junto com a versão mais recente do CodeIgniter. Que pode ser baixada aqui. O código principal é este aqui:

Eu usei os comandos trans_start e trans_complete de acordo com a documentação deles.

O teste de concorrência foi feito chamando-se o ab da seguinte maneira:
ab -c 50 -t 30 http://localhost/www/transactions/index.php/course_registration_codeigniter_version

Os parâmetros indicam que o servidor será acessado durante 30 segundos por 50 conexões simultâneas. O último parâmetro é a url do servidor.

Depois do teste executando-se a seguinte consulta:

Eu percebi que a regra da aplicação tinha sido violada. Existiam cursos com mais de 10 alunos. Após este primeiro teste me perguntei se isso poderia ter sido resultado da implementação interna do CodeIgniter. Não cheguei a investigar como o CodeIgniter implementa transações mas resolvi fazer outro teste. Desta vez usando um script php simples que por sua vez usa PDO para acesso ao banco de dados. A parte mais importante do código está logo abaixo:

Mais uma vez o comando ab é executado apenas mudando-se a url:
ab -c 50 -t 30 http://localhost/www/transactions/course_registration_pdo_sem_locks.php

E mais uma vez eu vejo que a regra da aplicação foi quebrada com cursos com mais de 10 estudantes. Será que esta pessoa com quem trabalhei tinha razão?

No meu teste usando-se apenas transações não foi o suficiente para garantir a integridade das regras da aplicação. Fiz algumas pesquisas e achei este documento. Foi nele que ouvi falar do SELECT FOR UPDATE. O que também não funcionou. O problema é que a opção bloqueia as linhas retornadas pelo SELECT executado de sofrerem operações as operações UPDATE, DELETE e SELECT FOR UPDATE. Como meu objetivo não é alterar nenhuma das linhas retornadas mas sim inserir na tabela o SELECT FOR UPDATE não adianta neste caso.

O que eu realmente preciso é bloquear a tabela para que não sofra atualizações enquanto eu estou checando a regra da aplicação. Uma operação de LOCK. Basicamente vou bloquear a tabela para que não sofra alterações, checar a regra da aplicação e desbloqueá-la no fim da transação. A parte principal do código está logo abaixo:
Novamente testo com o comando ab:
ab -c 50 -t 30 http://localhost/www/transactions/course_registration_pdo.php

E agora sim. A regra da aplicação foi satisfeita, não temos mais cursos com mais de 10 alunos. Uma coisa que percebi foi que as consultas durante o teste aparentemente ficaram bem mais lentas, o LOCK de toda a tabela deve cobrar seu preço. Outra observação sobre o LOCK é que ele não faz parte do padrão SQL, portanto um código que possa rodar em diferentes bancos de dados deve ficar sob a responsabilidade do desenvolvedor.

Conclusão

Sim é possível utilizarmos uma linguagem de programação cliente para validarmos e reforçarmos as regras de aplicação com alta concorrência de transações. Mas para isso temos que usar recursos oferecidos pelo próprio banco de dados.

Acredito que o uso de linguagens de programação cliente nestes casos traz facilidades de desenvolvimento e manutenção associadas aos recursos das linguagens e das bibliotecas disponíveis. Mas também temos que lembrar que existe o outro lado da moeda, apesar de não ter testado isso, acredito que haveria ganhos de velocidade significativos programando-se a lógica da aplicação diretamente no banco de dados.

Como sempre não existe bala de prata, você deve analisar o contexto, requisitos e recursos disponíveis para tomar estas decisões.

Todo o código da aplicação pode ser obtido aqui. Não se esqueça configurar os dados de acesso ao banco de dados nos arquivos pdo e no arquivo application/config/database.php.

sábado, 18 de agosto de 2012

Velocidade em PHP

O comando foreach é mais lento do que um simples for? Usar aspas duplas ou simples para strings faz muita diferença no tempo de execução? isset() é mais rápido do que empty()? Este tipo de discussão é realmente útil?

Um cara chamado Chris Vincent criou um site chamado The PHP Benchmark para te ajudar a achar respostas para estas questões. Ele apresenta vários exemplos com uma breve descrição, os resultados obtidos por ele e o código usado em cada exemplo para que você possa testar você mesmo.

Mas lembre-se! Geralmente seu maior gargalo de performance não está no seu código e sim na entrada e saída (bancos de dados, webservices, redes, sistemas de arquivos...)!

sábado, 28 de julho de 2012

Como exportar e fazer download de arquivos da aba Net do Firebug

Muitos desenvolvedores web provavelmente conhecem e usam o excelente plugin Firebug. Ele é muito útil tanto para programadores quanto para designers. Mas hoje estou aqui para falar especificamente da aba Rede/Net mostrada abaixo:
Mostra a aba Rede Ou Net do Firebug listando os arquivos de um site
Aba Rede ou Net Firebug

Ela lista todos os arquivos e seus respectivos tempos de download. Existem várias opções para listar somente imagens, arquivos de script ou css.

Pouco tempo atrás eu precisei obter os dados desta aba. Eu tinha feito download de um jogo feito usando-se html5, e usando-se a opção "Arquivo->Salvar como" do browser muitos dos arquivos de imagens não foram obtidos, já que eles não são referenciados em tags img ou no css. Eu queria uma forma de exportar esta lista de arquivos para que eu pudesse usá-la em um script que me permitisse fazer o download dos arquivos não encontrados, ou seja os arquivos que o servidor reportou com erro 404 quando tentei rodar o jogo localmente em meu computador. Para o problema de exportar esta lista de arquivos da aba Rede já existe um plugin (um plugin para um plugin?!) que faz isso. Ele se chama NetExport. Depois de instalar o NetExport, na aba rede vai aparecer uma opção chamada Export, depois de clicar nesta opção é só clicar na opção "Save as...". No local indicado será criado um arquivo com a extensão .har. Se você abrir este arquivo poderá ver que o conteúdo dele está no formato json.

Quando o conteúdo de um arquivo está no formato json, torna-se muito fácil ler tudo usando-se a função json_decode. Abaixo uma listagem do código que usei para a tarefa.



Dependendo do seu caso você precisará mudar um pouco o código. Na listagem a url poderia ser "$entry->request->url" diretamente em muitos casos sem a necessidade de usar basename.

Bom espero que o post seja útil para alguém, até mais!

sábado, 23 de junho de 2012

Porque usuários querem aplicações que façam tudo?

Recentemente estive em uma reunião para discutir sobre o desenvolvimento de uma nova aplicação. A aplicação em si provavelmente será simples. Os usuários vão alimentá-la com informações, o programa armazena, efetua validações e algum processamento posterior usando as regras de negócio. Depois disso os usuários podem acessar estas informações ou exportá-las usando algum formato aberto para que possam ser usadas em outros programas.

Nós temos um programa simples que faz pouca coisa e que exporta as informações armazenadas em um formato aberto, como texto por exemplo. Esta é basicamente a filosofia unix de se escrever programas. Acho que esta forma de pensar leva a programas mais fáceis de serem entendidos, com menos erros e mais fáceis de serem alterados.

Voltando ao programa mencionado no início do texto, depois de definido o escopo principal o usuário começou a dar ideias de como programa deveria incluir um sistema de gerenciamento de compromissos. Marcar compromissos com data e hora, ter um calendário etc, tudo que estes sistemas de agendamento possuem. Vejam, ser um sistema de agendamento não é razão de existir deste novo programa, incluir um demandaria tempo de desenvolvimento. A princípio um sistema de agendamento não parece muito complicado de ser desenvolvido. Mas com alguns anos de experiência nesta indústria vital eu aprendi que nada é tão simples quanto parece a primeira vista quando se trata de desenvolvimento de software. Não é toa que muitos projetos de software demoram mais tempo para ser desenvolvidos e saem mais caros do que inicialmente previsto.

Eu imagino que para as pessoas leigas software é uma coisa simples de ser criada e principalmente alterada. Quando o contrário disso deve estar mais próximo da verdade. E soma-se a isso os inflados egos que permeiam o meio dos desenvolvedores de software. "É claro que podemos desenvolver um sistema de agendamento perfeitamente funcional dentro do prazo e custo esperado. Você acha que nós somos amadores?".

Quanto ao sistema que mencionei? Provavelmente ele vai exportar as informações no formato csv e diremos para o usuário usar o Google Calendar, que acredito que seja um excelente software e o melhor de tudo é grátis.

sexta-feira, 25 de maio de 2012

PHP One-liners ou Incríveis coisas que você pode fazer em PHP com apenas uma linha de código

Uma linguagem de programação é considerada expressiva quando você consegue fazer coisas úteis sem precisar escrever muito código. Devido a sua extensa biblioteca de funções e sua natureza dinâmica a linguagem PHP é uma linguagem expressiva. E aqui vão alguns exemplos desta expressividade.

1. Validar Email


2. Converter Endereço IP para um número inteiro e vice-versa(útil para armazenamento)



3. Filtrar uma lista de números(usa closures)


4. Ler um arquivo


5. Somar uma lista de números



6. Achar o menor ou maior número de uma lista



7. Gerar e imprimir o alfabeto


8. Imprimir as linhas de um arquivo ignorando as linhas vazias



9. Gerar uma senha de 8 caracteres aleatória

10. Comprimir e descomprimir uma string muito longa




Espero que seja útil.

sexta-feira, 4 de maio de 2012

Coisas que você não deve colocar no Banco de Dados

Em minhas andanças pela internet eis que me deparo com um ótimo artigo chamada "Três coias que você nunca deve por no banco de dados". É um ótimo artigo, recomendo a leitura.

Basicamente ele fala que evitar armazenar dados binários(imagens, arquivos...), dados efêmeros (informações que são usadas por um curto período de tempo) e logs.

Eu concordo com o que é dito no artigo. Mas venho aqui falar de outra coisa que jamais em hipótese alguma você deve armazenar no banco de dados. Estou falando de CÓDIGO. E aqui estou falando de código mesmo, o mesmo código que você escreve quando está criando uma aplicação.

"O quê? Armazenar código? Isso é totalmente estúpido, quem em sã consciência faria isso?" Devem ser perguntas que permeiam sua mente agora. Mas me pesa muito dizer que já vi isso no mundo real, em uma aplicação web, e o pior de tudo é que eu tive que dar manutenção neste pesadelo.

Veja, com uma parte do código de sua aplicação armazenada no banco de dados coisas simples e corriqueiras como testar sua aplicação, corrigir um pequeno bug, versionar a aplicação, atualizá-la e simplesmente ler o código se tornam tediosas, demoradas e tremendamente propensas a erros.

Quando ocorre um erro no seu código o erro está no código que está dentro ou fora do banco de dados? Ou é um erro que depende de mudanças nos dois códigos? Quando você quiser ler o código para saber o que está errado você tem que manter sua IDE ou editor de texto abertos juntamente com um cliente de banco de dados. A cada novo trecho de código que você quiser ler você tem que fazer uma consulta no banco de dados. E quando você fizer uma alteração no código armazenado no BD você necessitará fazer uma operação de atualização no BD e depois rodar sua aplicação, torcendo para que não tenha cometido nenhum erro de sintaxe ou vai ter que refazer todo este processo. E como desenvolver em conjunto com uma equipe? Os desenvolvedores vão trabalhar juntos em um mesmo banco de dados e correr o risco de um sobrescrever alterações do outro? Ou cada vai ter seu banco de dados e depois sabe-se lá como eles vão sincronizar os códigos de cada um.

Olha eu já vi ideias ruins na área de TI, e algumas delas são minhas mesmo, mas isso de armazenar código da aplicação no banco de dados é de longe a mais abominável de todas. Aqui fica o aviso amigos.

quarta-feira, 18 de abril de 2012

Chamar Terminais Virtuais em um SO Linux virtualizado no Virtual Box

Trabalho com máquinas virtuais usando o VirtualBox. Um pequeno e excelente programa para virtualização pelo qual você não precisa desembolsar nenhum centavo para usar. Geralmente eu uso máquinas virtuais para fazer testes ou experimentos sem correr o risco de fazer algo errado com minha máquina de trabalho.

Recentemente em um destes experimentos com máquinas virtuais, um Linux Ubuntu 10.04, a interface gráfica ficou paralisada. Fiquei alegre que isso não foi na máquina host, e percebi que poderia tentar continuar usando máquina com a interface gráfica paralisada usando os terminais virtuais, que geralmente são acionados através da combinação de teclas Ctrl + Alt + F1 até F7. Os terminais de F1 até F6 são em modo texto e o F7 é o que exibe a sua interface gráfica. O problema é que apertando estas sequências de teclas eram acionados os terminais virtuais na minha máquina host e não na máquina virtual. Como simular esta sequência de teclas na máquina virtual rodando no Virtual Box?
Host Key + F1 (a host key geralmente é o Control direito no teclado)
Ou
F1, depois Ctrl e Alt (esta combinação também acionou o terminal na minha máquina host, mas quando voltei para o terminal F7 a máquina guest também estava no terminal virtual)

Muito útil para mim! Espero que ajude vocês.

quarta-feira, 4 de abril de 2012

Quantas funções a linguagem PHP tem?

8610
De acordo com o manual esta é a quantidade de funções que a linguagem PHP oferece. Usei o seguinte código javascript + jquery para chegar a este número:


E olha que todas estas funções estão no namespace global da linguagem. Mas também estão incluídas funções presentes em extensões como mysql, gd, simplexml etc.

Por isso eu não falo nada quando dizem que PHP é uma linguagem cujo design é feito por acidente. Mas isso não importa.

Update:
Neste link no fórum devshed tem um comando que permite saber a quantidade de funções definidas no seu ambiente. A função get_defined_functions retorna um array com todas as funções definidas, divididas em "internal", as funções definidas pelo php, e "user", funções definidas pelo usuário. Aqui está o comando:

$f = get_defined_functions();
echo "Functions: ".count($f["internal"])."\n";

No meu ambiente

PHP 5.3.3-1ubuntu9.10 with Suhosin-Patch (cli) (built: Feb 11 2012 06:40:29)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
    with Xdebug v2.1.0, Copyright (c) 2002-2010, by Derick Rethans

são reportadas 1762 funções do tipo internal.

segunda-feira, 26 de março de 2012

Jogo Side-Scroller para aprender SDL e C

Este aqui é um vídeo de um pequeno jogo que estou desenvolvendo usando SDL e C. Enquanto desenvolvo o jogo vou aprendendo um pouco dos dois.
É um jogo no estilo side-scroller, 2D daqueles que para quem viveu a fase de videogames como Super-Nes e Mega Drive vai trazer algumas boas lembranças! Mas ainda falta muita coisa para ser feita.

sexta-feira, 23 de março de 2012

Simular o comando stash do git no svn

O programa de controle de versão git tem um comando muito útil chamado stash. Ele permite que você "coloque de lado" as alterações não persistidas. É muito útil quando por exemplo você está trabalhando em alguma alteração profunda na base de código e uma alteração rápida para corrigir um bug surge. O que você faz neste caso? Você não vai querer perder as alterações já feitas, mas para corrigir o bug você precisa de uma versão "limpa" do código. Uma solução seria obter o código novamente do programa de controle de versão e corrigir o bug neste novo checkout, o que é muito trabalhoso e dependendo do tamanho de sua base de código pode tomar muito tempo. É aí que o comando stash entra, você coloca suas alterações na "espera", corrige o bug e depois traz novamente todas as alterações iniciais.

Agora como dar um stash no svn? O svn não tem o comando stash, mas podemos simulá-lo usando outros comandos. Primeiro nós precisamos criar um patch com todas as alterações feitas. Na raiz de seu diretório execute o seguinte comando:
svn diff > nome_patch.patch
Um patch nada mais é do que um arquivo que contem as alterações feitas em um ou mais arquivos. O comando diff cria exatamente isso. Se você abrir o arquivo nome_patch.patch em um editor de texto vai ver várias linhas com sinais de + ou - indicando linhas adicionadas ou removidas.
Antes de fazer o diff adicione os novos arquivos criados (com o comando svn add nome_arquivo) se você quiser que eles sejam enviados para o patch. Após isso você pode executar o seguinte comando:
svn revert -R .
Este comando vai desfazer todas as alterações feitas nos arquivos em todos os diretórios do projeto. Quando você quiser retornar todas as alterações feitas você deve executar o seguinte comando:
patch -p0 < nome_patch.patch
Lembrem-se de executar os comando de criação e restauração do patch no mesmo diretório e de preferência que seja o diretório raiz.

Pronto agora todas as alterações devem estar de volta!

segunda-feira, 5 de março de 2012

Fazer download de arquivos via Ajax

Na verdade o método que vou mencionar aqui não usa ajax. Mas permite que sejam enviadas requisições do tipo post ou get e que a partir destas requisições seja possível fazer um download de um arquivo.

A ideia não é minha e todos os créditos vão para o autor deste post. A implementação é bem simples e o truque usado é no mínimo inteligente. A requisição é enviada através de um form criado em tempo de execução, basta que o servidor que recebeu a requisição responda com o download do arquivo (em PHP geralmente é usada a função readfile). Ao invés de uma requisição ajax o browser envia uma requisição de form via post ou get conforme definido na chamada da função no parâmetro method. O autor criou a função na forma de um plugin jQuery, aqui está o código:



O uso é bem simples:
$.download('./url_download.php','parametro_1=valor_1&parametro_2=' + valor_2 );

Aqui está o projeto github do plugin. É isso aí até a próxima.

sexta-feira, 2 de março de 2012

E aqui está a nova versão PHP

Acabou de ser lançada a nova versão PHP. O anúncio pode ser visto aqui. Várias correções de bugs, melhoras no uso de memória e algumas coisas adicionais. Seu código está preparado para esta nova versão?

terça-feira, 28 de fevereiro de 2012

Novas características PHP 5.4 - Nova sintaxe para arrays e algumas baixas

Para começar o PHP 5.4 introduz uma nova sintaxe mais simples para a declaração de arrays:
Exemplo:
$array = [1, 2, 3];
Outro exemplo:
$foo = ['val_1' => 4, 'a', 2, 'bar' => 'na esquina'];

Pessoalmente acho esta nova forma menos verbosa e é uma abordagem mais parecida com a vista em outras linguagens como javascript e ruby.

Agora um minuto de silêncio para os que se foram:

  • break/continue $var syntax. Nunca usei este recurso para mais informações olhem aqui.
  • register_globals, allow_call_time_pass_reference, and register_long_arrays ini options. Só conheço o register_globals e pelo que dizem ele já vai tarde!
  • session_is_registered(), session_registered(), and session_unregister(). Estão aqui algumas funções que podem fazer falta para muitos desenvolvedores, principalmente em código mais antigo. Na versão 5.3 da linguagem PHP elas já disparam um warning do tipo E_DEPRECATED.
É isso aí! Melhor já ir preparando sua base de código para uma futura migração, dificilmente seus clientes e usuários vão aceitar que os erros no sistema foram devido a quebra de retrocompatibilidade na nova versão PHP.

domingo, 19 de fevereiro de 2012

Como saber o tamanho de um banco de dados Posgre

Dica rápida! Como obter o tamanho do espaço em disco utilizado por um banco de dados postgre? O processo é tão fácil quanto executar um comando sql:

SELECT pg_database_size('nome_do_banco');

Este comando vai retornar o tamanho em bytes, existe uma outra função que ajuda a converter este valor para um formato mais fácil de se ler:

SELECT pg_size_pretty(pg_database_size('nome_do_banco'));

É isso aí!

domingo, 5 de fevereiro de 2012

Standard Input e Standard Output

Amigos leitores vocês sabem o que é Standard Input e Standard Output (ou entrada padrão e saída padrão)? Bom, este post é para aqueles que não sabem e gostariam de saber.

Standard Input (SI) e Standard Output (SO) são respectivamente fluxos de entrada e saída de dados de uma aplicação. Basicamente qualquer aplicação rodando no seu computador tem acesso a estes fluxos de dados, seja ela um programa C compilado ou até mesmo seus scripts PHP. A forma e funcionamento destes fluxos é transparente para os programas já que este trabalho é feito pelo sistema operacional.

O sistema operacional também cuida da origem dos dados passados para a SI. Para um programa rodando na linha de comando geralmente os dados enviados para a SI deste programa vêm do teclado. Já tudo o que o programa escreve na SO o sistema operacional manda para o monitor. Ou seja, um programa que lê da SI e manda a saída para a SO se torna bastante flexível pois desta forma ele pode ser combinado com outros programas e scripts através destas interfaces universais. Este é o princípio da filosofia Unix:
This is the Unix philosophy: Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface. - Doug McIlroy 
Estas "text streams" citadas são a entrada e saída padrão.

E como fazer isso em PHP? No PHP a forma mais fácil de acessar a SI e SO é usando as constantes STDIN e STDOUT. Estas constantes são do tipo resource, o mesmo tipo retornado por funções como fopen.

Para lermos uma linha de texto digitada pelo usuário juntamente com o caractere "\n" (nova linha) podemos prosseguir da seguinte maneira:
$entrada = fgets(STDIN);

Se quisermos ler somente um caractere, para usar em uma construção switch por exemplo, podemo usar o seguinte código:
$opcao = fgetc(STDIN);

O STDIN é um stream que somente pode ser lido, e o STDOUT é um stream onde é permitido apenas escrever. Nos exemplos abaixo vamos demonstrar o uso do STDOUT.

Aqui vai um exemplo de dois programas que demonstram o poder da filosofia unix de criar programas pequenos que fazem apenas uma coisa bem e conversam com o mundo exterior através das interfaces universais SI e SO. Neste exemplo nós vamos processar o seguinte arquivo csv:

Astolfo,45
Bruna,22
Carlos,63
Daiana,15
Eriberto,30

É uma lista de nomes de pessoas com suas idades. Nós queremos criar um novo arquivo com os nomes em letras maiúsculas e com as idades em dias ao invés de anos. O nosso primeiro programa apenas processa os nomes das pessoas e passa o resultado para a SO permitindo que outros programas possam processar sua saída:



O próximo programa também lê a entrada através da SI, converte as idades de anos para dias e manda o resultado para SO.



Veja que os programas são praticamente iguais na forma como leem a entrada e escrevem na saída. Se você estiver em sistema *nix os seguintes comandos na linha de comando podem ser usados para lermos o arquivo original, usarmos os dois programas para processá-lo e criar um novo arquivo com a saída. Considerando-se que os scripts php e arquivo csv estão no mesmo diretório:

php capitalize_names.php < listanomes.csv | php ages_in_days.php > listanomes-saida.csv

Veja que estamos invocando o php para executar os scripts. Mas o que estes símbolos de menor, maior e tubo (|) estão fazendo ali?

Estes símbolos tem grande importância na execução dos programas.

  • <: Ele serve para redirecionarmos a Standard Input do script capitalize_names.php. No comando acima estamos dizendo para o sistema operacional que quando o script começar a ler o que estiver na SI ele mande o que estiver no arquivo listanomes.csv ao invés de mandar o que o usuário digitar no teclado.
  • >: Ele tem o mesmo propósito de redirecionamento do símbolo anterior. Só que agora estamos redirecionando a Standard Output. No comando acima estamos dizendo para o sistema operacional para que seja lá que o script age_in_days.php escrever em sua SO ele mande para um arquivo chamado listanomes-saida.csv, e o sistema operacional cuida da criação do arquivo caso ele não exista.
  • |: O tubo ou pipe como é chamado no mundo Unix é usado no comando acima para mandarmos a Standard Output do script capitalize_names.php para a Standard Input do script age_in_days.php.
No nosso exemplo acima usamos dois programas pequenos que nós mesmos criamos mas poderíamos ter usado muitos outros programas presentes no sistema operacional como grep, cat, wc etc.

O uso de redirecionamento da SI e SO juntamente com o uso de pipes é um recurso muito poderoso e bastante utilizado. Espero que com este post vocês possam assimilar este poder nos seus scripts PHP criar aplicações valiosas. Até a próxima!

sábado, 21 de janeiro de 2012

Cache de OpCodes para PHP

Sabe como diminuir o uso de memória e o tempo de resposta de suas aplicações PHP sem precisar modificar seu código? Não? E ainda tem mais! Você não precisa gastar nada para conseguir isso!

Parece bom demais para ser verdade não é mesmo? Mas existe uma ferramenta chamada APC (Alternative PHP Cache) que faz exatamente isso. O APC é uma extensão PECL que armazena e otimiza os opcodes PHP.

Os opcodes são as instruções que a máquina virtual PHP efetivamente lê. Todo código PHP que você escreve é transformado nestes opcodes e depois executado. O problema é que esse processo é feito para toda requisição recebida. Este processo é bem rápido, mas dependendo da quantidade de requisições recebidas em um determinado período (pense em algo como 500 requisições por segundo) e da capacidade de seu servidor, seus usuários vão ter de esperar cada vez mais para receber o conteúdo enviado pelo servidor.

Usando-se a ferramenta APC estes opcodes são gerados uma vez e armazenados na primeira requisição, nas próximas requisições o passo de ler o código PHP e gerar os opcodes já está feito, assim economizamos tempo e memória que seria usada na criação dos opcodes.

Se você tem o PECL instalado, a instalação do APC é bem simples. No linux execute:
#sudo pecl install apc

Eu tive um problema durante a compilação do APC e para resolver tive que também instalar o seguinte pacote:
#sudo apt-get install libpcre3-dev

Após fazer isso você pode copiar o script /usr/share/php/apc.php para uma pasta do apache. Quando você acessar este script através de seu navegador você poderá ver várias informações sobre o estado do APC no seu sistema. No menu "System Cache Entries" você pode ver quais scripts estão com seus opcodes armazenados.

Uma informação importante mostrada no apc.php é o Cache full count. Este número te diz quantas vezes o cache ficou totalmente cheio e o APC teve que excluir opcodes de scripts que estavam armazenados mas não foram acessados dentro do número de segundos estipulado por apc.ttl. Exemplo:
A página A.php está sendo acessada e o APC vai criar o cache dos opcodes para ela. Como a memória dedicada para o cache já está toda utilizada, o APC vai excluir o cache de D.php que não foi acessado nos últimos 5 segundos, estes 5 segundos estão definidos na varável de configuração apc.ttl. Você deve configurar o APC para que o Cache Full count não seja um número muito alto, pois este processo de limpar o cache frequentemente pode ter impacto na performance de seu sistema. Ou você aumenta a memória dedicada ao APC ou usa a configuração apc.filters para diminuir o número de scripts armazenados.

Espero que com esta dica vocês possam impressionar seus usuários com a velocidade de suas aplicações!

Ah sim! O APC não é a única ferramenta para cache de opcodes PHP:
http://en.wikipedia.org/wiki/List_of_PHP_accelerators

sexta-feira, 13 de janeiro de 2012

Novas características PHP 5.4 - Indireção de Arrays

Devo dizer que não me esforcei muito para me inteirar sobre as mudanças feitas na versão 5.3 da linguagem PHP. Não tive muitos problemas migrando código escrito para versões anteriores da linguagem. Os mais comuns foram warnings do tipo E_DEPRECATED causados por expressões deste tipo (dica para consertar o código: removam o "&"):
$obj =& new Class();

O uso de funções como eregi, split também passou a gerar warnings E_DEPRECATED.

Outra confissão é que eu nunca escrevi código que usa namespaces. E olha que a versão 5.3 foi lançada em junho de 2009!

Mas estou aqui para falar da vindoura versão 5.4 que possui algumas mudanças bem interessantes como a indireção de arrays. Mas o que é esta tal de indireção? Bom em inglês eles usam a palavra "dereference". Em computação é quando usamos uma referência ou endereço (pense nos ponteiros da linguagem C) para acessar e manipular um determinado valor. Em PHP quando usamos a referência $this para acessar algum membro da classe estamos fazendo uma indireção, ou seja, usando um endereço representado por $this para acessar o valor que realmente queremos seja uma varável escalar, uma instância de outra classe ou até mesmo um método.

Mas porque eu falei disso tudo? Até a versão 5.3 sempre que tínhamos uma função retornando um array nós só poderíamos acessar os valores do array usando uma varável para armazená-los, exemplo:

$meu_array = $objeto->retorna_array();
echo $meu_array[0];

Mas na versão 5.4 este código pode ficar menor:
echo $objeto->retorna_array()[0];

Agora nós podemos acessar o array diretamente na chamada do método que o criou. Acredito que o código ainda é fácil de ser entendido, pelo menos se o leitor já tiver um pouco de experiência.

Que venha o PHP 5.4!