Vitor Pamplona
Crônicas de um cotidiano geek

Documentação como Réplica

Postado em Mar 26, 2008 por Vitor Pamplona - Editar - História

Recentemente o Urubatan escreveu um belo post sobre documentação desatualizada usando o Easyb em Java, algo semelhante ao RSpec, famoso no mundo Ruby. Em suma, Urubatan defende a utilização da dita " documentação executável ", evitando documentos específicos, externos ao ambiente de programação, que deveriam esclarescer a maneira como as regras de negócio são implementadas. A motivação disto é que não há sincronismo formal entre este tipo de documento e o código, permitindo que o documento fique desatualizado.

Tanto o RSpec quando o Easyb, trouxeram grandes avanços tecnológicos no sentido de evitar a documentação desatualizada. No entanto, ainda há muito a ser feito. Eu, francamente, acho que ambos criaram uma solução para um problema que não precisa existir. Além da sintaxe de ambos ser um tanto poluída.  

Por exemplo, qual a diferença de fazer isto (Código 1):  

scenario "Um nome de usuário deve ser único no sistema", {
    given "Um usuário com o formulário preenchido corretamente", {
        user = new User('userName','password','password')
        userManager = UserManager.getInstance()
    }
    then "O registro deve criar o usuário no sistema", {
        userManager.create(user)
    }
    when "O nome de usuário ja existe no sistema", {
        user = new User('userName','otherPassword','otherPassword')
    }
    then "O registro do usuário deve falhar",{
        ensureThrows(UserAlreadyExistsException){
            userManager.create(user)
        }
    }
}

para isto (Código 2):

// Um nome de usuário deve ser único no sistema
function testNomeDeUsuárioÚnico() {
// Dado que existe um usuário com o
// formulário preenchido corretamente
user = new User('userName','password','password')
    userManager = UserManager.getInstance()
    // Então o registro deve criar o usuário no sistema
userManager.create(user)

// Se o nome de usuário ja existe no sistema
user = new User('userName','otherPassword','otherPassword')

// O registro do usuário deve falhar
    ensureThrows(UserAlreadyExistsException){
        userManager.create(user)
    }
}

Não sei se vocês perceberam, mas na prática nada muda. É apenas uma sintaxe diferente para escrever a sua documentação. E eu ainda acho mais fácil de ler a versão onde a documentação está nos comentários, pois na versão do Easyb mistura-se inglês e português e caracteres como aspas e chaves atrapalham. Claro, tanto o RSpec quanto o Easyb podem gerar relatórios html contendo somente as Strings de documentação para tornar a leitura mais fácil. Mas, sinceramente, com a documentação na sua frente no código, quem irá ler os documentos html?

Lembrem-se que, tanto no Código 1 quanto no 2, a documentação ainda não está sincronizada automaticamente com o fonte. Ela está apenas no mesmo lugar para que o desenvolvedor se toque de alterar ambas quando alguma mudança for feita.  

Outra. Observem atentamente as strings e os trechos de código que foram gerados a partir dela. O given do Código 1 pede: Um usuário com o formulário preenchido corretamente. Onde está o formulário no código? Pode parecer uma simples questão de interpretação, no entanto, estas divergências este tipo de questionamento pode ser feito por um novato naquele trecho de código e, se ele não entender, de que adiantou a documentação? Lembrem-se que este exemplo ainda é simples, regras de negócio complexas podem tornar a tarefa de interpretar a documentação e encontrar semelhanças no código, muito difícil.  

Uma vantagem da sintaxe do RSpec e do Easyb é que ambos estimulam os desenvolvedores a escreverem uma documentação. É quase uma obrigação. Afinal, ninguém é louco de fazer isso:  

scenario "", {
    given "", {
        user = new User('userName','password','password')
        userManager = UserManager.getInstance()
    }
    then "", {
        userManager.create(user)
    }
    when "", {
        user = new User('userName','otherPassword','otherPassword')
    }
    then "",{
        ensureThrows(UserAlreadyExistsException){
            userManager.create(user)
        }
    }
}

Além disso é possível personalizar a documentação com os parâmetros em tempo de execução. Isto permite gerar uma documentação mais " prática ", com valores e outras informações que podem ser validadas por qualquer um que visualizar os relatórios gerados pelo sistema de teste. Por exemplo, algo como isto (Não sei se a sintaxe é exatamente essa):  

scenario "Um nome de usuário deve ser único no sistema", {
    given "Um usuário com o formulário preenchido corretamente", {
        user = new User('userName','password','password')
        userManager = UserManager.getInstance()
    }
    then "O registro deve criar o usuário ${user.userName} no sistema", {
        userManager.create(user)
    }
    when "O nome de usuário ${user.userName} já existe no sistema", {
        user = new User('userName','otherPassword','otherPassword')
    }
    then "O registro do usuário ${user.userName} deve falhar",{
        ensureThrows(UserAlreadyExistsException){
            userManager.create(user)
        }
    }
}

Apesar da vantagem, a minha maior crítica está no fato do desenvolvedor precisar escrever essa documentação e permitir que ela fique desatualizada que, nada mais é, do que um problema de duplicação de código. Este é um problema amenizado pelas práticas de XP, nas quais o meu código ficaria assim:  

function testNomeDeUsuárioÚnicoNoSistema() {  
user = preencheUsuárioPeloFormulario('userName','password','password');
criarUsuárioNoBanco(user);
user2 = preencheUsuárioPeloFormulario('userName','otherPassword','otherPassword');
   ensureThrows(UserAlreadyExistsException){
criarUsuarioNoBanco(user2);
}
}

Óbvio, mais linhas de código são necessárias, mas evita-se a duplicação. Não estou dizendo que esta é a maneira correta de fazer, muito menos que seja a mais bonita, mas certamente é a mais eficiente na questão de amenizar o problema de desatualização. Este modo XPeiro de ser, ainda mistura inglês e português, fato presente em quase todas as aplicações que eu trabalhei e que, pessoalmente, eu odeio.

Concluindo, os reais benefícios que o Easyb e o RSpec trazem a um projeto são:

  • Geração automática de um html de documentação
  • Um toque psicológico para forçar os desenvolvedores a criarem documentação

Na contra mão, temos:  

  • Uma sintaxe nova e um novo " estilo " de documentar
  • A dificuldade de leitura relacionada a mistura de termos em inglês e português e a caracteres especiais.

Comentários


[...] Por exemplo, qual a diferença de fazer isto (Código 1) [...] para isto (Código 2) [...]
Simples: No primeiro caso, você pode gerar um HTML e mostrar para o cliente apenas o que o interessa, neste caso:
scenario " Um nome de usuário deve ser único no sistema "
given " Um usuário com o formulário preenchido corretamente "
then " O registro deve criar o usuário no sistema "
when " O nome de usuário ja existe no sistema "
then " O registro do usuário deve falhar "

No caso do método do JUnit não tem nada pronto para fazer isso. Esta é a diferença.

- - Antonio Carlos de Souza
Postado em Mar 30, 2008 por 201.51.255.239

Mas isso pode ser gerado a partir de qualquer comentário, num processo semelhante ao Javadoc.

- - Vitor Pamplona
Postado em Mar 30, 2008 por 189.27.241.214

Seu Nome:


Escreva o código existente na figura acima no texto abaixo.