[jabá] Treinamento Python e Django

Postado por Osvaldo Santana

A Triveos está lançando o seu treinamento de Desenvolvimento Web Ágil com Python e Django e por isso pega carona nesse conceituado blog (que por coincidência é um dos sócios da Triveos) para anunciar este lançamento.

Imagem ilustrativa do treinamento com a apostila e o texto 'Aprenda Python e Django em apenas 5 dias'

Eu não costumo fazer esse tipo de post (jabá) por aqui mas este é um caso especial por dois motivos: o produto anunciado foi criado pela minha empresa (como eu já havia dito); e porque que até o momento são poucas as empresas que ministram esse curso no Brasil.

Esse treinamento é o primeiro entre muitos que planejamos desenvolver no próximo ano sempre com algumas características:

  • treinamentos in-company — isso nos dá mobilidade e permite que o treinamento seja ministrado em qualquer lugar do Brasil e não somente no eixo Rio-São Paulo.
  • treinamentos de curta duração — achamos que tecnologias precisam ser simples e que se elas forem realmente simples não seria necessário investir meses num treinamento. O treinamento de Python e Django precisa de 5 dias apenas para ser ministrado com grande tranquilidade para pessoas que já desenvolvem em alguma linguagem OO.
  • treinamentos personalizáveis — a linha principal do treinamento é mantida mas algumas modificações podem ser feitas para adequar o treinamento aos requisitos das empresas. Exemplos: dedicar um tempo do treinamento à implantação do Django, apresentar alguma biblioteca Javascript para desenvolvimento de RIAs, ministrar só o módulo Django, etc.
  • materiais de qualidade — nada de apostilas contendo só slides impressos. Disponibilização de todo o material usado em aula (Slides, repositório de códigos, etc).
  • instrutores qualificados — não posso falar muito mais sobre isso. Sou um dos instrutores :D

Quem tiver interesse no treinamento pode entrar em contato com a gente através do site ou diretamente comigo.

Update: Pessoal, não tinha ficado claro mas, a Triveos só trabalha com treinamentos in-company, ou seja, não temos infra-estrutura para ministrar esse treinamento em nossa empresa. Fazemos isso dentro da sua empresa (ou da empresa onde você trabalha). De qualquer maneira estamos avaliando um modo de atender às demandas que estão surgindo.


“Cagadas” homéricas (ou YA-meme?)

Postado por Osvaldo Santana

Durante toda a minha carreira “computeira” eu cometi alguns erros absurdos (cagadas?) que eu gostaria de compartilhar com vocês neste post.

Vou listá-las aqui na esperança de que outros façam o mesmo e que, com isso, o meu sentimento de culpa por tamanhas “obras” fique menor.

killall foobar

Certo dia, quando trabalhava na GVT, eu estava numa sessão telnet em um servidor de produção PA-RISC que rodava um HP-UX. Estava logado como root e precisava matar alguns processos que estavam prejudicando o funcionamento da máquina (consumindo CPU, memória, load alto, etc).

Meu conhecimento de Unix até aquele momento era de ter mexido muito com Linux ao ponto de saber usar com maestria o comando killall. Foi então o que eu usei para matar tais processos.

Assim que eu apertei “enter” surgiu uma mensagem de que o servidor iria se desligar em X segundos. Entrei em pânico.

Pois bem… apesar de ser um ‘fera de killall’ eu nunca tinha lido o trecho da manpage deste comando que dizia (no Linux):

Be warned that typing killall name may not have
the desired effect on non-Linux systems, especially
when done by a privileged user.

O que aconteceu? O killall do HP-UX envia um sinal para todos os processos da máquina e é usado pelo comando shutdown para matar todos os processos em execução.

Foi assim que eu desliguei, pela primeira vez, um servidor em produção de uma grande empresa de telefonia praticamente parei as vendas da empresa por pelo menos 1 hora (uma máquina dessas leva cerca de 20 minutos para voltar pro ar + acertos de configuração perdidos por causa do reboot).

delete from tabelao;

Mais uma vez na GVT… coitados…

Eu estava desenvolvendo um programinha que fazia acesso ao banco de dados Oracle e para isso eu constantemente testava algumas queries, inserts e deletes nas tabelas de um banco de dados que ficava no ambiente de desenvolvimento da empresa.

Nos bancos de dados do ambiente de desenvolvimento a gente encontrava um subconjunto dos dados do ambiente de produção e podíamos manipulá-los com tranquilidade porque uma vez por dia/semana as bases eram repopuladas com dados oriundos do ambiente de produção.

Em certo momento eu precisava deletar todos os registros de uma tabela (cerca de 50 registros) da base de dados do ambiente de desenvolvimento e rodei um:

delete from tabela;

Fiz os testes que precisava fazer sem rodar um commit e no final fiz um rollback.

Neste intervalo de tempo ocorreu um problema que exigiu minha atenção em um dos servidores de produção e esse servidor era justamente o servidor ‘equivalente’ ao de desenvolvimento onde eu estava trabalhando. Resolvi o problema do servidor rapidamente e voltei para o desenvolvimento.

Aí é que está o problema… o meu cérebro trocou de servidor mas meus dedos não e no fim eu rodei um delete from tabela; no servidor de produção da empresa :D

O estrago teria sido pequeno se tal tabela não tivesse centenas de milhares de registros fazendo com que o Oracle praticamente parasse de responder à requisições até que ocorresse uma falha de “estouro de segmento de rollback” (falha que demorou pra acontecer porque as configurações do Oracle eram muito ‘generosas’).

Seria muito difícil acontecer do estrago ser grande. Para que isso ocorresse a falha que ocorreu não poderia acontecer e depois do delete eu ainda precisaria dar um commit.

Se isso tivesse acontecido eu teria mudado de profissão :)

/home/osvaldo/icons

Essa foi no meu “início de carreira” com Linux. Eu trabalhava na Conectiva (atual Mandriva) e fiquei responsável por criar um sistema de “temas” para o Conectiva Linux 5.

Os temas deveriam funcionar igualmente no Gnome, KDE e no WindowMaker que, até então, era o WM que eu usava.

Fiz os pacotes, scripts, configurações e enviei para a máquina de integração (mapi). Dei essa tarefa como terminada e passei para as próximas.

Lançado o Conectiva 5 o sistema “explodiu” nas máquinas dos usuários e o sistema de temas não funcionava como deveria em todas as máquinas que usavam o WindowMaker .

Ao analisar o problema vi que no arquivo de configuração do WindowMaker tinha um “/home/osvaldo” no caminho de busca de imagens e ícones que causava a ‘quebra’.

Resultado: as coisas funcionavam perfeitamente na minha máquina e em todas as outras máquinas do mundo que tivessem um usuário “osvaldo”.

Esse foi um bug entre os vários desse sistema de temas que criei e que futuramente (por razões óbvias) foi abandonado.

Se você ainda tem um Conectiva 5 para instalar por aí faça o teste. :D

Off-topic

Alguns, talvez, ainda não saibam mas eu vivi um período em que queria largar da área de informática e virar publicitário (ok, eu era jovem).

Neste período “publicitário” da minha vida eu trabalhei em uma agência de propaganda chamada DLMRozani e lá nós fazíamos toda a mídia local das várias Lojas Americanas do país (a conta nacional era da agência Talent).

A mídia local inclui anúncios televisivos (para as afiliadas locais), anúncios em jornais locais e aqueles folhetinhos de ofertas que todos já devem ter visto.

Num desses folhetos onde anunciamos carne de 1ª à R$3,90/kg quando o preço correto era algo como R$13,90/kg (não lembro detalhes da oferta).

A sorte que era uma dessas “ofertas relâmpago” (válidas por 1 hora), mas o fato é que vendemos 400kg de carne em 1 hora. Filas se formaram em volta do quarteirão das Lojas Americanas e caminhões não paravam de chegar trazendo carne para ser vendida (aquele blablabla de “enquanto durarem os estoques” não tem muito amparo legal pelo código de consumidor).

Só para contextualizar: nesta época as Lojas Americanas tinham lojas que funcionavam como supermercado em várias cidades do Brasil. Essa operação foi vendida posteriormente para um grupo francês chamado Stoc.

Finalizando

Se eu lembrar de mais algumas “cagadas” eu volto a atualizar esse post mas acho que essas foram as maiores.

E vocês? Fizeram alguma dessas já?


Cross-compiling fácil fácil

Postado por Osvaldo Santana

Como eu já contei no post anterior no meu novo trabalho a gente tem que lidar com cross-compiling (compilação cruzada) o tempo todo. A idéia da compilação cruzada é simples: você compila um programa P em uma plataforma A e o binário produzido deverá rodar em uma plataforma B.

O conceito é simples, o seu funcionamento na teoria também. Para compilar um típico programa Linux em um computador x86 para rodar na plataforma ARM bastaria ter o toolchain, que é o conjunto de ferramentas que engloba o binutils (onde fica o linker) o gcc (onde fica o compilador C/C++) e em algumas bibliotecas básicas já como binários ARM (a libc é uma delas).

O problema do ovo e da galinha dificulta um pouco a construção de um toolchain (você precisa compilar o compilador) mas não é incomum que esses toolchains já sejam distribuídos com a plataforma ‘alvo’, logo, esse problema não é muito grande.

Com cross-toolchain já instalado a teoria diz que bastariam os seguintes comandos (assumindo que a nossa plataforma alvo seja ARM) para compilar um programa:

$ ./configure --host=arm-linux
$ make
$ make install

Com algumas pequenas variações disso conseguiríamos fazer a compilação cruzada de ‘todo o Linux’, mas na prática a teoria não funciona… :)

O que acontece é que um grande percentual das aplicações (regra e não exceção) simplesmente ignora o fato de que no futuro elas serão submetidas à compilação cruzada e simplesmente não funcionam nessas circunstâncias.

O Python é um desses programas. O interpretador compila perfeitamente, mas as extensões em C da biblioteca padrão não. O problema é que o Python usa o módulo distutils para executar tal tarefa e o mesmo é feito em Python. Neste caso precisamos de um Python ARM para executar a segunda fase do processo de build. Como executar um Python ARM em uma máquina x86?

Uma das maneiras é compilar primeiro um interpretador Python x86, renomeá-lo para algo como ‘hostpython‘, depois compilar um interpretador Python para ARM e aplicar uns patches no Makefile.in do Python para que ele chame o ‘hostpython‘ para compilar as extensões C. Mas os efeitos colaterais dessa solução são enormes porque existem extensões que usam bibliotecas do sistema (OpenSSL, Socket, SQLite, …) e o distutils não irá procurá-las no lugar correto pois não sabe o que é compilação cruzada.

Aí então entra uma técnica de transparência de CPU que aprendi a fazer com a turma do projeto Scratchbox (aperfeiçoada pela turma do projeto Mamona) que é bem simples e permite fazer compilação cruzada sem modificar nada nas aplicações que estão sendo compiladas.

A idéia é usar o binfmt do Linux para dizer que todos os binários ARM deverão ser executados pelo qemu (pegadinha 1: esse qemu deve ser estático e estar instalado dentro do chroot no path definido nas configurações do binfmt) e criar um ambiente chroot com tais binários.

Dentro desse ambiente todos os binários ARM rodam com o qemu e todos os binários x86 rodam nativamente na sua plataforma (assumindo que ela é x86) sem que você sequer note a diferença entre o funcionamento deles. Desta forma podemos colocar então o nosso cross-toolchain dentro desse chroot fingindo ser um toolchain nativo ARM (tem uma pegadinha aqui: esse toolchain precisa ser estático e não dinâmico pois as bibliotecas nesse nosso ambiente são ARM e não mais x86).

Você está me perguntando “porque não compilar um toolchain nativo pra rodar dentro desse chroot“? Só por questão de velocidade. O gcc rodaria muito devagar sendo emulado pelo qemu.

Agora é só sair compilando os programas normalmente. Mesmo aqueles que não estão preparados para compilação cruzada:

$ ./configure
$ make
$ make install

Neste exato momento estou compilando o SQLite3 (após ter terminado o OpenSSL) dentro do ambiente chroot com binários ARM (XScale) que rodam emulados pelo qemu. Tudo isso para que no final eu tenha um Python com Pygame 100% funcional.

Ok. Agora é a hora das notícias ruins:

  • O qemu não emula 100% das syscalls, logo, você poderá esbarrar com uma das famigeradas mensagens “Unsuported syscall XX“. Nestes casos verifique se já não existe um patch que implementa o suporte à essa syscall no qemu e recompile-o (lembrando que o qemu precisa ser estático).
  • O qemu não lida muito bem com threads, logo, se os scripts de build do seu programa testam threads eles podem quebrar (ou bloquear). Neste caso a sugestão é: retire esses testes dos scripts e assuma que sua plataforma tem sim (ou não) suporte à threads.
  • Lembre-se sempre que o kernel não é emulado pelo qemu! Se o seu programa usa ferramentas como o uname, por exemplo, ele irá retornar informações da sua plataforma nativa e não da plataforma emulada. Desenvolvimento para o kernel também não é muito viável.
  • Pode acontecer da tua aplicação quebrar ’silenciosamente’. Lembre-se que pode ser o qemu quebrando e ocultando a real causa do problema. Nesses casos utilize as funções de depuração do qemu.
  • Lembre-se de ter o /proc e o /sys montados dentro do seu chroot. Alguns programas usam as informações disponíveis nesse lugar para a sua construção. Lembre-se também que esse /proc e /sys são da sua plataforma nativa e não da plataforma emulada, logo, eles poderão fornecer informações incorretas.
  • Dica: tenha a sua área de trabalho ($HOME) montada via mount --bind dentro de seu chroot para que você possa ter vários chroots compartilhando o mesmo $HOME.

O sistema de testes dos meus sonhos

Postado por Osvaldo Santana

O uso de testes no desenvolvimento de software já vem me acompanhando desde que trabalhei com Smalltalk na Objective Solutions. O sistema de testes que eles tinham lá chegava muito próximo do que eu idealizo para um sistema de testes.

Recentemente eu li o livro Test-Driven Development do Kent Beck e resolvi experimentar TDD de forma radical em um projeto pessoal em que estou desenvolvendo em Python. O meu sentimento geral sobre o uso de TDD é a de que estou programando num ritmo bem mais lento do que costumo ter mas com a certeza absoluta de que estou seguindo pelo caminho correto.

Como os detalhes de implementação desse projeto não estão muito claros em minha cabeça o uso de TDD está se mostrando ideal, mas não recomendo para o desenvolvimento de uma aplicação na qual você já tenha uma boa idéia de como implementar pois ela realmente ‘desacelera’ o seu ritmo. Mas atenção: estou desaconselhando o uso de TDD e não a criação de testes! Nos projetos onde é possível desenvolver testes é fundamental fazê-lo.

Mas voltando ao assunto deste post eu adoraria ver uma ferramenta para Python com as seguintes funcionalidades:

  1. Suportar testes escritos com xUnit (unittest) e doctests.
  2. Vir junto com framework xUnit mais poderoso que o unittest padrão do Python. O py.test tem umas idéias legais. Juntar outras bibliotecas auxiliares, tais como o mocker, também seria legal.
  3. Ter um sistema de discovery automático para testes (ex. nose).
  4. Ter uma interface texto para uso em servidores de testes.
  5. Ter uma interface gráfica para uso do desenvolvedor.
  6. Suportar execução distribuída de testes. Ainda não preciso disso mas estou prevendo que precisarei no futuro.
  7. Integração com algum software de lint (ex. pylint).
  8. Integração com sistemas de teste de cobertura (ex. coverage).
  9. Emitir relatório sobre a qualidade do código (baseado na análise do lint), da cobertura dos testes, do tempo de execução dos testes e, em caso de falha, o traceback do erro.
  10. Permitir a execução do pdb caso algum teste falhe.
  11. Integração com o mecanismo de persistência de objetos (ORM, OODBMS, …) para permitir a criação de savepoints (aka subtransactions) para testes que precisam construir cenários com muitos objetos. Criando esses savepoints um teste poderia fazer um rollback parcial dos objetos criados/alterados pelo teste executado anteriormente. Eu usei essa integração na Objective e garanto que era muito útil além de diminuir o tempo para execução dos testes de forma colossal.

Mockup da Tela
Modelo da interface gráfica dessa aplicação*.

Esse é o sistema dos meus sonhos e acredito que, conforme o desenvolvimento do meu projeto avance, eu acabe com algo muito parecido nas mãos. Mas se alguém quiser começar antes eu prometo que usarei e, caso me sobre tempo, ajudarei no desenvolvimento :)

Quem sabe um dia esse carinha trabalhe integrado a um SCM, ao reviewboard e a um sistema de issue tracker… mas chega de viagem, hora de voltar ao trabalho.

* Note que ainda está faltando uma Treeview para selecionar o módulo cujo código fonte será exibido.


Gadget da Livraria Cultura

Postado por Osvaldo Santana

Finalmente eu resolvi aprender a mexer com o sistema de gadgets do Google Personalized Pages.

Como sou fascinado por livros e sou afiliado da Livraria Cultura resolvi criar um componente que me mostre uma listagem dos livros mais vendidos e um campo de pesquisa por título.

Não foi fácil. Na verdade foi muito difícil porque o HTML produzido pela Livraria Cultura não é válido, vem com charset incorreto e não tem nenhuma marcação de onde começam e de onde terminam as informações relevantes sobre os livros. Aliás, eu notei esse mesmo problema em outras lojas on-line (mas o da Cultura realmente é o pior).

No lugar deles incentivarem pessoas como eu que estão criando um canal de venda eles preferem nos dificultar. Depois os empresários ficam dizendo que ser empresário no Brasil é difícil, e não é por menos, com essa pouca inteligência realmente fica difícil.

Enquanto isso, nos países “de primeiro mundo”, empresas como a Amazon fornecem Webservices específicamente para facilitar essa tarefa.

Bom, depois desse desabafo aí está a minha “obra”:


Mecânico vs. Engenheiro Mecânico

Postado por Osvaldo Santana

Depois de ler um artigo muito interessante que fala sobre o uso das “super ferramentas” e de acompanhar a fase de iniciação de dois ex-desenvolvedores Delphi que decidiram investir no aprendizado de Python eu andei pensando que existem muitos programadores no Brasil que julgam ser importante se tornar apenas um programador “mecânico” e não um programador “engenheiro mecânico”.

Eu programo há muito tempo. Desde a época em que os programadores tinham que digitar o número das linhas de um programa para que o computador pudesse saber a ordem de execução das instruções. Depois disso eu “evolui” e passei a ter como companheiro um bom editor de textos e uma dupla inseparável de compilador e “linkeditor” que eram executados de maneira quase manual.

As ferramentas de desenvolvimento foram então evoluindo e chegamos então à era das IDEs e super-IDEs que transformavam as intermináveis horas de digitação de um programa em uma meia-dúzia de cliques de mouse.

Tudo muito bom, moderno, legal e ágil, mas ao mesmo tempo emburrecedor. Emburrecedor porque deste ponto em diante os programadores passaram a usar apenas as ferramentas e a usar somente aquilo que elas lhes ofereciam. Passamos então a “consertar os carros” usando ferramentas prontas e pré-fabricadas e deixamos de entender os conceitos físicos e científicos envolvidos no funcionamento dos “motores” desses carros.

A dependência dessas ferramentas e o decorrente emburrecimento dos desenvolvedores fez com que a adaptação desses mesmos desenvolvedores às novas tecnologias se tornasse muito mais complexo do que era antes.

O que eu quero dizer com isso tudo é que de fato é muito bom você ter ferramentas poderosas para agilizar o seu trabalho mas se você se preocupar em usar apenas essas ferramentas você estará limitando suas possibilidades ao que essa ferramenta oferece.

Quando você decidir se tornar um desenvolvedor pense se você pretende ser só um “mecânico” preocupado em usar as ferramentas prontas ou se você quer ser um “engenheiro mecânico” que além de usar as ferramentas também são capazes de criar novas ferramentas.

E vejam: eu não sou contra IDEs, mas acho que os programadores deveriam ser capazes de trabalhar sem elas.


Eu programo em Foo, eu sou superior!

Postado por Osvaldo Santana

Essa eu recebi de um amigo do trabalho.

Hierarquia de programadores

Viram? Nós somos inferiores à programadores Perl! :) Isso é uma afronta…


Duck Typing

Postado por Osvaldo Santana

Lendo os comentários de uma notícia que foi postada recentemente no BR-Linux eu pude observar que algumas pessoas não entendem muito bem o que é duck typing.

Ao contrário do que muitas pessoas pensam duck typing não é um mecanismo disponível em linguagens de programação que usam tipagem dinâmica mas sim uma técnica (ou prática) de desenvolvimento. Essa técnica é explicada da seguinte forma:

Se um objeto anda como um pato e faz quack como um pato então ele é um pato.1

O problema dessa explicação é que ela não fornece muitos elementos úteis para que as pessoas possam entender exatamente como isso funciona então irei recorrer à outra citação extraída do livro Design Patterns:

Program to an interface, not an implementation. (Programe para uma interface, não para uma implementação).

Duck Typing é uma técnica que funciona com qualquer linguagem de programação com suporte ao paradigma OO e diz basicamente que se o seu objeto responde à uma determinada mensagem (chamada de método) característica de um determinado tipo de objeto então esse objeto também pode ser considerado do mesmo tipo.

Trocando em miúdos: Se eu tenho um objeto do tipo “Conta” e um objeto do tipo “Lançamento” e ambos os objetos respondem ao método “.cancela()” pouco me importa se eles são derivados de uma classe em comum ou se ao definir a classe deles eu especifiquei algo como “implements Cancelable” :), o que me importa é que quando eu fizer “objeto_cancelavel.cancela()” esse objeto será cancelado.

Alguns defensores da tipagem estática podem dizer: “mas e se o objeto não implementar o método “.cancela()” e eu chamá-lo o meu programa vai quebrar!”. Sim, vai, e é exatamente isso que teria que acontecer, afinal de contas se você está tentando “cancelar” um objeto que não pode ser cancelado (não implementa “.cancela()”) é muito provável que o seu programa esteja com algum bug que precisa ser corrigido, implementando o método “cancela()” no objeto ou não chamando esse método onde ele está sendo chamado, já que essa chamada estaria violando o polimorfismo.

Então, para terminar, é necessário lembrar que duck typing não é um tipo de tipagem (tocradilho não intencional) dessa ou daquela linguagem de programação. É apenas a forma com que você faz uso das interfaces de seus objetos.

1O nome duck typing surgiu a partir dessa explicação.