Novo Blog

Novo endereço

https://blog.nilo.pro.br

sábado, 12 de março de 2011

Khan no TED


Eu ainda me impressiono com a Khan Academy. Fantástica ferramenta para quem precisa relembrar e aprender conceitos de matemática, física, etc. Agora ele ataca problemas de nivelamento entre estudantes com ritmos de aprendizagem diferente. Quando teremos este tipo de iniciativa em português? Vídeos e não mini novelas! O potencial das video aulas, com playback controlado pelos alunos é interessante, mesmo em áreas sem Internet ou infra-estrutura para video aulas transmitidas ao vivo.

terça-feira, 8 de fevereiro de 2011

Programe ou seja programado

Leia no novo blog
Eu vi este vídeo ano passado, mas como não tinha legendas em português... não o coloquei aqui.
Porém, mesmo sem legendas, estas ideias não poderiam ficar sem um comentário breve.
Assista ao vídeo:



Douglas Rushkoff apresenta a importância do conhecimento de programação no mundo moderno.
Não que ele defenda um mundo de programadores ou que aborde uma linguagem de programação X ou Y.
O que é fantástico no vídeo é a relação entre a invenção da escrita, programação e as mídias modernas.
Do início do compartilhamento do conhecimento através da escrita, de livros e depois com a invenção da prensa moderna, ele compara o acesso do cidadão comum a cada uma destas formas de transmissão do saber. Como esse conhecimento era controlado e distribuído entre as pessoas comuns e como sempre a sociedade comum estava um passo atrás das últimas tecnologias de produção e distribuição deste mesmo conhecimento.

A questão é realmente saber se hoje estamos ficando para trás, ao não incluirmos a programação no mundo de nossos filhos. Hoje, tão importante quanto ler e escrever, programar é necessário. De uma simples planilha a sistemas complexos, diferentes níveis de programação são utilizados. Assim como a invenção da escrita não levou a uma sociedade de escritores, como apresentado no vídeo, a programação não criará uma sociedade de programadores. O ponto é realmente ter ideia do que pode ser programado, de ter noções básicas de como as coisas funcionam e não de simplesmente utilizar os meios como nos são fornecidos: Twitter, Facebook, Google e mesmo a web.

O vídeo postado pela Wilmara no Facebook me chamou a atenção para o problema da educação:



Isso me fez pensar no por quê meus filhos ainda perguntam que língua é falada em tal ou tal país... tendo a Wikipédia e o Google disponíveis. Eles sabem acessar o Facebook, jogos e principalmente o YouTube. Mas a capacidade de síntese não é dada ou ensinada na escola. Continuamos a ensinar a decorar e não a reunir novas informações e criticar o conhecimento. Lembro do tempo que passei para achar o nome científico de 10 animais quando estava no primário... hoje isso seria feito em segundos!

O foco continua sendo: ler, memorizar, repetir. Eu fui confrontado com esta realidade no meu primeiro emprego, como professor de lógica de programação. Os alunos estavam na faixa dos 15 anos, e eu tinha acabado de completar 18. Quando começamos a trabalhar com problemas simples de matemática, como porcentagens e proporções a casa caiu. Isso era muito estranho, pois eu era professor numa escola técnica, digamos elitista do ponto de vista que você tinha que ser aprovado num concurso para estudar lá. Não eram alunos ruins ou com problemas de aprendizado, mas alunos acima da média! O que alguns tinham dificuldade era em como utilizar o conhecimento passado através de exercícios de cálculo para uma nova realidade. Repito, não era problema em calcular, mas de saber que técnica já conhecida utilizar para resolver um problema similar, mas em outro contexto. Era simplesmente desenvolver suas equações, escrever enunciados de novos problemas, aplicar o que já sabiam, o contrário da forma como tinham sido preparados a vida toda!

Traçando um paralelo: será que ao invés de apenas deixar nossas crianças assistirem vídeos no YouTube, deveríamos ensiná-las a criar seus próprios vídeos? A escrever corretamente, ou pelo menos tentar escrever corretamente, usando wikis e mesmo criando suas próprias home pages? Aqui falamos de programação em sentido mais amplo, como dominar as ferramentas que utilizamos. Afinal, eu não sou artista, mas recebi noções básicas de arte na escola... ainda sei combinar cores, embora não saiba desenhar ou pintar. Precisamos ensinar nossas crianças a dominar as novas mídias. Não para criar uma sociedade de programadores, mas para evitar que eles simplesmente consumam conhecimento sem a menor noção de como este é produzido, armazenado, disponibilizado e principalmente as formas que pode ser controlado.

Vídeo bônus:

Only at OR Books: Program or Be Programmed by Douglas Rushkoff from OR Books on Vimeo.

quinta-feira, 2 de dezembro de 2010

Livro de Introdução Programação com Python já está venda

Leia no novo blog

Nada como uma noite fria e cheia de neve para colocar o blog em dia!
Meu livro de programação foi publicado pela Editora Novatec e já está disponível para venda.
Eu criei uma página sobre o livro, com links para livrarias e emails de contato:

http://www.nilo.pro.br/iprog/

O livro foi escrito de forma a apresentar novos conceitos gradualmente, com exemplos e exercícios.   Quando comecei a dar aulas, eu ensinava Basic e Pascal. Com o Basic, tinha o problema dos números de linha. Com o Pascal os ponto-e-vírgula... era muita coisa para escrever antes de começar a programar. Nestes casos, o uso de um pseudo-código claro e simples, livre de símbolos em excesso era interessante. Eu evitei usar pseudo-código ou fluxogramas, pois acredito que ao se aprender a programar, o melhor é ir direto ao ponto. Com a linguagem Python, isso tudo fica muito mais simples. Escrever em pseudo-código pode até ser mais complicado que escrever em Python!
O leitor/aluno precisa ver algo acontecer para continuar estudando. O importante é saber ler o programa e entender o que vai acontecer quando o programa for executado. Eu realmente acredito que o aluno deve saber se o programa está correto antes de executá-lo. A execução é apenas uma confirmação. Uma seção sobre rastreamento foi incluída no livro, para preservar esta importante etapa no aprendizado de programação.

A clareza e simplicidade da linguagem são realmente muito importantes para facilitar o aprendizado. Python torna a programação acessível par estudantes de outras áreas e não apenas de computação e engenharia.
Outra característica do Python é que ela permite usar quase tudo que temos no computador. Uma vez aprendendo a programar em Python, pode-se continuar estudando outras linguagens de programação ou partir diretamente para aplicações web, jogos, banco de dados, etc. O caminho é mais suave e sem interrupções. Não serve apenas de linguagem introdutória, mas do dia a dia.

Escrever um livro era algo que eu sempre quis fazer. Dá muito trabalho, tem que ler, reler, re-escrever e corrigir inúmeras vezes. O trabalho de revisão é realmente incrível, principalmente com a nova ortografia e com os desafios de escrever um livro técnico para leigos. Ter uma editora ajuda muito nesta tarefa, pois sozinhos nós começamos a não perceber mais os erros. Digo nós porque minha esposa ajudou na revisão.


Título: Introdução à Programação com Python
Autor: Nilo Ney Coutinho Menezes
ISBN: 978-85-7522-250-8
Páginas: 224

Editora: Novatec
Ano: 2010


Resenha do Livro:


Este livro é orientado ao iniciante em programação. Os conceitos básicos de programação, como expressões, variáveis, repetições, decisões, listas, funções e arquivos, são apresentados um a um com exemplos e exercícios. A obra visa explorar a programação de computadores como ferramenta do dia a dia. Ela pode ser lida durante um curso de introdução à programação de computadores e usada como guia de estudo para autodidatas. Para aproveitamento pleno do conteúdo, conhecimentos básicos de informática, como digitar textos, abrir e salvar arquivos, são suficientes. Todo software utilizado no livro pode ser baixado gratuitamente, sendo executado em Windows, Linux e Mac OS X.
Embora a linguagem Python (versão 3.x) seja muito poderosa e repleta de recursos modernos de programação, este livro não pretende ensinar a linguagem em si, mas ensinar a programar. Alguns recursos da linguagem não foram utilizados para privilegiar os exercícios de lógica de programação e oferecer uma preparação mais ampla ao leitor para outras linguagens. Essa escolha não impediu a apresentação de recursos poderosos da linguagem, embora o livro não seja fundamentalmente uma obra de referência.

Sumário (PDF)

sexta-feira, 13 de agosto de 2010

Um vídeo sobre educação

A pensar:



Disponível com legendas em português e outras línguas.
Clique em View Subtitles e depois em portuguese (Brazil).

domingo, 11 de julho de 2010

Como não desenvolver software

Eu nunca vi dois programadores desenvolverem o mesmo programa da mesma forma. Dizer o que é certo em desenvolvimento de software é muito difícil, tudo depende de quais correntes de pensamento você segue. Orientação a objetos, script-maníacos, programação funcional? Tem espaço para todo mundo e ninguém escapa em maior ou menor grau de vários sintomas aqui descritos.

Algumas coisas são tão ruins que mesmo em um assunto tão "quente" como desenvolvimento de software, pode-se achar um consenso. Eu vou relatar algumas das más práticas que conheci, pois acredito que elas são bastante comuns, especialmente com as novas tecnologias, Internet e código open source. Quanto maior o time de desenvolvimento, mais frequentes ficam esse pequenos problemas. O intuito deste post é relatar algumas experiências com o mesmo rigor científico de uma conversa de bar. Todas as afirmações são relativas e dependem do humor de quem as lê. Tudo deve ser encarado com várias pitadas de sal e bom humor. Eu avisei :-D
  • Over-engineering: quem nunca viu um pequeno exemplo com 1000 linhas de código não sabe do que estou falando... era para ser um "Hello World"... 1000 linhas depois ninguém sabia o que era. Um programa de computador precisa ser razoavelmente robusto a falhas, mas existe uma grande diferença entre uma aplicação crítica e uma aplicação simples, que pode simplesmente parar de funcionar e dar uma mensagem de erro! O sintoma se apresenta quando a confiabilidade do Sol começa a ser posta em jogo. E a pergunta cruel surge: quando o Sol explodir, o que faremos? Variações desta realidade são exigências como confiabilidade e disponibilidade de sistemas web comparáveis às do Facebook ou do Google, exceto que você ainda não tem o tráfego nem o dinheiro destes sites. Variações incluem o desejo incotrolável de utilizar o maior número de patterns no maior número de classes possível. Nada pode ser feito em apenas uma classe. Classes ficam melhor em dúzias. Porque deixar para um futuro refactoring o que já pode ser feito hoje?
  • Paralisia por análise: quando os programadores se lançam na quest máxima: a busca DO framework. Perdem-se às vezes meses com experimentos para simplesmente escolher um novo framework, ignorando toda a experiência anterior do time, ou que o tempo perdido não volta mais. Em informática é muito difícil escapar desta situação, principalmente com software open source, constantemente atualizado e melhorado. Parar de trocar pode simplesmente significar a morte do programador, ou sua condenação ao castigo máximo, como programar para sempre em Clipper ou Cobol :-D A questão é que uma decisão deve ser tomada e normalmente nenhum framework oferece solução para tudo, ou torna tudo simples, fácil e claro. Algumas pessoas buscam soluções que "não dão trabalho", mas esquecem que o fruto desta automatização é normalmente seguir padrões e conceitos do novo framework, conceitos que demandam tempo para ser aprendidos. Uma mistura de paralisia por análise com over-engineering é quando o time resolve encontrar uma solução perfeitamente escalável, adaptável a qualquer cliente e que possa rodar por uns 10 anos com pouca manutenção... ou seja, buscam alcançar o nirvana da programação. Isso não é desculpa para não analisar as melhores alternativas para resolver o problema, mas esta análise não deve durar mais tempo que o desenvolvimeno da solução em si.
  • Bala de prata: é quando o time decide resolver tudo com a mesma tecnologia sempre. Normalmente com C ou Java, mas começam a aparecer mais e mais casos com linguagens scripts. A verdade é que não existe bala de prata (no sentido de solução universal), nem lobizomem. Toda solução deve ser cuidadosamente analisada, dentro de um prazo bem definido, para não cair no problema da paralisia. Já se dizia há muito tempo: "Se a única ferramenta que você conhece é um martelo, tudo vira prego". 
  • Time Bom Bril: é o sonho de todo gerente de software. Um time multiplataforma, multilinguagem, com profissionais altamente inteligentes, simpáticos e dóceis. Entre outras características deste tipo de alucinação é usar "O time" em todo e qualquer tipo projeto, ignorando o conhecimento de domínio. Hospital, eleições, lançamento de foguetes, hardware? Não tem problema, "O time" resolve. Além deste tipo de patia causar danos ao pobres membros do time, a perda de produtividade é enorme, causando a aparição do folclórico Jack-of-all-trades-master-of-none. Ninguém consegue dominar tudo e alcançar resultados excelentes em tudo, isso é ilusão. Profissionais altamente capazes podem aprender muito rápido e superar o resultado de times ordinários, mas isso tem um preço. A pulverização de esforços e a constante pressão podem queimar um time de desenvolvimento muito rápidamente.
  • Cada um por si e ninguém por todos: muitos chefes atrapalham, mas quando não há algum chefe, todos são chefes! Essa é fácil de se cair quando se tem um time super star ou um dream team em determinada tecnologia. Como todos são profissionais de alto valor e experientes, independência total é dada a cada membro do time. No final, ninguém se entende, pois cada membro do tal time resolveu utilizar as práticas e conceitos da corrente de desenvolvimento que mais lhe agrada. No fim, a empresa fica com uma salada de códigos-fonte, provavelmente escritos em várias linguagens de programação, frameworks diferentes, etc. Um pouco de ordem ajuda a manter a sanidade do time.
  • Commits preciosos: alguns times são intruídos a só "comitarem" suas alterações após finalizarem sua tarefa de implementação. Isso funciona bem e evita que código inacabado perturbe o desenvolvimento de outros desenvolvedores devido a anomalias no build. O problema é que algumas pessoas não dividem as tarefas em espaços razoáveis de tempo. O sintoma são commits quinzenais ou mesmo mensais! Indagados sobre a prática, alguns podem responder que fazem isso para não poluir o repositório com commits pequenos. A questão toda é que o próprio desenvolvedor precisa de um sistema de controle de versão para seu desenvolvimento inacabado. Se um sistema de controle de versão distribuído, como o GIT ou Mercurial é usado, pode-se resolver este tipo de problema com branches locais. Com SVN não tem muito jeito... você tem que comitar após testar e garantir que o que foi commitado não quebra o build. Se algo estiver errado, o sistema de controle de versão tem ferramentas para corrigir estas falhas. Além disso, fazer o merge após um mês de desenvolvimento pode ser muito trabalhoso, pois a probabilidade de se ter alterado o mesmo arquivo que outras pessoas é alta, gerando conflitos.
  • Repo killer: quando um membro decide comitar e atualizar apenas partes do repositório, privando os outros membros do time de trabalharem com a mesma versão do código. Essa é inexplicável. Uma variação é o desenvolvedor que escolhe a dedo o que atualizar, esquecendo de incluir novos arquivos e mudanças que nem ele mesmo lembra que fez. Esse problema é uma bomba relógio, pois as diferenças entre os repositórios será evidente cedo ou tarde.
  • Builds locais: poupar o dinheiro de uma máquina de build pode ser a pior economia a fazer em um time de software. Se apenas uma pessoa desenvolve o código, você só saberá que tudo foi comitado ou não no dia que ela sair da empresa. Aí começa a caça aos arquivos perdidos. Outro grande problema é a não documentação do ambiente de desenvolvimento, mas esse problema aparece mais rápido, normalmente quando o HD do desenvolvedor pifa e ele passa uma semana para lembrar tudo que usava (IDE's, bibliotecas, paths, etc). Esse problema também expõe um mais grave: a falta de testes.
  • Ausência de testes: uma das causas de se perder um usuário de seu sistema é transformá-lo em testador. Para isso, você não desenvolve testes automatizados e normalmente não realiza qualquer controle de releases. Isso gera inúmeros problemas durante todo ciclo de desenvolvimento e o único teste acaba sendo feito pelo compilador. Um código que compila está longe de estar livre de erros. Não controlar os erros já reportados pelo usuário é grave. Não corrigi-los é pior e ressuscitar bugs antigos por falta de testes é imperdoável.
  • Zipmania: desenvolvedores param de usar o sistema de controle de versão e começam a trocar Zips com nomes poderosos por IM: sistema20100610_XPO.zip. O vetor de transmissão é um desenvolvedor suicida que resolve fazer a integração na máquina de outro desenvolvedor, antes de fazer os devidos commits, para "evitar conflitos". Fica melhor ainda quando eles começam a criar zips para "congelar" um release e fazer "backup".
  • Variáveis com apenas dois ou três caracteres: essa é muito boa. Um dia você será castigado, tendo que rastrear código em C que usa strtok e variáveis como z, zz e zzz! Fica mais interessante quando esse código é responsável por crashes imprevisíveis no código, do tipo null pointer/segfaults :-D. O pior é que o carrasco pode ter sido você mesmo! É sempre bom comentar o código, principalmente quando o método implementa algo mais complexo que 10 linhas. Mesmo que você não comente, o minimo que pode ser feito é utilizar nomes de variáveis que ainda signifiquem algo dentro de 6 meses ou 2 anos.
  • Gotos: código em C com goto ninguém merece. Tirando raríssimas exceções, usar goto's em C é imperdoável. Fica ainda pior quando os "labels" tem sempre o mesmo nome, em várias funções e o tal goto é escondido por macros. Eu aprendi programar nos anos 80, gotos eram a única saída em Basic, mas já eram abominados em C e Pascal há bastante tempo e mesmo antes (Dijkstra, 1968). Para programadores modernos, um goto é simplesmente um atentado a programação estruturada.
  • A praga do log: aqui os sintomas são diferentes dependendo da linguagem. Em C/C++ você pode usar o pré-processador para esconder seu log de DEBUG ou fazer a coisa certa e usar um framework descente. Em Java, você tem os loggers da vida. O pior que você pode fazer é usar múltiplos System.outs ou printfs para fazer o log na mão. A praga do log é que mesmo usando um framework, você acaba espalhando linhas de log para tudo e usando apenas dois ou três níveis de log. No final, você tem arquivos de log gigantescos que chegam mesmo a retardar a execução do programa. Eu já procurei causas de lentidão em sistemas Java para descobrir que tínhamos deixado o log das bibliotecas em C ligado! Simplesmente, cada linha do log abria, escrevia, dava um flush e fechava o arquivo na mesma linha, claro, escondendo tudo isso numa macro! C hoje em dia é tão rápido que você pode fazer barbaridades, mas quando você loga deste jeito dentro de um XML parser... a coisa explode.
  • Ignorar mensagens de erro do compilador: essa aqui é um prelúdio para o sofrimento. Se no gcc seu código não compila com -Wall ou se você é o rei dos pragmas do Visual C++, lembre que se estas mensagens fossem realmente pouco importantes, elas não seriam geradas pelo compilador! No Java, usa-se o -Xlint para ter warnings mais precisos. O importante é que seu build seja limpo! Isso faz com que qualquer erro seja rapidamente notado. O mesmo para os logs. Se tudo é mostrado na tela, você simplesmente pára de olhar, pois se acostuma a ver lixo ou mensagens que não são interessantes.
  • Localização tabajara: ao trabalhar com código para múltiplas línguas, melhor não improvisar. Java resolve este tipo de problema muito bem e o Python na sua versão 3 melhorou bastante. Misturar strings em páginas de código diferentes é fatal! Fazer localização com ifs no código é pior ainda. Até a Microsoft tenta forçar o uso de UNICODE no Visual C++. O pior é ignorar diferenças de codificação e mesmo de tratamento de mensagens. Além da ordem das palavras, línguas diferentes tem critérios também diferentes para ordenação de caracteres, plural e letras maiúsculas, por exemplo. 
  • Build scripts escritos em Perl e batches: quem ainda trabalha com Perl merece todo castigo :-D O problema são pessoas que não utilizam Perl e que tentam fazer scripts de build em Perl. O mais legal é quando o build é multiplataforma é os tais scripts geram código em C ou C#, sem nada dizer. Para melhorar a festa, pode-se utilizar múltiplos scripts (multiplicados pelo padrão: copy and paste, rename). Agora a cereja do sorvete é fazer isso tudo usando Windows ou Cygwin.
  • Babel: por que utilizar apenas uma linguagem de programação? Seu projeto pode ter muitas, você pode até deixar seus programadores escolherem a linguagem de programação mais adaptada a cada tarefa e depois reunir isso tudo via SOAP. Usar Perl com qualquer outra coisa é trabalhar contra a empresa. C/C++ e Java, tudo bem, um pouco de Python ok. Mas se seu código é realmente escrito partes em Basic, partes em C/C++/C# e você resolveu colocar a parte concorrente em F# é porque você já vive o sonho do .Net. O mesmo acontece em Java: Jython ou JRuby, Groovy e Scala. Você pode misturar como quiser, mas a manutenção do código vai ser um pesadelo. Quanto mais linguagens você utilizar, mais difícil será encontrar alguém capaz de trabalhar com todas estas linguagens. Lembre-se que toda linguagem evolui, forçando um esforço arqueológico para entender o que a versão X fazia com a versão Z. Melhor evitar ou pedir aprovação do alto conselho Klingon antes de começar a construir sua torre. E por que apenas uma torre? Você pode desenvolver seu código para múltiplas plataformas, para adicionar um pouco de tempero. Mesmo com Java, faz-se milagre: J2SE, Java ME CDC e Java ME CLDC... a festa! Com C# você pode brincar com o compact framework e por que não com Mono?
  • Demos: demo é coisa do cão :-D Quem trabalha comigo ouve essa todo dia. O problema de "demos" que elas são normalmente escritas para rodar apenas uma vez e num curto espaço de tempo. O que leva ao próximo problema. Uma demo é diferente de um protótipo. Um protótipo normalmente é criado para resolver um problema específico ou para demonstrar como os analistas entenderam o problema, um instrumento para refinar e melhorar programas. Uma demo é normalmente criada para demonstrar o domínio de uma tecnologia, é um PPT executável e com código fonte! Normalmente elas resistem a aposentadoria e tem a tendência a evoluir. O ambiente propício para proliferação é a véspera de exposições e eventos.
  • Códigos escritos para rodarem apenas uma vez: não acredite nisso. Uma vez que um programa é escrito, o universo conspira para que ele seja mantido por muito tempo. Quase nunca você vai escrever código para rodar apenas uma vez. Se for o caso, tenha certeza de apagar o bicho logo depois da primeira execução, só para garantir.
  • XML Doom: alguém resolve que tudo deve ser escrito em XML. Eu já via até métodos que recebem os seus parâmetros no formato mágico que começa com X. O mais interessante do XML é que ele foi criado para facilitar o intercâmbio de informações e também ser legível tanto por computadores quanto por seres humanos. A ideia era poder ter um formato simples, baseado em UTF, ou pelo menos ciente dos inúmeros problemas de internacionalização e de representação de dados binários em formato texto. A coisa começou a desandar quando começamos a escrever arquivos XML na mão, para facilitar o parsing de arquivos de configuração. O XML que deveria ser gerado pelo computador, acabou sendo gerado manualmente. Alguns conseguem ter a sorte de ter editores de textos adaptados e mesmo ferramentas que ajudam na árdua tarefa de criação destes monstros. Uma ideia muito boa que acabou sendo abusada. XML não deve ser usado pra tudo.
  • Copy and Paste hell: essa é a pior de todas. Se você copia e cola o mesmo código várias vezes, algo está errado. Ou você não usa os recursos de template de seu IDE (aqueles que transformam syso em System.out.println()) ou você está realmente perdido. Grave mesmo é se você copia grandes partes de código, criando métodos gigantes. Programas criados com alta participação de copy and paste demonstram um problema grave de modularização e normalmente não isolam conceitos adequadamente. Lembre-se que cada código copiado e colado terá os mesmos problemas do código de origem, se você tiver sorte, fazendo com que alterações e modificações tenham que ser propagadas para todas as cópias. É realmente um desafio a sua memória. Sempre se esquece um ou dois... e lá estarão os problemas. Duro mesmo é corrigir o mesmo problema várias vezes. Além disso o tamanho do programa cresce assustadoramente rápido. Depois de ver código em javascript com 10000 linhas por arquivo você fica com medo desta síndrome.

Parece comédia, mas tudo isso é real. Profissão alguma é perfeita ou sem dificuldades, a diferença em informática é que nós criamos e retiramos os obstáculos no nosso caminho :-). Normalmente misturando novas soluções com antigos problemas numa velocidade fantástica.

quarta-feira, 9 de junho de 2010

Lendo livros em formato PDF

Um problema que sempre tive com livros em formato PDF é marcar o ponto onde parei de ler para depois continuar. Nos últimos anos, livros em formato PDF se popularizaram e eu consumo principalmente os livros da Pragmatic Programmers neste formato. Um simples documento PDF de até 5 ou 10 páginas pode ser lido inteiramente em poucos minutos, mas um livro de 500 ou 600 páginas não pode ser consumido de uma só vez. É nesses casos que um leitor adaptado a esta tarefa é necessário.

No Mac eu vinha usando o Skim, um leitor de PDF que permite fazer anotações e outras modificações no PDF que só o Acrobat da Adobe permitiriam, a diferença é que o Skim é open souce. Com o Skim, pode-se utilizar uma barra de leitura que ajuda muito na hora de ler, principalmente para quem pula linhas como eu :-D

Mas como todo grande aplicativo de Mac, o Skim não tem versão para Ruindows e também não grava a última página de cada PDF... tornando a leitura de livros difícil. Para contornar este tipo de problema, eu acabei por utilizar anotações no meu telefone para registrar a página que parei em cada livro, verdadeiramente low tech.

Semana passada eu encontrei o Adode Digital Editions, gratuito e multiplataforma, desenvolvido pela mesma companhia que inventou o formato PDF. Ele foi criado para permitir acesso aos livros digitais da plataforma e-book da Adobe, mas também pode ser utilizado para ler livros já baixados em formato PDF ou ePub. A grande vantagem é poder utilizar o recurso de biblioteca, permitindo juntar os PDFs espalhados pelo disco rígido em uma só interface, organizar estes PDFs em pastas e marcar onde paramos de ler facilmente. No Digital Editions, quando reabro um PDF ele está exatamente na mesma posição que deixei da última vez. A interface é bem limpa e facilita a leitura, tendo apenas os controles básicos de navegação e visualização do PDF e opcionalmente o conteúdo a esquerda.

Ainda não experimentei em vários micros, mas como o recurso de criar uma conta na Adobe, acredito que a sincronização seja possível. Outros recursos parecem bem interessantes, como a possibilidade de emprestar livros. Por enquanto, a funcionalidade de marcar o último ponto de leitura e o tamanho de apenas 19Mb x 195Mb do Acrobat Reader para Mac já são bem interessantes.

sábado, 5 de dezembro de 2009

Configurando BIND para utilizar o servidor DNS Público do Google

O Google lançou esta semana o Google Public DNS, visando aumentar a velocidade de resolução de nomes de Internet.

A resolução de DNS (Serviço de Resolução de Nomes) é responsável por converter o nome de um site em endereço IP (www.google.com --> 64.233.163.163). Esse serviço é utilizado sempre que seu computador precisa de um endereço de Internet. Cada vez que um novo nome é convertidio em endereço IP, o resultado desta conversão é guardado em uma tabela de acesso rápido em seu computador para agilizar acessos futuros, ou seja, uma tabela cache ou simplesmente cache.

Um exemplo simples é resolver www.google.com. A primeira vez que você acessar o domínio, o serviço de DNS de seu computador vai verificar o cache local e retornar o endereço IP, mas como é a primeira vez que você tenta acessar o Google hoje, não vai encontrar este nome de domínio em sua tabela cache. Quando isso acontece, uma requisição será feita ao seu servidor de DNS.

Um servidor de DNS também faz um cache dos últimos domínios pesquisados, porém vai recorrer aos Root Servers da Internet caso também não tenha o domínio cadastrado. E assim funciona o DNS e toda a Internet como a conhecemos hoje. A grande questão é entender o problema que o Google Public DNS Resolve.

O primeiro problema é que o tempo de acesso entre computadores na Internet pode ser medido em milisegundos (uma eternidade em termos de transmissão de dados :-) ). O tempo de resposta (Round Trip Time - RTT) é simplesmente o tempo que um computador demora para enviar um pacote e receber a resposta de outro computador. Ou seja, o tempo que o computador A leva para receber a resposta do computador B. Um caso prático é o tempo exibido pelo comando ping. O comando ping envia um pacote usando o protocolo ICMP e espera a resposta do outro sistema, imprimindo o tempo entre a requisição e o recebimento da resposta. Quanto mais distantes os computadores, maior o tempo de acesso. Este efeito é causado pelos meios de transmissão (fibra, satélite, cabos, etc) e pelo roteamento da Internet.

Quando um servidor de DNS não encontra um nome de domínio/host em sua tabela cache, este precisa realizar uma nova pesquisa. No caso de www.google.com, a primeira pesquisa será ao servidor responsável pelos domínios .com sobre o endereço dos servidores do Google. Só então seu servidor fará outra pesquisa, desta vez perguntando o endereço de www ao servidor de google.com. A coisa piora quando você tem nomes com vários níveis, mas o servidor faz um cache destas requisições de forma a evitar todo esse trabalho a cada acesso. O tempo de resposta de cada uma destas pesquisas é igual ao tempo de resposta entre os servidores mais o tempo para processar a resposta propriemente dita.

O problema que o Google Public DNS resolve é centralizar de forma Googleludiana toda essa informação. Isso significa poder utilizar a rede global da Google para armazenar e atualizar estas tabelas de conversão. Outro ponto é responder as requisições de forma muito rápida, coisa que o Google é campeão em fazer. Vários provedores de acesso tem mega-caches de domínios, porém a atualização deste cache é um outro problema. O Google pretende resolver o problema dos grandes caches e ainda aumentar o nível de segurança do serviço de resolução de nomes (DNS).

Um exemplo: imagine que o tempo de resposta entre seu servidor de DNS é igual a T. Para responder o endereço IP de www.google.com, teríamos algo como 3T ou 4T. Considere que no caso do Brasil, com redes lentas, esse T é bem grande (>100ms). Pense também que uma simples página web pode ter dezenas de nomes a resolver. Isso causa um atraso enorme ao tempo total de carga da página. Usando o serviço do Google, o tempo de resposta se aproxima de T (uma vez que as tabelas cache do Google tendem a ser maiores e mais rápidas que a do seu pobre ou rico servidor).

Uma descrição completa do problema e da solução pode ser encontrada neste link.

Agora, como usar isso. A tentação pode ser de simplesmente trocar o IP do seu servidor de DNS para 8.8.8.8 e 8.8.4.4. Esta solução é muito interessante e é descrita nas páginas do serviço, mas o melhor mesmo é configurar seu servidor local de DNS para utilizar este serviço. Isto minimiza o tempo de acesso de todas as máquinas da rede e como o tempo de acesso ao servidor local é muito menor que acessar o servidor do Google, o tempo de resolução de domínios ficará bem baixo.

Para quem usa o Bind no Linux sem ter o mesmo configurado como servidor de domínios local ou principal, simplesmente como cache de DNS, basta adicionar as seguintes linhas no /etc/bind/named.conf (o endereço pode mudar de acordo com a sua distribuição Linux).

Adicione as linhas com os servidores do Google (em negrito) logo depois de directory, dentro de options:

options {
directory "/var/bind";


forwarders { 8.8.8.8; 8.8.4.4; };
forward only;


Depois disso, recarrege a configuração do Bind (/etc/init.d/named reload) e tudo feito. Agora você conta com seu cache local e com o serviço público do Google. A diferença é bem perceptível.

Você também pode obter um bom desempenho configurando os servidores do Google em seu roteador de acesso sem fio, mas isso vai depender da velocidade de resposta do mesmo. Vale experimentar!

quinta-feira, 29 de outubro de 2009

Windows 7 64 bits no iMac com Snow Leopard - BootCamp 3.0


A vida não é facil para quem tem um iMac e quer instalar o Windows 7 64 bits. A Apple decidiu que os drivers de 64 bits não poderiam ser instalados nos iMacs, só nos MacPros, mas tudo tem jeito :-D. Neste outro post, eu descrevi como instalar a versão 32 bits do Windows 7 RC, mas com o Boot Camp 2.1 do velho Leopard.

O problema é que eu gostei do novo brinquedo e comprei o Windows 7 Edição Familiar Premium. Eu já sabia que o RC seria destruído, então comecei preparado. A caixa chegou na segunda-feira, comprei por 56€ numa super-promoção ainda em Julho na PixMania.be! Por 56€ é uma opção muito interessante, não sei se teria feito o mesmo se tivesse que pagar os 99 que a Microsoft pede hoje. Backup feito, começa a aventura!

Usando a mesma partição do meu Windows 7 RC, eu apenas pedi ao BootCamp 3.0 do Snow Leopard para iniciar o CD de instalação Windows. Fiz o boot e instalei normalmente, usando o setup do Windows. O Windows 7 vem com dois DVDs, um com a versão 32 bits e outro com a versão 64. É bom olhar antes de dar o boot, porque não lembro de nenhum indicador visual de qual dos dois estava instalando (salvo no próprio DVD!).

Instalei o Windows 7 64 bits na mesma partição do Windows 7 32 bits RC, mas para minha surpresa o instalador disse que estaria movendo tudo para uma pasta Windows.OLD. Eu já estava preparado para começar do zero, aguardando a formatação do disco, coisa que não aconteceu. Tudo do Windows 7 RC antigo foi movido para a Windows.Old, inclusive o Program Files e outros diretórios.

Terminada a instalação, não tive qualquer problema no Mac, até precisar instalar o boot camp. A mensagem que apareceu é que a versão 64 bits dos drivers não é suportada na minha máquina: Boot Camp x64 is unsupported on this computer model.

Uma rápida visita no site da Apple, revela que os iMacs não estão na lista dos equipamentos suportados para os drivers de 64 bits do Windows Vista ! Uma rápida busca no Google, revela este artigo. Eu já havia lido outros, mas poucos sobre o problema da restrição do iMac. Meu iMac é modelo 2008. Antes disso, nem adianta tentar. Nao precisa baixar nada de sites estranhos, tudo que você precisa está no DVD do Snow Leopard. Um dos comentários do artigo diz que conseguiu instalar o BootCamp pelo arquivo .msi. Aparentemente é o setup.exe que verifica a restrição aos iMacs. O problema é que clicando no Boot Camp\Drivers\Apple\BootCamp64.msi no Windows Explorer ele não instala. O comentário também diz para executar em linha de comando privilegiada. Aí a coisa ficou esquisita, pois eu já era administrador do sistema. Lembrei que o Windows 7 é um primo próximo do Vista, chato mesmo.

O que precisa fazer:

  • A partir do menu iniciar, abra a pasta de acessórios e clique com o botão direito no Command Prompt. Escolha a opção de executar em modo privilegiado.
  • Na janela de comandos que abriu, vá para o diretório do BootCamp64, no meu caso o drive D: é o DVD-ROM:
d:
cd "\Boot Camp\Drivers\Apple"
msiexec /i BootCamp64.msi

Depois é só prender o fôlego e ter fé. A instalação do Boot Camp é assustadora. Telas pretas e piscadas alucinantes aconteceram no meu caso, mas é coisa rápida, bips também acontecem. Nada que não assuste durante a instalação de um novo Windows, principalmente instalando drivers do Vista 64 no Windows 7... mas já da para aguardar até os drivers nativos do Windows 7 serem lançados.

Um boa é que mesmo antes do Boot Camp ser instalado eu já tinha rede. Rede com cabo e sem fio funcionaram de primeira após a instalação. O som, o eject e a camera só funcionaram depois de instalar o BootCamp. Alias, o som não está tão bom assim. Uma dica é que o eject funciona pelo Windows Explorer, mesmo antes de instalar o Boot Camp. É só clicar no drive de DVD com o botão direito e selecionar ejetar.

A melhor surpresa foi poder acessar a partição do Mac pelo Windows Explorer. Isso é muito legal, principalmente quando você procura um arquivo que está no outro sistema.

Em relação a utilização de memória, aqui eu perdi uns 200 MB de cara, só trocando de 32 para 64 bits. O Windows 32 pedia uns 400 MB para mostrar o Desktop :-)... o 64 ja começa com 600MB. Era a desculpa que eu precisava para colocar mais 2G :-D

domingo, 25 de outubro de 2009

Capturando a saída interativa do interpretador Python em Python

Tudo tem que ser automatizado. Como estou escrevendo um pequeno livro sobre Python já há muito tempo, tenho que atualizar a versão da linguagem todo ano :-D. Com o Python 3.1 o problema ficou mais sério, pois agora tenho que testar os exemplos do livro com essa nova versão que não é totalmente compatível. O livro está sendo escrito em Latex, usando o TextMate e o Skim no Mac OS X. Eu fiz a besteira de inserir manualmente o código fonte Python no texto Latex, agora tenho que revisar os scripts um a um. Como vou revisar, aproveito para consertar e desta vez gravar os programas Python em arquivos separados.

Resolvi então utilizar o SCONS para ajudar na tarefa. Para isso, um builder customizado precisa ser criado. No SConstruct:
PYTHON_BIN="/opt/local/bin/python2.6"

python_output=Builder(action= '$PYTHON_BIN capture.py $SOURCE $TARGET',
                  suffix     = '.pyt',
                  src_suffix = '.py')

env = Environment(BUILDERS = {'python_output': python_output})
env["PYTHON_BIN"]=PYTHON_BIN

env.python_output("p1")

e depois o programa em Python que faz a captura, capture.py:
import pexpect
import sys

PYTHON_BIN="/opt/local/bin/python3.1"

interacao = file(sys.argv[1], "r").readlines()

python = pexpect.spawn(PYTHON_BIN)
python.logfile_read = file(sys.argv[2], "w")

for l in interacao:
   python.expect([">>> ", "... "])
   python.send(l)

python.sendline("exit()")
python.expect(pexpect.EOF)

O script capture.py recebe dois parâmetros: o nome do arquivo Python e o nome do arquivo de saida.
Para testar, crie um arquivo p1.py:
a=5
b=10
print(a+b)
c = a + b
d = c * a / 100
print(c,d)
for x in range(3):
    print ("Oi")

#Erro:
=d=d
rrrrr

Deve produzir a seguinte saída em p1.pyt:
Python 3.1.1 (r311:74480, Oct 24 2009, 17:11:04) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> a=5
>>> b=10
>>> print(a+b)
15
>>> c = a + b
>>> d = c * a / 100
>>> print(c,d)
15 0.75
>>> for x in range(3):
...     print ("Oi")
... 
Oi
Oi
Oi
>>> #Erro:
... =d=d
  File "", line 2
    =d=d
    ^
SyntaxError: invalid syntax
>>> rrrrr
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'rrrrr' is not defined
>>> 
>>> exit()

Se você utilizar este arquivo, não esqueça de modificar as variaveis PYTHON_PATH. Eu uso MacPorts e devo especificar o caminho completo da versão de Python que quero utilizar. Isso evita problemas com outras versões instaladas no sistema, como o Python da Apple. Eu utilizei o Python 3.1 nos exemplos do livro, mas ainda uso o 2.6 para instalar meus módulos no Mac Ports.

Eu espero que isto ajude alguém com o mesmo tipo de problema: capturar a saída interativa de um programa como se fosse um terminal comum.

sábado, 24 de outubro de 2009

Aventuras com FSCK

Back-ups sempre vão bem... essa semana acabei perdendo 2 HDs. Um no PC, consegui retirar todos os dados e transferir para um servidor remoto. O outro, meu Ubuntu, Tambaqui de guerra.

Cheguei de manhã ao trabalho e vi que computador estava desligado. Como o Tambaqui é um pequeno servidor também, eu já o deixo ligado. Liguei o peixe e o boot ocorreu normalmente (eu sempre digo que só dá problema o que antes estava funcionando perfeitamente :-), senão ninguém viria com aquela desculpa-esfarrapada-padrão-de-quem-não-tem-backup: ontem estava bonzinho!).Olhando os arquivos depois do boot, vi que haviam vários arquivos com nomes estranhos com ??? e !!!!... sinal de problemas no sistema de arquivos, mas o fsck jurava que estava tudo bem :-)

Rodei então o init 1 para inicializar em usuário único. E lá rodei o fsck no menu do Ubuntu... que detectou vários problemas. Terminada a análise, fiz o boot e para minha surpresa o disco estava vazio !

Como já havia perdido um HD no dia anterior, disse: de novo! :-( Vi que a raiz tinha ido pro saco. Eu precisava apenas de dois diretórios com meus dados, prática que sigo já há alguns anos. Bom, dei uma olhada rápida no disco e constatei que estava mesmo vazio. Eu só consegui dar o boot com o CD do Ubuntu, mas não tive problemas em montar a tal partição. Começei a me preparar para reinstalar o Ubuntu quando vi que a partição não estava vazia.

Eu nunca acreditei muito no lost+found. Toda vez que tive problemas no Linux, encontrei apenas pedaços dos meus arquivos dentro do lost+found. Mas desta vez a coisa estava diferente. Entre estes pedaços estavam diretórios com nomes como #xxxxxx, milhares deles. Logo descobri aonde meus arquivos haviam ido parar.

Iniciei então o seguinte procedimento para procurar meus arquivos:
ls -laR lost+found > bigls.txt

O fsck havia recortado meus diretórios e deixado tudo em um só nível! A opção de gerar o arquivo bigls.txt era de justamente poder procurar com calma tudo que eu poderia salvar. O arquivo final tinha mais de 40MB ! Mas isso não é nada para o less. Utilizando a / para pesquisar, pude navegar no pequeno ls monstro que havia criado e logo detectar o que precisava ser salvo.

Depois, ficou fácil de mover os diretórios mais importantes para um disco de rede. O nome do arquivo eu pegava no bigls.txt, aberto em outra janela com o less. Simples e prático. Ainda estou recuperando as instalações que havia feito na máquina, pois não consegui quase nada do meu /etc (tomcat com ldap é chato).

Nessa nova instalação vou deixar um rsync rodando para o disco de rede... pelo menos dos dados e do /etc :-)

Quanto ao outro disco, rodando Windows XP... no meu velho notebook (2HDs perdidos em 2 meses e contando !)... também consegui montar o disco que nem boot mais tinha usando também o CD do Ubuntu. Ficou tudo muito simples porque o Ubuntu já identifica o disco Windows e é ultra fácil montá-lo, bastando clicar no volume correspondente no menu. Eu gosto muito de usar a linha de comando, mas confesso que gostei desta vez de utilizar as ferramentas gráficas no Ubuntu. Abri dois navegadores, um com a partição Windows e outro com um disco remoto usando Samba. A cópia foi tranqüila, bastando arrastar e soltar! Quem diria um dia fazer isso no Linux :-)

Um programa que ajuda a ver os problemas de boot no Windows é o testdisk. Ele detecta as partições e ajuda a reconstruir o setor de boot entre outras coisas. Pena que ele não está disponível pelo apt-get do Ubuntu 9.04. Mas no link acima tem uma opção para download. Basta baixar e desempacotar a versão binária. Um executável pronto (linkado estaticamente) já está pronto para ser utilizado.

Outro programa para o cinto de utilidades é o SmartMonTools. Ele acessa as informações do S.M.A.R.T. do seu HD e ajuda a decidir o que aconteceu. Claro que é melhor usar essa ferramenta antes de ter problemas, mas meu Windows XP resolveu morrer sem último suspiro. Cheguei de manhã e ele já estava morto, mas sem perda de dados. Nunca se sabe se é um problema de vírus ou simplesmente um defeito no HD que você não havia percebido. Esses utilitários ajudam a executar os testes mesmo post mortem. Claro, dependendo do estado do seu HD, porque se ele nem liga ou nem mesmo é detectado... esqueça.