sábado, 12 de julho de 2014

Purismo vs. Pragmatismo: A definição de Testes como melhor forma de especificação de um sistema

Hoje li (pela segunda vez) esse trecho do livro Object Oriented Software Construction, de Bertrand Meyer (leitura altamente recomendável):

"Em Tecnologia Orientada a Objetos, os objetos descritos por uma classe são definidos apenas pelo que é possível fazer com eles: operações, e propriedades formais dessas operações (os contratos).
(...)
A tradição na modelagem dos sistemas de informação geralmente pressupõe uma "realidade externa" que antecede qualquer programa que a utilize; para um desenvolvedor orientado a objetos, essa noção não tem sentido, pois a realidade não existe independentemente daquilo que se pretende fazer com ela. (Mais precisamente, é irrelevante se ela existe ou não, pois nós só conhecemos aquilo que podemos usar, e o que sabemos a respeito de alguma coisa é definido inteiramente pela forma como podemos usá-la)."

Essa ideia reflete bem duas diferentes posturas com relação à modelagem e ao desenvolvimento de software: uma purista, e a outra pragmática.

A visão purista busca modelar os objetos de forma platônica, em que as propriedades e operações características derivam de sua própria natureza. São os tipos abstratos de que fala Meyer. Objetos que existem na realidade tenderiam a ser modelados em sua completude, e de forma que cada propriedade ou operação computacional fosse a contrapartida de uma propriedade ou operação real.

A outra visão, pragmática, é aquela proposta pelo último parágrafo citado: a definição de uma classe é a definição de suas operações, ou seja, deve ser representado aquilo que é conveniente representar, pois essa é a realidade relevante. Essa visão se mostra aparentemente mais saudável para orientar o desenvolvimento de software, especialmente após algumas leituras sobre Test Drivem Development.

São perspectivas opostas sobre o mesmo tema, como duas faces da mesma moeda: na primeira, aquilo que se pode fazer com o objeto é consequência da definição de sua natureza canônica, que vem primeiro e é tratada como sendo mais importante; na segunda, a declaração das operações possíveis é que de fato acaba por definir o objeto.

A tentativa de esgotar a definição de um objeto a partir de sua natureza intrínseca, independente de suas potenciais aplicações, pode facilmente levar à paralisia por análise (analysis paralysis), que foi um sintoma já observado para algumas classes e propriedades do Modelo de Dados de GPS, tratado em postagens anteriores.

Portanto, o plano daqui por diante, no desenvolvimento do Modelo de Dados de GPS, é inverter - mesmo que temporariamente -  essa abordagem bottom-up na definição de um modelo de domínio e modelo de dados, e passar a utilizar algumas práticas da metodologia agile, as quais seriam principalmente:
  • Desenvolvimento Orientado a Testes (test-driven development, TDD). Nessa metodologia, o teste é definido antes, e a implementação é levada adiante apenas para satisfazer o teste. Assim, temos a descrição do teste como a especificação definitiva do sistema (pois descreve como ele deve se comportar), e o código-fonte como a descrição definitiva do sistema propriamente dito.
  • Desenvolvimento Orientado por Comportamento (behavior-driven development, BDD), uma vertente do TDD, que pode ser equiparado (de forma generosamente relaxada) ao Design Dirigido por Objetivos (goal-directed design, Alan Cooper). Ambas as propostas buscam orientar qualquer desenvolvimento de software à satisfação dos objetivos do usuário. Assim sendo, cada linha de código, cada método, cada classe deve ter sua existência à satisfação de alguma necessidade real do usuário. Para isso, o software deve ter um conjunto de funções, que deriva de um conjunto (lista) de requisitos, que por sua vez deriva (ou deveria derivar) de um conjunto de casos de uso. Esses casos de uso (associados a personas e cenários) são justamente a definição dos testes do BDD.
  • YAGNI: you ain't gonna need it. Implementar somente o que é necessário. Isso se opõe ao anti-pattern "big design up-front", que é o que eu (inspirado, é verdade, na ISO) vinha tentando fazer. Nas palavras de Ron Jeffries: "implemente funcionalidade apenas quando você realmente precisar, e não quando você apenas pensa que vai precisar".
Portanto, o plano é deixar um pouco de lado a super-especificação de implementação, e abordar o lado oposto do desenvolvimento, que são os usuários e as aplicações pretendidas, e ao invés de ter um modelo de implementação exaustivo, ter um sistema que surja simples porém operacional (atendendo a alguma necessidade inicial básica), podendo a partir de então evoluir, ser refatorado, e ser expandido.