BDD: Requisitos Executáveis

O problema

Não importa se seu background é Agil, Iterativo, Waterfall ou Tradicional. Uma coisa é certa e todos concordamos: Requisitos excelentes combinados a uma arquitetura perfeitamente executada é uma ótima fórmula para o sucesso. Inicialmente, a fórmula parece ser simples. E é! O problema está em sua execução. Como saber se estamos exagerando nos requisitos e no design? Em outras palavras: quão profundos (ou superficiais) os requisitos devem ser para serem o bastante para um encaixe perfeito entre negócio e tecnologia?

A quantidade certa de cada ingrediente nesta fórmula tem assombrado a comunidade de desenvolvimento de software desde os tempos do COBOL até os dias de Internet/Cloud/.Net/Java/Ruby/Python/PHP de hoje. Esse mistério precisa ser desvendado!

Uma solução

Uma solução para este dilema pode ser encontrado em metodologias ágeis. Se fizer esta pergunta para um “agilista” a resposta será, na maioria dos casos: evite BDUF (Big Design Up Front). Faz sentido. Uma das características de requisitos é que eles tem a tendência de mudar. Portanto, se você demorar demais definido seus requisitos e arquitetura, tão logo você esteja pronto para iniciar a codificação, adivinhe o que acontece? Os danandos dos requisitos decidem mudar!

Bem… então temos um bom começo! Evitar BDUF! Mas esta é uma abordagem restritiva, não prescritiva. É ótimo saber o que NÃO fazer. Mas o que DEVEMOS fazer? Bem… mais uma vez os “agilistas” dirão: TDD é o caminho, irmão: vá e comece pelos testes. Novamente, uma grade diretiva, dessa vez bem prescritiva… mas completa? Sinto-me na obrigação de responder: não. Infelizmente, saber que os testes devem ser escritos antes da implementação em si é parte do “caminho para a perfeição”. TDD é fantástico: concordo com todas as minhas forças. Basicamente força o desenvolvedor a escrever código utilizando componentes desacoplados. Se a arquitetura seguir boas práticas comprovadas, design patterns e bom e velho bom senso, melhor ainda. Porém, uma última pergunta perdura: O QUE deve-se testar?

Vejo algumas mãos levantadas na audiência? Ah, sim. O senhor, por favor pode falar:

- Bem, Daniel, é claro! A resposta está nos requisitos. O desenvolvedor deve ler os requisitos, entender a necessidade de negócio e desenhar os testes de acordo com os requisitos.

Muto bem! Excelente sugestão. Mas resta um porém na seguinte combinação de palavras: “entender a necessidade de negócio”. Desenvolvedores são, geralmente, um grupo de indivíduos cartesianos. Vivemos em um mundo de zeros e uns, “Trues” e “Falses”, “ifs” e “elses”. Requisitos de negócio precisam identificar claramente a necessidade do cliente, mas se não forem escritos muito cuidadosamente, a ambiguidade se prolifera e o resultado vai acabar parecendo com o antigo, mas ainda muito verdadeiro desenho do “balanço na árvore”.

Ah, e mais um detalhe: e a rastreabilidade? Qual frase dos paragráfos da especificação clássica de requisitos é rastreável ao código que precisa ser revisado sempre que algo muda? Difícil, não é?

A solução

Mutio bem: diversas abordagens para definir requistos não ambíguos, verificáveis, atingíveis e específicos tem sido o objeto de muitos artigos, metodologias e frameworks. De agora em diante, vou focar em uma metodologia/framework que tem funcionado impressionantemente bem na minha experiência: Behavior Driven Development (ou BDD). O BDD tenta diminuir a distância entre os analistas de requisitos e desenvolvedores especificando uma “linguagem” bem definida. Esta “linguagem” é, ao mesmo tempo, natural e específica. É claramente entendível por stakeholders técnicos e de negócio e descrevem o comportamenteo de um sistema. Por exemplo:

Funcionalidade: Pedidos
  De modo a comprar um item
  Como um cliente
  Eu quer ser capaz de fazer pedidos


Cenário
: Adicionar um item ao carrinho de compras
 
Dado
que eu tenha selecionado um item
 
E
eu tenha informado a sua quantidade
 
Quando
eu pressionar o botão "adicionar ao carrinho"
 
Então
o item deve ser adicionado ao carrinho
 
E o valor total do carrinho deve ser incrementado da quantidade do item multiplicada pelo seu valor


O texto certamente parece ser não ambíguo, verificável, atingível e específico, não é?



E se cada uma destas linhas do cenário se transformasse em um passo específico em um test case N/J/x/Unit, a partir do qual arquitetura e código pudessem ser derivados, a-lá TDD? Não seria fantástico? Este e exatamente o objetivo do BDD.



Próximos passos



Acho que isto já é o bastante para justificar um par de artigos no futuro (próximo) que irá clarificar e exemplificar ainda mais o BDD. Como meu background é em .Net, vou fornecer exemplos em C# usando uma implementação muito bacana de BDD específica de .Net baseada no Cucumber: o Specflow, um projeto open source patrocinado pela TechTalk.

Consumindo RESTful WebServices em C# com WCF e JSON (parte 1/2)

Introdução

Faz realmente muito tempo que não escrevo um artigo sobre desenvolvimento de sistemas mais técnico. Quem me conhece, sabe do meu passado bem próximo de linguagens como Pascal, Delphi, Java e C#. Já escrevi muitos artigos quando trabalhava na Borland, e alguns deles sobre WebServices. WebServices, lembram? Aquela tecnologia super moderna que permite a publicação e consumo de serviços e metadados (WSDL) via Web trafegando pacotes em XML? Pois é… super moderno não?

Na verdade, não. Apesar de se ainda suportar WebServices SOAP por aí, a tendência da Web 2.0 é a de se manter as coisas o mais simples e fáceis possíveis (KISS, entende?). Além disso, com o advento do AJAX e do browser como a plataforma cliente preferida da Web 2.0, o consumo de XMLs passou a ser uma coisa um pouco, por assim dizer, pesada para ser feita em AJAX, que normalmente faz uso de JavaScript.

Este conjunto de novos requisitos tecnológicos fez surgir dois novos “animais” magrinhos para a implementação de serviços via web, que estão rapidamente suplantando os WebServices SOAP convencionais (e gordinhos):

  • WebServices RESTful (versus SOAP-based)
  • JSON (versus XML)

Este é o primeiro de dois artigos que exploram as capacidades do WCF para comunicação com RESTFul WebServices e JSON.

WebServices RESTful

O protocolo SOAP é extremamente rico e cheio de funcionalidades. Via SOAP você consegue descrever objetos e mensagens de forma fortemente tipada, utilizando XML. Contudo, a infraestrutura para suporte a WebServices SOAP é bem pesada e, como já citei, pouco aderente a clientes “leves” como JavaScript rodando em um browser.

Com o objetivo de tornar a invocação de métodos remotos e de troca de dados um processo mais leve, surgiu o conceito de WebServices RESTful. Estes WebServices não seguem um protocolo complexo como o SOAP, mas devem seguir as características REST definidas por Roy T. Fielding. Basicamente, WebServices RESTFul são stateless e acessados a partir de operações HTTP padrão (GET, POST, PUT, DELETE) e retornam qualquer conteúdo (normalmente XML, JSON ou outro mime type).

Outra característica interessante desse tipo de WebServices é a de que a infraestrutura existente de servidores web pode ser utilizada, sem a necessidade de se incluir application servers, gateways, proxies, etc. (contudo, não há proibição de usá-los). O melhor é que servidores web existentes (Apache, IIS, etc.) suportam caching, autenticação, criptografia, etc.  sem grande necessidade de programação ou configuração, o que aumenta a performance e diminui a necessidade de recursos dos serviços.

JSON

Como uma alternativa ao XML, Douglas Crockford criou o JSON, que se tornou um RFC oficial (RFC 4627). A sua sintaxe é bem mais leve que o XML e é facilmente “parseavel” por qualquer linguagem de desenvolvimento. Baseia-se em um subset do JavaScript. Segue um exemplo de um bloco JSON:

  1: {"menu": {
  2:   "id": "file",
  3:   "value": "File",
  4:   "popup": {
  5:     "menuitem": [
  6:       {"value": "New", "onclick": "CreateNewDoc()"},
  7:       {"value": "Open", "onclick": "OpenDoc()"},
  8:       {"value": "Close", "onclick": "CloseDoc()"}
  9:     ]
 10:   }
 11: }}

WCF – Acessando a API do Twitter


Como exemplo de uso de WebServices RESTful com JSON, vou utilizar a api do Twitter, mais especificamente a chamada “statuses/public_timeline”.


Para começar, em seu Visual Studio 2008 ou Visual C# 2008 Express, crie um projeto Console.


Adicione referências aos assemblies abaixo:



  • System.ServiceModel.dll
  • System.ServiceModel.Web.dll

Ótimo! Estamos prontos para definir o contrato de dados


Definido o contrato de dados


Vamos utilizar o atributo DataContract para definir nosso “contrato de dados” com o serviço “statuses/public_timeline” em uma nova classe assim:

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: using System.ServiceModel;
  6: using System.Runtime.Serialization;
  7: 
  8: namespace TwitterClientPlayground
  9: {
 10:     [DataContract]
 11:     public class Status
 12:     {
 13:         [DataMember(Name = "text")]
 14:         public string text {get; set;}
 15: 
 16:         [DataContract]
 17:         public class User
 18:         {
 19:             [DataMember(Name = "screen_name")]
 20:             public string screenName {get; set;}
 21:         }
 22:         [DataMember (Name="user")]
 23:         public User user { get; set; }
 24: 
 25: 
 26:     }
 27: }

Você pode ver acima que a classe é uma classe C# como qualquer outra, com anotações em seus membros. A anotação “DataContract” define que a classe deve ser utilizada como contrato de dados pelo WCF. “DataMember” define membros do contrato de dados.


Uma questão interessante é que quando estamos utilizando uma “nested class”, esta também precisa ser marcada com “DataContract” (ver a classe “User” acima).


Definindo o contrato de serviço


O contrato de serviços é equivalente a um “stub” SOAP criado pelo “Add Web Reference” do IDE. Segue o nosso exemplo abaixo:

  1: using System;
  2: using System.Collections.Generic;
  3: using System.Linq;
  4: using System.Text;
  5: using System.ServiceModel;
  6: using System.ServiceModel.Web;
  7: 
  8: namespace TwitterClientPlayground
  9: {
 10:     [ServiceContract]
 11:     public interface ITwitterClient
 12:     {
 13:         [OperationContract]
 14:         [WebGet(
 15:             ResponseFormat = WebMessageFormat.Json,
 16:             UriTemplate="statuses/public_timeline.json"
 17:             )]
 18:         List<Status> Statuses_PublicTimeLine();
 19:     }
 20: }

O atributo “ServiceContract” define uma interface que irá ser utilizada pelo WCF como contrato de serviços entre o cliente e o servidor. “OperationContract” define uma operação e “WebGet” indica que a operação (método) será equivalente a uma chamada HTTP GET e permite que configuremos detalhes como o formato da resposta em ResponseFormat(no caso, JSON) e o fragmento da URI para acesso ao serviço em UriTemplate. A UriTemplate suporta parâmetros (entre chaves {}), que devem ter o mesmo nome do parâmetro do método sendo anotado, quando a operação do serviço assim o requerer. No caso, “statuses/public_timeline” não aceita parâmetros.


Conclusão


Por enquanto, neste artigo, procurei explicar os conceitos de WebServices RESTful e JSON, bem como a definição de contratos WCF para o consumo deste tipo de WebServices. No próximo artigo, iremos finalmente utilizar os contratos aqui definidos para efetuarmos chamadas ao WebService do Twitter.


Até lá!