Posts Tagged ‘Integração Contínua’

Estamos contratando no Yahoo! Brasil

Thursday, November 18th, 2010

Estamos contratando desenvolvedores para o Yahoo! Brasil!

Nosso time é responsável pelo desenvolvimento e manutenção do Yahoo! Meme. Para trabalhar conosco é imprescindível ser faixa preta em Python, PHP ou JavaScript e conhecer pelo menos uma segunda outra dessas três. Mesmo sendo essas as principais linguagens que usamos por aqui, precisamos de desenvolvedores multidisciplinares que saibam usar diferentes tipos de ferramentas – porque nunca sabemos quais produtos virão no futuro e que tipos de vantagens poderemos ter usando ferramentas diferentes.

Tão ou mais importante do que isso é ter ótimos conhecimentos sobre desenvolvimento ágil (especialmente XP), conhecer ferramentas de testes unitários, ser capaz de trabalhar com TDD, entender sobre CI e a sua importância, automatização de rotinas/build/etc., melhores práticas de desenvolvimento de software, Orientação à Objetos, Domain-Driven Design e tudo mais que puder ser relevante para ajudar a construir software confiável e manutenível de forma rápida e com ritmo/qualidade sustentável. Experiência com automatização de testes com Selenium ou Webdriver também é essencial. Como trabalhamos com web, também é necessário ter conhecimento em HTML, CSS e desenvolvimento de aplicações cross-browser.

Como desenvolvemos produtos de escala mundial, é necessário ter experiência com aplicações de alta performance e disponibilidade, identificação e otimização de gargalos de performance, escalabilidade, caching e sharding. É importante também ter bons conhecimentos de pelo menos um tipo de Unix e seus derivados.

Conhecimentos em C, C++, arquitetura de serviços, desenvolvimento de mashups, experiência com uso e desenvolvimento de APIs (REST, YQL, etc.) e experiência em desenvolvimento para iPhone/iPad são bons diferenciais, porém não são requeridos.

Para estas posições é necessário saber inglês bem, o que quer dizer que você deve ser capaz de conversar e ler/escrever em inglês sem problemas (e eventualmente ser entrevistado em inglês caso necessário).

Estamos procurando por pessoas criativas, que gostem de inovação, de pesquisar e identificar novas tendências e de encarar desafios complexos com agilidade e velocidade. Nosso time é pequeno, jovem e nosso ambiente está em constante mudança e evolução. Queremos pessoas irreverentes, que gostem de desafios, com idéias novas e com vontade de criar produtos incríveis!

A empresa oferece contratação apenas por CLT e benefícios como plano de saúde e vale refeição. Estamos localizados na Vila Olímpia em São Paulo. Geralmente contratamos pessoas de outros estados, mas desta vez infelizmente só estamos contratando pessoas de São Paulo/Capital. Update: Voltamos a contratar pessoas pessoas de outros estados e oferecemos auxílio para mudança (passagem, hospedagem, etc.).

Se você se encaixa neste perfil, envie seu curriculo em inglês para mim (gc AT yahoo-inc.com) com uma lista dos últimos 3 livros técnicos que leu. Não esqueça de colocar links para o seu Twitter, LinkedIn, GitHub e o que mais você achar relevante e que pode nos ajudar a te conhecer melhor. :)

Update: mais detalhes sobre a vaga (em inglês) na página de desenvolvedores do Meme.

Yahoo! procura Ninjas

Thursday, January 14th, 2010

Estamos procurando Desenvolvedores e Scrum Masters Ninjas para integrarem nossa equipe no Yahoo!

Nosso time é o que chamamos de “Innovation Cell”, que é algo como uma incubadora de projetos, responsável por pesquisar e criar novos produtos. Atualmente nosso carro-chefe é o Yahoo! Meme, que foi inteiramente desenvolvido no Brasil no último ano e já está em vários outros países como Indonésia, Filipinas, México, Argentina e Taiwan.

Desenvolvedor Ninja

Os Desenvolvedores Ninja serão responsáveis pelo desenvolvimento e manutenção de aplicações web, em especial o Yahoo! Meme e outros aplicativos de integração com redes sociais. É imprescindível ser faixa preta em Python, PHP ou JavaScript e conhecer bem pelo menos uma segunda outra dessas três. Mesmo sendo essas as principais linguagens que usamos por aqui, precisamos de desenvolvedores multidisciplinares que saibam usar diferentes tipos de ferramentas – porque nunca sabemos quais produtos virão no futuro e que tipos de vantagens poderemos ter usando ferramentas diferentes.

Tão ou mais importante do que isso é ter ótimos conhecimentos sobre desenvolvimento ágil e ser capaz de trabalhar com TDD, entender sobre CI e a sua importância, automatização de rotinas/build/etc., melhores práticas de desenvolvimento de software, Orientação à Objetos, Domain-Driven Design e tudo mais que puder ser relevante para ajudar a construir software confiável e manutenível de forma rápida e com ritmo/qualidade sustentável. Experiência com automatização de testes com Selenium ou Webdriver também é essencial.

Como desenvolvemos produtos de escala mundial, é necessário ter experiência com aplicações de alta performance e disponibilidade, identificação e otimização de gargalos de performance, escalabilidade, caching e sharding. É importante também ter bons conhecimentos de pelo menos um tipo de Unix e seus derivados.

Conhecimentos de OpenSocial, desenvolvimento de mashups, arquitetura de serviços e experiência com uso e desenvolvimento de APIs (REST, YQL, etc.) são diferenciais.

Scrum Master Ninja

O Scrum Master Ninja deverá ajudar o time de desenvolvimento a produzir no máximo da sua capacidade. Sua missão será organizar e facilitar os Sprint Plannings e Reviews, bem como Retrospectivas e o que mais for necessário para suportar os times de desenvolvimento e produto. Ele deverá identificar e remover impedimentos, ajudar o time a manter o foco mas dando todo o espaço e autonomia que ele precisa para se auto-organizar e gerenciar. É necessário já ter tido alguma experiência anterior relevante nesta posição.

Como o Yahoo! é uma empresa que em sua maioria ainda trabalha com métodos tradicionais de desenvolvimento, esta pessoa também será responsável por fazer com que o time esteja dentro das normas da empresa, gerando relatórios para as células de gerenciamento de projetos e fazendo algum trabalho burocrático de registro e comunicação de métricas.

Queremos um Scrum Master influente, que seja capaz de entender questões técnicas mesmo que em alto nível, que seja apaixonado por procurar maneiras de melhorar o processo de desenvolvimento, construtivo na hora de resolver problemas e solucionar conflitos e com muita vontade de descobrir novas maneiras de trabalhar com métodos ágeis. O Yahoo! é uma empresa que ainda está engatinhando em métodos ágeis e por isso precisamos de alguém com muita disposição e vontade de mudar a empresa!

Por último, experiência com XP, Lean Software Development, Kanban e diversos métodos ágeis são diferenciais.

Continuando…

Para ambas as posições é necessário inglês avançado, o que quer dizer que você deve ser capaz de conversar e ler/escrever em inglês sem problemas (e eventualmente ser entrevistado em inglês caso necessário).

Estamos procurando por pessoas criativas, que gostem de inovação, de pesquisar e identificar novas tendências e de encarar desafios complexos com agilidade e velocidade. Nosso time é pequeno, jovem e nosso ambiente está em constante mudança e evolução. Queremos pessoas irreverentes, que gostem de desafios, com idéias novas e com vontade de criar produtos incríveis!

A empresa oferece contratação apenas por CLT e benefícios como plano de saúde e ticket refeição. Estamos localizados na Vila Olímpia em São Paulo. Vamos dar preferência para pessoas de São Paulo mas também vamos olhar com carinho currículos de pessoas de fora e daremos auxílio para mudança caso necessário.

Se você se encaixa em algum destes perfis, mande seu curriculo em inglês para mim (gc AT yahoo-inc.com) com uma lista dos últimos 3 livros técnicos que leu. Não esqueça de colocar links para o seu Twitter, LinkedIn, GitHub e o que mais você achar relevante e que pode nos ajudar a te conhecer melhor. :)

Uma história de fracasso com Scrum

Friday, March 13th, 2009

Veja o que pode acontecer quando você usa Scrum mas não é ágil de verdade: :D

CruiseControl 2.7

Sunday, June 17th, 2007

Acabei de ler no blog da ThoughtWorks sobre o lançamento de uma nova versão do CruiseControl.

Esta versão é a primeira lançada depois do anúncio do CruiseControl Enterprise, eu pessoalmente estava com uma expectativa grande para ver os resultados práticos desta mudança.

Dentre várias melhorias, a mais legal delas foi o novo dashboard que possibilita que você saiba rapidamente o status dos builds do seu projeto, dentre outras informações. Além disso será possível desenvolver os seus próprios widgets e montar uma tela com todas as informações do projeto que você desejar!

Testes com JUnit + HSQLDB

Thursday, May 17th, 2007

Hoje fiz uma experiência legal no projeto em que estou trabalhando.

Estou há um tempinho bolando uma forma razoável para testar a aplicação de cabo a rabo. A única coisa que eu ainda não estava convencido totalmente sobre como fazer era testar as classes DAO ou fazer testes envolvendo elas.

Já lí em alguns lugares algumas pessoas falando que os testes não devem utilizar o banco de dados por uma série de motivos e que os DAOs sempre devem ser mocks. Até eu mesmo já cheguei a questionar se isso é realmente necessário. Depois de um tempinho com a idéia fermentando na cabeça eu penso o seguinte:

Primeiro: É interessante testar os DAOs porque você precisa garantir por exemplo que todos os campos estão sendo lidos corretamente para os objetos e que as queries funcionam. No caso de utilização de JPA/Hibernate ainda te ajuda a validar se o mapeamento objeto-relacional está correto.

Segundo: Existem alguns tipos de testes que podem ser feitos na sua aplicação. Se falarmos de teste unitário eu concordo que não deve haver utilização de banco de dados mas sim mocks para os DAOs e tudo mais que não for objeto do teste em questão. Porém para testes de integração ou aceitação é desejável que o banco de dados seja incluído no teste já que faz parte da aplicação.

Mas o problema de envolver o BD nos testes é que eles (os testes) ficam muito lentos e isso desfavorece o desenvolvimento guiado por testes, que eu não vivo sem. Se os testes demoram eles são executados menos vezes e isso não é bom. Sem contar que se os dados do banco forem modificados os testes quebram. Argh!

Eis que surge o HSQLDB. O HSQLDB é um banco de dados escrito em Java puro, tem driver JDBC que funciona direitinho e entende comandos SQL com JOINs, GROUP BYs e praticamente tudo mais que você utiliza numa aplicação que utiliza o banco de dados de forma NORMAL (normal = não utiliza aquelas tosqueiras proprietárias do BD que depois que se usa não dá mais para trocar nem a versão do bicho!).

O que eu fiz foi fazer com que os testes se conectassem num HSQLDB ao invés do banco de dados de desenvolvimento. Para melhorar, esse HSQLDB não está nem rodando em modo server em lugar nenhum. Ele é iniciando junto com os testes e roda em memória na mesma JVM que os testes rodam.

Quais foram os ganhos obtidos com este approach:

1) Minhas queries agora estão sendo testadas, assim como a criação dos meus objetos pelos DAOs.

2) Os testes estão muito rápidos, nem parece que usam banco de dados! Eu tinha criado duas suites de testes, uma que tinha testes com BD e outra sem BD. Isso nem será mais necessário agora.

3) Agora eu tenho a garantia de que os dados de teste não serão modificados e com isso os testes não quebrarão mais por este motivo. Sabendo que os dados não mudarão posso fazer testes mais completos e elaborados.

Porém também experimentei alguns pontos negativos:

1) Qualquer alteração de modelo tem que ser refletida no script de startup do HSQLDB. O script de startup é necessário para indicar quais tabelas com quais campos e dados ele criará em memória. São CREATE TABLEs com duas ou três coisinhas a mais, muda pouca coisa.

2) Em algumas aplicações que eu trabalho tem lógica da query no hint!!! Isso acontece porque lá na empresa tem um trilhão de aplicações rodando em produção no mesmo Oracle que eu rodo minha aplicação. Sendo assim se eu faço uma query ferrada eu derrubo o banco e junto com ele uma boa parte da empresa. Para evitar que isso aconteça os DBAs otimizam uma boa parte das queries que fazemos, só que as vezes a coisa fica tão dramática que os DBAs têm que fazer MAGIAS no hint para a query executar num tempo razoável. Aí eles mexem tanto no hint que no final a query depende do hint para funcionar, quando o hint deveria ser só para ela ficar mais rápida. Aí fica assim: com o hint a query retorna o resultado de um jeito e sem hint de outro! Como hint é coisa do Oracle e o HSQLDB entende como comentário, eventualmente não será possível testar uma ou outra query porque no HSQLDB o resultado será retornado sem executar a lógica contida no raio do hint!

Vou evoluir mais em cima desta idéia e na medida que as coisas forem acontecendo eu posto aqui mais comentários.

Test Driven Development in a nutshell

Wednesday, May 9th, 2007

Semana passada tivemos uma reunião na empresa em que trabalho sobre os procedimentos de controle de qualidade dos softwares que produzimos. Antes de fazer o release de um software é necessário que sejam tomadas algumas precauções básicas para garantir que ele funcione satisfatoriamente em produção e estávamos apresentando para os nossos gerentes e equipe de controle de qualidade da empresa as ferramentas e procedimentos adotados pela nossa equipe para isto.

Das várias medidas que estamos tomando, talvez a principal por ser a base para todas as outras direta ou indiretamente é o “desenvolvimento guiado pelos testes” ou “test driven development” (TDD para os mais íntimos).

No TDD você desenvolve os testes do software antes mesmo de desenvolver o software. A cada peça da aplicação que é construída uma série de testes são escritos ANTES do desenvolvimento para garantir que a aplicação funciona como deveria funcionar.

O conceito de TDD é bem simples de ser aplicado mas para quem não está acostumado com testes unitários e práticas de desenvolvimento ágil pode parecer meio estranho e ser um pouco mais difícil de entender.

Inspirado nesse cenário vou tentar explicar rapidamente como funciona o TDD com um exemplo prático e bem simples. Vou explicar seguindo a linha de raciocínio que normalmente se tem em tempo de programação pois a maneira de pensar no processo de desenvolvimento também faz parte do TDD.

Imagine que você está desenvolvendo um sistema no qual um usuário deve cadastrar seu endereço. O CEP digitado precisa ser validado para que tenha o formato 00000-000 e para isso será necessário desenvolver uma classe que faça a validação dos dados. Vamos definir a interface para esta classe de validação de dados:

public interface ValidadorDeDados {
    boolean isCepValido(String cep);
}

A partir deste ponto já temos o comportamento do nosso validador claramente definido: dada uma String contendo o valor de um CEP ele retornará verdadeiro se o CEP for válido e falso caso contrário. Por exemplo, se o validador receber uma String “teste” ou “” obviamente deverá retornar falso. Por outro lado se ele receber uma String “00000-000″ ou “12345-123″ deverá retornar verdadeiro.

Então já podemos desenvolver uma classe de teste que faça estas verificações e mais algumas outras pertinentes. Vou utilizar para os testes o framework JUnit que é o framework de testes unitários Java mais popular do mercado.

public class ValidadorDeDadosTest extends TestCase {
    private ValidadorDeDados validador = null; // instância de validador de dados para o teste
 
    public void testIsCepValido() {
        assertFalse("retorno deve ser FALSE", validador.isCepValido(null));
        assertFalse("retorno deve ser FALSE", validador.isCepValido(""));
        assertFalse("retorno deve ser FALSE", validador.isCepValido("iodfjodfd"));
        assertFalse("retorno deve ser FALSE", validador.isCepValido("03490340"));
        assertTrue("retorno deve ser TRUE", validador.isCepValido("20202-020"));
        assertTrue("retorno deve ser TRUE", validador.isCepValido("00000-000"));
        assertTrue("retorno deve ser TRUE", validador.isCepValido("99999-999"));
    }
}

Para quem não conhece o JUnit, o método assertFalse checa se o retorno da execução retornou falso e o método assertTrue checa se o retorno da execução retornou verdadeiro. Em todos os casos que o assertTrue foi utilizado o validador deverá retornar verdadeiro e o oposto deverá acontecer para os assertFalse. Se isto não acontecer, significa que tem alguma coisa errada.

Além disso colocamos uma pequena mensagem explicando o que esperamos que aconteça na execução do método. Isso é util para que outros desenvolvedores da equipe possam entender com facilidade o que você programou e está esperando que aconteça nos seus testes, bem como para deixar as mensagens de erro mais explicativas.

Só para não deixar dúvida nenhuma, vamos ler uma das linhas de teste:

assertFalse("retorno deve ser FALSE", validador.isCepValido(""));

Que é: Ao executar a validação do CEP “”, certifique-se que ele retornará FALSO.

Então vamos executar o teste para ver o que vai acontecer:

TDD 1

Ele falhou com NullPointerException porque não há uma implementação de validador, desenvolvemos somente a interface. No teste unitário o validador está setado como null.

Sendo assim, vamos desenvolver a primeira implementação de validador:

public class ValidadorDeDadosImpl implements ValidadorDeDados {
    public boolean isCepValido(String cep) {
        return false;
    }
}

Além disso é necessário alterar a classe de teste para utilizar esta implementação de validador de dados que desenvolvemos.

public class ValidadorDeDadosTest extends TestCase {
    private ValidadorDeDados validador = new ValidadorDeDadosImpl(); // agora o validador não é mais null
 
    public void testIsCepValido() {
        assertFalse("retorno deve ser FALSE", validador.isCepValido(null));
        assertFalse("retorno deve ser FALSE", validador.isCepValido(""));
        assertFalse("retorno deve ser FALSE", validador.isCepValido("iodfjodfd"));
        assertFalse("retorno deve ser FALSE", validador.isCepValido("03490340"));
        assertTrue("retorno deve ser TRUE", validador.isCepValido("20202-020"));
        assertTrue("retorno deve ser TRUE", validador.isCepValido("00000-000"));
        assertTrue("retorno deve ser TRUE", validador.isCepValido("99999-999"));
    }
}

Agora o teste já está rodando, o resultado foi bem diferente. Antes estava sendo lançada uma exception porque a implementação do validador de dados sequer existia. Agora o que acontece é que temos um problema na implementação do validador e o teste acusou isso:

TDD 2

Veja a implementação do validador de dador e repare que independente da String passada para o método ele retorna falso, ou seja, está errado. Vamos corrigir essa implementação:

public class ValidadorDeDadosImpl implements ValidadorDeDados {
    public boolean isCepValido(String cep) {
        if ((cep == null) || (cep.length() != 9) || cep.charAt(5) != '-') {
                return false;
        }
        return true;
    }
}

E executando novamente os testes podemos verificar que agora todos estão passando:

TDD 3

Desenvolvimento finalizado? Nada disso. Navegando pelo sistema e fazendo outros testes manuais descobrimos que é possível entrar com um CEP com letras tipo ABCDE-FGH. Se analisarmos a implementação do método veremos que isso realmente é possível. Não há nenhuma verificação que impeça isto.

Mas caramba, os testes não passaram? É verdade, os testes ainda estão passando. Acabamos de descobrir um bug.

Quando um bug é descoberto ou é reportado para a equipe de desenvolvimento, a primeira coisa a se fazer é escrever um teste para comprovar a existência do bug. Vamos então complementar a nossa classe de teste:

public class ValidadorDeDadosTest extends TestCase {
    private ValidadorDeDados validador = new ValidadorDeDadosImpl();
 
    public void testIsCepValido() {
        assertFalse("retorno deve ser FALSE", validador.isCepValido(null));
        assertFalse("retorno deve ser FALSE", validador.isCepValido(""));
        assertFalse("retorno deve ser FALSE", validador.isCepValido("iodfjodfd"));
        assertFalse("retorno deve ser FALSE", validador.isCepValido("03490340"));
        assertTrue("retorno deve ser TRUE", validador.isCepValido("20202-020"));
        assertTrue("retorno deve ser TRUE", validador.isCepValido("00000-000"));
        assertTrue("retorno deve ser TRUE", validador.isCepValido("99999-999"));
    }
 
    public void testIsCepValidoComLetras() {
        assertFalse("retorno deve ser FALSE", validador.isCepValido("AAAAA-AAA"));
        assertFalse("retorno deve ser FALSE", validador.isCepValido("A2AA1-333"));
        assertFalse("retorno deve ser FALSE", validador.isCepValido("x2334-567"));
    }
}

Executando os testes novamente vemos que o teste que acabamos de escrever falhou. Ao entrar com este CEP o validador deveria retornar falso pois é um CEP inválido mas ele está retornando verdadeiro. Muito bem, o bug está comprovado:

TDD 4

Repare que somente o teste novo está falhando, os testes antigos estão passando normalmente (em verde).

Com os testes prontos já podemos fazer a correção na implementação:

public class ValidadorDeDadosImpl implements ValidadorDeDados {
    public boolean isCepValido(String cep) {
        if ((cep == null) || (cep.length() != 9) || cep.charAt(5) != '-') {
            return false;
        }
        for (int i = 0; i < cep.length(); i++) {
            if (i != 5) {
                char posicao = cep.charAt(i);
                if (!Character.isDigit(posicao)) {
                    return false;
                }
            }
        }
        return true;
    }
}

E corrigida a implementação, vamos executar os testes novamente para verificar se o bug foi corrigido:

TDD 5

Agora sim tudo funcionando.

Podemos perceber como é fácil implementar funcionalidades e corrigir bugs com TDD. Alguns pontos fortes que merecem destaque:

1) Qualquer tipo de implementação por mais complexa que seja será suportada pelos testes e com isso você programa com mais confiança. Dado um comportamento do método que será definido antes do desenvolvimento você pode executar os testes inúmeras vezes até que eles passem. E quando eles passam você tem certeza absoluta de que o que você fez está efetivamente funcionando.

2) TDD facilita o refactoring: depois de cada reescrita de código ou qualquer tipo de alteração, especialmente em códigos que você não conhece bem porque foram feitos por outros membros da equipe, você pode rodar os testes da aplicação inteira afim de garantir que você não está quebrando nenhuma funcionalidade. Alguns sistemas são tão podres que dependendo do lugar que você mexe quebra tudo. Os testes te ajudam a não fazer isso.

3) Mesmo que seja um pouco mais demorado escrever testes ao desenvolver, com esta prática você praticamente não encontra bugs em produção e quando encontra eles podem ser corrigidos rapidamente e com confiança. Então no final das contas você GANHA tempo. E o melhor de tudo é que você programador não precisa ficar pisando em ovos e sem dormir porque mexeu na aplicação. Algumas aplicações são tão difĩceis de serem alteradas (porque são mal programadas) que você vai para casa e dorme com o celular do lado porque tem certeza que ele vai tocar porque deu pau no sistema!

Então, preserve seus cabelos e sua saúde: programe com qualidade! ;)

Download do código fonte.