Especificações, código e como mantê-los unidos?
Já faz algum tempo que testes de unidade, ou unitários, tem sido assunto frequente, e as vezes acalorado, em listas de discussões. Apesar de fazer tempo que este assunto é discutido o argumento mais famoso para não adoção da técnica continua sendo o curto prazo dos projetos. Alega-se que se os desenvolvedores começarem a escrever testes, os prazos para realizações das tarefas serão aumentados, o que consequentemente aumentaria o prazo final do projeto.
Aquela velha historia
A maioria dos projetos, tem uma documentação inicial, onde são colocadas as necessidades do cliente. Num projeto tradicional, ou não, esta documentação será entregue aos desenvolvedores para fazer o milgre de transformar texto impresso no papel, em software. Até agora não contei novidade alguma, mas a coisa vai ficar mais interessante a partir de agora.
Os desenvolvedores começam então, a escrever o software baseado nas informações contidas na documentação entregue a eles. Agora imagine que boa parte do software já está implementada e o gerente de proejetos está super feliz em ver o gráfico do project bonitinho, mostrando que o projeto está até adiantado. Quando... acontece o que sempre acontece em projetos de software. Uma grande mudança, uma alteração tão radical que afetará varios pontos do sistema. Vocês já viram este filme, e sabem que numa situação dessas é comum ter que fazer tudo pra ontem e sem prejuizo ao cronograma. O que se traduz em horas extras e trabalho nos finais de semana. O ambiente de trabalho legal para os desenvolvedores costuma acabar neste ponto. Como as alterações são todas urgentes, é muito comum que a equipe concentre forças na alteração do código fonte, enquanto a alteração da documentação fica pra depois. Um depois que geralmente nunca acontece.
TDD e Documentos... onde você quer chegar?
Pronto agora cheguei onde queria =). Comecei falando de TDD e no paragrafo anterior falei de documentação desatualizada. Que relação essas coisas podem ter?
Bem, a documentação incial do projeto, em papel, descreve o que o software deve fazer (comportamento), os métodos das classes escritas pelos desenvolvedores são responsáveis por realizar este comportamento. Em um cenário, como posso dizer, "mais comum" depois do desenvolvedor implementar o software, uma pessoa seria encarregada de testar o comportamento do software, para isso ela precisaria recorrer a documentação do projeto. Mas depois da mudança a documentação vai estar desatualizada o que abre margem para problemas maiores.
Uma maneira de resolver este problema seria automatizando os testes, e neste ponto entram os testes de unidade. Imagine que nossos desenvolvedores escreveram testes de unidade automatizados para checar o compotamento de cada um dos métodos implemetados por eles. Agora não precisarimos de mais uma pessoa para testar, e o mais importante, agora temos uma documentação executável. Isso mesmo pense nos testes de unidade como sendo uma documentação executável, uma documentação que quebra se não for atualizada.
Documentação Executável
Como todos sabem a documentação mais atualizada de um software é o código fonte. O problema é que ele não é "amigavel e legivel" para todos. Pode ser pouco agradavel ter de ficar olhando varios arquivos, classes e métodos para entender o que eles fazem realmente. Na tentativa de melhorar, esse cenário pessoas passaram a utilizar uma técnica para escrita de testes que tenta expressar mais a intenção daquele comportamento. Esta técnica é conhecida como Behaviour Driven Development (BDD), foi um termo cunhado por Dan North mais informações aqui. Mas continua sendo muito código, e fica ainda complicado identificar o que é uma pré-condição, o que realmente está sendo testado é o que é a pós-condição. No JUnit por exemplo, a responsabilidade de descrever o comportamento testado fica no nome do método, que pode ficar quilometrico (nada contra), como por exemplo: deveSerCapazDeCriarUmaListaDePedidosAPartirDoXML.
Na tentativa de tornar os comportamentos mais evidentes, sugriam framework's como RSpec utilizado por desenvolvedores ruby.
Veja abaixo um exemplo de código do RSpec
describe "Uma Conta" it "nao deve permitir saques superiores ao valor de seu saldo" do conta = Conta.new conta.deposita 100 lambda{ conta.saca 200}.should raise_error ArgumentError end
Apesar de ter menos "ruido", muito também devido a linguagem ruby, este código ainda tem muito apelo programático. Fica dificil usar um negocio desses com seu cliente, ou especialista de negocios. Então o bacana mesmo seria escrever especificações/documentação, usando o bom e velho português, e ter algum vodoo que tornasse essa documentação executável.
Sobrecarga e argumentos marotos nos métodos Ruby
Continuando com o assunto de métodos em ruby, vamos falar sobre sobrecarga e argumentos. Para isso imagine um método para fazer uma saudação para alguma pessoa do tipo: Bom Dia Jõao, Boa Tarde Maria, etc...
def seja_educado(saudacao, pessoa) puts "#{saudacao} #{pessoa}" end seja_educado("Bom Dia","Iuri") => Bom Dia Iuri
Essa foi muito fácil! Afinal de contas já sabemos "tudo" sobre criar métodos em ruby.
Então vamos tornar o exemplo mais interessante. Eu quero poder usar o metodo seja_educado das seguintes formas:
seja_educado("Boa Tarde","Joao") => Boa Tarde Joao seja_educado("Joao") => Olá Joao
Uma típica solução seria usar o velho truque do metodo sobrecarregado então vamos tentar.
Idéias sobre encapsulamento, linq e delegates em C#
Atualmente estou trabalhando em projeto .Net. É a primeira vez que utilizo a plataforma profissionalmente e não dá para negar o quanto a .Net está interessante. Estou bastante impressionado com a linguagem C#. Apesar de todos os recursos interesantes da linguagem, tenho percebido que está acontecendo uma espécie de “relaxamento” em relação as boas práticas, principalmente de orientação a objetos. Umas coisas que mais tenho notado é a falta de preocupação com o encapsulamento, principalmente quando se usa delegates e linq.
Neste post vou analisar alguns pontos relacionados a encapsulamento e o uso do Linq.
Vamos começar a analisar um modelo de objetos simples:
