Processo de build com o Maven

Por Lucas Cavalcanti em 07/07/08

O Maven é uma ferramenta de gerenciamento, construção e implantação de projetos muito interessante, que te ajuda no processo de gerenciamento de dependências e no de build, geração de relatórios e de documentação. Na Caelum esta é a ferramenta usada em todos os projetos internos e nas consultorias.

Muitas pessoas migram seus projetos para o Maven, mas acabam arrumando mais problemas que soluções, pois não conseguem configurá-lo corretamente, e acabam desistindo e fazendo tudo na mão, ou voltando para o Ant. Mas se você conseguir ajustar as configurações, o Maven vai te ajudar muito e vai compensar todos os (poucos) problemas que ele eventualmente causa. No início do uso do Maven, espere formar com ele uma relação de amor e ódio.

Para começar a usar o Maven, tudo o que você precisa fazer é baixá-lo e configurar umas poucas variáveis de ambiente. Depois de ter feito isso, é só digitar mvn [target] na linha de comando. Alguns sistemas operacionais já te oferecem essa instalação através do macport ou apt-get.

A unidade básica de configuração do Maven é um arquivo chamado pom.xml, que deve ficar na raiz do seu projeto. Ele é um arquivo conhecido como Project Object Model: lá você declara a estrutura, dependências e características do seu projeto. A idéia é bem parecida com o build.xml do Ant: você deixa o pom.xml na raiz do seu projeto para poder chamar as targets de build do seu projeto. O menor arquivo pom.xml válido é o seguinte:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>br.com.caelum</groupId>
  <artifactId>teste</artifactId>
  <version>1.0</version>
</project>

Que contém apenas a identificação do projeto, e uma informação a mais: modelVersion, que é a identificação da versão do arquivo pom.xml e deve ser sempre 4.0.0. A identificação do projeto consiste em três informações:

  • groupId: um identificador da empresa/grupo ao qual o projeto pertence. Geralmente o nome do site da empresa/grupo ao contrário. Ex: br.com.caelum.
  • artifactId: o nome do projeto. Ex: teste.
  • version: a versão atual do projeto. Ex: 1.0-SNAPSHOT.

Essas informações são usadas em muitos lugares, ccomo o controle de dependências que é, na minha opinião, a funcionalidade mais útil do Maven. Por exemplo, para dizer que o log4j 1.2.15 é uma dependência da sua aplicação é só acrescentar no seu pom as linhas:

<project>
...
  <dependencies>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.15</version>
    </dependency>
  </dependencies>
...
</project>

Quando necessário, o Maven vai baixar pra você o jar do log4j 1.2.15, e todas as suas dependências, e vai colocá-las no classpath da sua aplicação durante os builds, testes, etc. Ou seja, você não precisa mais entrar no site do log4j, baixar um zip com vários jars e ter que procurar quais jars devem ser colocados no classpath! No Repositório de Bibliotecas do Maven você encontra os jars que você pode colocar como dependência do seu projeto, e o pedaço de xml que você deve copiar e colar dentro da tag dependencies do seu pom para incluir essas bibliotecas.

Todos os jars baixados pelo Maven são guardados na pasta repository dentro da M2_HOME que você configurou quando instalou o Maven. Assim, se mais de um projeto seu depende do mesmo jar, ele não é baixado de novo.

A grande diferença entre o build.xml do Ant e o pom.xml do Maven é o paradigma. No Ant usamos esse XML praticamente como uma linguagem de programação, onde você da comandos em relação ao build do projeto. No Maven usamos o XML para definir a estrutura do projeto, e a partir dessas declarações o Maven possui targets bem definidos que usam essas informações para saber como realizar aquela tarefa. Um exemplo: para compilar com o Ant criamos um target que chama o javac, mas para compilar com o Maven usamos um target já existente (não o criamos), e ele vai usar a informação que define onde está o código fonte e para onde ele deve ser compilado (sendo que muitas dessas informações possuem convenções e defaults, e nem precisam ser configuradas).

Além dos principais targets do Maven, você pode executar targets de plugins. Você só precisa digitar na linha de comando:

mvn [nomedoplugin]:[target]

e então o Maven baixa o plugin, se necessário, e executa a target pra você. Existe uma lista bem grande de plugins do Maven e uma boa parte desses plugins podem ser usados sem nenhuma configuração adicional no seu pom.

Para dar um exemplo de plugin do Maven nada melhor do que o plugin que cria um protótipo de projeto do Maven: o Archetype. É bem parecido com o scaffold do Ruby: ele cria um protótipo de projeto a partir de um modelo escolhido. O jeito mais fácil de usar esse plugin é digitando na linha de comando:

mvn archetype:create

E então o Archetype vai perguntar qual é o tipo de projeto que você deseja, o groupID, artifactID, version e o pacote referentes ao seu projeto. Depois disso você terá uma estrutura de projeto pronta para ser usada.
Por exemplo se você escolheu o tipo de projeto maven-archetype-quickstart, o Archetype vai criar uma estrutura de pastas parecidas com a seguinte:


teste
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- br
    |           `-- com
    |               `-- caelum
    |                   `-- teste
    |                       `-- App.java
    `-- test
        `-- java
            `-- br
                `-- com
                    `-- caelum
                        `-- teste
                            `-- AppTest.java

E então é só continuar o seu projeto a partir daí. O código de teste já vem separado do código principal, e o junit já vem como dependência da aplicação. Você também pode criar as pastas src/main/resources e src/test/resources para colocar os recursos (arquivos de configuração, de teste, e etc) do código principal e do de testes, respectivamente. Tudo que estiver dentro dessas pastas é copiado diretamente para o diretório onde as classes são compiladas, sem que seja necessário fazer nenhuma configuração adicional.

Se você, por algum motivo, não gostou da estrutura que o Maven criou, ou está querendo migrar um projeto para o Maven que não segue essa estrutura, você pode configurar os diretórios do projeto
acrescentando algumas linhas no pom:

<project>
...
<build>
    <sourceDirectory>
      ${project.basedir}/src/java/main
    </sourceDirectory>
    <testSourceDirectory>
      ${project.basedir}/src/java/test
    </testSourceDirectory>
    <resources>
          <resource>
                 <directory>
                   ${project.basedir}/src/resources/main
                 </directory>
          </resource>
    </resources>
    <testResources>
          <testResource>
                 <directory>
                   ${project.basedir}/src/resources/test
                 </directory>
          </testResource>
    </testResources>
</build>

...
</project>

Nesse exemplo o diretório principal de código e de recursos estarão em src/java/mainsrc/resources/main respectivamente, e os diretorios de teste em src/java/test e src/resources/test.

Agora com um projeto Maven já preparado, vamos para a principal funcionalidade: o build. O build do Maven é baseado no conceito de ciclo de vida: o processo de construção e distribuição da sua aplicação é dividido em partes bem definidas chamadas fases, seguindo um ciclo. O ciclo padrão é o seguinte:

  • compile - compila o código fonte do projeto
  • test - executa os testes unitários do código compilado, usando uma ferramenta de testes unitários, como o junit.
  • package - empacota o código compilado de acordo com o empacotamento escolhido, por exemplo, em JAR.
  • integration-test - processa e faz o deploy do pacote em um ambiente onde os testes de integração podem ser rodados.
  • install - instala o pacote no repositório local, para ser usado como dependência de outros projetos locais
  • deploy - feito em ambiente de integração ou de release, copia o pacote final para um repositório remoto para ser compartilhado entre desenvolvedores e projetos

Você pode invocar qualquer dessas fases na linha de comando, digitando:

mvn [fase]

Por exemplo se você digitar mvn package o Maven vai executar todas as fases anteriores do ciclo até a fase package. Uma lista completa das fases do ciclo de vida possíveis pode ser encontrada aqui.

Algumas das fases do ciclo possuem plugins associadas a elas, e esses plugins são executados assim que a fase é chamada para ser executada. Você pode também registrar plugins para rodarem em qualquer fase do ciclo, conseguindo, assim, personalizar o build do seu projeto facilmente. Por exemplo, se você quiser criar um jar com o código fonte do projeto, e que esse jar seja gerado depois que o projeto foi empacotado, é só acrescentar no seu pom:

<project>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-source-plugin</artifactId>
        <executions>
          <execution>
            <id>attach-sources</id>
            <phase>package</phase>
            <goals>
              <goal>jar</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  ...
</project>

Assim, o plugin Source vai executar seu goal jar na fase package do ciclo de vida. É como se fosse chamado mvn source:jar quando o build passa pela fase de package. A fase package já possui um plugin associado a ela: o jar:jar (supondo que é um projeto jar), então o plugin source só será executado depois do jar:jar. Em geral se você registrar mais de um plugin pra mesma fase, eles serão executados na ordem em que eles forem declarados. O jeito de configurar o plugin para colocá-lo dentro de uma fase do ciclo geralmente está no site principal do plugin, na seção Usage.

O Maven possui ainda outras funcionalidades interessantes, como geração de relatórios. Alguns plugins também merecem uma atenção especial, como o Eclipse que gera informações de projeto para o eclipse (.classpath e .project), o Antrun que te permite executar código Ant dentro do Maven, o Cobertura que gera um relatório mostrando a cobertura de testes no seu projeto, o Jetty que sobe uma instância do Jetty com sua aplicação deployed, o Selenium que sobe uma instância do servidor do Selenium para poder fazer os testes de aceitação do selenium, enfim, existem vários plugins interessantes e é relativamente fácil achar o plugin que faz o que você precisa. É igualmente fácil, também, fazer um plugin para o Maven, o chamado Mojo.

Aqui na Caelum, além do Maven e JUnit, usamos muito o Selenium, juntamente com o SeleniumDSL, para os testes de integração, e o Cruise Control para o controle da integração contínua. Esperamos colocar tutoriais e vídeos sobre essas ferramentas também.

Caelum Stella - o cinto de utilidades para o desenvolvedor brasileiro

Por Fabio Kung em 21/05/08

stellaDurante o Falando em Java 2008 do último fim de semana (18/05/2008), anunciamos o lançamento do novo Caelum Stella.

O projeto vem para auxiliar os desenvolvedores brasileiros, suprindo algumas das necessidades comumente encontradas em aplicações desenvolvidas aqui no Brasil. Atualmente, o Caelum Stella fornece uma biblioteca de validadores, formatadores e conversores para documentos brasileiros, tais como CPF, CNPJ e PIS/PASEP.

 String cpf = "867.554.707-24";
 CPFValidator vld = new CPFValidator();
 for(ValidationMessage error : vld.invalidMessagesFor(cpf)) {
   System.out.println(error.getMessage());
 }

Há uma alternativa que lança uma exceção caso ocorra algum problema de validação:

 new CPFValidator().assertValid("867.554.707-24");

O Stella também inclui módulos extras, como o de geração de boletos bancários, adaptadores para JSF, VRaptor, JBoss Seam e Hibernate Validator. Veja um exemplo de validação para CPFs usando o Caelum Stella junto ao Hibernate Validator:

  @Entity
  public class Modelo {
    @CPF
    private String cpf;
  
    public String getCpf() {
      return cpf;
    }
  }

O módulo Stella Faces conta com alguns validadores compatíveis com a especificação JSF, que você pode adicionar aos seus componentes:


<h:inputText id="cpf" value="#{usuarioBean.cpf}">
  <stella:validateCPF/>
</h:inputText>

O Stella Boleto procura fornecer um idioma mais fluente para a geração de boletos, através do encadeamento de métodos, gerando PDFs, PNGs e em breve TXT, RTF e HTML:

  Boleto boleto = Boleto.newBoleto()
      .withBanco(banco).withDatas(datas)
      .withDescricoes("descricao 1""descricao 2""descricao 3")
      .withEmissor(emissor).withSacado(sacado)
      .withValorBoleto("200.00").withNoDocumento("1234")
      .withInstrucoes("instrucao 1""instrucao 2""instrucao 3")
      .withLocaisDePagamento("local 1""local 2");

  new BoletoGenerator(boleto).toPNG("teste.png");

Estão ainda previstas no roadmap do projeto funcionalidades como JSP taglibs, rotinas JavaScript para máscaras, validação e suporte a formulários, seleção de cidades dependente da seleção de estados, suporte a mais documentos, geração da nota fiscal eletrônica, webservices para busca de endereços através de CEP, entre muitas outras. A lista vem sendo constantemente atualizada e você pode conferi-la através deste link.

Todas estas funcionalidades estão divididas em diversos módulos dentro do Stella. Atualmente são quatro: Stella Core, Stella Hibernate, Stella Faces e Stella Boleto. Cada um com um propósito diferente, mas todos relacionados aos problemas do dia a dia recorrentes no mercado brasileiro.

Além de facilitar a vida dos desenvolvedores brasileiros, o projeto prima pela alta qualidade (extensa quantidade de testes unitários, cobertura e documentação) e facilidade de uso. Você pode conferir diversas características técnicas do projeto e dos vários módulos na página técnica, gerada pelo maven. Lá você encontra a lista de responsáveis (e respectivos emails), a ótima cobertura dos testes para cada um dos módulos e o código fonte navegável para cada um dos módulos.

Como de costume em qualquer projeto open-source, o código fonte está disponível em um repositório SVN (subversion) no sourceforge.net. Para baixar os fontes basta usar seu cliente preferido:

svn checkout http://caelum-stella.svn.sourceforge.net/svnroot/caelum-stella/trunk

Você também pode navegar pelo repositório neste link.

Para tirar as suas dúvidas, sugerir funcionalidades, apontar bugs e discutir sobre o projeto, não deixe de assinar as listas de discussão, que podem ser encontradas aqui. Se preferir, pode postar também no GUJ.

Visite, use, comente e participe do desenvolvimento do projeto!

stella.caelum.com.br

Competições de programação: Google, IBM e FISL

Por Guilherme Silveira em 19/04/07

A alguns anos atrás fiz uma entrevista em uma grande empresa de Java, uma dessas com 3 letras, e a primeira frase que o entrevistador me dirigiu ao ver meu curriculum foi um sonoro:

Essas competições de programação não dizem nada!

Essas competições não dizem se o programador é um bom engenheiro de software ou profundo conhecedor de alguma tecnolgoia, é verdade. Nem é essa a intenção.
As questões dessas provas apresentam problemas mais complexos que o comumente exigido no mercado de TI, e não foca tanto na parte de desenvolvimento, mas mais na capacidade de encontrar soluções. Para um cientista da computação (ou um matemático, no meu caso), essa capacidade é mais importante do que o próprio desenvolvimento e codificação. Vou relatar aqui três competições as quais tiver a oportunidade de participar este ano. Em todas as três, grandes empresas como o Google e IBM, sempre estavam a caça de talentos. Pode-se dizer que um bom resultado nessas competições certamente atrairão diversas propostas de emprego, mestrado e doutorado.

Primeiro veio o Google Code Jam Latin America. Os problemas tinham o mesmo nível das competições internacionais, mas com menos fases. Na última etapa, em Belo Horizonte, tive a chance de encontrar alguns conhecidos e fazer novas amizades no meio dos 50 finalistas, dentre elas Jelani Nelson, aluno de PhD e técnico do MIT, participando pela Virgin Islands; Vinicius Fortuna ex-competidor e agora engenheiro de software do Google em Nova Iorque, que veio entrevistar os competidores; Wanderley Guimarães, atual técnico do IME-USP, além de já conhecidos e excelentes competidores do ITA e PUC-RIO. Pelo vídeo promocional, da para você ter uma idéia do quão a sério o Google leva essas competições:

Depois teve a final mundial da ACM (ACM-ICPC) em Tokyo, Japão, onde fui representando o time do IME-USP, depois da qualificação pela Maratona de Programação brasileira. Lá contamos com a presença de diversos nomes interessantes, como o criador do Ruby, Yukihiro Matsumoto, que palestrou sobre sua linguagem de programação. Entre seus comentários oportunos, disse que eficácia não é a grande preocupação de Ruby; 80% do design de uma linguagem está feito se o nome for curto, pequeno e bonito (Ruby). Outra frase dele foi “Web 2.0, o que é isso?”. Modesto.

Também estava presente Stuart Feldman que, além de presidente da ACM e criador do primeiro compilador de Fotran 77, fez parte do grupo que criou o Unix e o make. Yuhichi Nakamura, criador do Xerces (xml4j), e diretor do IBM Tokyo Research Lab estava ajudando na coordenação do evento.

Nessa competição, mais de seis mil equipes participaram do evento nas competições regionais, de mais de 1700 universidades diferentes do mundo inteiro. A competição foi emocionante, com os quatro times brasileiros bem colocados. Além disso, dois times brasileiros resolveram 4 problemas, um marco na história da competição, onde o problema mais simples envolvia um algoritmo do tipo Longest Common Subsequence. Esse é um algoritmo muito usado em inúmeros lugares, como em biologia computacional para verificar padrões de sequencias de DNA. No fim das contas, os problemas dessas competições não são tão irreais assim! Alguns problemas são muito difíceis, sendo que nenhuma equipe do mundo conseguiu resolver. Você pode ver a prova da competição aqui.

O evento aconteceu no Hilton Tokyo Bay, um hotel dentro da Disney de Tokyo e muito bonito. Os quartos tinham vista para o monte Fuji e foi possível conhecer um pouco do país e de sua história.

07-DH_CON-_D4V0186[LO] 07-DH_TP-_MG_0281
07-DH_CON-_D4V0178[LO] 07-DH_CON2-_D4V0240[LO]

O Fórum Internacional de Software Livre preparou esse ano uma competição diferente, a Arena de programação, composta por duas fases. Para poder se inscrever, era necessário resolver um problema de lógica no próprio site, no estilo python-challenge, mas bem mais simples. A idéia era encontrar o caminho para a inscrição usando de seus dotes “hackers”. O Dorneles postou a descrição de como se inscrever em detalhes.

Chegando no evento, pronto para a primeira fase, a Arena era um cercado de vidro, quase um aquário, onde os animais eram os programadores.

A primeira fase terminou com alguns conhecidos entre os top. O Hugo Corbucci, colega de viagem ao fisl pelo IME-USP, o Klaus Wustefeld e o Kalecser Kurtz, o Dornelles Tremea e eu nos qualificamos entre os top 12. A segunda fase começou no dia seguinte e era composta por, supostamente, 24 horas de programação non-stop. Os 12 primeiros da fase anterior foram divididos em quatro grupos de três competidores. Na minha equipe? Kalecser, expert em Java e Dornelles, expert em Python e linux em geral. A tarefa? Resolver quatro bugs ou feature requests do Debian. Isso mesmo. Eles deram quatro códigos de bugs que estão ocorrendo em pacotes do Debian ou que feature requests que os usuários postaram e pediram para as equipes resolverem. Excelente proposta!

O primeiro bug envolvia um problema com o teclado. Você que é fã incondicional do Debian pode alternar para o tty1 (Ctrl+alt+F1), ativar o CAPS LOCK e tentar digitar “ABCD”… se o resultado for “ABcD”, você reproduziu o bug - que só funciona com alguns layouts de teclado. Encontramos muitas informações sobre o assunto e não conseguimos resolvê-lo, fomos capazes de encontrar textos indicando que o problema era mais delicado. Tudo isso após passar por muito código fonte em bash, perl etc. O segundo bug estava no pacote cdebconf, que é responsável pelo processo de configuração de pacotes debian durante o processo de instalação dos mesmos. Após correr por diversos arquivos feitos em C, com um “quê” de orientação a objeto, fomos capazes de isolar o bug e corrigi-lo, e o patch deve se tornar disponível em breve.

O terceiro bug envolve o bugtracking do debian, que não apresentava os dados da maneira que era requisitado, enquanto o último problema estava ligado ao particionador, que encontrava problemas durante o redimensionamento em determinados casos. Muito código perl apareceu enquanto solucionávamos o terceiro bug, mas não houve tempo suficiente para sequer olhar com calma o último. No dia seguinte, a segunda parte dessa fase envolveu o desenvolvimento do zero de um programa para facilitar a internacionalização dos pacotes debian. Nosso objetivo era utilizar o Lucene para fazer o partial matching de palavras ou frases já traduzidas anteriormente em outros pacotes, mas devido ao padrão de i18n adotado pelo debian, o Java acabou segurando um pouco o desenvolvimento, mas ainda fomos capazes de mostrar algo funcional com uma implementação do Edit Distance para procurar palavras similares.

O resultado de tudo isso saiu no final do dia, durante o fechamento do evento, nossa equipe ficou em primeiro lugar! O que ganhei com tudo isso? Conheci novas pessoas que trabalham com projetos open source de áreas diferentes de Java, coloquei em prática o meu conhecimento de C que só usava na teoria, e ajudei com um projeto que jamais sonhei ser possível ajudar. Claro, o notebook que deram para cada um de nossa equipe também conta! Fui entrevistado a respeito dessa competição. Espero encontrar vocês nas próximas!

USP, São Carlos, software livre e o OLPC

Por Paulo Silveira em 08/02/07

Esses últimos dois dias estive em São Carlos, no ICMC da USP (casa de alguns colegas da comunidade). Dois professores do IME, instituto onde estudo e mantenho alguns trabalhos, não puderam participar então fui, jutamente com o Alexandre Freire, a apresentação do italiano Stefano De Panfilis da Engineering Ingegneria Informatica (maior empresa de software da Itália), que veio falar sobre o projeto Qualipso e os centros de competência de software livre que estão sendo criados na União Européia (e eles estão bancando um na China e outro aqui no nosso Brasil). A previsão da união européia sobre o uso de software livre nas empresas não poderia ser mais animadora. A polêmica idéia da UE é a de criar um certificado “CMM-like” para projetos open source. Arrojado.

O Alexandre Freire é um cara ímpar: foi desenvolvedor java em Trevenso na Itália, couch de XP na paggo, hospedou o Richard Stallman em sua própria casa por uma semana, é um dos responsáveis pelo Estúdio Livre, gerente de projeto do Ministério da Cultura (MinC) quando palestrou em diversos lugares do mundo, desde a Inglaterra até a Tunísia, já jantou com o Carlos Villela e com o chefão da Thoughtworks por lá, e até instalou internet via satélite em uma aldeia cabloca no interior do Pará: Aritapera. Um ativista. Sempre que o encontro ele está tecendo muitas idéias novas. O volume de informações que eu adquiro é incrível.

Durante a apresentação do Alexandre, me dei conta que o IME já produziu bastante software livre: avançados hacks no kernel do linux, agendamento de carga didática usando algoritmos genéticos, diversos plugins para o eclipse, organizadores de aula, sistemas de prontuário eletrônico usando PDAs, possui comitters no JBoss e Jacorb, entre uma lista com mais de 20, e devem haver mais sem contar as implementações de algoritmos sem uso direto na indústria.

O grande problema é gerenciar todo esse trabalho e código: como reaproveitá-lo. O Centro de Competência em Software Livre da USP, que está sendo construído grudado ao bloco do IME, será responsável por isso e muito mais!

CIMG1121 CIMG1117
CIMG1113 CIMG1111

Também tive ontém meu primeiro contato com o OLPC devido a proximidade do Alexandre com o MinC. É o primeiro protótipo (deverá haver mais dois). Fiquei muito impressionado com o que conseguiram fazer com 145 dólares: 256 mb de ram, um excelente lcd, câmera, som, wifi e dois slots usb. O teclado e o touchpad desta versão não estão muito funcionais (leia-se: as vezes não funcionam). Quando fechado ele realmente parece um brinquedo (passaria desapercebido como uma lancheira).

O Sugar, o desktop manager do OLPC, é um show a parte: eles mudaram totalmente o conceito de desktop: as crianças possuem três ambientes (que podem ser acessados por teclas): as suas aplicações, as aplicações que estão comparilhadas entre seus amigos, e as aplicações que estão compartilhadas entre todo mundo. Isso tudo via descoberta ad-hoc e sem usar palavras, apenas ícones, aumentando o apelo para as crianças.

O Etoys é uma aplicação escrita em Smalltalk rodando no Squeak, que tem inspirações no nosso bom e velho Logo (saudades do CP400 de meu pai), vai certamente trazer algumas crianças para o nosso ramo. Confira no vídeo abaixo uma apresentação do sugar e repare no Etoys.

Java não vem instalado, mas com o Java 6 sendo GPL talvez isso mude. A maioria das aplicações são escritas em python. Todas as aplicações são colaborativas: até mesmo o firefox pode ser compatilhado para que o guri mostre a seus amigos o incrível artigo que descobriu no wikipedia (ou quem sabe um tutorial de como quebrar MD5 por força bruta com menos tentativas). Confesso que sempre duvidei do sucesso do projeto, agora mudei de lado.

Conheci lá o Christian Reis, um python hacker amigo do Alexandre que dirige a Async, uma empresa fortemente ligada com a Canonical, prestando serviço para fora e fabricando software livre. Fiquei impressionado com a relação da empresa com a universidade e a comunidade. Seu modelo de negócios vale um estudo aprofundado.

Foram dois dias bem agitados. A Caelum vai participar de perto do centro de competência e em breve teremos novidades.