Porque você deveria aprender várias linguagens de programação

tpp_xlargecover

O programador pragmático não está preso a nenhuma tecnologia.

Há um tempo eu li “The Pragmatic Programmer“, uma espécie de livro de auto-ajuda para programadores. Não é um livro técnico, não vai te ensinar técnicas ou tecnologias, mas fala de um jeito de pensar e traz uma coleção de conselhos daquele tipo que parece óbvio mas ninguém nunca faz.

Um desses conselhos era aprender novas linguagens de programação. Os autores recomendam que você se torne proficiente em uma nova linguagem de programação por ano. O que, eu sei, é muito difícil. Eu não tenho conseguido aprender uma nova linguagem por ano. Mas isso não invalida o conselho de que você deve aprender novas linguagens de programação.

Por que aprender linguagens de programação novas?

Cada linguagem de programação traz consigo um jeito de pensar, um conjunto de soluções e uma comunidade com cultura diferente. E isso enriquece você. O bom programador tem uma visão ampla e não está “preso” a uma única tecnologia.

Por exemplo, digamos que você esteja desenvolvendo um sistema em PHP e precise, de tempos em tempos, fazer parsing de feeds RSS cuja URL foi cadastrada pelos usuários. Digamos que você queira fazer o parsing em segundo plano, a cada meia hora. Claro, você pode usar SimplePie, mas ele não é tão “Simple” assim. Dê uma olhada na documentação. SimplePie é muito poderoso, tem uma porção de recursos, mas vai dar algum trabalho para instalar direito, montar seu script, testar e automatizar.

E se você procurar soluções em outras linguagens de programação? Quanto trabalho vai ter? Vamos ver o que Python tem para nós, usando o excelente módulo feedparser. O módulo feedparser está disponível no gerenciador de pacotes do Ubuntu, e também para instalação via PIP.

import feedparser
print feedparser.parse('http://elcio.com.br/feed')

Mais uma meia dúzia de linhas para ler as URLs e salvar os resultados no banco de dados e pronto, temos um arquivo simples com excelente performance para ser colocado no cron. Bom, falando em performance, esse é o típico processamento que vai rodar muito mais rápido se feito em paralelo. Processamento em paralelo com PHP é um parto, certo? Com Python você pode usar o módulo multiprocessing e fazer isso quase que em uma linha só.

Além de ferramentas, linguagens de programação carregam jeitos de pensar

Uma vez que você já tenha resolvido um problema em uma linguagem de programação, você consegue resolver o mesmo problema em qualquer outra, certo? Bom, quando você aprende uma linguagem nova, você acaba tendo que ler um bocado de código de outras pessoas. E isso te ensina novas soluções para os seus velhos problemas.

Isso é diferente de se aprofundar no estudo de sua linguagem atual. O aprofundamento vai fazer você ler mais códigos das mesmas pessoas, da mesma comunidade, da mesma cultura. Aprender uma linguagem nova faz você ler códigos de gente nova, com outra cultura. Na prática, aprender Python vai fazer você melhor programador PHP, aprender Smalltalk vai fazer você melhor programador Java, etc.

Porque Python

De todas as linguagens de programação que você poderia escolher para começar a aprender algo novo hoje, eu recomendo que, se você ainda não sabe Python, comece por ela. Python roda no Google App Engine, no AWS Elastic Beanstalk e é a linguagem de programação por trás da maioria das ferramentas de administração do Ubuntu. Se você quer construir pequenos scripts para automatizar tarefas em seu servidor, ou quer construir grandes aplicações web para rodar em Cloud, ou se quer criar ferramentas de processamento paralelo massivo, ou interfaces gráficas multiplataforma, Python vai servir.

E é, ao mesmo tempo, uma linguagem que possui recurso fantásticos e vai te ensinar coisas incríveis, e uma das linguagens mais fáceis de aprender que eu conheço.

Que tal começar agora? Leia o excelente “Dive Into Python“, faça os exercícios, depois tente desenvolver alguma coisa na linguagem. E veja se você não vai se tornar mais eficiente em sua linguagem atual.

“Jabá”: Python é a linguagem que escolhemos para a aula de integração multi-linguagem do DevOps Heroes, treinamento da Visie que acontece a partir do dia 27 em São Paulo. Quem estiver lá vai ver isso tudo funcionando na prática. As vagas estão se esgotando.

Artigo recomendado: Two Things About Conditionals in JavaScript

Detalhezinho sobre a linguagem que vale a pena conhecer, e uma boa dica de lógica sobre um erro muito cometido por iniciantes:

“We shouldn’t be fearful of writing about what we know. Even if you write from the most basic point of view, about something which has been ‘around for ages’, you’ll likely be saying something new to someone. That’s because there is no else if in JavaScript.”

Papo de Maluco

Hoje estava brincando com Requests e tive essa ideia maluca:

import requests
import re

def Ed(text):
params=dict(server=’0.0.0.0:8085′,charset_post=’utf-8′,
charset=’utf-8′,pure=1,js=0,tst=1,msg=text)
return re.sub(‘<[^>]*>’,”,re.sub(r’\n+$’,”,
requests.get(‘http://www.ed.conpet.gov.br/mod_perl/bot_gateway.cgi’,
params=params).text))

def SeteZoom(text):
params=dict(server=’127.0.0.1:8088′,pure=1,js=0,tst=1,msg=text)
return re.sub(r’\n+$’,”,
requests.get(‘http://bot.insite.com.br/cgi-bin/bot_gateway.cgi’,
params=params).text)

msg=’Oi!’
while True:
print ‘SeteZoom: %s’ % msg
msg=Ed(msg)
print ‘Ed: %s’ % msg
msg=SeteZoom(msg)

Teste aí, o resultado às vezes é mais inteligente que muito chat entre seres humanos por aí…

Números bem torturados

Dizem que Delfim Neto dizia que números, quando bem torturados, são capazes de confessar qualquer coisa. Eu concordo. Sempre que você ouvir números impressionantes gaste algum tempo pensando, aplique um pouco de matemática básica e duvide um pouco do que você ouviu.

Vi no Facebook hoje o pessoal compartilhando esse artigo:

Paulistas compram mais carros por hora do que roraimenses o mês todo

O artigo destaca o fato de que “São Paulo vendeu em agosto o dobro do segundo colocado e 212 vezes mais do que Roraima, o último do ranking”, dando a impressão ao leitor de que isso é reflexo de uma tremenda desigualdade social.

Acontece que a população de São Paulo é maior que o dobro que a de Minas Gerais, segundo colocado no ranking de venda de carros. Assim, per-capita, o mineiro comprou quase a mesma quantidade de carro que o paulista em agosto.

Veja, para cada dez mil habitantes em São Paulo foram vendidos 28 veículos, e em Minas 26. E quanto a Roraima? Bem, as diferenças sociais são gritantes. Mas o artigo coloca as coisas assim:

São Paulo vende por hora 621 unidades, mais do que Roraima vende por mês: 538.

Olhando assim, parece que o paulista ganha dezenas de vezes mais dinheiro que o roraimense. Mas em Roraima, para cada dez mil habitantes, foram vendidos 11 carros. Ainda uma desigualdade, claro, mas não de dezenas de vezes, não é?

Em tempo: antes que os comentários enveredem por esse assunto, eu concordo que nossas cidades precisam de menos carros e mais bicicletas/metrôs/corredores de ônibus/trabalho remoto. Mas o fato de isso ser uma boa causa não nos dá o direito de fazer esses absurdos com os números, não é?

Qual é exatamente o problema com eval()?

Para iniciar este post, é preciso deixar algo claro: diferente da minha postura com os polêmicos ponto-e-vírgula, em que sei que sou “promíscuo e relaxado”, eu sou muito reticente quanto ao uso de eval() em javascript. O principal motivo é que eval() me cheira a gambiarra. Mas tenho muita dificuldade em dizer porquê. Na verdade, acho mesmo que é só uma questão de elegância.

Já li muita coisa sobre o assunto, mas nenhum argumento me convenceu. Os dois principais argumentos são performance e segurança. Em minha opinião nem um dos dois argumentos procede.

Performance

Em primeiro lugar, é preciso dizer que o argumento de que JSON tem pior performance raramente é verdade. Há alguns anos, código executado via eval não poderia ser cacheado ou pré-otimizado. Isso não é mais verdade hoje em dia. A V8 (Chrome), a Nitro (Safari) e a SpiderMonkey (Firefox) já trabalham com caching do código passado a eval em diversas circunstâncias. Além disso, pense nas situações em que eval seria útil. Não consigo imaginar uma em que performance seja um problema. Por exemplo, uso eval como um fallback para navegadores que não tem suporte nativo a JSON. Sinceramente, depois de um delay de dois segundos esperando por uma requisição Ajax, não faz absolutamente nenhuma diferença se interpretar esse retorno vai levar dez milissegundos a mais.

Alguém pode dizer que seria melhor nessa situação usar uma biblioteca JSON com validações, como a do Douglas Crockford. Mas isso acrescentaria 17Kb de código em troca de absolutamente nada. Alguém pode então argumentar que o que se ganha usando uma biblioteca dessas não é exatamente nada, mas pelo menos um validador do código antes da execução. Respondo a isso no final.

Segurança

O segundo argumento mais usado contra o uso de eval() é segurança. O fato de executar uma string, gerada dinamicamente, e não código escrito diretamente por você, pode dar calafrios. Puxa, mas não dá para ter a menor ideia do que será executado! Um agressor não poderia usar isso para executar código arbitrário? Isso não abre as portas para ataques XSS ou man-in-the-middle?

Aqui também, ninguém nunca conseguiu me demonstrar um único caso em que isso fosse uma preocupação real. Imagine o caso de uso que citei acima, por exemplo, de fazer parsing de dados JSON vindos via Ajax. Embora o código que vá passar por eval() não esteja no seu javascript, ele efetivamente foi escrito por você, no servidor. Se alguém consegue acesso a sua aplicação server afim de enviar dados maliciosos para suas requisições Ajax, por que ele se daria ao trabalho de fazer isso se ele poderia simplesmente gerar Javascript malicioso ou HTML malicioso? Se alguém teve esse nível de acesso a seu servidor, XSS é a menor de suas preocupações.

Outra variação do argumento da segurança diz que se você usa eval() a partir de uma entrada de dados do usuário, isso sim poderia abrir as portas para a execução de código malicioso. É preciso lembrar aqui que código javascript roda no client. Assim, o fato de eu poder digitar um script malicioso num campo de formulário, por exemplo, não significa nada exceto o fato de que posso “invadir minha própria máquina”.

Claro, se você recebe os dados gerados por esse eval() no servidor sem validá-los, isso pode causar problemas. Mas, nesse caso, o problema não está no eval() mas em sua validação porca no servidor. Se não houvesse eval() no código, a mesma coisa poderia ser feita na Firebug ou no console do Chrome.

Há ainda a preocupação com buscar dados de um servidor externo e executá-los, o que faria com que seu site possa executar código malicioso. Bom, se você inclui javascript em sua página gerado pelo Google Analytics, e pelo Twitter, Facebook, AddThis e outros geradores de widgets, porque não confiaria em executar código dessas mesmas fontes via eval()? Qual é exatamente a diferença?

Em suma, se as fontes de dados para o eval() não são confiáveis, não use-as de jeito nenhum. O problema não está no eval().

Qualidade de código

Um último argumento, menos usado mas em minha opinião mais relevante, tem a ver com a qualidade de código. O principal motivo que me faz evitar o uso de eval() é o fato de, se houver algum erro no código avaliado, será bem mais difícil debugar. O navegador vai acusar o número da linha do eval(). Esse é um forte argumento, mas não para todas as situações. Geralmente eu gero JSON no servidor com uma biblioteca ou módulo bastante confiáveis, tanto em PHP quanto em Python. Quais são sinceramente as chances de meu software falhar porque há um problema na biblioteca padrão de JSON do PHP?

Por isso, eu não costumo trocar um simples eval() pelo uso de uma biblioteca de JSON, por exemplo.

Fazendo errado

Não importa quão útil e boa seja uma ferramenta, sempre há uma infinidade de maneiras erradas de usá-la. Vi esses dias código assim:

eval('document.'+obj).className='selected'

Esse código é muito ruim, demonstrando um desconhecimento básico dos recursos da linguagem. Pode facilmente ser substituído por isso:

document[obj].className='selected'

Entenda que este artigo questionando os argumentos comuns contra o uso de eval() não é uma defesa de seu uso, principalmente de seu uso indiscrimado.

Seu argumento

Perdi alguma coisa? Há algo mais que precise ser dito? Por favor, fique à vontade para deixar seus comentários.

 

 

 

XML não é a resposta 2: parsing

Em meu último post sobre esse assunto, expliquei porque prefiro, na maioria dos casos, usar um formato de descrição de dados como JSON ao invés de XML. Infelizmente, parece que nem todo mundo concorda comigo, e há uma porção de dados úteis disponíveis apenas em XML. O que não é um problema, certo? Do que eu estou reclamando? Os dados estão lá, disponíveis publicamente, muitos de graça, e eu aqui reclamando do formato?

Vamos dar um jeito e ler XML!

A maneira óbvia parece ser usar um parser de XML, e é o que eu faço na maioria dos casos. Toda linguagem e ambiente de desenvolvimento hoje possuem bons parsers de XML para você escolher. Mas nem sempre o parser de XML é a melhor solução.

Vamos tomar como exemplo o retorno do rssWeather.com:

http://www.rssweather.com/wx/br/sao+paulo+aeropor-to/rss.php

A resposta é um RSS com uma tag content:encoded, contendo uma seção CDATA com um trecho de HTML. Você vai ter que fazer duplo parsing se quiser as informações de dentro desse HTML. Ou pode adotar uma solução assim:

import urllib2,re
url='http://www.rssweather.com/wx/br/sao+paulo+aeropor-to/rss.php'
xml=urllib2.urlopen(url).read()
data=dict(re.findall('<dt.*>(.*)</dt><dd.*> ?(.*)</dd>',
        xml.replace(':','').replace('&#176;','\xc2\xb0')))

Cinco linhas de código. Dê uma olhada no retorno disso:

>>> data
{'Barometer': '1028 mb', 'Wind Speed': '10 KMH', 'Dewpoint': '15\xc2\xb0C', 'Wind Direction': 'SSE (160\xc2\xb0)', 'Visibility': '6 km', 'Humidity': '93%', 'Wind Chill': '15\xc2\xb0C', 'Heat Index': '16\xc2\xb0C'}
>>> for i in data.iteritems(): print '%s => %s' % i
... 
Barometer => 1028 mb
Wind Speed => 10 KMH
Dewpoint => 15°C
Wind Direction => SSE (160°)
Visibility => 6 km
Humidity => 93%
Wind Chill => 15°C
Heat Index => 16°C

É importante entender os riscos que estamos assumindo ao adotar essa solução. Se o formato desse HTML for ligeiramente modificado, nosso código pode parar de funcionar. Neste caso, como os dados estão em HTML dentro do XML, isso não é uma desvantagem, porque você teria o mesmo tipo de problema usando um parser SGML.

Será que conseguimos a mesma simplicidade lendo HTML?

import urllib2
url='http://www.bancocentral.gov.br/'
html=urllib2.urlopen(url).read()
dados=html.replace(',','.').split('')[0].split('\r\n')[-7:]
dados=map(float,(dados[0].strip(),dados[3].strip()))

Veja o retorno:

>>> print 'Compra: %.4f, Venda: %.4f' % tuple(dados)
Compra: 1.7784, Venda: 1.7792

XML não é a resposta

Não me entenda mal, XML é uma idéia interessantíssima, pela qual sou apaixonado. Tenho dado aula de XML, escrito HTML como XML válido, publicado e consumido dados em XML, acompanhado as iniciativas de Open Data e RDF no W3C.

O problema é que, enquanto alguns mercados subutilizam XML, tornando o intercâmbio de dados muito complexo, outros exageram no uso. XML não é a panaceia da troca de dados.

Há, por exemplo, uma porção de sistemas que usam XML como arquivos de configuração. Isso torna complicado o trabalho de editar esses XML, e na maioria dos casos torna complicado o parsing disso para rodar o sistema.

Veja um breve exemplo: a busca do Twitter está disponível em três formatos, HTML, ATOM e JSON. Teste a busca a seguir nesses três formatos (veja a diferença nas URLs):

http://search.twitter.com/search?q=%40elcio (HTML)

http://search.twitter.com/search.atom?q=%40elcio (ATOM)

http://search.twitter.com/search.json?q=%40elcio (JSON)

A maneira como o Twitter publica suas buscas é inspiradoras. O formato ATOM servirá para leitores de feeds e para aqueles programadores que adoram escrever parsers XML. E para o resto do mundo, temos JSON. Veja como consumir a URL JSON e obter dados nativos no Python:

import json,urllib2
url='http://search.twitter.com/search.json?q=%40elcio'
dados=json.load(urllib2.urlopen(url))

A dica então é se perguntar se XML é necessário e, se não tiver um bom motivo para usá-lo, trabalhar com JSON, YAML ou, quem sabe, um arquivo de configuração declarando variáveis em sua própria linguagem.

Dica de Python: glob

Um módulo Python pequeno, com uma única função muito simples, mas que você precisa conhecer é o glob. O que ele faz é obter uma listagem de diretório:

import glob
files=glob.glob('*')

O que equivale a:

import os
files=os.listdir('.')

Porém o glob é muito poderoso. Podemos fazer:

glob.glob('*.mad')

Ou:

glob.glob('../pasta/*')

Fica a dica.

Parallel Python

Embora seu computador possa ter dois, quatro, oito ou até dezesseis núcleos de processamento, o Python só usa um deles de cada vez (mesmo trabalhando com threads). Parallel Python resolve o problema. Um exemplo simples, para você entender como funciona:

ppserver = pp.Server(ppservers=())
job1 = ppserver.submit(funcao_demorada, (), (), ())
job2 = ppserver.submit(funcao_demorada, (), (), ())
print job1()+job2()

Os quatro argumentos do método submit são: a função que será executada, os argumentos passados a ela, as funções que ele pode chamar e os módulos dos quais ela depende. Veja um exemplo de como chamar com esses parâmetros:

ppserver = pp.Server(ppservers=())
job1 = ppserver.submit(funcao_demorada, (44,), 
                        (sub_funcao,), ("sys","math",))
job2 = ppserver.submit(funcao_demorada, (25,),
                        (sub_funcao,), ("sys","math",))
print job1()+job2()

Divirta-se!

Desafio de programação: resolvendo Lights Off

Fiz essa versão do clássico joguinho Lights Off:

O jogo é simples, e o objetivo é apenas apagar todas as luzes. Por curiosidade, fiz também o algoritmo que resolve o jogo:

O desafio está lançado. O primeiro que colocar nos comentários a URL de uma página com um botão “solve” como o meu ganha uma entrada para o Codeshow. Importante:

  1. Vale o primeiro comentário. Mesmo que você comente de madrugada e eu demore a moderar, ganha quem comentar primeiro.
  2. O solucionador tem que ser escrito em Javascript. Você pode copiar minha versão do jogo e desenvolver em cima dela.
  3. Não pode resolver na base da tentativa e erro. Tem que ser uma boa solução, que resolva qualquer estado do tabuleiro em 20 passos ou menos.

Divirtam-se!

(O pessoal da Visie, se quiser participar, pode. Só não vai ganhar nada ;-))

utf8_decode em Javascript

Navegando por aí, acabei esbarrando no blog do meu amigo Marcos Rossow (nossa, quanto tempo!)

E encontrei esse post: JavaScript UTF-8 Decode, com um código tirado daqui: JavaScript utf8_decode.

Tem duas coisas que me incomodam nessa abordagem. A primeira é essa mania que muita gente tem, particularmente programadores PHP, de tratar UTF-8 como um “código alienígena” e ISO-8859-1 como normal e padrão. Alô, ISO-8859-1 é usado por parte do mundo. Não dá para escrever hebraico, mandarim, japonês, árabe ou russo com isso. ISO-8859-1 é uma das diversas tabelas de caracteres que existem mundo afora. E Unicode é a única maneira sensata de escrever um sistema que possa ser usado aqui e na China.

A segunda coisa que me incomoda é a quantidade de código. Não testei profundamente, mas tenho a impressão de que o código abaixo resolve o problema:

function utf8_decode(t){
  return decodeURIComponent(escape(t))
}

Hein?

Trecho de código legado (ASP) que pegamos aqui:

if len(request("price")) = 3 then
    valorTotal = left(request("price"),1)
elseif len(request("price")) = 4 then
    valorTotal = left(request("price"),2)
elseif len(request("price")) = 5 then
    valorTotal = left(request("price"),3)
end if

Jênio.

Brincando com a API do twitter

Resolvi experimentar um pouco a Twitter API. É linda, do jeito que toda API deveria ser. É REST, muito fácil de entender e colocar para funcionar, e devolve dados em XML, JSON, RSS e ATOM.

Essa simplicidade permite interagir com a API usando ferramentas simples da linha de comando do Unix, como o wget e a cURL. Para nossos exemplos, vamos usar cURL. Se você usa Ubuntu, antes de começar faça:

sudo apt-get install curl

Para fazer um simples post, por exemplo, você pode digitar, em seu terminal:

curl -u seu_username:sua_senha -d status="Twittando do terminal. Aprendi com o Elcio: http://blog.elcio.com.br/brincando-com-a-api-do-twitter/" http://twitter.com/statuses/update.json

É isso mesmo, meninos e meninas, é só um post com autenticação, mais nada. RESTful, simples e elegante, deixar qualquer SOAP no chinelo. Inspirador para qualquer um que precise projetar uma API. Isso retorna dados em JSON. Se você quiser os mesmos dados em XML, ATOM ou RSS, basta mudar a extensão na url.

Agora vamos automatizar isso. Eu criei um arquivo /usr/local/bin/twitter com o seguinte conteúdo:

source $HOME/.twitter
curl -u $user:$password -d status="$@" http://twitter.com/statuses/update.json

Naturalmente, criei o arquivo como root e dei permissão de execução para todos os usuários. Agora, no diretório de cada usuário, basta criar um arquivo .twitter com o seguinte conteúdo:

user=seu_username
password=sua_senha

Pronto, tendo feito isso, qualquer usuário que tenha o arquivo .twitter em seu home pode twittar do terminal com:

twitter "Twittando do terminal, aprendi com o Elcio: http://blog.elcio.com.br/brincando-com-a-api-do-twitter/"

Simples e indolor, agora você pode automatizar suas twittadas com shell script. Pode, por exemplo, twittar toda vez que seu servidor baleiar, ou agendar twits com cron.

Search API

A Search API também é espetacularmente simples, dê uma olhada. Fiz a UPBox usando a Twitter Search API, por exemplo, com 22 linhas de código.

Fuja da complexidade

Abri o OpenOffice Writer, mandei gravar uma macro, escrevi “teste”, selecionei e pintei de vermelho. Olha o código gerado:

sub Main
rem ----------------------------------------------------------------------
rem define variables
dim document   as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
rem ----------------------------------------------------------------------
dim args1(0) as new com.sun.star.beans.PropertyValue
args1(0).Name = "Text"
args1(0).Value = "teste"
dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args1())
rem ----------------------------------------------------------------------
dispatcher.executeDispatch(document, ".uno:SelectAll", "", 0, Array())
rem ----------------------------------------------------------------------
dim args3(0) as new com.sun.star.beans.PropertyValue
args3(0).Name = "FontColor"
args3(0).Value = 16711680
dispatcher.executeDispatch(document, ".uno:FontColor", "", 0, args3())
end sub

Há muito código complexo por aí. Nesse caso, para invocar os métodos dos objetos do OpenOffice, é preciso usar um objeto dispatcher, chamando executeDispatcher, e passando o objeto, o nome do método e um array de argumentos. Que espécie de sadismo leva alguém a projetar uma solução como essa? Vale lembrar o que diz o Zen do Python:

Se uma implementação é difícil de explicar, é uma idéia ruim.

Outro exemplo interessantíssimo é o protocolo SOAP. Se você precisar construir um serviço SOAP do zero, dê uma investigada na documentação que você vai ter que ler. Compare com a documentação do protocolo XML-RPC, para ter uma idéia.

Meninos, o tio vai ensinar um segredo a vocês, a complexidade se reproduz assexuadamente. Há muito código complexo demais por aí. Se você encontrar indícios de complexidade hoje, corte antes que ela se reproduza, porque ela tende a fugir do controle. Cada vez que você deixa uma implementação complexa num componente de um sistema, você está complicando um pouquinho todos os pontos do sistema que usam aquele. Os resultados ruins são exponenciais. Por mais talentoso que você seja, se deixar a complexidade se enraizar e crescer, vai chegar um momento em que a lógica vai “jogar a toalha” e você vai começar a programar na base da tentativa e erro.

Lembre-se, então, partes simples, conectadas por interfaces simples. Complicado é errado, feio e mau, faz você entregar atrasado e com bugs. E, se precisar de inspiração, abra o Python e digite:

import this

Data errada no Javascript? Bug?

Um amigo me escreveu agora para mostrar algo muito curioso. Abra sua Firebug, ou qualquer outro lugar onde você roda Javascript, e teste:

new Date(2008,8,11)

Você deve ter como retorno um objeto de data, que se impresso mostra:

Thu Sep 11 2008 00:00:00 GMT-0300 (BRT)

Porque setembro e não agosto, você pode se perguntar. É porque em Javascript, assim com na maioria das linguagens de programação, arrays começam com zero, então faz sentido que contadores também comecem com zero. Assim, janeiro é o mês zero, e se você precisar construir um array com os nomes dos meses, janeiro será o primeiro do array. Faz todo o sentido.

Agora, o que não faz sentido. Tente:

new Date(2008,9,12)

Aqui no meu sistema eu obtive:

Sat Oct 11 2008 23:00:00 GMT-0300 (BRT)

Ou seja, uma hora mais cedo. O que será isso? Correção para o horário de verão? Se é, em que regra se baseia? Os horários de verão no Brasil mudam todo ano, e dependem de em que estado você está.

Alguém tem alguma dica?

Não entre em pânico

Você está usando um terminal conectado a um servidor Unix quando as coisas começam a se comportar de maneira estranha. Depois de algum tempo você descobre o problema. Vai até a mesa de um programador novato e descobre que ele, como root, digitou:

# cd
# rm -rf *

O sujeito percebeu a burrada antes de apagar os diretórios /usr e /users. Nesse caso, /users continha os diretórios home. Mas todo o resto do sistema se foi, incluindo /dev, /etc e /bin.

O que você faria? Para complicar as coisas, esta história aconteceu há um bocado de tempo, numa VAX. Ou seja, não era só fazer um boot com um live-CD, fazer um backup dos dados dos usuários e reinstalar o sistema.

O que fazer? Não entrar em pânico. Uma história e tanto.