Internacionalização colaborativa

A ideia de colaboração realmente deve invadir o desenvolvimento de software. Para sistemas que são mundiais é interessante ter um processo eficaz de internacionalizar a linguagem do software.

Descobri hoje que o sistema de compressão de arquivos B1 é desenvolvido sobre o framework Crowdin, uma excelente ferramenta para que deseja internacionalizar colaborativamente.

,

Deixe um comentário

Aprendendo TDD (ou Desenvolvimento Orientado a Testes) Python

Reblogado de: http://blog.thiagobelem.net/aprendendo-tdd-ou-desenvolvimento-orientado-a-testes/

Mas afinal, que diabos é TDD?

Segundo a Wikipédia, TDD é:

Test Driven Development (TDD) ou em português Desenvolvimento dirigido guiado por testes é uma técnica de desenvolvimento de software que baseia em um ciclo curto de repetições:

Primeiramente o desenvolvedor escreve um caso de teste automatizado que define uma melhoria desejada ou uma nova funcionalidade. Então, é produzido código que possa ser validado pelo teste para posteriormente o código ser refatorado para um código sob padrões aceitáveis.

Kent Beck, considerado o criador ou o ‘descobridor’ da técnica, declarou em 2003 que TDD encoraja designs de código simples e inspira confiança.

E qual a vantagem disso?

Pra mim, TDD é uma forma de você garantir que, através de pequenos passos, você vai chegar à um “todo-completo”, que é uma aplicação que funciona baseado apenas nas especificações que foram definidas, e lá na frente quando você for mudar algo, é só rodar os testes novamente para garantir que tudo continue funcionando.

Mas por via das dúvidas, pesquisem mais sobre o assunto, tem um mundo por trás disso tudo.

“Talk is cheap! Shut up and show me the code!”

(eu amo essa frase)

Vamos direto ao ponto e vamos ver um pequeno exemplo de como criar uma função baseada em TDD… e vamos começar pelo exemplo mais simples e usado por todos: o famoso Fizz Buzz, que segundo a nossa amiga Wikipédia é:

Bizz buzz (also known as fizz buzz, or simply buzz) is a group word game frequently encountered as a drinking game. Players take turns to count incrementally, replacing any number divisible by three with the word “bizz”, and any number divisible by five with the word “buzz”.

Tradução deste que vos fala:

Bizz buzz (também conhecido com fizz buzz, ou apenas buzz) é uma brincadeira em grupo, comummente jogada como desculpa pra encher a cara. Os jogadores jogam em turnos incrementais, onde cada um fala um número substituindo números divisíveis por três pela palavra “fizz“, e números divisíveis por cinco pela palavra “buzz“.

Sendo que você precisa falar “fizz buzz” quando o número for múltiplo de três e de cinco.

Básicamente o resultado final do jogo seria algo assim:

1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, Fizz Buzz, 16, 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, Fizz Buzz, 31, 32, Fizz, 34, Buzz, Fizz, …

Então vamos criar uma função FizzBuzz que receba um parâmetro N e retorne o número, fizz, buzz ou fizz buzz dependendo do número que ela recebeu. :)

Antes de qualquer coisa, vou fazer algo que aprendi com esse livro e recomendo muito: vamos montar uma lista de especificações que precisaremos testar/implementar.

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”

Essas não são todas as regras do jogo, mas já é um bom começo… Cada um desses itens vai significar um teste e – possivelmente – uma melhoria no código da função.

Ao longo desse artigo irei copiar essa lista diversas vezes, marcando com negrito os itens que iremos atacar, e riscando os itens que forem concluídos.

Mas peraí… e a linguagem?

Verdade… temos que decidir uma linguagem, e como eu falo MUITO de PHP aqui no blog vamos fazer esse FizzBuzz em Python, que já vem com um framework de testes embutido na linguagem, pra quem quiser brincar de testes unitários no PHP recomendo muito o PHPUnit.

Baby steps, ou “Passos de bebê”

Uma das maiores características do desenvolvimento orientado à testes é que você sempre tente dar passos menores que suas pernas, não significa que você não possa dar uma corrida se o projeto exigir, mas sempre avance com pequenos passos, nada de escrever 100 linhas de código sem testar (com testes)… e eu vou tentar seguir essa metodologia aqui.

Mãos à obra!

No TDD você SEMPRE começa pelo teste, então vamos começar criando nosso arquivo de testes:

#!/usr/bin/env python

import unittest

if __name__ == '__main__':
unittest.main()

Fizemos três coisas no nosso arquivo fizzbuzz_test.py:

  1. Primeiro temos #!/usr/bin/env python que permite que executemos o arquivo sem ser através do executável do Python, mas isso é opcional.
  2. Depois importamos a biblioteca nativa de testes unitários do Python
  3. E por fim usamos uma condição que – resumidamente – permite que o arquivo seja executado pelo terminal já rodando os testes

Quando a gente rodar esse arquivo com o comando ./fizzbuzz_test.py ou o comando python fizzbuzz_test.py vamos ter o seguinte output:

$ python fizzbuzz_test.py

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK
view raw
gistfile1.sh
This Gist brought to you by GitHub.

Então sabemos que tudo está funcionando… prontos para o primeiro teste?

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”

Nosso primeiro teste, da forma mais simples e reduzida possível, ficaria assim:

#!/usr/bin/env python

import unittest

class TestFizzBuzz(unittest.TestCase):

def test_FizzBuzz(self):
self.assertEqual(FizzBuzz(1), 1)

if __name__ == '__main__':
unittest.main()

Criamos uma classe TestFizzBuzz, que é um caso de teste (contém vários testes) para testar a classe/funcionalidade FizzBuzz.

Definimos nosso primeiro teste (test_FizzBuzz), onde fizemos uma asserção (verificação):

O resultado de FizzBuzz(1) é IGUAL a 1?

A asserção de igualdade é justamente o método assertEqual:)

Prontos pra rodar o teste? Vamos ver o que acontece…

$ python fizzbuzz_test.py
E
======================================================================
ERROR: test_FizzBuzz (__main__.TestFizzBuzz)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "fizzbuzz_test.py", line 8, in test_FizzBuzz
    self.assertEqual(FizzBuzz(1), 1)
NameError: global name 'FizzBuzz' is not defined

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

view raw
gistfile1.sh
This Gist brought to you by GitHub.

UHU! Nosso primeiro erro! (sim, no TDD os testes não passando significam progresso).. mas não é o erro que eu estava esperando! :(

O problema é que nós ainda não definimos FizzBuzz, por isso o Python xiou dizendo “global name ‘FizzBuzz’ is not defined“.

Vamos criar nosso arquivo fizzbuzz.py com o seguinte conteúdo:

#!/usr/bin/env python

def FizzBuzz():
pass
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

Criamos a estrutura da nossa função FizzBuzz que ainda não faz nada.

O “pass” no Python é usado quando uma função/método ainda não tem conteúdo.. e como não temos chaves pra dizer onde ela começa e termina, precisamos de uma instrução que faça exatamente nada.

Vamos voltar ao nosso teste e importar essa função para que ela possa ser usada nos nossos testes, depois vamos rodar os testes novamente e ver se aquela mensagem de erro mudou.

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_FizzBuzz(self):
self.assertEqual(FizzBuzz(1), 1)

if __name__ == '__main__':
unittest.main()

A linha “from fizzbuzz import FizzBuzz” significa “Importe a classe/função FizzBuzz do arquivo ou módulo chamado fizzbuzz“… isso mesmo, no Python podemos importar apenas parte de um arquivo! :)

E o resultado da execução dos testes é…

$ python fizzbuzz_test.py
E
======================================================================
ERROR: test_FizzBuzz (__main__.TestFizzBuzz)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "fizzbuzz_test.py", line 9, in test_FizzBuzz
    self.assertEqual(FizzBuzz(1), 1)
TypeError: FizzBuzz() takes no arguments (1 given)

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

view raw
gistfile1.sh
This Gist brought to you by GitHub.

E estamos chegando lá… agora o Python reclamou que – segundo sua definição – a função FizzBuzz não recebe parâmetros.. que é justamente o primeiro item da nossa lista, então vamos fazer isso acontecer.

#!/usr/bin/env python

def FizzBuzz(numero):
pass
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

Isso.. tudo beeeeem de vagar, lembre-se dos passos de bebê!

Agora rodamos os testes novamente e…

$ python fizzbuzz_test.py
F
======================================================================
FAIL: test_FizzBuzz (__main__.TestFizzBuzz)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "fizzbuzz_test.py", line 9, in test_FizzBuzz
    self.assertEqual(FizzBuzz(1), 1)
AssertionError: None != 1

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

view raw
gistfile1.sh
This Gist brought to you by GitHub.

Conseguimos! O primeiro item da lista foi resolvido! :D

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”

Mas agora temos outro problema… que é justamente a nossa asserção de “FizzBuzz(1) é 1″ falhando.

Fazendo um teste passar

Agora vem a parte (pra mim) mais importante do TDD:

Sempre que você escrever um teste e ele quebrar, pergunte-se: “Qual o menor passo, a menor mudança no código, que eu posso fazer pra esse teste passar?” Não importa se esse passo é elegante, segue padrões de projeto ou está simplesmente enganando o código… A primeira vez que você faz o teste passar tem a ver com velocidade e simplicidade, boas práticas fica pro momento da refatoração, com todos os testes passando.

A menor mudança que a gente pode fazer pra esse código funcionar, sem pensar nos outros casos de FizzBuzz(n) que ainda não estão testados é:

#!/usr/bin/env python

def FizzBuzz(numero):
return 1
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

Você pode querer me matar depois dessa, mas não estou brincando.. isso é sério, é assim que a coisa funciona! :)

E os testes?

$ python fizzbuzz_test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

view raw
gistfile1.sh
This Gist brought to you by GitHub.

Satisfação! Finalmente, nosso primeiro teste passou!!!

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”

Decidindo o próximo teste

Quando você estiver decidindo o próximo teste, tente seguir as seguintes dicas:

  • Escreva um teste que você SABE não vai passar.. Não adianta ficar testando coisas que já estão passando, né?
  • Mas se você não tem certeza, escreva o teste e veja o que acontece… Testes nunca são demais.
  • Escreva um teste que você ACHA que pode ser resolvido de forma simples, nada de testar o programa todo de uma vez.. o ideal é que você tenha apenas um teste quebrando em cada “rodada”
  • Teste com valores plausíveis e facilmente compreensíveis… testar soma (1, 2) == 3 é muito melhor do que testar soma (12312512312, 31653341265312) = ????, entendeu onde quero chegar?

Então vamos seguir a lista e testar FizzBuzz(2) que deveria retornar 2, e provavelmente não vai passar por causa do nosso roubo (return 1).

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_FizzBuzz_de1(self):
self.assertEqual(FizzBuzz(1), 1)

def test_FizzBuzz_de2(self):
self.assertEqual(FizzBuzz(2), 2)

if __name__ == '__main__':
unittest.main()

Eu poderia fazer a nova asserção dentro do mesmo teste, mas preferi trocar o nome dele e criar um segundo teste, assim as coisas ficam mais claras e você pode ver cada teste falhando separadamente.

$ python fizzbuzz_test.py
.F
======================================================================
FAIL: test_FizzBuzz_de2 (__main__.TestFizzBuzz)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "fizzbuzz_test.py", line 12, in test_FizzBuzz_de2
    self.assertEqual(FizzBuzz(2), 2)
AssertionError: 1 != 2

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=1)

view raw
gistfile1.sh
This Gist brought to you by GitHub.

E com esse teste, concluímos que ao roubar (mesmo valendo pra quele momento) acabamos cuspindo pra cima, e agora o cuspe caiu na nossa cabeça… 2 (esperado) é diferente de 1 (resultado).

Mais uma vez, hora de se perguntar: ”Qual o menor passo, a menor mudança no código, que eu posso fazer pra esse teste passar?“.. e se a função retornar o número que recebeu?

#!/usr/bin/env python

def FizzBuzz(numero):
return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

Feita a mudança, rodamos os testes e…

$ python fizzbuzz_test.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

view raw
gistfile1.sh
This Gist brought to you by GitHub.

Excelente! Nosso segundo teste está passando e, quase sem perceber, refatoramos o código para algo realmente dentro das regras do problema :)

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”

Qual o nosso próximo teste? Vamos seguir a lista e ver no que vai dar… Se entendemos bem o que fizemos até agora, FizzBuzz(3) vai retornar 3 e não “fizz” como manda a especificação do problema (múltiplos de três retornam “fizz”).

Como voltamos na especificação do problema, vamos adicionar mais um item à nossa lista:

  • FizzBuzz(9) retorna “fizz”

Agora vamos ao teste do FizzBuzz(3) retorna “fizz”:

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_FizzBuzz_de1(self):
self.assertEqual(FizzBuzz(1), 1)

def test_FizzBuzz_de2(self):
self.assertEqual(FizzBuzz(2), 2)

def test_FizzBuzz_de3_retorna_fizz(self):
self.assertEqual(FizzBuzz(3), "fizz")

if __name__ == '__main__':
unittest.main()

E o resultado dos testes, como esperado, falhou:

$ python fizzbuzz_test.py
..F
======================================================================
FAIL: test_FizzBuzz_de3_retorna_fizz (__main__.TestFizzBuzz)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "fizzbuzz_test.py", line 15, in test_FizzBuzz_de3_retorna_fizz
    self.assertEqual(FizzBuzz(3), "fizz")
AssertionError: 3 != 'fizz'

----------------------------------------------------------------------
Ran 3 tests in 0.000s

FAILED (failures=1)

view raw
gistfile1.sh
This Gist brought to you by GitHub.

Minha função FizzBuzz ainda não está preparada para retornar fizz, o teste quebrou e nós progredimos em direção a solução de mais um problema… viu como é legal?

Eu sei que você está querendo começar a correr e verificar se numero é múltiplo de três, mas não temos testes pra isso ainda.. temos apenas um teste onde FizzBuzz(3) deveria retornar “fizz”… é esse pequeno passo que vamos dar. TDD também tem a ver com ansiedade, e você precisa aprender a controlar a sua.

#!/usr/bin/env python

def FizzBuzz(numero):
if (numero == 3):
return "fizz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

E os testes passaram! :D

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”
  • FizzBuzz(9) retorna “fizz”

Eu poderia seguir a lista e partir para o FizzBuzz(4) mas ele provavelmente vai passar, mas ao mesmo tempo, entre a dúvida e o teste, fique com o teste:

def test_FizzBuzz_de4(self):
self.assertEqual(FizzBuzz(4), 4)
view raw
gistfile1.py
This Gist brought to you by GitHub.

Ok.. os testes continuam passando, então esse teste não colaborou em nada para o problema.. Vamos dar um pulo e testar nosso caso mais recente:

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_FizzBuzz_de1(self):
self.assertEqual(FizzBuzz(1), 1)

def test_FizzBuzz_de2(self):
self.assertEqual(FizzBuzz(2), 2)

def test_FizzBuzz_de3_retorna_fizz(self):
self.assertEqual(FizzBuzz(3), "fizz")

def test_FizzBuzz_de4(self):
self.assertEqual(FizzBuzz(4), 4)

def test_FizzBuzz_de9_retorna_fizz(self):
self.assertEqual(FizzBuzz(9), "fizz")

if __name__ == '__main__':
unittest.main()

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”
  • FizzBuzz(9) retorna “fizz”

Ok.. os testes quebraram.. mas como vamos resolver o problema?

Sabemos que nosso código ainda tem um “roubo”, podemos fazer outro roubo ou partir para uma refatoração que resolva o FizzBuzz(3) e FizzBuzz(9), como o problema é ridiculamente simples e esse artigo está ficando longo demais, vamos pra segunda opção:

#!/usr/bin/env python

def FizzBuzz(numero):
if not numero % 3:
return "fizz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

E os testes passaram! :)

Vejam que foi uma refatoração bem simples, ao invés de verificar se o número é igual a três, eu verifiquei se não sobrou resto da sua divisão por três, ou seja: se ele é múltiplo de três.

Uma coisa que está me incomodando um pouco são todos os nomes testes, acho que podemos refatorar o teste a grupar casos semelhantes:

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_numeroSimples(self):
self.assertEqual(FizzBuzz(1), 1)
self.assertEqual(FizzBuzz(2), 2)
self.assertEqual(FizzBuzz(4), 4)

def test_numeroMultiploDeTres(self):
self.assertEqual(FizzBuzz(3), "fizz")
self.assertEqual(FizzBuzz(9), "fizz")

if __name__ == '__main__':
unittest.main()

Agora sim! Bem melhor, e continuamos testando a mesma coisa… só que com menos testes e mais asserções por teste.

Nossa lista está quase acabando…

  • FizzBuzz recebe um número
  • FizzBuzz(1) retorna 1
  • FizzBuzz(2) retorna 2
  • FizzBuzz(3) retorna “fizz”
  • FizzBuzz(4) retorna 4
  • FizzBuzz(5) retorna “buzz”
  • FizzBuzz(9) retorna “fizz”

Falta apenas o FizzBuzz(5) mas acho que é hora de revisar o problema e adicionar mais alguns itens à lista:

  • FizzBuzz(5) retorna “buzz”
  • FizzBuzz(10) retorna “buzz”
  • FizzBuzz(15) retorna “fizzbuzz”
  • FizzBuzz(30) retorna “fizzbuzz”

Claro que eu já sei como o problema funciona, mas podemos levantar esses exemplos só de olhar pra descrição do problema lá em cima..

Então vamos partir pro primeiro item da lista: FizzBuzz(5) retorna “buzz”

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_numeroSimples(self):
self.assertEqual(FizzBuzz(1), 1)
self.assertEqual(FizzBuzz(2), 2)
self.assertEqual(FizzBuzz(4), 4)

def test_numeroMultiploDeTres(self):
self.assertEqual(FizzBuzz(3), "fizz")
self.assertEqual(FizzBuzz(9), "fizz")

def test_numeroMultiploDeCinco(self):
self.assertEqual(FizzBuzz(5), "buzz")

if __name__ == '__main__':
unittest.main()

Os testes voltam a quebrar, apenas o último teste falhou pois 5 != “buzz”.

Como ainda não explicitamos a regra do “multiplo de 5″ através de testes, o correto aqui é fazer com que apenas essse teste passe (e não testes futuros):

#!/usr/bin/env python

def FizzBuzz(numero):
if not numero % 3:
return "fizz"

if numero == 5:
return "buzz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

E todos os testes passaram! :D

Agora vamos colocar mais um múltiplo de cinco, como por exemplo FizzBuzz(10) e o teste vai quebrar:

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_numeroSimples(self):
self.assertEqual(FizzBuzz(1), 1)
self.assertEqual(FizzBuzz(2), 2)
self.assertEqual(FizzBuzz(4), 4)

def test_numeroMultiploDeTres(self):
self.assertEqual(FizzBuzz(3), "fizz")
self.assertEqual(FizzBuzz(9), "fizz")

def test_numeroMultiploDeCinco(self):
self.assertEqual(FizzBuzz(5), "buzz")
self.assertEqual(FizzBuzz(10), "buzz")

if __name__ == '__main__':
unittest.main()

Vamos então parar de roubar e fazer o que fizemos com com os múltiplos de três:

#!/usr/bin/env python

def FizzBuzz(numero):
if not numero % 3:
return "fizz"

if not numero % 5:
return "buzz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

E todos os três testes (com as 7 asserções) passaram novamente.

  • FizzBuzz(5) retorna “buzz”
  • FizzBuzz(10) retorna “buzz”
  • FizzBuzz(15) retorna “fizzbuzz”
  • FizzBuzz(30) retorna “fizzbuzz”

Agora vamos atacar a última parte do problema, múltiplos de três e de cinco.

Nada de escrever código, primeiro o teste:

#!/usr/bin/env python

import unittest
from fizzbuzz import FizzBuzz

class TestFizzBuzz(unittest.TestCase):

def test_numeroSimples(self):
self.assertEqual(FizzBuzz(1), 1)
self.assertEqual(FizzBuzz(2), 2)
self.assertEqual(FizzBuzz(4), 4)

def test_Fizz(self):
self.assertEqual(FizzBuzz(3), "fizz")
self.assertEqual(FizzBuzz(9), "fizz")

def test_Buzz(self):
self.assertEqual(FizzBuzz(5), "buzz")
self.assertEqual(FizzBuzz(10), "buzz")

def test_FizzBuzz(self):
self.assertEqual(FizzBuzz(15), "fizzbuzz")

if __name__ == '__main__':
unittest.main()

(Aproveitei também pra mudar o nome dos testes)

Vejam vocês… o teste falhou.. mas diferente do que vimos até agora, não temos “15 != fizzbuzz” mas sim “fizz != fizzbuzz” pois 15 é multiplo de 3, correto?

$ python fizzbuzz_test.py
..F.
======================================================================
FAIL: test_FizzBuzz (__main__.TestFizzBuzz)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "fizzbuzz_test.py", line 22, in test_FizzBuzz
    self.assertEqual(FizzBuzz(15), "fizzbuzz")
AssertionError: 'fizz' != 'fizzbuzz'

----------------------------------------------------------------------
Ran 4 tests in 0.000s

FAILED (failures=1)

view raw
gistfile1.sh
This Gist brought to you by GitHub.

Primeiro roubamos (o que o Kent Beck chama de “implementação óbvia”):

#!/usr/bin/env python

def FizzBuzz(numero):
if numero == 15:
return "fizzbuzz"

if not numero % 3:
return "fizz"

if not numero % 5:
return "buzz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

E todos os testes voltam a passar… Agora adicionamos mais um teste da nossa lista:

  • FizzBuzz(5) retorna “buzz”
  • FizzBuzz(10) retorna “buzz”
  • FizzBuzz(15) retorna “fizzbuzz”
  • FizzBuzz(30) retorna “fizzbuzz”

E fazemos uma implementação simples, que resolva o problema:

#!/usr/bin/env python

def FizzBuzz(numero):
if not numero % 15:
return "fizzbuzz"

if not numero % 3:
return "fizz"

if not numero % 5:
return "buzz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

Agora, que todos os testes estão passando e o problema está resolvido, podemos refatorar nossa função pra algo mais elegante:

#!/usr/bin/env python

def MultiploDeTres(numero):
return not numero % 3

def MultiploDeCinco(numero):
return not numero % 5

def FizzBuzz(numero):
if MultiploDeTres(numero) and MultiploDeCinco(numero):
return "fizzbuzz"

if MultiploDeTres(numero):
return "fizz"

if MultiploDeCinco(numero):
return "buzz"

return numero
view raw
fizzbuzz.py
This Gist brought to you by GitHub.

Não que essa solução seja a mais elegante e mais eficiente em Python, mas acredito que ela deixe a lógica mais clara.

Enfim… TDD é isso!

Espero que vocês tenham gostado. :D

Deixe um comentário

Envio de email via prompt windows 7

Overview

Em certas circunstâncias temos que testar o envio de e-mail via linha de comando de uma forma básica sem utilizar cliente de e-mail, com isto temos mais agilidade nos testes.

Solução

Para o teste de SMTP devemos utilizar somente o telnet que já vem com o Sistema Operacional.

Devemos ir em Start e depois em Run
E digitar cmd e OK
No prompt devemos digitar telnet 25
Devemos digitar Helo andersonpatricio.org (ou seu domínio que está enviando a mensagem)
Em seguida: mail from: anderson@andersonpatricio.org
Depois: rcpt to: anderson@quattuor.com.br, onde é o e-mail que está residente no servidor que estamos testando, no meu exemplo dei um telnet no servidor mail.quattuor.com.br e estou enviando um teste para anderson@quattuor.com.br
Devemos digitar data e depois para podermos escrever o e-mails, para terminar o corpo da mensagem temos que colocar um “.” em uma linha vazia e dar um
O servidor de e-mail irá dizer que a mensagem ficou na fila para entrega (Queued mail for delivery)
Depois é só digitar um quit para fecharmos o teste de e-mail.

Fonte: http://www.andersonpatricio.org/Tutoriais/AP040_b.html

OBS: Para windows 7 é necessario habilitar o recurso em: Painel de Controle > Programas e Recursos > Ativar ou desativar recursos do Windows > Selecionar Cliente Telnet e clicar em OK

 

Bem, tentei dessa forma, mas para conexão com smtp.gmail.com, ele exige autenticação TLS.

Essa autenticação não é possível com telnet nativo, pensei em usar openSSL, mas um arquivo “bat” não conseguiria enviar todas as informações para envio do email.

Então criei uma applicação console em C#. Foi simples e fácil. Só usando o namespace System.Net consegui o que eu queria.

Veja como ficou:

Class Program:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text;
namespace MgSendEmail {
     class Program
     {
         static int Main(string[] args)
         {
             if (args.Length != 7)
             {
                 Console.WriteLine("Informe os 7 argumentos:");
                 Console.WriteLine("emitente senha destinatario assunto mensagem servidor porta");
                 return 1;
             }
             else
             {
                 SendEmail se = new SendEmail();
                 se.MgSendEmail(args[0], args[1], args[0], args[2], args[3], args[4], args[5], Int32.Parse(args[6]));
                 return 0;
             }
         }
     }
 }

 

Class SendEmail

using System;
 using System.Collections.Generic;
 using System.Linq; using System.Text;
 using System.Net.Mail;
namespace MgSendEmail 
{
     class SendEmail
     {
         public void MgSendEmail(string user, string pass,
         string from, string to,
         string subject, string message,
         string server, int port)
         {
             SmtpClient client = new SmtpClient();
             client.Host = server;
             client.Port = port;
             client.EnableSsl = true;
             System.Net.NetworkCredential nc = new System.Net.NetworkCredential(user, pass);
             client.Credentials = nc;
             MailMessage msg = new MailMessage(from, to, subject, message);
             client.Send(msg);
         }
     }
 }

 

Pronto agora criei um bat que chama a aplicação compilada passando os dados.

,

Deixe um comentário

Investimento do governo em TI para inovação

Ótima noticia que recebemos no começo desse mês: http://blog.planalto.gov.br/com-o-programa-ti-maior-governo-vai-investir-r-500-milhoes-para-a-producao-de-software-no-brasil-diz-dilma/

O governo federal vai investir meio bilhão para a produção de software.

Com certeza, se o governo deseja que a produção científica e tecnológica seja valorizada esse é um começo.

Os estudantes precisam se preparar melhor para conseguir inovar de verdade. Temos tudo a nosso favor (pelo menos a grana está vindo, hehe). Vamos por a mão na massa!

Deixe um comentário

Escrever menos código

One of the fundamental truths of software development is that you have to write code, but one of the biggest fallacies is the idea that writing code is your job. When I first started out as a software developer, I fell into that trap, writing code is a powerful thing, its empowering, you feel like you are productive and you are accomplishing things. However, what I have learned over the years is the real truth of the matter. The truth that the job of a software developer is to write as little code as possible.

Now, don’t get me wrong, we should not be getting ourselves into code golf situations where we are compacting code and saving keystrokes to the point where the code you produce is no longer understandable. When you think about it though the fact that most of your time will be maintaining the terrible code you wrote, writing less code and not creating more work for yourself will start to look like an exceptionally good idea.

Why?

Look around, look at your tools, look at the framework you likely use to produce that thing you work on. Everything you do, all the tools you use, everything is trying make you write less code. Your tools are trying to make you less error prone, and abstracting away the things that will cause you trouble down the road.

So why should you write less code? When I said earlier that your job was to write less code, I was fibbing a little bit. Really your job is to think, your job is to think about the problem at hand, devise an elegant solution and then turn that solution into software. One of the byproducts of creating software is that you have to write code to solve problems.

Code is a by-product

Code isn’t that important. We love to convince ourselves that it is because as we actually start executing and turning our solutions into software, it seems like writing code is both a means and an end unto itself. We talk about our editors, we talk about our language of choice and we talk about our environments. I do it, you do it, we all do it. There is no shame in enjoying the craft of the work you do. The trick is to stay focused. Code is awesome, but its also the enemy, it takes time to write, it can be fragile, it can be unclear and not particularly robust.

This is why I stick with the mantra “Write less code”. Whenever I feel like something is getting bigger than it should be or more complicated than it should be, I say “Write less code”. Whenever I write so much code that it gets hard to keep it in context, I refactor, I clean it up, all the while, thinking about “Write less code”.

As much as it pains me to say, sometimes there is no way to get around writing a bunch of code, but if you can’t be concise, be clear. Writing less code is writing clean code. Writing less code is also about writing clear code. When you are economical with the code you write the purpose of your code becomes clear.

So, whats the lesson here? Most importantly I think the lesson here is that code is a by-product, its an unavoidable thing that you generate in the process of doing your job. So think more, refactor more, remove some old code and write less new code, do yourself a favor and start this today.

From: http://mikegrouchy.com/blog/2012/06/write-less-code.html

, , ,

Deixe um comentário

Lançado Projeto Open Source

Foi lançado um novo projeto na rede social GitHub.com.

Mais informações em:

http://newbl0g.wordpress.com/projeto-vendas/

e http://github.com/ptcmariano/Vendas

Estou precisando fazer um sistema de vendas e atualmente estou sem muito tempo, por isso qualquer contribuição será bem vinda.

, ,

Deixe um comentário

Melhoria de processo (externa) melhora?

Sobre: http://blog.aspercom.com.br/2008/05/27/nao-jogue-dinheiro-fora-com-melhoria-de-processos/

A ideia que o Rodrigo deseja passar é que as pessoas que fazem as coisas na empresa, não os processos. Investir no crescimento das pessoas terá resultados melhores do que uma melhoria de processos imposta de alguém que é “supremo” fora da equipe.

As pessoas gostam de aprender, não é necessário ensinar uma criança a perguntar, todas pessoas levanta questões e gosta de ver o resultado. Se bloquear esse processo de questões e resultados, impondo um processo definido que outra pessoa coloca, vai limitar o potencial de crescimento da equipe.

Sugestão é que as empresas liberte as equipes, trazer as pessoas a criar suas questões e deixar as soluções surgir. Cada projeto vai ter um processo, cada interação haverá mudança.

Sei que uma mudança radical na mentalidade não será possível, vou aplicar o conceito de interações integrando novas ideias aos poucos e que estas tragam esse resultado esperado.

, , ,

Deixe um comentário

Seguir

Obtenha todo post novo entregue na sua caixa de entrada.