segunda-feira, 25 de julho de 2011

formspring.me

O que você quer saber? (What'd you wanna know?) http://formspring.me/davispeixoto

segunda-feira, 1 de novembro de 2010

Testes de Software - Inspeção de código e teste unitário

Fala pessoal, olha eu reacendendo a série sobre testes de software. No último post falei sobre testes de requisito. Agora é hora de falar do segundo lugar onde mais se encontram e corrigem defeitos: inspeção de código e testes unitários.

A inspeção de código

Este teste se caracteriza pelo fato de ser executado apenas por quem entende o código-fonte, quem vai testar precisa ser desenvolvedor também. Aqui cabem várias abordagens. Uma delas é quem fez o código é quem faz a inspeção, mas ao mesmo tempo que quem escreveu o código é a pessoa que mais o compreende, seus olhos também correm o risco de estar viciados naquilo, então uma outra abordagem é um desenvolvedor que não fez o código que o inspecione. Uma terceira é revisar em grupo. Acho esta última a mais segura.

Note que a inspeção de código é uma revisão, um highlevel checkout, você lê e tenta achar erros óbvios de lógica ou gramática/digitação. Não mais que isso. Existem outros métodos mais complexos e formais de verificação. A inspeção é importante porque é rápida em detectar erros grosseiros (ou nem tanto).

Testes unitários

Testes unitários são o teste de comportamento de uma função, de um método ou de um conjunto intimamente relacionado de funções ou métodos. Eles são a base dos testes dinâmicos (aqueles realizados executando de fato o programa), e por serem altamente específicos, aumentam a confiabilidade dos testes.

Eles geralmente são automatizados, ou seja, você escreve um programa para executá-los.

Vou me estender no assunto, porque a automação de testes é algo válido para muitos outros tipos de teste (funcionais, cobertura de código, segurança, performance...).

Vamos supor que você tenha um código como:
<php
function soma($a, $b) {
return ($a + $b);
}
?>


VocÊ pode testar esse código com uma função similar a:
<php
function testSoma() {
$source = array(
array(1,1,2),
array(0,1,1),
array(1,0,1),
array(0,-1,-1),
array(-1,1,0),
array('non', 'sense', "??")
);

$i = 1;
foreach ($source as $unit) {
if (soma($unit[0], $unit[1]) === $unit[2]) {
echo "Test $i OK
\n";
} else {
echo "Test $i FAIL. Dataset: " . print_r($unit, TRUE) . "
\n";
}
$i++;
}
}

testSoma();
?>


Não se deixe enganar pela simplicidade dos exemplos. Automatizar testes traz uma série de vantagens. Uma delas delas é livrar o código principal de echos e prints. Mantendo a integridade do código e separando os conceitos. Sempre que você sentir a necessidade de checar de alguma forma qual o estado atual do programa, escreva um teste.

Uma outra vantagem é a possibilidade de reuso. Se você alterar algo no código, poderá executar a mesma bateria de testes, sem precisar reescrever.

E uma última vantagem com o exemplo que dei, é um conceito bastante poderoso e utilizado em automação de testes: os datasources. Eles permitem que você mude o conjunto de inputs, sem alterar a função verificadora.

No exemplo utilizei um array, escrito à mão mesmo. Porém, em ambientes de produção, você pode criar seus datasources em planilhas ou bancos de dados, o que facilita tanto a criação como a manutenção.

Existem vários frameworks disponíveis para realizar testes unitários. Aqui está um ótimo tutorial sobre o uso de frameworks de teste unitário.

OK, agora vamos dissecar um pouco mais o exemplo que dei acima. Temos uma função a ser testada, uma função para testar que contém um datasource e um loop que verifica e imprime o resultado dos testes. Para ambientes de produção ou cujo volume de testes se torne alto o suficiente, podemos e devemos refatorar deixando as responsabilidades divididas. O esquema muito utilizado é o seguinte:

-> uma função para obter o datasource
-> uma função de logging, para registrar os resultados
-> uma função que faça o papel de juntar tudo (chama a função, itera sobre os dados do data source e registra o resultado).

Com essa estrutura fica fácil manter os inputs e controlar os resultados.

Voltando ao Unit Test. O Unit Test é a base dos testes dinâmicos. A maioria dos bugs é encontrada aqui, porém vale ressaltar que mesmo softwares que passam pelo unit test podem conter bugs, isto porque o unit é focado na parte e não no todo. Assim, nos testes funcionais e de integração podem aparecer bugs novos que não poderiam ter sido detectados antes. Esta questão passa muito mais por design e por arquitetura do que propriamente a funcionalidade específica de um módulo, método ou classe.

Agora um exemplo mais real e prático de Unit Test. Vamos supor que você tenha um processo de login no seu site. Um usuário fornece nome e senha, e você tem uma função que verifica a validade e loga o usuário. Para efeitos de simplicidade:

<php
/*
retorna TRUE se a combinação é válida
retorna FALSE se a combinação não é válida
*/
function isValidUser($username, $pass) {
// código que checa as condições
}
?>


O seu datasource (viu, se você tiver as ferramentas/métodos certos para reutilizar, 95% do seu trabalho vai ser focar apenas nos data sources) será mais ou menos assim:

usernamepassexpected
user1 pass1 TRUE
user1 '' FALSE
user1 inválido FALSE
'' pass1 FALSE
inválidopass1 FALSE
user1 pass2 FALSE
'' '' FALSE
inválidoinválido FALSE

Legenda:
user1 = username 1
pass1 = senha correspondente ao user1
'' = vazio
inválido = username/password não existente nos registros
pass2 = senha correspondente ao user2

Bem, espero que o conceito e a importância dos unit tests e da automação tenham ficado claros neste post. Até a próxima.
----------- keepReading

quinta-feira, 28 de outubro de 2010

Exemplo de desnormalização de banco de dados

Se você já trabalhou a mais de 2 meses em TI já ouviu os termos "normalização de banco de dados" e
"boas práticas". E provavelmente também ouviu a relação das duas coisas: é uma boa prática normalizar um banco de dados.

Não há o que se discutir sobre isso numa primeira instância. Sim, porque uma das técnicas avançadas de tuning é a desnormalização. Aqui vamos a um exemplo prático de como se fazer isso. Mas antes, as ressalvas:

- Aprenda a normalizar um banco de dados de forma decente, nada de fazer um serviço porco e querer dizer que é um padrão avançado inventado no Paquistão.

- Assim como para normalizar, estude o que pode ser desnormalizado. O processo é um método, racional e com suas próprias regras.

O exemplo.

Vamos supor que você cuide de um portal de artigos médicos, que são publicados sempre em 4 línguas (inglês, francês, alemão e espanhol).

Numa forma normalizada, você teria um banco de dados com estrutura semelhante a:

Tabela [autor]
- id
- nome

Tabela [idioma]
- id
- idioma

Tabela [artigo]
- id
- autor_id

Tabela [artigo_contents]
- id
- artigo_id
- idioma_id
- conteudo

Como vemos acima, temos uma tabela para idioma, uma para artigo com informações gerais, e uma tabela com o conteúdo dos artigos, indexada ao artigo e ao idioma. Essa estrutura facilita a organização dos conceitos uma vez que está normalizada.

Agora como saber se essa estrutura poderia ser otimizada e desnormalizada? Bem, poderíamos ter o conteúdo na própria tabela artigos. Antes de prosseguir com a idéia, precisamos responder a algumas perguntas:

- o número de idiomas vai/pode mudar? quais as chances disso acontecer?
- pode ser que um artigo seja publicado num número parcial de línguas, por exemplo só em inglês e alemão?


A resposta a estas perguntas é que determina se a atual estrutura do banco de dados pode ser desnormalizada ou não.

Se o número de línguas NÃO vai mudar ao longo do tempo, ou a chance disto é extremamente remota E os artigos serão todos sempre publicados em todas as línguas, então podemos desnormalizar o banco de dados, movendo o conteúdo para a tabela artigos.

A nova estrutura seria semelhante a:

Tabela [autor]
- id
- nome

Tabela [artigo]
- id
- autor_id
- conteudo_en
- conteudo_de
- conteudo_fr
- conteudo_es

Muito mais simples. A vantagem explícita desse tipo de operação é a simplicidade na hora de escrever e rodar as queries.

Antes deveria ser algo como:

SELECT c.conteudo, at.nome FROM artigo_conteudo c, autor a WHERE a.id = artigo.autor_id AND ac.artigo_id = artigo.id AND ac.idioma_id = '2' AND artigo.id = 27;

Agora se traduz em algo como:

SELECT a.conteudo_fr, at.nome FROM artigo a, autor at WHERE at.id = a.autor_id AND artigo.id = 27;


Reduzindo o número de joins e tudo o mais. Claro, vai ser necessário refatorar parte dos códigos, mas pode valer a pena. O ideal é desnormalizar ANTES de criar o código, na fase de design da solução. Assim o custo de refactor é 0.
----------- keepReading

sábado, 9 de outubro de 2010

Turbinando suas buscas internas

O problema

Quase sempre vemos um formulário de busca interna em sites que publicam conteúdos com frequencia. Este formulário, assim como a navegação por categorias ou por tags, ajuda muito os visitantes a encontrarem o que procuram. Mas desenvolvedores iniciantes - ou nem tão iniciantes assim - ainda implementam esse mecanismo de busca de uma forma "crua".

Geralmente é um simples formulário, com método GET, um campo de texto e um botão de OK. Até aí, sem problemas. No front end é isso mesmo. Mas no back end, geralmente a implementação que vemos é algo assim:


<?php
$terms = explode(' ', $_GET);
$query = "SELECT * FROM table WHERE conteudo LIKE ";

foreach ($terms as $term) {
$query .= "%" . $term . "% OR LIKE";
}
... // roda a query, pega resultados, mostra
?>


Pois bem, esta abordagem, apesar de funcional, não é elegante, nem tem a precisão desejável. Se você buscar por "um cone" pode encontrar "a coleção de ícones do Humberto". Isso sem falar da performance das queries, que é seriamente afetada quanto mais registros no banco e mais termos são procurados.

A solução? Um recurso que os principais RDBMS tem chamado Full-Text Search. Vou ensinar aqui como implementar e usar estes recursos na prática (no MySQL e no PostgreSQL).

MySQL

NOTA: o recurso de Full-Text Search só está disponível para tabelas MyISAM.
Vamos supor que você tenha uma tabela de posts ou artigos com a estrutura parecida com a seguinte:

id
titulo
intro
conteudo
autor
tags
publishdate

Em primeiro lugar vamos precisar adicionar um índice, que é composto pelos campos que desejamos que sejam buscados. Rode isso pelo seu programa de administração do MySQL (MySQL Admin, phpMyAdmin).

ALTER TABLE posts ADD FULLTEXT (titulo, intro, conteudo, tags);


Depois disso, basta reescrever a query no PHP:

SELECT * FROM posts
WHERE MATCH (titulo, intro, conteudo, tags)
AGAINST (". $_GET .");


A busca será mais rápida e os resultados com menos falsos positivos. Sem contar que o código fica mais limpo e elegante.

PostgreSQL

O PostgreSQL dá um pouco mais de trabalho para fazer a implementação.

Pelo seu programa de administração, rode as seguintes queries.

ALTER TABLE posts ADD COLUMN postsfts tsvector;

UPDATE posts SET postsfts =
setweight(to_tsvector('pg_catalog.portuguese', coalesce(titulo,'')), 'A') ||
setweight(to_tsvector('pg_catalog.portuguese', coalesce(intro,'')), 'B') ||
setweight(to_tsvector('pg_catalog.portuguese', coalesce(conteudo,'')), 'C');

CREATE INDEX postsfts_idx
ON posts
USING gin(postsfts);

CREATE TRIGGER postsfts_tg
BEFORE INSERT OR UPDATE ON posts
FOR EACH ROW EXECUTE PROCEDURE
tsvector_update_trigger('postsfts', 'pg_catalog.portuguese', 'titlulo', 'intro', 'conteudo');


Entendendo o que foi feito.
A primeira query adiciona um outro campo à tabela, onde o vetor de busca ficará armazenado (isso aumenta de forma significativa a performance).
A segunda query define quais campos farão parte do full-text search. Note que no PostgreSQL você pode definir o peso de cada campo - A, B, C ou D, sendo A o campo mais importante, D o menos importante. Ah, e claro definimos a linguagem para português.
Na terceira query, construímos um index sobre o campo que acabamos de criar.
Por último, criamos um trigger que vai atualizar o campo que criamos, sempre que o o conteúdo da tabela for atualizado.

Com isto feito, podemos transformar as queries no PHP para:

SELECT * FROM posts, to_tsquery(' . $_GET . ') query
WHERE query @@ postsfts;


No PostgreSQL o operador "@@" funciona como o MATCH AGAINST do MySQL. E precisamos converter o que vai ser buscado através da função to_tsquery().

Qual é o mais relevante?

Os recursos de full-text search permitem ir um pouco mais além e definir um ranking sobre quais registros são mais relevantes sobre os termos buscados. No PostgreSQL isso pode ser feito com uma query similar à seguinte:


SELECT *, ts_rank_cd(postsfts, query) AS rank
FROM posts, to_tsquery(' . $_GET . ') query
WHERE query @@ postsfts
ORDER BY rank DESC LIMIT 5;


Aqui temos a função ts_rank_cd que faz essa função do ranking (além de já termos setado os pesos dos campos antes). E vocês podem notar que estamos ordenando pelo ranking. Ou seja, essa query trás os 5 resultados mais relevantes.

Para obter o mesmo efeito no MySQL podemos fazer a query da seguinte forma:

SELECT *, MATCH (titulo, intro, conteudo, tags) AGAINST (". $_GET .") AS rank
FROM posts
WHERE MATCH (titulo, intro, conteudo, tags) AGAINST (". $_GET .")
ORDER BY rank DESC LIMIT 5;


Conclusão

Espero ter criado um guia rápido e prático para que vocês possam aplicar o full-text search em seus próximos trabalhos e assim obter melhores resultados. Vocês codificam mais rápido, o sistema ganha em performance, e os usuários agradecem os resultados mais precisos.

Abraços e keep readin'

----------- keepReading

segunda-feira, 20 de setembro de 2010

PHP Mail Class

Subi hoje no sourceforge uma classe que fiz a quase um ano, e que me ajudou muito.

É uma classe para envio de emails no PHP, inclusive com arquivos anexados. A classe é bem simples, enxuta e muito útil (senão eu não estaria compartilhando).

Dúvidas? Deixe um comentário.
----------- keepReading

sexta-feira, 17 de setembro de 2010

Tipografia básica para web

Desde o meu início com o desenvolvimento para web, sempre foquei mais em programação, códigos, bancos de dados do que em design. Isto por aptidão. E se falta talento e bom gosto, também me faltou informação simples, direta e suficiente para criar algo esteticamente atraente. Não uma obra-prima, mas visualmente decente.

Vamos ao básico da tipografia, que é a área do design que estuda as fontes, as letras e suas formas. A intenção não é gabaritar o leitor a ser um especialista no assunto, longe disso, e sim fornecer as bases para que as produções venham a ter funcionalidade e cumprir decentemente com seu propósito.

Tipos de fonte

Com serifa e sem serifa (serif e sans-serif).


As serifas são os pequenos traços ou prolongamentos no fim das hastes das letras. A divisão das fontes entre tipos serifados e sem serifa é a principal divisão na tipografia.

Na mídia impressa, costuma-se usar fontes serifadas para o texto, e fontes sem serifa para títulos e outros elementos de destaque, isso mais por uma questão funcional do que estética. As serifas dão uma impressão de continuidade, o que facilita a leitura, e por isso é usada no fluxo de texto. Já as fontes sem serifa não dão esta sensação de continuidade, funcionando bem para elementos de destaque.

Mas na web a história muda. Fontes serifadas são mais difíceis de ler em monitores, e o uso de fontes sem serifa facilita a leitura.

Além da diferenciação entre fontes com e sem serifa, existem outras propriedades importantes de fontes. Os espaçamentos são uma dessas características. As fontes geralmente têm largura diferentes para letras diferentes. Quando a largura para cada letra é igual entre todas as letras, dizemos que a fonte é monoespaçada. Fontes monospace não são boas para leitura de textos, mas dão destaque em legendas e principalmente códigos fonte de programação, onde a organização visual que elas promovem ajudam o raciocínio e facilitam a leitura do código fonte.

Com o advento e suporte à propriedade @font-face no mainstream, com a abundância de formatos suportados (EOT, TTF, SVG, WOFF) pelos navegadores, e também pelo suporte a propriedades gráficas de transformação (scale, skew, rotate,...) a tipografia na web alcança um novo patamar a ser explorado pelos desenvolvedores.

O conjunto

Não basta escolher a fonte visto que textos geralmente não são apenas uma palavra e sim um conjunto delas, com linhas e outros elementos em volta. Trabalhar este espaço é tão importante quanto a escolha da fonte, e na verdade influencia diretamente na escolha da fonte.

Linhas muito longas ou muito curtas são mais difíceis de ler. Algo entre 50 e 90 caracteres por linha é o recomendado para leitura em telas de computador.
O distanciamento entre as letras também influi na qualidade da leitura. Encontrar o ponto de equilíbrio, de conforto, é a chave.
O distanciamento entre linhas é outro aspecto muito importante da composição. Linhas muito próximas dificultam a leitura, muito distantes não passam a sensação de unidade, de conjunto do texto.

Estes espaçamentos mudam conforme o propósito, o público-alvo, o tipo de texto, o tamanho da fonte, entre outras variáveis. Não existe uma regra de ouro, o bom senso é quem comanda (quando for o caso de mudanças). Mas via de regra, espaçamento entre linhas em 1.5 ou 1.4 é considerado como padrão para uma boa leitura. Para o espaçamento entre letras, só mude quando houver necessidade.

Contraste

Quando ouvimos falar de contraste, logo pensamos em cor, mas contraste é um termo mais abrangente em design. É algo que quebra o padrão de repetição. As formas básicas de contraste são: tamanho, posição, textura, cor, forma e orientação. E estes se aplicam também à tipografia.
Não é somente através da mudança de fonte que podemos dar ênfase, destaque para algum elemento. Saber trabalhar com estes conceitos de contraste ajuda o design a ganhar volume e importância, mantendo a uniformidade do conjunto (sem bombardear o leitor com diversas fontes e cores diferentes), em outras palavras, criar a hierarquia visual.

Acessibilidade

Apesar de ser uma importante área do design, e existir uma infinidade de belas fontes, usar mal as fontes pode destruir o design ou pior, a credibilidade de toda a obra.
Para texto comum, de fluxo, conteúdo, use fontes com as quais as pessoas estão habituadas. Arial, Verdana, Helvetica, Tahoma, Times New Roman, Courier New, Lucida... todas estas fontes são usadas pela maioria dos grandes sites e portais, e por um motivo simples: todos estão acostumados com elas, e geralmente tem estas fontes instaladas nos seus computadores ou celulares.

E as fontes bonitas? Use elas em elementos de destaque. No logotipo, na logomarca, nos cabeçalhos, em mensagens promocionais, etc, mas não nos textos, formulários, menus e barras de navegação.

E para completar a acessibilidade, não podemos esquecer de um antigo (mas não raro esquecido ou mal usado) recurso do CSS 2.1, as famílias genéricas de fontes. O CSS prevê 5 famílias genéricas (serif, sans-serif, monospace, cursive e fantasy), que podem (devem) ser usadas nas declarações de fontes, sempre ao final, provendo uma regra de fallback. A idéia é simples, se o usuário não tem instalada a fonte que você declarou, ou mesmo se por algum motivo a fonte não pode ser baixada/processada pelo @font-face, você fornece pelo menos a família de onde a fonte pertence, e o navegador do usuário utilizará a fonte configurada para tal fim (falando sério, isso é algo bem comum de acontecer), e ainda assim, seu site manterá a aparência de conformidade para o usuário.

Se você não entendeu, deixe-me explicar melhor com um exemplo meu, real. Eu uso Linux. Não tenho instalado aqui as fontes Helvetica e Tahoma. Alguns sites, como o google code, declaram a fonte Helvetica para ser usada (font-family: Helvetica, sans-serif;). Como eu não tenho, o Firefox, o Opera e o Chrome, vão utilizar a fonte que está configurada para o tipo sans-serif, que no meu caso é a FreeSans. O site, apesar de não aparentar da forma original que os designers gostariam, ainda podem se valer desta regra de fallback, e o Google Code, assim como muitos blogs e sites que não declaram a fonte, têm uma aparência familiar pra mim, o que gera conforto visual, e passa uma sensação de confiança (não é algo bizarro ou estranho).

Então fica o lembrete: SEMPRE usar uma família genérica junto das declarações de fonte no CSS.

Resumo

  • Na maioria dos textos use fontes simples, comuns.
  • Não utlize muitas fontes, nem muitos estilos (negrito/itálico/cores) diferentes. Se necessário, reescreva o texto.
  • Use contraste como negrito, tamanho ou cores para elementos especiais ou específicos, mas procure manter a unidade e a hierarquia visual.
  • Prefira fontes sem serifa para a maior parte do texto.
  • Não crie linhas muito longas ou muito curtas.
  • Respeite o espaçamento entre linhas.
  • Sempre coloque regras de fallback.
  • Permita-se usar fontes diferentes em elementos especiais como logotipos ou cabeçalhos de seção.
  • Lembre-se sempre de ter famílias genéricas como fallback.
  • Se possível não use fontes com tamanho abaixo de 12px.
  • Use o bom senso. É melhor ficar com o lugar comum e funcional do que inventar um novo conceito que fique estranho.

Referências

On Web Typography (em inglês)
10 typography tips to bring you to the next level (em inglês)
----------- keepReading

Algumas coisas sobre PHP que você provavelmente não sabia...

Pois é, tem milhares e milhares de páginas e posts na internet com um título semelhante, e chegou minha hora de escrever um também.

Depois de alguns anos de muito código e de muito polir eles me sinto confortável pra fazer um posts desse que relatem algo realmente útil e não apenas justifique o porque usar aspas simples ou duplas no echo.

1 - Use variáveis de servidor

Vemos muita aplicação dos arrays $_GET, $_POST e $_SESSION por aí. Fora eles, dificilmente vemos algum tutorial ou artigo falando dos outros arrays, como $_COOKIE, $_REQUEST, $_ENV, $_SERVER, $_FILES....

Bom, o vetor $_SERVER[] tem muitas variáveis úteis, como SERVER_NAME, SCRIPT_NAME, REMOTE_ADDR, REQUEST_METHOD, HTTP_REFERER...

Claro que muitas dessas variáveis, como tudo quando se trata de web, podem ser manipuladas por usuários mal intencionados. Mas caso geral, são confiáveis.

Agora o bom mesmo é tirar vantagem da manipulação dessas variáveis, por exemplo para criar respostas on demand para requisições ajax. A idéia é setar uma variável no request header, que depois é lida pelo PHP. Se a variável estiver setada a requisição é Ajax.

No Javascript:
var myXHR = new XMLHttpRequest();
myXHR.setRequestHeader("X_HTTP_REQUESTED_WITH", "XMLHttpRequest");
// resto do código

No PHP:
<?php
//código...
//agora na hora da saída
if (isset($_SERVER['X_HTTP_REQUESTED_WITH'] && $_SERVER['X_HTTP_REQUESTED_WITH'] == "XMLHttpRequest") {
    echo $output;
} else {
    include("header.php");
    echo $output;
    include("bottom.php");
}
?>

2 - Constantes pré-definidas

Usar constantes do sistema deixa o código mais bonito e portável. Aprendi isso usando a constante PHP_EOL (fim de linha) para escrever uma classe de email.

Ao invés de escrever vários códigos, um para cada plataforma (o caracter é diferente para UNIX, Mac e Windows), usei apenas essa constante. Mas existem outras úteis como o PATH_SEPARATOR.

NOTA: Muitas das constantes são REALMENTE úteis para internacionalização da aplicação, juntamente das funções setlocale.

3 - Operador Ternário

Seja lá qual for a lista de top 10, 20, 382 dicas de PHP, operador ternário tá no meio. E não é a toa. Ele é simples, higiênico e poderoso.

Basicamente é a mesma coisa que um if else. Só que é interessante notar que dá pra usar ele (e aí sim ver toda sua elegância) diretamente em atribuições ou returns.
<?php
$var = 10;
echo ($var >= 10) ? 'Great!' : 'Damn!';

return (mail()) ? 'Sent with success' : 'Sorry... bad server';
?>

4 - Escreva funções

Outro jargão, mas que merece estar aqui também. Escrever funções e rotinas é o básico do básico em programação. Não adianta você querer aprender OOP, ou Design Patterns, se não sabe fazer o arroz com feijão.

Funções são simples de escrever, rápidas, poupam trabalho, limpam o código principal... Enfim, são o primeiro passo rumo a deixar de ser o sobrinho que faz sites.

5 - Extensão Filter

Extensão não muito conhecida, e menos ainda falada e comentada. Disponível built-in desde a versão 5.2 do PHP (ou seja, tem em quase todo host decente).

A extensão filter simplifica a validação e higienização de variáveis, além de fornecer funções prontas para tipos de validação comuns e/ou padronizadas. Checar se um email ou uma URL passada num formulário é válido e limpar se for o caso é muito fácil.

Claro, ela também é flexível, e fornece uma opção de callback. Então crie sua função para validar CPF, e use a extensão filter a partir de agora.

6 - Arrays

Mais um da galeria dos óbvios que estaria aqui. Bem, não tão óbvio, senão não estaria aqui. Se você já teve contato com programação mais de 3 dias na vida, já conhece os arrays. Mas o que você provavelmente desconhece são as funções para lidar com eles.

array_unique, uasort, array_intersect, array_search, array_diff, array_walk... Existe um grande número de funções úteis que geralmente por ignorância são reescritas (nem sempre da melhor forma) pelos programadores, incorrendo no caso da reinvenção da roda.

PEAR, PECL e Tuning

Ainda no tema de parar de reinventar a roda, saiba que você pode - e deveria - consultar repositórios de códigos como o PEAR, o PECL e o PHPClasses. Existem muitas soluções prontas na web para resolver problemas que você tem exatamente agora. E geralmente soluções feitas por programadores mais experientes ou mesmo por comunidades inteiras.

Além de poupar trabalho, você pode se valer disso para aprender através da leitura destes códigos, e com o tempo, pode inclusive modificar estes códigos quando for usar. Adaptar às suas necessidades ou corrigir um bug.

Conclusão

Todas as "dicas" que coloquei aqui se resumem a algumas noções não-tão-comuns sobre boas práticas.

Geralmente o que se discute quando o assunto são boas práticas e estilo são formas e padrões de se escrever o código, mas quase nunca se fala em:
  1. Aproveitar o que o sistema te oferece de forma nativa
  2. Explorar o que a linguagem tem de recursos
  3. Explorar o que já foi feito pela comunidade

Até a próxima.
----------- keepReading

quinta-feira, 16 de setembro de 2010

Como os crawlers funcionam?

Crawler, spider, bot, entre outros nomes, são programas que navegam na internet e indexam conteúdo. Os mais famosos de longe são os do google e do yahoo. Mas existem diversos, e o funcionamento básico deles é bem parecido (o que difere é como cada sistema organiza e classifica as páginas para mostrar nos resultados).

De alguma forma eles chegam à sua página, seja buscando nos bancos de DNS disponíveis na internet, ou seguindo um link. E quando chegam na sua página, eis o que eles fazem:

Primero lêem sua página, mais especificamente, o código HTML da sua página. E antes de começarem a analisar o que sua página faz ou vende, eles tentam separar os links, links internos, action de formulários... Note que eles não leem e não executam scripts, formatos de arquivo estranhos como PDF, imagens, nem nada do tipo.

Alguns buscadores é claro também indexam fotos (juntamente com o atributo alt), arquivos em flash, PDFs e outros arquivos, mas isso é outro assunto. O importante é entender que eles, antes de qualquer outra coisa, tentam descobrir o quais são as páginas dentro do seu site, e isso só pode ser feito desta forma, através do seu código HTML.

Se você possui um arquivo ou mesmo um diretório inteiro, que não esteja conectado a nenhuma página, seja através de um link, de um atributo src ou href, este arquivo ou diretório não será magicamente descoberto pelo crawler.

Bom, os crawlers do buscadores geralmente procuram informações sobre permissões sobre o conteúdo. Em espcial existem duas formas de bloquear um crawler decente de indexar uma determinada página (e os links nela contidos). A primeira forma, e mais comum, é através do arquivo robots.txt. A outra forma é através da tag meta robots, com valor "noindex" ou "nofollow", usados para não indexar (a própria página) e não seguir (os links contidos na página), respectivamente. Há também uma terceira possibilidade, muito menos explorada, que é o uso do atributo rel="nofollow" em links, indicando ao crawler que aquele link em especial não deve ser seguido.

Recapitulando... o crawler chega na sua página, lê o código HTML, procura o arquivo robots.txt, confere os links da página, confere se há alguma tag meta específica para ele, depois organiza o que ele deve seguir ou não dentro e a partir do seu site.

Ah sim, uma outra forma de um crawler indexar páginas e conteúdos é através de outros sites. Vamos supor que você tem uma página no seu site, chamada apropriadamente de secredo.html.

Se você digitar direto na barra de endereço, você acessa essa página, mas a partir de todas suas outras páginas não existe link para esta página. Certo, os crawlers nunca descobrirão esta página, de acordo com o que expliquei acima. Porém um amigo seu coloca o link desta página no site dele. Pronto, agora sua página secreta está pronta para ser indexada pelos crawlers.

Claro que usar uma restrição no robots.txt ou uma tag meta basta para que os bons crawlers não indexem esta página, afinal o autor (no caso você) explicitamente não quer que isso aconteça.

Mas nem todos buscadores são tão corretos (google, yahoo, bing, ask, baidu,... esses são). Os crawlers do mal às vezes se baseiam exatamente nas restrições para fazer descobertas e indexar conteúdo. Mas isso não é de longe motivo para alarde, afinal, a maioria desses bad crawlers não são famosos, não tem visitantes, e na maioria das vezes nem mesmo cacife financeiro para sobreviver muito tempo.

Bem, espero que eu tenha esclarecido como o processo de descoberta e indexação funciona. O processo de organização das informações como eu disse, é o que é diferente entre os buscadores.

Até a próxima.

----------- keepReading

Qual a diferença?

No meio do boom de possibilidades e novos recursos trazidos pelo CSS3 temos as Media Queries. E do meu ponto de vista esse novo recurso vem numa velha roupagem, trazendo junto algo que parece persistir no mundo do desenvolvimento para web.

O que são as media queries?

No CSS 2, havia a possibilidade de definir folhas de estilo diferentes para meios diferentes. O exemplo clássico é usar duas folhas distintas, uma para leitura na tela com fontes sans-serif, e uma para impressão com fontes serif, melhorando a legibilidade do conteúdo segundo onde ele for usado. O CSS 2 define alguns tipos de media, a saber:
  • all
  • braille
  • embossed
  • tv
  • tty
  • handheld
  • screen
  • print
  • projection
  • speech/aural

Com as media queries do CSS3 essas possibilidades foram estendidas para propriedades dos meios. Por exemplo, largura ou altura da tela (ou da folha), quantidade de cores, resolução, etc. Isso é media query.

Por que o estardalhaço com isso?

Resumidamente: por causa da expansão da internet 3G e nos dispositivos móveis capazes de navegar na internet.

Com as medias queries é possível detectar larguras, alturas, orientação da tela, etc, e com isso formatar o conteúdo de acordo, deixando um aspecto muito mais agradável e legível para as páginas. Seja num smarthphone, seja numa TV full HD de 30+ polegadas, seja numa folha A4, seja num outdoor.

Assim, agora as folhas de estilo poderão se adaptar aos dispositivos e meios onde serão mostradas, tudo sem nenhuma linha de script ou programação adicional, apenas com marcação HTML/XML e CSS.

Se essas media queries são um recurso tão legal, qual o problema?

O problema disso é a carga de trabalho para criação e manutenção, além da postura de alguns sites e entusiastas que proclamam esta solução como definitiva. Rotular algo como definitivo é um tiro no pé, e isso é duplamente verdade no mundo da tecnologia. Nada é definitivo porque ninguém pode prever o mercado dentro de 5 ou 10 anos.

Mas falando sobre o lado ruim do operacional, da hora do vamos ver, o problema é que as media queries podem adicionar trabalho de forma desnecessária e ineficiente. Explico. Ou você vai aumentar muito o tamanho dos arquivos CSS, ou vai criar algumas dezenas.

Como se fazia antes?

É engraçado notar que sites para dispositivos móveis existem a mais de 10 anos. Claro que a quantidade de sites aumentou muito com o aumento da participação do mercado na internet destes dispositivos, e com a evolução das tecnologias. O que antes era raro, agora é tendência. Antes era WAP, agora é HTML e CSS mesmo, só que mais enxuto.

Como mencionei antes, o CSS 2 já previa o uso de arquivos CSS diferentes, baseados em mídias e dispositivos diferentes. Uma das abordagens adotadas era - e ainda é - deixar um redirecionamento para um domínio específico ou uma folha de estilo específica quando acontecer do dispositivo se enquadrar na media handheld.

Para se ter uma idéia, o Yahoo!, o Youtube, o A List Apart, o McDonald's e o Walmart adotam esta solução ainda hoje.

Eles tem as tags
<!-- este faz o redirecionamento para um domínio separado -->
<link rel="alternate" href="http://m.domain.com" media="handheld" />
ou
<!-- este aponta para uma folha de estilo separada -->
<link rel="stylesheet" type="text/css" href="mobileStyle.css" media="handheld" />

Abordagens alternativas e seus pontos positivos e negativos

Estas claro que não são as únicas soluções, mas são as mais difundidas atualmente. E com as Media Queries do CSS3, surge uma leva de críticos teóricos a este modelo. Uma das críticas é que o conteúdo fica espalhado. Vários domínios, várias folhas de estilo... É ruim para o controle, etc...

Frente ao mercado atual de tecnologias disponíveis e de dispositivos/suporte, temos algumas soluções que fazem sentido e outras nem tanto.

A primeira seria usar apenas o atributo media para importar um arquivo CSS para handhelds. É uma solução muito difundida, talvez a mais difundida. É eficiente, testada, funcional. O problema é que as capacidades variam de acordo com os dispositivos móveis. Largura, altura, resolução, cores e orientação são as mais significativas em termos de design (por isso as media queries foram criadas).

Outra solução é adotar um subdomínio diferente. Esta solução também é bastante popular, mas recebe duras críticas. O motivo é simples. Se para cada faixa de resolução for criado um novo subdomínio e uma nova folha de estilo, isso pode gerar um monstro dentro de alguns anos. Bem, isso é um ponto de vista dos teóricos. Na prática, esta abordagem traz alguns outros benefícios, como o lado do servidor, que pode processar e gerar respostas mais leves (usar outras imagens, remover flash, javascript, anúncios...), o que é muito interessante para quem usa dispositivos móveis, afinal é consumo de banda menor, download e processamento mais rápidos.

Usar media queries para importar diferentes estilos. A idéia queridinha do momento. Mas ninguém pensa (ou apenas ignora, ou dá importância menor) no fato de que neste caso, várias folhas de estilo são necessárias, o que representa um problema tão grande para a manutenção quanto ter um domínio separado. HTML com cabeçalho maior para TODOS os casos, e uma trabalheira muito grande para os desenvolvedores e designers.

Usar media queries dentro do arquivo CSS para criar regras específicas para determinados dispositivos. Parece interessante, mas o arquivo ficaria simplesmente gigante, com uma variação de regras repetidas várias vezes. Continua uma solução estranha, com um arquivo de CSS ruim de dar manutenção, e extremamente grande pra baixar e lento pra processar.

Usa ou não usar?

Faladas as soluções (ou futuras tendências de), hora de pesar cada coisa, e de escolher uma abordagem. Claro que isto irá variar de caso para caso, mas no geral, as minhas consideração estão abaixo.

Usar um (ou mais, caso necessário) domínio alternativo, e fazer uso de redirecionamentos com a tag link. Um para dispositivos móveis, um para desktops normais, e talvez um para monitores grandes e TVs. Eu sou a favor do uso de domínios alternativos principalmente pelo fato de poder valer-se de programação server-side e fornecer conteúdos diferentes, economizando banda e outros recursos dos clientes.

Para cada domínio, um CSS diferente. Apesar de parecer mais complicado, é mais leve, depois de um arquivo CSS pronto, basta duplicar o conteúdo e adicionar/subtrair algumas regras.

Ah sim, nestes arquivos CSS diferentes sim usar as media queries. Continua aumentando o número de regras, mas é muito mais conveniente e leve fazer desta forma, ao invés de servir um único arquivo CSS grande.

Conclusões

Media queries são um novo recurso muito interessante e poderoso sem sombra de dúvidas. Mas do meu ponto de vista ele não resolve perfeitamente a condição de ter que filtrar de alguma forma informações do cliente. Aliás, esta realidade de exibir páginas diferentes (layouts diferentes) é algo que depende do mercado de monitores, dispositivos, browsers, e não tem como servir um conteúdo único, apenas um arquivo html e um arquivo CSS, que enquadre todas as soluções de forma otimizada. No passado e no presente bibliotecas javascript serviram a este propósito, agora temos como fazer isso em CSS.

Antes não haviam padrões W3C para realizar este tipo de tarefa, e sempre que o assunto pende para este lado, surgem defensores fanáticos ressaltando todos os pontos ruins de uma solução em javascript (não é standard, e não serve para todos os dispositivos). Apesar de ter um fundo de verdade nesta afirmação, na prática 99.8% do fluxo na internet vai para navegadores que contam com esta tecnologia, daí o porque deste fanatismo ser exacerbado em meu ponto de vista (que sou um standardista).

Agora temos as media queries, um jeito W3C de fazer essa diferenciação para dispositivos diferentes. No entanto, a necessidade de ter marcações ou regras diferentes para dispositivos diferentes continua existindo, assim como o trabalho de criar regras diferentes.

O fiel da balança, junto desta necessidade de servir conteúdos/formatos diferentes, é o usuário. Se por um lado temos como servir estes conteúdos, o forma de serví-los pode não ser otimizada. Por que ter um aumento de 150% no tamanho do arquivo CSS, sendo que pode-se criar um domínio separado, e servir arquivos menores (inclusive o output HTML menor)? O que é melhor para os usuários? E para os desenvolvedores? Será que criar mais de uma folha de estilo é tão complicado assim, ou seria melhor para fazer manutenção?

Sou a favor do uso das media queries, mas não como solução única, absoluta e ótima. Cada caso deve ser analisado, e outros fatores devem sim ser levados em consideração, principalmente no que diz respeito aos usuários.
----------- keepReading

terça-feira, 14 de setembro de 2010

Web Semântica: HTML5 e Microformats

O que é Web Semântica?

No início da internet, tivemos o HTML para criar e marcar o conteúdo. Com ele, que é usado até hoje em todas as páginas existentes, é possível criar textos, links, inserir imagens e tabelas, formulários, e muito mais. Porém a classificação e o uso destes elementos permite apenas funcionalidade e não significado. Um link geralmente assume a forma de um texto ou imagem, que uma vez clicado leva a outra página, mas não diz o significado, a natureza dessa relação. Adicionar significado à relação dos elementos é a idéia principal por trás da semantica na web.

Por que é importante?

Para os usuários a diferença não é tão transparente ou mesmo útil no dia a dia. Pouca ou nenhuma funcionalidade nova é agregada para a intereção do usuário. Mas para os buscadores e indexadores, isso faz toda a diferença, e isso sim acaba afetando a qualidade da navegação dos usuários, além das relações comerciais (ou não) entre os próprios sites. Um exemplo seria procurar restaurantes, com determinada faixa de preço, com boa avaliação dos frequentadores, em determinada região. Outro exemplo seria procurar todos os artigos de um determinado autor que estão publicados sob determinada licensa de uso.

Hmm... será que isso pega?

Essa idéia é relativamente antiga. Nenhum buscador tinha esse tipo de tecnologia, por isso ninguém investia em desenvolver padrões ou criar sites com esses recursos. Hoje os buscadores (Yahoo!, Google, Bing entre outros) já tem suporte a ler e classificar essas informações. O que está em falta são sites que implementem esses recursos. Os que implementam certamente ganham destaque (e todos os grandes sites já implementaram ou estão implementando).

Não existe um único formato de se adicionar significado aos elementos. Dos padrões mais conhecidos temos o RDFa e os Microformats, com uma certa vantagem em maturidade e simplicidade para este último. Mas a semantica ganhou mais força junto com o suporte dos buscadores, e com o HTML5 (que é o grande preferido entre os buscadores agora).

Se faltam páginas com microformats, falta ainda mais páginas feitas em HTML5. E pra completar a história, o HTML5 já preve o uso de muitos microformats, entre outros mecanismos úteis para adicionar significado de uma forma ordenada.

#Comofas?

A semantica é adicionada através de atributos dos elementos. Os microformats usam geralmente o atributo class, mas também se valem em alguns casos dos atributos id e rel.

Como este post NÃO É um tutorial, por hora recomendo a leitura das especificações: HTML5 Metadata, HTML5 rel values, Microformats.

O único ponto de conflito que vejo entre microformats e HTML5 é o uso do atributo rel. O HTML5 define uma lista de possíveis valores que podem ser usados (e alguns valores sugeridos pelos Microformats não estão nesta lista). O jeito de contornar estes conflitos, mantendo consistência com a especificação do HTML5, seria adotar o mecanismo de metadados do próprio HTML5 para fazer essas marcações ao invés de usar os Microformats. No mais, geralmente os dois, Microformats e HTML5 são completamente compatíveis.

Conclusão

A web semântica é vista como tendência futura a muito tempo, e com o impulso dado pelos buscadores e pelo HTML5, espero que os desenvolvedores comecem a adotar o uso dos mesmos em breve.

----------- keepReading